[MSI]
[reactos.git] / reactos / dll / win32 / msi / record.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2002-2004 Mike McCormack for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "wine/debug.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "msipriv.h"
33 #include "objidl.h"
34 #include "winnls.h"
35 #include "ole2.h"
36
37 #include "winreg.h"
38 #include "shlwapi.h"
39
40 #include "query.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
43
44 #define MSIFIELD_NULL 0
45 #define MSIFIELD_INT 1
46 #define MSIFIELD_WSTR 3
47 #define MSIFIELD_STREAM 4
48 #define MSIFIELD_INTPTR 5
49
50 static void MSI_FreeField( MSIFIELD *field )
51 {
52 switch( field->type )
53 {
54 case MSIFIELD_NULL:
55 case MSIFIELD_INT:
56 case MSIFIELD_INTPTR:
57 break;
58 case MSIFIELD_WSTR:
59 msi_free( field->u.szwVal);
60 break;
61 case MSIFIELD_STREAM:
62 IStream_Release( field->u.stream );
63 break;
64 default:
65 ERR("Invalid field type %d\n", field->type);
66 }
67 }
68
69 void MSI_CloseRecord( MSIOBJECTHDR *arg )
70 {
71 MSIRECORD *rec = (MSIRECORD *) arg;
72 UINT i;
73
74 for( i=0; i<=rec->count; i++ )
75 MSI_FreeField( &rec->fields[i] );
76 }
77
78 MSIRECORD *MSI_CreateRecord( UINT cParams )
79 {
80 MSIRECORD *rec;
81 UINT len;
82
83 TRACE("%d\n", cParams);
84
85 if( cParams>65535 )
86 return NULL;
87
88 len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
89 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
90 if( rec )
91 rec->count = cParams;
92 return rec;
93 }
94
95 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
96 {
97 MSIRECORD *rec;
98 MSIHANDLE ret = 0;
99
100 TRACE("%d\n", cParams);
101
102 rec = MSI_CreateRecord( cParams );
103 if( rec )
104 {
105 ret = alloc_msihandle( &rec->hdr );
106 msiobj_release( &rec->hdr );
107 }
108 return ret;
109 }
110
111 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
112 {
113 return rec->count;
114 }
115
116 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
117 {
118 MSIRECORD *rec;
119 UINT ret;
120
121 TRACE("%d\n", handle );
122
123 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
124 if( !rec )
125 return -1;
126
127 msiobj_lock( &rec->hdr );
128 ret = MSI_RecordGetFieldCount( rec );
129 msiobj_unlock( &rec->hdr );
130 msiobj_release( &rec->hdr );
131
132 return ret;
133 }
134
135 static BOOL string2intW( LPCWSTR str, int *out )
136 {
137 int x = 0;
138 LPCWSTR p = str;
139
140 if( *p == '-' ) /* skip the minus sign */
141 p++;
142 while ( *p )
143 {
144 if( (*p < '0') || (*p > '9') )
145 return FALSE;
146 x *= 10;
147 x += (*p - '0');
148 p++;
149 }
150
151 if( str[0] == '-' ) /* check if it's negative */
152 x = -x;
153 *out = x;
154
155 return TRUE;
156 }
157
158 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
159 MSIRECORD *out_rec, UINT out_n )
160 {
161 UINT r = ERROR_SUCCESS;
162
163 msiobj_lock( &in_rec->hdr );
164
165 if ( in_n > in_rec->count || out_n > out_rec->count )
166 r = ERROR_FUNCTION_FAILED;
167 else if ( in_rec != out_rec || in_n != out_n )
168 {
169 LPWSTR str;
170 MSIFIELD *in, *out;
171
172 in = &in_rec->fields[in_n];
173 out = &out_rec->fields[out_n];
174
175 switch ( in->type )
176 {
177 case MSIFIELD_NULL:
178 break;
179 case MSIFIELD_INT:
180 out->u.iVal = in->u.iVal;
181 break;
182 case MSIFIELD_INTPTR:
183 out->u.pVal = in->u.pVal;
184 break;
185 case MSIFIELD_WSTR:
186 str = strdupW( in->u.szwVal );
187 if ( !str )
188 r = ERROR_OUTOFMEMORY;
189 else
190 out->u.szwVal = str;
191 break;
192 case MSIFIELD_STREAM:
193 IStream_AddRef( in->u.stream );
194 out->u.stream = in->u.stream;
195 break;
196 default:
197 ERR("invalid field type %d\n", in->type);
198 }
199 if (r == ERROR_SUCCESS)
200 out->type = in->type;
201 }
202
203 msiobj_unlock( &in_rec->hdr );
204
205 return r;
206 }
207
208 INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField )
209 {
210 int ret;
211
212 TRACE( "%p %d\n", rec, iField );
213
214 if( iField > rec->count )
215 return MININT_PTR;
216
217 switch( rec->fields[iField].type )
218 {
219 case MSIFIELD_INT:
220 return rec->fields[iField].u.iVal;
221 case MSIFIELD_INTPTR:
222 return rec->fields[iField].u.pVal;
223 case MSIFIELD_WSTR:
224 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
225 return ret;
226 return MININT_PTR;
227 default:
228 break;
229 }
230
231 return MININT_PTR;
232 }
233
234 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
235 {
236 int ret = 0;
237
238 TRACE("%p %d\n", rec, iField );
239
240 if( iField > rec->count )
241 return MSI_NULL_INTEGER;
242
243 switch( rec->fields[iField].type )
244 {
245 case MSIFIELD_INT:
246 return rec->fields[iField].u.iVal;
247 case MSIFIELD_INTPTR:
248 return rec->fields[iField].u.pVal;
249 case MSIFIELD_WSTR:
250 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
251 return ret;
252 return MSI_NULL_INTEGER;
253 default:
254 break;
255 }
256
257 return MSI_NULL_INTEGER;
258 }
259
260 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
261 {
262 MSIRECORD *rec;
263 UINT ret;
264
265 TRACE("%d %d\n", handle, iField );
266
267 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
268 if( !rec )
269 return MSI_NULL_INTEGER;
270
271 msiobj_lock( &rec->hdr );
272 ret = MSI_RecordGetInteger( rec, iField );
273 msiobj_unlock( &rec->hdr );
274 msiobj_release( &rec->hdr );
275
276 return ret;
277 }
278
279 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
280 {
281 MSIRECORD *rec;
282 UINT i;
283
284 TRACE("%d\n", handle );
285
286 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
287 if( !rec )
288 return ERROR_INVALID_HANDLE;
289
290 msiobj_lock( &rec->hdr );
291 for( i=0; i<=rec->count; i++)
292 {
293 MSI_FreeField( &rec->fields[i] );
294 rec->fields[i].type = MSIFIELD_NULL;
295 rec->fields[i].u.iVal = 0;
296 }
297 msiobj_unlock( &rec->hdr );
298 msiobj_release( &rec->hdr );
299
300 return ERROR_SUCCESS;
301 }
302
303 UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal )
304 {
305 TRACE("%p %u %ld\n", rec, iField, pVal);
306
307 if( iField > rec->count )
308 return ERROR_INVALID_PARAMETER;
309
310 MSI_FreeField( &rec->fields[iField] );
311 rec->fields[iField].type = MSIFIELD_INTPTR;
312 rec->fields[iField].u.pVal = pVal;
313
314 return ERROR_SUCCESS;
315 }
316
317 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
318 {
319 TRACE("%p %u %d\n", rec, iField, iVal);
320
321 if( iField > rec->count )
322 return ERROR_INVALID_PARAMETER;
323
324 MSI_FreeField( &rec->fields[iField] );
325 rec->fields[iField].type = MSIFIELD_INT;
326 rec->fields[iField].u.iVal = iVal;
327
328 return ERROR_SUCCESS;
329 }
330
331 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
332 {
333 MSIRECORD *rec;
334 UINT ret;
335
336 TRACE("%d %u %d\n", handle, iField, iVal);
337
338 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
339 if( !rec )
340 return ERROR_INVALID_HANDLE;
341
342 msiobj_lock( &rec->hdr );
343 ret = MSI_RecordSetInteger( rec, iField, iVal );
344 msiobj_unlock( &rec->hdr );
345 msiobj_release( &rec->hdr );
346 return ret;
347 }
348
349 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
350 {
351 BOOL r = TRUE;
352
353 TRACE("%p %d\n", rec, iField );
354
355 r = ( iField > rec->count ) ||
356 ( rec->fields[iField].type == MSIFIELD_NULL );
357
358 return r;
359 }
360
361 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
362 {
363 MSIRECORD *rec;
364 UINT ret;
365
366 TRACE("%d %d\n", handle, iField );
367
368 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
369 if( !rec )
370 return 0;
371 msiobj_lock( &rec->hdr );
372 ret = MSI_RecordIsNull( rec, iField );
373 msiobj_unlock( &rec->hdr );
374 msiobj_release( &rec->hdr );
375 return ret;
376
377 }
378
379 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
380 LPSTR szValue, LPDWORD pcchValue)
381 {
382 UINT len=0, ret;
383 CHAR buffer[16];
384
385 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
386
387 if( iField > rec->count )
388 {
389 if ( szValue && *pcchValue > 0 )
390 szValue[0] = 0;
391
392 *pcchValue = 0;
393 return ERROR_SUCCESS;
394 }
395
396 ret = ERROR_SUCCESS;
397 switch( rec->fields[iField].type )
398 {
399 case MSIFIELD_INT:
400 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
401 len = lstrlenA( buffer );
402 if (szValue)
403 lstrcpynA(szValue, buffer, *pcchValue);
404 break;
405 case MSIFIELD_WSTR:
406 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
407 NULL, 0 , NULL, NULL);
408 if (szValue)
409 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
410 szValue, *pcchValue, NULL, NULL);
411 if( szValue && *pcchValue && len>*pcchValue )
412 szValue[*pcchValue-1] = 0;
413 if( len )
414 len--;
415 break;
416 case MSIFIELD_NULL:
417 if( szValue && *pcchValue > 0 )
418 szValue[0] = 0;
419 break;
420 default:
421 ret = ERROR_INVALID_PARAMETER;
422 break;
423 }
424
425 if( szValue && *pcchValue <= len )
426 ret = ERROR_MORE_DATA;
427 *pcchValue = len;
428
429 return ret;
430 }
431
432 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
433 LPSTR szValue, LPDWORD pcchValue)
434 {
435 MSIRECORD *rec;
436 UINT ret;
437
438 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
439
440 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
441 if( !rec )
442 return ERROR_INVALID_HANDLE;
443 msiobj_lock( &rec->hdr );
444 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
445 msiobj_unlock( &rec->hdr );
446 msiobj_release( &rec->hdr );
447 return ret;
448 }
449
450 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
451 {
452 if( iField > rec->count )
453 return NULL;
454
455 if( rec->fields[iField].type != MSIFIELD_WSTR )
456 return NULL;
457
458 return rec->fields[iField].u.szwVal;
459 }
460
461 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
462 LPWSTR szValue, LPDWORD pcchValue)
463 {
464 UINT len=0, ret;
465 WCHAR buffer[16];
466 static const WCHAR szFormat[] = { '%','d',0 };
467
468 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
469
470 if( iField > rec->count )
471 {
472 if ( szValue && *pcchValue > 0 )
473 szValue[0] = 0;
474
475 *pcchValue = 0;
476 return ERROR_SUCCESS;
477 }
478
479 ret = ERROR_SUCCESS;
480 switch( rec->fields[iField].type )
481 {
482 case MSIFIELD_INT:
483 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
484 len = lstrlenW( buffer );
485 if (szValue)
486 lstrcpynW(szValue, buffer, *pcchValue);
487 break;
488 case MSIFIELD_WSTR:
489 len = lstrlenW( rec->fields[iField].u.szwVal );
490 if (szValue)
491 lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
492 break;
493 case MSIFIELD_NULL:
494 if( szValue && *pcchValue > 0 )
495 szValue[0] = 0;
496 default:
497 break;
498 }
499
500 if( szValue && *pcchValue <= len )
501 ret = ERROR_MORE_DATA;
502 *pcchValue = len;
503
504 return ret;
505 }
506
507 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
508 LPWSTR szValue, LPDWORD pcchValue)
509 {
510 MSIRECORD *rec;
511 UINT ret;
512
513 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
514
515 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
516 if( !rec )
517 return ERROR_INVALID_HANDLE;
518
519 msiobj_lock( &rec->hdr );
520 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
521 msiobj_unlock( &rec->hdr );
522 msiobj_release( &rec->hdr );
523 return ret;
524 }
525
526 static UINT msi_get_stream_size( IStream *stm )
527 {
528 STATSTG stat;
529 HRESULT r;
530
531 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
532 if( FAILED(r) )
533 return 0;
534 return stat.cbSize.QuadPart;
535 }
536
537 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
538 {
539 TRACE("%p %d\n", rec, iField);
540
541 if( iField > rec->count )
542 return 0;
543
544 switch( rec->fields[iField].type )
545 {
546 case MSIFIELD_INT:
547 return sizeof (INT);
548 case MSIFIELD_WSTR:
549 return lstrlenW( rec->fields[iField].u.szwVal );
550 case MSIFIELD_NULL:
551 break;
552 case MSIFIELD_STREAM:
553 return msi_get_stream_size( rec->fields[iField].u.stream );
554 }
555 return 0;
556 }
557
558 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
559 {
560 MSIRECORD *rec;
561 UINT ret;
562
563 TRACE("%d %d\n", handle, iField);
564
565 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
566 if( !rec )
567 return 0;
568 msiobj_lock( &rec->hdr );
569 ret = MSI_RecordDataSize( rec, iField);
570 msiobj_unlock( &rec->hdr );
571 msiobj_release( &rec->hdr );
572 return ret;
573 }
574
575 static UINT MSI_RecordSetStringA( MSIRECORD *rec, UINT iField, LPCSTR szValue )
576 {
577 LPWSTR str;
578
579 TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
580
581 if( iField > rec->count )
582 return ERROR_INVALID_FIELD;
583
584 MSI_FreeField( &rec->fields[iField] );
585 if( szValue && szValue[0] )
586 {
587 str = strdupAtoW( szValue );
588 rec->fields[iField].type = MSIFIELD_WSTR;
589 rec->fields[iField].u.szwVal = str;
590 }
591 else
592 {
593 rec->fields[iField].type = MSIFIELD_NULL;
594 rec->fields[iField].u.szwVal = NULL;
595 }
596
597 return 0;
598 }
599
600 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
601 {
602 MSIRECORD *rec;
603 UINT ret;
604
605 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
606
607 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
608 if( !rec )
609 return ERROR_INVALID_HANDLE;
610 msiobj_lock( &rec->hdr );
611 ret = MSI_RecordSetStringA( rec, iField, szValue );
612 msiobj_unlock( &rec->hdr );
613 msiobj_release( &rec->hdr );
614 return ret;
615 }
616
617 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
618 {
619 LPWSTR str;
620
621 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
622
623 if( iField > rec->count )
624 return ERROR_INVALID_FIELD;
625
626 MSI_FreeField( &rec->fields[iField] );
627
628 if( szValue && szValue[0] )
629 {
630 str = strdupW( szValue );
631 rec->fields[iField].type = MSIFIELD_WSTR;
632 rec->fields[iField].u.szwVal = str;
633 }
634 else
635 {
636 rec->fields[iField].type = MSIFIELD_NULL;
637 rec->fields[iField].u.szwVal = NULL;
638 }
639
640 return 0;
641 }
642
643 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
644 {
645 MSIRECORD *rec;
646 UINT ret;
647
648 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
649
650 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
651 if( !rec )
652 return ERROR_INVALID_HANDLE;
653
654 msiobj_lock( &rec->hdr );
655 ret = MSI_RecordSetStringW( rec, iField, szValue );
656 msiobj_unlock( &rec->hdr );
657 msiobj_release( &rec->hdr );
658 return ret;
659 }
660
661 /* read the data in a file into an IStream */
662 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
663 {
664 DWORD sz, szHighWord = 0, read;
665 HANDLE handle;
666 HGLOBAL hGlob = 0;
667 HRESULT hr;
668 ULARGE_INTEGER ulSize;
669
670 TRACE("reading %s\n", debugstr_w(szFile));
671
672 /* read the file into memory */
673 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
674 if( handle == INVALID_HANDLE_VALUE )
675 return GetLastError();
676 sz = GetFileSize(handle, &szHighWord);
677 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
678 {
679 hGlob = GlobalAlloc(GMEM_FIXED, sz);
680 if( hGlob )
681 {
682 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);
683 if( !r )
684 {
685 GlobalFree(hGlob);
686 hGlob = 0;
687 }
688 }
689 }
690 CloseHandle(handle);
691 if( !hGlob )
692 return ERROR_FUNCTION_FAILED;
693
694 /* make a stream out of it, and set the correct file size */
695 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
696 if( FAILED( hr ) )
697 {
698 GlobalFree(hGlob);
699 return ERROR_FUNCTION_FAILED;
700 }
701
702 /* set the correct size - CreateStreamOnHGlobal screws it up */
703 ulSize.QuadPart = sz;
704 IStream_SetSize(*pstm, ulSize);
705
706 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
707
708 return ERROR_SUCCESS;
709 }
710
711 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
712 {
713 if ( (iField == 0) || (iField > rec->count) )
714 return ERROR_INVALID_PARAMETER;
715
716 MSI_FreeField( &rec->fields[iField] );
717 rec->fields[iField].type = MSIFIELD_STREAM;
718 rec->fields[iField].u.stream = stream;
719
720 return ERROR_SUCCESS;
721 }
722
723 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
724 {
725 IStream *stm = NULL;
726 HRESULT r;
727
728 if( (iField == 0) || (iField > rec->count) )
729 return ERROR_INVALID_PARAMETER;
730
731 /* no filename means we should seek back to the start of the stream */
732 if( !szFilename )
733 {
734 LARGE_INTEGER ofs;
735 ULARGE_INTEGER cur;
736
737 if( rec->fields[iField].type != MSIFIELD_STREAM )
738 return ERROR_INVALID_FIELD;
739
740 stm = rec->fields[iField].u.stream;
741 if( !stm )
742 return ERROR_INVALID_FIELD;
743
744 ofs.QuadPart = 0;
745 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
746 if( FAILED( r ) )
747 return ERROR_FUNCTION_FAILED;
748 }
749 else
750 {
751 /* read the file into a stream and save the stream in the record */
752 r = RECORD_StreamFromFile(szFilename, &stm);
753 if( r != ERROR_SUCCESS )
754 return r;
755
756 /* if all's good, store it in the record */
757 MSI_RecordSetStream(rec, iField, stm);
758 }
759
760 return ERROR_SUCCESS;
761 }
762
763 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
764 {
765 LPWSTR wstr = NULL;
766 UINT ret;
767
768 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
769
770 if( szFilename )
771 {
772 wstr = strdupAtoW( szFilename );
773 if( !wstr )
774 return ERROR_OUTOFMEMORY;
775 }
776 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
777 msi_free(wstr);
778
779 return ret;
780 }
781
782 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
783 {
784 MSIRECORD *rec;
785 UINT ret;
786
787 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
788
789 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
790 if( !rec )
791 return ERROR_INVALID_HANDLE;
792
793 msiobj_lock( &rec->hdr );
794 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
795 msiobj_unlock( &rec->hdr );
796 msiobj_release( &rec->hdr );
797 return ret;
798 }
799
800 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
801 {
802 ULONG count;
803 HRESULT r;
804 IStream *stm;
805
806 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
807
808 if( !sz )
809 return ERROR_INVALID_PARAMETER;
810
811 if( iField > rec->count)
812 return ERROR_INVALID_PARAMETER;
813
814 if ( rec->fields[iField].type == MSIFIELD_NULL )
815 {
816 *sz = 0;
817 return ERROR_INVALID_DATA;
818 }
819
820 if( rec->fields[iField].type != MSIFIELD_STREAM )
821 return ERROR_INVALID_DATATYPE;
822
823 stm = rec->fields[iField].u.stream;
824 if( !stm )
825 return ERROR_INVALID_PARAMETER;
826
827 /* if there's no buffer pointer, calculate the length to the end */
828 if( !buf )
829 {
830 LARGE_INTEGER ofs;
831 ULARGE_INTEGER end, cur;
832
833 ofs.QuadPart = cur.QuadPart = 0;
834 end.QuadPart = 0;
835 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
836 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
837 ofs.QuadPart = cur.QuadPart;
838 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
839 *sz = end.QuadPart - cur.QuadPart;
840
841 return ERROR_SUCCESS;
842 }
843
844 /* read the data */
845 count = 0;
846 r = IStream_Read( stm, buf, *sz, &count );
847 if( FAILED( r ) )
848 {
849 *sz = 0;
850 return ERROR_FUNCTION_FAILED;
851 }
852
853 *sz = count;
854
855 return ERROR_SUCCESS;
856 }
857
858 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
859 {
860 MSIRECORD *rec;
861 UINT ret;
862
863 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
864
865 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
866 if( !rec )
867 return ERROR_INVALID_HANDLE;
868 msiobj_lock( &rec->hdr );
869 ret = MSI_RecordReadStream( rec, iField, buf, sz );
870 msiobj_unlock( &rec->hdr );
871 msiobj_release( &rec->hdr );
872 return ret;
873 }
874
875 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
876 {
877 TRACE("%p %d %p\n", rec, iField, stm);
878
879 if( iField > rec->count )
880 return ERROR_INVALID_FIELD;
881
882 MSI_FreeField( &rec->fields[iField] );
883
884 rec->fields[iField].type = MSIFIELD_STREAM;
885 rec->fields[iField].u.stream = stm;
886 IStream_AddRef( stm );
887
888 return ERROR_SUCCESS;
889 }
890
891 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
892 {
893 TRACE("%p %d %p\n", rec, iField, pstm);
894
895 if( iField > rec->count )
896 return ERROR_INVALID_FIELD;
897
898 if( rec->fields[iField].type != MSIFIELD_STREAM )
899 return ERROR_INVALID_FIELD;
900
901 *pstm = rec->fields[iField].u.stream;
902 IStream_AddRef( *pstm );
903
904 return ERROR_SUCCESS;
905 }
906
907 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
908 {
909 ULARGE_INTEGER size;
910 LARGE_INTEGER pos;
911 IStream *out;
912 DWORD stgm;
913 HRESULT r;
914
915 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
916 r = SHCreateStreamOnFileW( name, stgm, &out );
917 if( FAILED( r ) )
918 return ERROR_FUNCTION_FAILED;
919
920 pos.QuadPart = 0;
921 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
922 if( FAILED( r ) )
923 goto end;
924
925 pos.QuadPart = 0;
926 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
927 if( FAILED( r ) )
928 goto end;
929
930 r = IStream_CopyTo( stm, out, size, NULL, NULL );
931
932 end:
933 IStream_Release( out );
934 if( FAILED( r ) )
935 return ERROR_FUNCTION_FAILED;
936 return ERROR_SUCCESS;
937 }
938
939 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
940 {
941 IStream *stm = NULL;
942 UINT r;
943
944 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
945
946 msiobj_lock( &rec->hdr );
947
948 r = MSI_RecordGetIStream( rec, iField, &stm );
949 if( r == ERROR_SUCCESS )
950 {
951 r = msi_dump_stream_to_file( stm, name );
952 IStream_Release( stm );
953 }
954
955 msiobj_unlock( &rec->hdr );
956
957 return r;
958 }
959
960 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
961 {
962 MSIRECORD *clone;
963 UINT r, i, count;
964
965 count = MSI_RecordGetFieldCount(rec);
966 clone = MSI_CreateRecord(count);
967 if (!clone)
968 return NULL;
969
970 for (i = 0; i <= count; i++)
971 {
972 if (rec->fields[i].type == MSIFIELD_STREAM)
973 {
974 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
975 &clone->fields[i].u.stream)))
976 {
977 msiobj_release(&clone->hdr);
978 return NULL;
979 }
980 clone->fields[i].type = MSIFIELD_STREAM;
981 }
982 else
983 {
984 r = MSI_RecordCopyField(rec, i, clone, i);
985 if (r != ERROR_SUCCESS)
986 {
987 msiobj_release(&clone->hdr);
988 return NULL;
989 }
990 }
991 }
992
993 return clone;
994 }
995
996 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
997 {
998 UINT i;
999
1000 if (a->count != b->count)
1001 return FALSE;
1002
1003 for (i = 0; i <= a->count; i++)
1004 {
1005 if (a->fields[i].type != b->fields[i].type)
1006 return FALSE;
1007
1008 switch (a->fields[i].type)
1009 {
1010 case MSIFIELD_NULL:
1011 break;
1012
1013 case MSIFIELD_INT:
1014 if (a->fields[i].u.iVal != b->fields[i].u.iVal)
1015 return FALSE;
1016 break;
1017
1018 case MSIFIELD_WSTR:
1019 if (lstrcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
1020 return FALSE;
1021 break;
1022
1023 case MSIFIELD_STREAM:
1024 default:
1025 return FALSE;
1026 }
1027 }
1028
1029 return TRUE;
1030 }