msi: Include the terminating null in the buffer size for decoded stream names.
[wine/wine-gecko.git] / dlls / msi / record.c
blob88d94a9da1d60ad77e529bd97f0604e24a743841
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 "wine/unicode.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "objidl.h"
35 #include "winnls.h"
36 #include "ole2.h"
38 #include "winreg.h"
39 #include "shlwapi.h"
41 #include "query.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
45 #define MSIFIELD_NULL 0
46 #define MSIFIELD_INT 1
47 #define MSIFIELD_WSTR 3
48 #define MSIFIELD_STREAM 4
49 #define MSIFIELD_INTPTR 5
51 static void MSI_FreeField( MSIFIELD *field )
53 switch( field->type )
55 case MSIFIELD_NULL:
56 case MSIFIELD_INT:
57 case MSIFIELD_INTPTR:
58 break;
59 case MSIFIELD_WSTR:
60 msi_free( field->u.szwVal);
61 break;
62 case MSIFIELD_STREAM:
63 IStream_Release( field->u.stream );
64 break;
65 default:
66 ERR("Invalid field type %d\n", field->type);
70 void MSI_CloseRecord( MSIOBJECTHDR *arg )
72 MSIRECORD *rec = (MSIRECORD *) arg;
73 UINT i;
75 for( i=0; i<=rec->count; i++ )
76 MSI_FreeField( &rec->fields[i] );
79 MSIRECORD *MSI_CreateRecord( UINT cParams )
81 MSIRECORD *rec;
83 TRACE("%d\n", cParams);
85 if( cParams>65535 )
86 return NULL;
88 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]),
89 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 WCHAR *msi_strdupW( const WCHAR *value, int len )
160 WCHAR *ret;
162 if (!value) return NULL;
163 if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
164 memcpy( ret, value, len * sizeof(WCHAR) );
165 ret[len] = 0;
166 return ret;
169 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
170 MSIRECORD *out_rec, UINT out_n )
172 UINT r = ERROR_SUCCESS;
174 msiobj_lock( &in_rec->hdr );
176 if ( in_n > in_rec->count || out_n > out_rec->count )
177 r = ERROR_FUNCTION_FAILED;
178 else if ( in_rec != out_rec || in_n != out_n )
180 LPWSTR str;
181 MSIFIELD *in, *out;
183 in = &in_rec->fields[in_n];
184 out = &out_rec->fields[out_n];
186 switch ( in->type )
188 case MSIFIELD_NULL:
189 break;
190 case MSIFIELD_INT:
191 out->u.iVal = in->u.iVal;
192 break;
193 case MSIFIELD_INTPTR:
194 out->u.pVal = in->u.pVal;
195 break;
196 case MSIFIELD_WSTR:
197 if ((str = msi_strdupW( in->u.szwVal, in->len )))
199 out->u.szwVal = str;
200 out->len = in->len;
202 else r = ERROR_OUTOFMEMORY;
203 break;
204 case MSIFIELD_STREAM:
205 IStream_AddRef( in->u.stream );
206 out->u.stream = in->u.stream;
207 break;
208 default:
209 ERR("invalid field type %d\n", in->type);
211 if (r == ERROR_SUCCESS)
212 out->type = in->type;
215 msiobj_unlock( &in_rec->hdr );
216 return r;
219 INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField )
221 int ret;
223 TRACE( "%p %d\n", rec, iField );
225 if( iField > rec->count )
226 return MININT_PTR;
228 switch( rec->fields[iField].type )
230 case MSIFIELD_INT:
231 return rec->fields[iField].u.iVal;
232 case MSIFIELD_INTPTR:
233 return rec->fields[iField].u.pVal;
234 case MSIFIELD_WSTR:
235 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
236 return ret;
237 return MININT_PTR;
238 default:
239 break;
242 return MININT_PTR;
245 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
247 int ret = 0;
249 TRACE("%p %d\n", rec, iField );
251 if( iField > rec->count )
252 return MSI_NULL_INTEGER;
254 switch( rec->fields[iField].type )
256 case MSIFIELD_INT:
257 return rec->fields[iField].u.iVal;
258 case MSIFIELD_INTPTR:
259 return rec->fields[iField].u.pVal;
260 case MSIFIELD_WSTR:
261 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
262 return ret;
263 return MSI_NULL_INTEGER;
264 default:
265 break;
268 return MSI_NULL_INTEGER;
271 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
273 MSIRECORD *rec;
274 UINT ret;
276 TRACE("%d %d\n", handle, iField );
278 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
279 if( !rec )
280 return MSI_NULL_INTEGER;
282 msiobj_lock( &rec->hdr );
283 ret = MSI_RecordGetInteger( rec, iField );
284 msiobj_unlock( &rec->hdr );
285 msiobj_release( &rec->hdr );
287 return ret;
290 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
292 MSIRECORD *rec;
293 UINT i;
295 TRACE("%d\n", handle );
297 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
298 if( !rec )
299 return ERROR_INVALID_HANDLE;
301 msiobj_lock( &rec->hdr );
302 for( i=0; i<=rec->count; i++)
304 MSI_FreeField( &rec->fields[i] );
305 rec->fields[i].type = MSIFIELD_NULL;
306 rec->fields[i].u.iVal = 0;
308 msiobj_unlock( &rec->hdr );
309 msiobj_release( &rec->hdr );
311 return ERROR_SUCCESS;
314 UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal )
316 TRACE("%p %u %ld\n", rec, iField, pVal);
318 if( iField > rec->count )
319 return ERROR_INVALID_PARAMETER;
321 MSI_FreeField( &rec->fields[iField] );
322 rec->fields[iField].type = MSIFIELD_INTPTR;
323 rec->fields[iField].u.pVal = pVal;
325 return ERROR_SUCCESS;
328 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
330 TRACE("%p %u %d\n", rec, iField, iVal);
332 if( iField > rec->count )
333 return ERROR_INVALID_PARAMETER;
335 MSI_FreeField( &rec->fields[iField] );
336 rec->fields[iField].type = MSIFIELD_INT;
337 rec->fields[iField].u.iVal = iVal;
339 return ERROR_SUCCESS;
342 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
344 MSIRECORD *rec;
345 UINT ret;
347 TRACE("%d %u %d\n", handle, iField, iVal);
349 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
350 if( !rec )
351 return ERROR_INVALID_HANDLE;
353 msiobj_lock( &rec->hdr );
354 ret = MSI_RecordSetInteger( rec, iField, iVal );
355 msiobj_unlock( &rec->hdr );
356 msiobj_release( &rec->hdr );
357 return ret;
360 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
362 BOOL r = TRUE;
364 TRACE("%p %d\n", rec, iField );
366 r = ( iField > rec->count ) ||
367 ( rec->fields[iField].type == MSIFIELD_NULL );
369 return r;
372 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
374 MSIRECORD *rec;
375 UINT ret;
377 TRACE("%d %d\n", handle, iField );
379 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
380 if( !rec )
381 return FALSE;
382 msiobj_lock( &rec->hdr );
383 ret = MSI_RecordIsNull( rec, iField );
384 msiobj_unlock( &rec->hdr );
385 msiobj_release( &rec->hdr );
386 return ret;
390 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
391 LPSTR szValue, LPDWORD pcchValue)
393 UINT len = 0, ret = ERROR_SUCCESS;
394 CHAR buffer[16];
396 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
398 if( iField > rec->count )
400 if ( szValue && *pcchValue > 0 )
401 szValue[0] = 0;
403 *pcchValue = 0;
404 return ERROR_SUCCESS;
407 switch( rec->fields[iField].type )
409 case MSIFIELD_INT:
410 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
411 len = lstrlenA( buffer );
412 if (szValue)
413 lstrcpynA(szValue, buffer, *pcchValue);
414 break;
415 case MSIFIELD_WSTR:
416 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
417 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
418 if (szValue)
419 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
420 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
421 if( szValue && *pcchValue && len>*pcchValue )
422 szValue[*pcchValue-1] = 0;
423 if( len )
424 len--;
425 break;
426 case MSIFIELD_NULL:
427 if( szValue && *pcchValue > 0 )
428 szValue[0] = 0;
429 break;
430 default:
431 ret = ERROR_INVALID_PARAMETER;
432 break;
435 if( szValue && *pcchValue <= len )
436 ret = ERROR_MORE_DATA;
437 *pcchValue = len;
439 return ret;
442 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
443 LPSTR szValue, LPDWORD pcchValue)
445 MSIRECORD *rec;
446 UINT ret;
448 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
450 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
451 if( !rec )
452 return ERROR_INVALID_HANDLE;
453 msiobj_lock( &rec->hdr );
454 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
455 msiobj_unlock( &rec->hdr );
456 msiobj_release( &rec->hdr );
457 return ret;
460 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
462 if (field > rec->count)
463 return NULL;
465 if (rec->fields[field].type != MSIFIELD_WSTR)
466 return NULL;
468 if (len) *len = rec->fields[field].len;
470 return rec->fields[field].u.szwVal;
473 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
475 return msi_record_get_string( rec, iField, NULL );
478 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
479 LPWSTR szValue, LPDWORD pcchValue)
481 static const WCHAR szFormat[] = {'%','d',0};
482 UINT len = 0, ret = ERROR_SUCCESS;
483 WCHAR buffer[16];
485 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
487 if( iField > rec->count )
489 if ( szValue && *pcchValue > 0 )
490 szValue[0] = 0;
492 *pcchValue = 0;
493 return ERROR_SUCCESS;
496 switch( rec->fields[iField].type )
498 case MSIFIELD_INT:
499 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
500 len = lstrlenW( buffer );
501 if (szValue)
502 lstrcpynW(szValue, buffer, *pcchValue);
503 break;
504 case MSIFIELD_WSTR:
505 len = rec->fields[iField].len;
506 if (szValue)
507 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
508 break;
509 case MSIFIELD_NULL:
510 if( szValue && *pcchValue > 0 )
511 szValue[0] = 0;
512 break;
513 default:
514 break;
517 if( szValue && *pcchValue <= len )
518 ret = ERROR_MORE_DATA;
519 *pcchValue = len;
521 return ret;
524 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
525 LPWSTR szValue, LPDWORD pcchValue)
527 MSIRECORD *rec;
528 UINT ret;
530 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
532 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
533 if( !rec )
534 return ERROR_INVALID_HANDLE;
536 msiobj_lock( &rec->hdr );
537 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
538 msiobj_unlock( &rec->hdr );
539 msiobj_release( &rec->hdr );
540 return ret;
543 static UINT msi_get_stream_size( IStream *stm )
545 STATSTG stat;
546 HRESULT r;
548 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
549 if( FAILED(r) )
550 return 0;
551 return stat.cbSize.QuadPart;
554 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
556 TRACE("%p %d\n", rec, iField);
558 if( iField > rec->count )
559 return 0;
561 switch( rec->fields[iField].type )
563 case MSIFIELD_INT:
564 return sizeof (INT);
565 case MSIFIELD_WSTR:
566 return rec->fields[iField].len;
567 case MSIFIELD_NULL:
568 break;
569 case MSIFIELD_STREAM:
570 return msi_get_stream_size( rec->fields[iField].u.stream );
572 return 0;
575 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
577 MSIRECORD *rec;
578 UINT ret;
580 TRACE("%d %d\n", handle, iField);
582 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
583 if( !rec )
584 return 0;
585 msiobj_lock( &rec->hdr );
586 ret = MSI_RecordDataSize( rec, iField);
587 msiobj_unlock( &rec->hdr );
588 msiobj_release( &rec->hdr );
589 return ret;
592 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
594 WCHAR *valueW = NULL;
595 MSIRECORD *rec;
596 UINT ret;
598 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
600 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
602 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
603 if( !rec )
605 msi_free( valueW );
606 return ERROR_INVALID_HANDLE;
608 msiobj_lock( &rec->hdr );
609 ret = MSI_RecordSetStringW( rec, iField, valueW );
610 msiobj_unlock( &rec->hdr );
611 msiobj_release( &rec->hdr );
612 msi_free( valueW );
613 return ret;
616 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
618 if (field > rec->count)
619 return ERROR_INVALID_FIELD;
621 MSI_FreeField( &rec->fields[field] );
623 if (value && len < 0) len = strlenW( value );
625 if (value && len)
627 rec->fields[field].type = MSIFIELD_WSTR;
628 rec->fields[field].u.szwVal = msi_strdupW( value, len );
629 rec->fields[field].len = len;
631 else
633 rec->fields[field].type = MSIFIELD_NULL;
634 rec->fields[field].u.szwVal = NULL;
635 rec->fields[field].len = 0;
637 return 0;
640 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
642 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
644 return msi_record_set_string( rec, iField, szValue, -1 );
647 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
649 MSIRECORD *rec;
650 UINT ret;
652 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
654 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
655 if( !rec )
656 return ERROR_INVALID_HANDLE;
658 msiobj_lock( &rec->hdr );
659 ret = MSI_RecordSetStringW( rec, iField, szValue );
660 msiobj_unlock( &rec->hdr );
661 msiobj_release( &rec->hdr );
662 return ret;
665 /* read the data in a file into an IStream */
666 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
668 DWORD sz, szHighWord = 0, read;
669 HANDLE handle;
670 HGLOBAL hGlob = 0;
671 HRESULT hr;
672 ULARGE_INTEGER ulSize;
674 TRACE("reading %s\n", debugstr_w(szFile));
676 /* read the file into memory */
677 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
678 if( handle == INVALID_HANDLE_VALUE )
679 return GetLastError();
680 sz = GetFileSize(handle, &szHighWord);
681 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
683 hGlob = GlobalAlloc(GMEM_FIXED, sz);
684 if( hGlob )
686 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
687 if( !r )
689 GlobalFree(hGlob);
690 hGlob = 0;
694 CloseHandle(handle);
695 if( !hGlob )
696 return ERROR_FUNCTION_FAILED;
698 /* make a stream out of it, and set the correct file size */
699 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
700 if( FAILED( hr ) )
702 GlobalFree(hGlob);
703 return ERROR_FUNCTION_FAILED;
706 /* set the correct size - CreateStreamOnHGlobal screws it up */
707 ulSize.QuadPart = sz;
708 IStream_SetSize(*pstm, ulSize);
710 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
712 return ERROR_SUCCESS;
715 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
717 if ( (iField == 0) || (iField > rec->count) )
718 return ERROR_INVALID_PARAMETER;
720 MSI_FreeField( &rec->fields[iField] );
721 rec->fields[iField].type = MSIFIELD_STREAM;
722 rec->fields[iField].u.stream = stream;
724 return ERROR_SUCCESS;
727 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
729 IStream *stm = NULL;
730 HRESULT r;
732 if( (iField == 0) || (iField > rec->count) )
733 return ERROR_INVALID_PARAMETER;
735 /* no filename means we should seek back to the start of the stream */
736 if( !szFilename )
738 LARGE_INTEGER ofs;
739 ULARGE_INTEGER cur;
741 if( rec->fields[iField].type != MSIFIELD_STREAM )
742 return ERROR_INVALID_FIELD;
744 stm = rec->fields[iField].u.stream;
745 if( !stm )
746 return ERROR_INVALID_FIELD;
748 ofs.QuadPart = 0;
749 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
750 if( FAILED( r ) )
751 return ERROR_FUNCTION_FAILED;
753 else
755 /* read the file into a stream and save the stream in the record */
756 r = RECORD_StreamFromFile(szFilename, &stm);
757 if( r != ERROR_SUCCESS )
758 return r;
760 /* if all's good, store it in the record */
761 MSI_RecordSetStream(rec, iField, stm);
764 return ERROR_SUCCESS;
767 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
769 LPWSTR wstr = NULL;
770 UINT ret;
772 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
774 if( szFilename )
776 wstr = strdupAtoW( szFilename );
777 if( !wstr )
778 return ERROR_OUTOFMEMORY;
780 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
781 msi_free(wstr);
783 return ret;
786 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
788 MSIRECORD *rec;
789 UINT ret;
791 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
793 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
794 if( !rec )
795 return ERROR_INVALID_HANDLE;
797 msiobj_lock( &rec->hdr );
798 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
799 msiobj_unlock( &rec->hdr );
800 msiobj_release( &rec->hdr );
801 return ret;
804 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
806 ULONG count;
807 HRESULT r;
808 IStream *stm;
810 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
812 if( !sz )
813 return ERROR_INVALID_PARAMETER;
815 if( iField > rec->count)
816 return ERROR_INVALID_PARAMETER;
818 if ( rec->fields[iField].type == MSIFIELD_NULL )
820 *sz = 0;
821 return ERROR_INVALID_DATA;
824 if( rec->fields[iField].type != MSIFIELD_STREAM )
825 return ERROR_INVALID_DATATYPE;
827 stm = rec->fields[iField].u.stream;
828 if( !stm )
829 return ERROR_INVALID_PARAMETER;
831 /* if there's no buffer pointer, calculate the length to the end */
832 if( !buf )
834 LARGE_INTEGER ofs;
835 ULARGE_INTEGER end, cur;
837 ofs.QuadPart = cur.QuadPart = 0;
838 end.QuadPart = 0;
839 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
840 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
841 ofs.QuadPart = cur.QuadPart;
842 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
843 *sz = end.QuadPart - cur.QuadPart;
845 return ERROR_SUCCESS;
848 /* read the data */
849 count = 0;
850 r = IStream_Read( stm, buf, *sz, &count );
851 if( FAILED( r ) )
853 *sz = 0;
854 return ERROR_FUNCTION_FAILED;
857 *sz = count;
859 return ERROR_SUCCESS;
862 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
864 MSIRECORD *rec;
865 UINT ret;
867 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
869 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
870 if( !rec )
871 return ERROR_INVALID_HANDLE;
872 msiobj_lock( &rec->hdr );
873 ret = MSI_RecordReadStream( rec, iField, buf, sz );
874 msiobj_unlock( &rec->hdr );
875 msiobj_release( &rec->hdr );
876 return ret;
879 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
881 TRACE("%p %d %p\n", rec, iField, stm);
883 if( iField > rec->count )
884 return ERROR_INVALID_FIELD;
886 MSI_FreeField( &rec->fields[iField] );
888 rec->fields[iField].type = MSIFIELD_STREAM;
889 rec->fields[iField].u.stream = stm;
890 IStream_AddRef( stm );
892 return ERROR_SUCCESS;
895 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
897 TRACE("%p %d %p\n", rec, iField, pstm);
899 if( iField > rec->count )
900 return ERROR_INVALID_FIELD;
902 if( rec->fields[iField].type != MSIFIELD_STREAM )
903 return ERROR_INVALID_FIELD;
905 *pstm = rec->fields[iField].u.stream;
906 IStream_AddRef( *pstm );
908 return ERROR_SUCCESS;
911 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
913 ULARGE_INTEGER size;
914 LARGE_INTEGER pos;
915 IStream *out;
916 DWORD stgm;
917 HRESULT r;
919 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
920 r = SHCreateStreamOnFileW( name, stgm, &out );
921 if( FAILED( r ) )
922 return ERROR_FUNCTION_FAILED;
924 pos.QuadPart = 0;
925 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
926 if( FAILED( r ) )
927 goto end;
929 pos.QuadPart = 0;
930 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
931 if( FAILED( r ) )
932 goto end;
934 r = IStream_CopyTo( stm, out, size, NULL, NULL );
936 end:
937 IStream_Release( out );
938 if( FAILED( r ) )
939 return ERROR_FUNCTION_FAILED;
940 return ERROR_SUCCESS;
943 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
945 IStream *stm = NULL;
946 UINT r;
948 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
950 msiobj_lock( &rec->hdr );
952 r = MSI_RecordGetIStream( rec, iField, &stm );
953 if( r == ERROR_SUCCESS )
955 r = msi_dump_stream_to_file( stm, name );
956 IStream_Release( stm );
959 msiobj_unlock( &rec->hdr );
961 return r;
964 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
966 MSIRECORD *clone;
967 UINT r, i, count;
969 count = MSI_RecordGetFieldCount(rec);
970 clone = MSI_CreateRecord(count);
971 if (!clone)
972 return NULL;
974 for (i = 0; i <= count; i++)
976 if (rec->fields[i].type == MSIFIELD_STREAM)
978 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
979 &clone->fields[i].u.stream)))
981 msiobj_release(&clone->hdr);
982 return NULL;
984 clone->fields[i].type = MSIFIELD_STREAM;
986 else
988 r = MSI_RecordCopyField(rec, i, clone, i);
989 if (r != ERROR_SUCCESS)
991 msiobj_release(&clone->hdr);
992 return NULL;
997 return clone;
1000 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
1002 if (a->fields[field].type != b->fields[field].type)
1003 return FALSE;
1005 switch (a->fields[field].type)
1007 case MSIFIELD_NULL:
1008 break;
1010 case MSIFIELD_INT:
1011 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
1012 return FALSE;
1013 break;
1015 case MSIFIELD_WSTR:
1016 if (a->fields[field].len != b->fields[field].len) return FALSE;
1017 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
1018 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
1019 break;
1021 case MSIFIELD_STREAM:
1022 default:
1023 return FALSE;
1025 return TRUE;
1029 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
1031 UINT i;
1033 if (a->count != b->count)
1034 return FALSE;
1036 for (i = 0; i <= a->count; i++)
1038 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1039 return FALSE;
1042 return TRUE;
1045 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1047 DWORD sz = 0;
1048 WCHAR *str;
1049 UINT r;
1051 if (MSI_RecordIsNull( rec, field )) return NULL;
1053 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1054 if (r != ERROR_SUCCESS)
1055 return NULL;
1057 sz++;
1058 str = msi_alloc( sz * sizeof(WCHAR) );
1059 if (!str) return NULL;
1060 str[0] = 0;
1061 r = MSI_RecordGetStringW( rec, field, str, &sz );
1062 if (r != ERROR_SUCCESS)
1064 ERR("failed to get string!\n");
1065 msi_free( str );
1066 return NULL;
1068 return str;