strmbase: Implement BaseFilter in strmbase.
[wine/multimedia.git] / dlls / msi / record.c
blob7bc82814b2e414d6cf8cf0570fc35d57798edf34
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2004 Mike McCormack for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
23 #define COBJMACROS
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"
37 #include "winreg.h"
38 #include "shlwapi.h"
40 #include "query.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
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
50 static void MSI_FreeField( MSIFIELD *field )
52 switch( field->type )
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);
69 void MSI_CloseRecord( MSIOBJECTHDR *arg )
71 MSIRECORD *rec = (MSIRECORD *) arg;
72 UINT i;
74 for( i=0; i<=rec->count; i++ )
75 MSI_FreeField( &rec->fields[i] );
78 MSIRECORD *MSI_CreateRecord( UINT cParams )
80 MSIRECORD *rec;
81 UINT len;
83 TRACE("%d\n", cParams);
85 if( cParams>65535 )
86 return NULL;
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;
95 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
97 MSIRECORD *rec;
98 MSIHANDLE ret = 0;
100 TRACE("%d\n", cParams);
102 rec = MSI_CreateRecord( cParams );
103 if( rec )
105 ret = alloc_msihandle( &rec->hdr );
106 msiobj_release( &rec->hdr );
108 return ret;
111 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
113 return rec->count;
116 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
118 MSIRECORD *rec;
119 UINT ret;
121 TRACE("%d\n", handle );
123 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
124 if( !rec )
125 return -1;
127 msiobj_lock( &rec->hdr );
128 ret = MSI_RecordGetFieldCount( rec );
129 msiobj_unlock( &rec->hdr );
130 msiobj_release( &rec->hdr );
132 return ret;
135 static BOOL string2intW( LPCWSTR str, int *out )
137 int x = 0;
138 LPCWSTR p = str;
140 if( *p == '-' ) /* skip the minus sign */
141 p++;
142 while ( *p )
144 if( (*p < '0') || (*p > '9') )
145 return FALSE;
146 x *= 10;
147 x += (*p - '0');
148 p++;
151 if( str[0] == '-' ) /* check if it's negative */
152 x = -x;
153 *out = x;
155 return TRUE;
158 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
159 MSIRECORD *out_rec, UINT out_n )
161 UINT r = ERROR_SUCCESS;
163 msiobj_lock( &in_rec->hdr );
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 )
169 LPWSTR str;
170 MSIFIELD *in, *out;
172 in = &in_rec->fields[in_n];
173 out = &out_rec->fields[out_n];
175 switch ( in->type )
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);
199 if (r == ERROR_SUCCESS)
200 out->type = in->type;
203 msiobj_unlock( &in_rec->hdr );
205 return r;
208 INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField )
210 int ret;
212 TRACE( "%p %d\n", rec, iField );
214 if( iField > rec->count )
215 return MININT_PTR;
217 switch( rec->fields[iField].type )
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;
231 return MININT_PTR;
234 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
236 int ret = 0;
238 TRACE("%p %d\n", rec, iField );
240 if( iField > rec->count )
241 return MSI_NULL_INTEGER;
243 switch( rec->fields[iField].type )
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;
257 return MSI_NULL_INTEGER;
260 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
262 MSIRECORD *rec;
263 UINT ret;
265 TRACE("%d %d\n", handle, iField );
267 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
268 if( !rec )
269 return MSI_NULL_INTEGER;
271 msiobj_lock( &rec->hdr );
272 ret = MSI_RecordGetInteger( rec, iField );
273 msiobj_unlock( &rec->hdr );
274 msiobj_release( &rec->hdr );
276 return ret;
279 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
281 MSIRECORD *rec;
282 UINT i;
284 TRACE("%d\n", handle );
286 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
287 if( !rec )
288 return ERROR_INVALID_HANDLE;
290 msiobj_lock( &rec->hdr );
291 for( i=0; i<=rec->count; i++)
293 MSI_FreeField( &rec->fields[i] );
294 rec->fields[i].type = MSIFIELD_NULL;
295 rec->fields[i].u.iVal = 0;
297 msiobj_unlock( &rec->hdr );
298 msiobj_release( &rec->hdr );
300 return ERROR_SUCCESS;
303 UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal )
305 TRACE("%p %u %ld\n", rec, iField, pVal);
307 if( iField > rec->count )
308 return ERROR_INVALID_PARAMETER;
310 MSI_FreeField( &rec->fields[iField] );
311 rec->fields[iField].type = MSIFIELD_INTPTR;
312 rec->fields[iField].u.pVal = pVal;
314 return ERROR_SUCCESS;
317 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
319 TRACE("%p %u %d\n", rec, iField, iVal);
321 if( iField > rec->count )
322 return ERROR_INVALID_PARAMETER;
324 MSI_FreeField( &rec->fields[iField] );
325 rec->fields[iField].type = MSIFIELD_INT;
326 rec->fields[iField].u.iVal = iVal;
328 return ERROR_SUCCESS;
331 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
333 MSIRECORD *rec;
334 UINT ret;
336 TRACE("%d %u %d\n", handle, iField, iVal);
338 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
339 if( !rec )
340 return ERROR_INVALID_HANDLE;
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;
349 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
351 BOOL r = TRUE;
353 TRACE("%p %d\n", rec, iField );
355 r = ( iField > rec->count ) ||
356 ( rec->fields[iField].type == MSIFIELD_NULL );
358 return r;
361 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
363 MSIRECORD *rec;
364 UINT ret;
366 TRACE("%d %d\n", handle, iField );
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;
379 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
380 LPSTR szValue, LPDWORD pcchValue)
382 UINT len=0, ret;
383 CHAR buffer[16];
385 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
387 if( iField > rec->count )
389 if ( szValue && *pcchValue > 0 )
390 szValue[0] = 0;
392 *pcchValue = 0;
393 return ERROR_SUCCESS;
396 ret = ERROR_SUCCESS;
397 switch( rec->fields[iField].type )
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;
425 if( szValue && *pcchValue <= len )
426 ret = ERROR_MORE_DATA;
427 *pcchValue = len;
429 return ret;
432 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
433 LPSTR szValue, LPDWORD pcchValue)
435 MSIRECORD *rec;
436 UINT ret;
438 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
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;
450 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
452 if( iField > rec->count )
453 return NULL;
455 if( rec->fields[iField].type != MSIFIELD_WSTR )
456 return NULL;
458 return rec->fields[iField].u.szwVal;
461 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
462 LPWSTR szValue, LPDWORD pcchValue)
464 UINT len=0, ret;
465 WCHAR buffer[16];
466 static const WCHAR szFormat[] = { '%','d',0 };
468 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
470 if( iField > rec->count )
472 if ( szValue && *pcchValue > 0 )
473 szValue[0] = 0;
475 *pcchValue = 0;
476 return ERROR_SUCCESS;
479 ret = ERROR_SUCCESS;
480 switch( rec->fields[iField].type )
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;
500 if( szValue && *pcchValue <= len )
501 ret = ERROR_MORE_DATA;
502 *pcchValue = len;
504 return ret;
507 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
508 LPWSTR szValue, LPDWORD pcchValue)
510 MSIRECORD *rec;
511 UINT ret;
513 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
515 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
516 if( !rec )
517 return ERROR_INVALID_HANDLE;
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;
526 static UINT msi_get_stream_size( IStream *stm )
528 STATSTG stat;
529 HRESULT r;
531 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
532 if( FAILED(r) )
533 return 0;
534 return stat.cbSize.QuadPart;
537 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
539 TRACE("%p %d\n", rec, iField);
541 if( iField > rec->count )
542 return 0;
544 switch( rec->fields[iField].type )
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 );
555 return 0;
558 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
560 MSIRECORD *rec;
561 UINT ret;
563 TRACE("%d %d\n", handle, iField);
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;
575 static UINT MSI_RecordSetStringA( MSIRECORD *rec, UINT iField, LPCSTR szValue )
577 LPWSTR str;
579 TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
581 if( iField > rec->count )
582 return ERROR_INVALID_FIELD;
584 MSI_FreeField( &rec->fields[iField] );
585 if( szValue && szValue[0] )
587 str = strdupAtoW( szValue );
588 rec->fields[iField].type = MSIFIELD_WSTR;
589 rec->fields[iField].u.szwVal = str;
591 else
593 rec->fields[iField].type = MSIFIELD_NULL;
594 rec->fields[iField].u.szwVal = NULL;
597 return 0;
600 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
602 MSIRECORD *rec;
603 UINT ret;
605 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
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;
617 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
619 LPWSTR str;
621 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
623 if( iField > rec->count )
624 return ERROR_INVALID_FIELD;
626 MSI_FreeField( &rec->fields[iField] );
628 if( szValue && szValue[0] )
630 str = strdupW( szValue );
631 rec->fields[iField].type = MSIFIELD_WSTR;
632 rec->fields[iField].u.szwVal = str;
634 else
636 rec->fields[iField].type = MSIFIELD_NULL;
637 rec->fields[iField].u.szwVal = NULL;
640 return 0;
643 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
645 MSIRECORD *rec;
646 UINT ret;
648 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
650 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
651 if( !rec )
652 return ERROR_INVALID_HANDLE;
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;
661 /* read the data in a file into an IStream */
662 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
664 DWORD sz, szHighWord = 0, read;
665 HANDLE handle;
666 HGLOBAL hGlob = 0;
667 HRESULT hr;
668 ULARGE_INTEGER ulSize;
670 TRACE("reading %s\n", debugstr_w(szFile));
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 )
679 hGlob = GlobalAlloc(GMEM_FIXED, sz);
680 if( hGlob )
682 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);
683 if( !r )
685 GlobalFree(hGlob);
686 hGlob = 0;
690 CloseHandle(handle);
691 if( !hGlob )
692 return ERROR_FUNCTION_FAILED;
694 /* make a stream out of it, and set the correct file size */
695 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
696 if( FAILED( hr ) )
698 GlobalFree(hGlob);
699 return ERROR_FUNCTION_FAILED;
702 /* set the correct size - CreateStreamOnHGlobal screws it up */
703 ulSize.QuadPart = sz;
704 IStream_SetSize(*pstm, ulSize);
706 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
708 return ERROR_SUCCESS;
711 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
713 if ( (iField == 0) || (iField > rec->count) )
714 return ERROR_INVALID_PARAMETER;
716 MSI_FreeField( &rec->fields[iField] );
717 rec->fields[iField].type = MSIFIELD_STREAM;
718 rec->fields[iField].u.stream = stream;
720 return ERROR_SUCCESS;
723 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
725 IStream *stm = NULL;
726 HRESULT r;
728 if( (iField == 0) || (iField > rec->count) )
729 return ERROR_INVALID_PARAMETER;
731 /* no filename means we should seek back to the start of the stream */
732 if( !szFilename )
734 LARGE_INTEGER ofs;
735 ULARGE_INTEGER cur;
737 if( rec->fields[iField].type != MSIFIELD_STREAM )
738 return ERROR_INVALID_FIELD;
740 stm = rec->fields[iField].u.stream;
741 if( !stm )
742 return ERROR_INVALID_FIELD;
744 ofs.QuadPart = 0;
745 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
746 if( FAILED( r ) )
747 return ERROR_FUNCTION_FAILED;
749 else
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;
756 /* if all's good, store it in the record */
757 MSI_RecordSetStream(rec, iField, stm);
760 return ERROR_SUCCESS;
763 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
765 LPWSTR wstr = NULL;
766 UINT ret;
768 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
770 if( szFilename )
772 wstr = strdupAtoW( szFilename );
773 if( !wstr )
774 return ERROR_OUTOFMEMORY;
776 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
777 msi_free(wstr);
779 return ret;
782 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
784 MSIRECORD *rec;
785 UINT ret;
787 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
789 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
790 if( !rec )
791 return ERROR_INVALID_HANDLE;
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;
800 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
802 ULONG count;
803 HRESULT r;
804 IStream *stm;
806 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
808 if( !sz )
809 return ERROR_INVALID_PARAMETER;
811 if( iField > rec->count)
812 return ERROR_INVALID_PARAMETER;
814 if ( rec->fields[iField].type == MSIFIELD_NULL )
816 *sz = 0;
817 return ERROR_INVALID_DATA;
820 if( rec->fields[iField].type != MSIFIELD_STREAM )
821 return ERROR_INVALID_DATATYPE;
823 stm = rec->fields[iField].u.stream;
824 if( !stm )
825 return ERROR_INVALID_PARAMETER;
827 /* if there's no buffer pointer, calculate the length to the end */
828 if( !buf )
830 LARGE_INTEGER ofs;
831 ULARGE_INTEGER end, cur;
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;
841 return ERROR_SUCCESS;
844 /* read the data */
845 count = 0;
846 r = IStream_Read( stm, buf, *sz, &count );
847 if( FAILED( r ) )
849 *sz = 0;
850 return ERROR_FUNCTION_FAILED;
853 *sz = count;
855 return ERROR_SUCCESS;
858 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
860 MSIRECORD *rec;
861 UINT ret;
863 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
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;
875 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
877 TRACE("%p %d %p\n", rec, iField, stm);
879 if( iField > rec->count )
880 return ERROR_INVALID_FIELD;
882 MSI_FreeField( &rec->fields[iField] );
884 rec->fields[iField].type = MSIFIELD_STREAM;
885 rec->fields[iField].u.stream = stm;
886 IStream_AddRef( stm );
888 return ERROR_SUCCESS;
891 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
893 TRACE("%p %d %p\n", rec, iField, pstm);
895 if( iField > rec->count )
896 return ERROR_INVALID_FIELD;
898 if( rec->fields[iField].type != MSIFIELD_STREAM )
899 return ERROR_INVALID_FIELD;
901 *pstm = rec->fields[iField].u.stream;
902 IStream_AddRef( *pstm );
904 return ERROR_SUCCESS;
907 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
909 ULARGE_INTEGER size;
910 LARGE_INTEGER pos;
911 IStream *out;
912 DWORD stgm;
913 HRESULT r;
915 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
916 r = SHCreateStreamOnFileW( name, stgm, &out );
917 if( FAILED( r ) )
918 return ERROR_FUNCTION_FAILED;
920 pos.QuadPart = 0;
921 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
922 if( FAILED( r ) )
923 goto end;
925 pos.QuadPart = 0;
926 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
927 if( FAILED( r ) )
928 goto end;
930 r = IStream_CopyTo( stm, out, size, NULL, NULL );
932 end:
933 IStream_Release( out );
934 if( FAILED( r ) )
935 return ERROR_FUNCTION_FAILED;
936 return ERROR_SUCCESS;
939 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
941 IStream *stm = NULL;
942 UINT r;
944 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
946 msiobj_lock( &rec->hdr );
948 r = MSI_RecordGetIStream( rec, iField, &stm );
949 if( r == ERROR_SUCCESS )
951 r = msi_dump_stream_to_file( stm, name );
952 IStream_Release( stm );
955 msiobj_unlock( &rec->hdr );
957 return r;
960 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
962 MSIRECORD *clone;
963 UINT r, i, count;
965 count = MSI_RecordGetFieldCount(rec);
966 clone = MSI_CreateRecord(count);
967 if (!clone)
968 return NULL;
970 for (i = 0; i <= count; i++)
972 if (rec->fields[i].type == MSIFIELD_STREAM)
974 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
975 &clone->fields[i].u.stream)))
977 msiobj_release(&clone->hdr);
978 return NULL;
980 clone->fields[i].type = MSIFIELD_STREAM;
982 else
984 r = MSI_RecordCopyField(rec, i, clone, i);
985 if (r != ERROR_SUCCESS)
987 msiobj_release(&clone->hdr);
988 return NULL;
993 return clone;
996 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
998 UINT i;
1000 if (a->count != b->count)
1001 return FALSE;
1003 for (i = 0; i <= a->count; i++)
1005 if (a->fields[i].type != b->fields[i].type)
1006 return FALSE;
1008 switch (a->fields[i].type)
1010 case MSIFIELD_NULL:
1011 break;
1013 case MSIFIELD_INT:
1014 if (a->fields[i].u.iVal != b->fields[i].u.iVal)
1015 return FALSE;
1016 break;
1018 case MSIFIELD_WSTR:
1019 if (lstrcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
1020 return FALSE;
1021 break;
1023 case MSIFIELD_STREAM:
1024 default:
1025 return FALSE;
1029 return TRUE;