winemaker: Remove trailing semicolon from PreprocessorDefinitions.
[wine.git] / dlls / msi / record.c
blobde45191786cf0412e4afc797490e5511d56d37b8
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] );
337 if (iVal == MSI_NULL_INTEGER)
339 rec->fields[iField].type = MSIFIELD_NULL;
340 rec->fields[iField].u.szwVal = NULL;
342 else
344 rec->fields[iField].type = MSIFIELD_INT;
345 rec->fields[iField].u.iVal = iVal;
348 return ERROR_SUCCESS;
351 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
353 MSIRECORD *rec;
354 UINT ret;
356 TRACE("%d %u %d\n", handle, iField, iVal);
358 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
359 if( !rec )
360 return ERROR_INVALID_HANDLE;
362 msiobj_lock( &rec->hdr );
363 ret = MSI_RecordSetInteger( rec, iField, iVal );
364 msiobj_unlock( &rec->hdr );
365 msiobj_release( &rec->hdr );
366 return ret;
369 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
371 BOOL r = TRUE;
373 TRACE("%p %d\n", rec, iField );
375 r = ( iField > rec->count ) ||
376 ( rec->fields[iField].type == MSIFIELD_NULL );
378 return r;
381 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
383 MSIRECORD *rec;
384 UINT ret;
386 TRACE("%d %d\n", handle, iField );
388 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
389 if( !rec )
390 return FALSE;
391 msiobj_lock( &rec->hdr );
392 ret = MSI_RecordIsNull( rec, iField );
393 msiobj_unlock( &rec->hdr );
394 msiobj_release( &rec->hdr );
395 return ret;
399 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
400 LPSTR szValue, LPDWORD pcchValue)
402 UINT len = 0, ret = ERROR_SUCCESS;
403 CHAR buffer[16];
405 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
407 if( iField > rec->count )
409 if ( szValue && *pcchValue > 0 )
410 szValue[0] = 0;
412 *pcchValue = 0;
413 return ERROR_SUCCESS;
416 switch( rec->fields[iField].type )
418 case MSIFIELD_INT:
419 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
420 len = lstrlenA( buffer );
421 if (szValue)
422 lstrcpynA(szValue, buffer, *pcchValue);
423 break;
424 case MSIFIELD_WSTR:
425 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
426 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
427 if (szValue)
428 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
429 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
430 if( szValue && *pcchValue && len>*pcchValue )
431 szValue[*pcchValue-1] = 0;
432 if( len )
433 len--;
434 break;
435 case MSIFIELD_NULL:
436 if( szValue && *pcchValue > 0 )
437 szValue[0] = 0;
438 break;
439 default:
440 ret = ERROR_INVALID_PARAMETER;
441 break;
444 if( szValue && *pcchValue <= len )
445 ret = ERROR_MORE_DATA;
446 *pcchValue = len;
448 return ret;
451 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
452 LPSTR szValue, LPDWORD pcchValue)
454 MSIRECORD *rec;
455 UINT ret;
457 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
459 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
460 if( !rec )
461 return ERROR_INVALID_HANDLE;
462 msiobj_lock( &rec->hdr );
463 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
464 msiobj_unlock( &rec->hdr );
465 msiobj_release( &rec->hdr );
466 return ret;
469 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
471 if (field > rec->count)
472 return NULL;
474 if (rec->fields[field].type != MSIFIELD_WSTR)
475 return NULL;
477 if (len) *len = rec->fields[field].len;
479 return rec->fields[field].u.szwVal;
482 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
484 return msi_record_get_string( rec, iField, NULL );
487 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
488 LPWSTR szValue, LPDWORD pcchValue)
490 static const WCHAR szFormat[] = {'%','d',0};
491 UINT len = 0, ret = ERROR_SUCCESS;
492 WCHAR buffer[16];
494 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
496 if( iField > rec->count )
498 if ( szValue && *pcchValue > 0 )
499 szValue[0] = 0;
501 *pcchValue = 0;
502 return ERROR_SUCCESS;
505 switch( rec->fields[iField].type )
507 case MSIFIELD_INT:
508 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
509 len = lstrlenW( buffer );
510 if (szValue)
511 lstrcpynW(szValue, buffer, *pcchValue);
512 break;
513 case MSIFIELD_WSTR:
514 len = rec->fields[iField].len;
515 if (szValue)
516 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
517 break;
518 case MSIFIELD_NULL:
519 if( szValue && *pcchValue > 0 )
520 szValue[0] = 0;
521 break;
522 default:
523 break;
526 if( szValue && *pcchValue <= len )
527 ret = ERROR_MORE_DATA;
528 *pcchValue = len;
530 return ret;
533 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
534 LPWSTR szValue, LPDWORD pcchValue)
536 MSIRECORD *rec;
537 UINT ret;
539 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
541 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
542 if( !rec )
543 return ERROR_INVALID_HANDLE;
545 msiobj_lock( &rec->hdr );
546 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
547 msiobj_unlock( &rec->hdr );
548 msiobj_release( &rec->hdr );
549 return ret;
552 static UINT msi_get_stream_size( IStream *stm )
554 STATSTG stat;
555 HRESULT r;
557 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
558 if( FAILED(r) )
559 return 0;
560 return stat.cbSize.QuadPart;
563 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
565 TRACE("%p %d\n", rec, iField);
567 if( iField > rec->count )
568 return 0;
570 switch( rec->fields[iField].type )
572 case MSIFIELD_INT:
573 return sizeof (INT);
574 case MSIFIELD_WSTR:
575 return rec->fields[iField].len;
576 case MSIFIELD_NULL:
577 break;
578 case MSIFIELD_STREAM:
579 return msi_get_stream_size( rec->fields[iField].u.stream );
581 return 0;
584 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
586 MSIRECORD *rec;
587 UINT ret;
589 TRACE("%d %d\n", handle, iField);
591 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
592 if( !rec )
593 return 0;
594 msiobj_lock( &rec->hdr );
595 ret = MSI_RecordDataSize( rec, iField);
596 msiobj_unlock( &rec->hdr );
597 msiobj_release( &rec->hdr );
598 return ret;
601 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
603 WCHAR *valueW = NULL;
604 MSIRECORD *rec;
605 UINT ret;
607 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
609 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
611 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
612 if( !rec )
614 msi_free( valueW );
615 return ERROR_INVALID_HANDLE;
617 msiobj_lock( &rec->hdr );
618 ret = MSI_RecordSetStringW( rec, iField, valueW );
619 msiobj_unlock( &rec->hdr );
620 msiobj_release( &rec->hdr );
621 msi_free( valueW );
622 return ret;
625 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
627 if (field > rec->count)
628 return ERROR_INVALID_FIELD;
630 MSI_FreeField( &rec->fields[field] );
632 if (value && len < 0) len = strlenW( value );
634 if (value && len)
636 rec->fields[field].type = MSIFIELD_WSTR;
637 rec->fields[field].u.szwVal = msi_strdupW( value, len );
638 rec->fields[field].len = len;
640 else
642 rec->fields[field].type = MSIFIELD_NULL;
643 rec->fields[field].u.szwVal = NULL;
644 rec->fields[field].len = 0;
646 return 0;
649 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
651 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
653 return msi_record_set_string( rec, iField, szValue, -1 );
656 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
658 MSIRECORD *rec;
659 UINT ret;
661 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
663 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
664 if( !rec )
665 return ERROR_INVALID_HANDLE;
667 msiobj_lock( &rec->hdr );
668 ret = MSI_RecordSetStringW( rec, iField, szValue );
669 msiobj_unlock( &rec->hdr );
670 msiobj_release( &rec->hdr );
671 return ret;
674 /* read the data in a file into an IStream */
675 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
677 DWORD sz, szHighWord = 0, read;
678 HANDLE handle;
679 HGLOBAL hGlob = 0;
680 HRESULT hr;
681 ULARGE_INTEGER ulSize;
683 TRACE("reading %s\n", debugstr_w(szFile));
685 /* read the file into memory */
686 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
687 if( handle == INVALID_HANDLE_VALUE )
688 return GetLastError();
689 sz = GetFileSize(handle, &szHighWord);
690 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
692 hGlob = GlobalAlloc(GMEM_FIXED, sz);
693 if( hGlob )
695 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
696 if( !r )
698 GlobalFree(hGlob);
699 hGlob = 0;
703 CloseHandle(handle);
704 if( !hGlob )
705 return ERROR_FUNCTION_FAILED;
707 /* make a stream out of it, and set the correct file size */
708 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
709 if( FAILED( hr ) )
711 GlobalFree(hGlob);
712 return ERROR_FUNCTION_FAILED;
715 /* set the correct size - CreateStreamOnHGlobal screws it up */
716 ulSize.QuadPart = sz;
717 IStream_SetSize(*pstm, ulSize);
719 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
721 return ERROR_SUCCESS;
724 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
726 if ( (iField == 0) || (iField > rec->count) )
727 return ERROR_INVALID_PARAMETER;
729 MSI_FreeField( &rec->fields[iField] );
730 rec->fields[iField].type = MSIFIELD_STREAM;
731 rec->fields[iField].u.stream = stream;
733 return ERROR_SUCCESS;
736 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
738 IStream *stm = NULL;
739 HRESULT hr;
740 UINT ret;
742 if( (iField == 0) || (iField > rec->count) )
743 return ERROR_INVALID_PARAMETER;
745 /* no filename means we should seek back to the start of the stream */
746 if( !szFilename )
748 LARGE_INTEGER ofs;
749 ULARGE_INTEGER cur;
751 if( rec->fields[iField].type != MSIFIELD_STREAM )
752 return ERROR_INVALID_FIELD;
754 stm = rec->fields[iField].u.stream;
755 if( !stm )
756 return ERROR_INVALID_FIELD;
758 ofs.QuadPart = 0;
759 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
760 if (FAILED( hr ))
761 return ERROR_FUNCTION_FAILED;
763 else
765 /* read the file into a stream and save the stream in the record */
766 ret = RECORD_StreamFromFile(szFilename, &stm);
767 if (ret != ERROR_SUCCESS)
768 return ret;
770 /* if all's good, store it in the record */
771 MSI_RecordSetStream(rec, iField, stm);
774 return ERROR_SUCCESS;
777 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
779 LPWSTR wstr = NULL;
780 UINT ret;
782 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
784 if( szFilename )
786 wstr = strdupAtoW( szFilename );
787 if( !wstr )
788 return ERROR_OUTOFMEMORY;
790 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
791 msi_free(wstr);
793 return ret;
796 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
798 MSIRECORD *rec;
799 UINT ret;
801 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
803 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
804 if( !rec )
805 return ERROR_INVALID_HANDLE;
807 msiobj_lock( &rec->hdr );
808 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
809 msiobj_unlock( &rec->hdr );
810 msiobj_release( &rec->hdr );
811 return ret;
814 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
816 ULONG count;
817 HRESULT r;
818 IStream *stm;
820 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
822 if( !sz )
823 return ERROR_INVALID_PARAMETER;
825 if( iField > rec->count)
826 return ERROR_INVALID_PARAMETER;
828 if ( rec->fields[iField].type == MSIFIELD_NULL )
830 *sz = 0;
831 return ERROR_INVALID_DATA;
834 if( rec->fields[iField].type != MSIFIELD_STREAM )
835 return ERROR_INVALID_DATATYPE;
837 stm = rec->fields[iField].u.stream;
838 if( !stm )
839 return ERROR_INVALID_PARAMETER;
841 /* if there's no buffer pointer, calculate the length to the end */
842 if( !buf )
844 LARGE_INTEGER ofs;
845 ULARGE_INTEGER end, cur;
847 ofs.QuadPart = cur.QuadPart = 0;
848 end.QuadPart = 0;
849 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
850 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
851 ofs.QuadPart = cur.QuadPart;
852 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
853 *sz = end.QuadPart - cur.QuadPart;
855 return ERROR_SUCCESS;
858 /* read the data */
859 count = 0;
860 r = IStream_Read( stm, buf, *sz, &count );
861 if( FAILED( r ) )
863 *sz = 0;
864 return ERROR_FUNCTION_FAILED;
867 *sz = count;
869 return ERROR_SUCCESS;
872 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
874 MSIRECORD *rec;
875 UINT ret;
877 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
879 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
880 if( !rec )
881 return ERROR_INVALID_HANDLE;
882 msiobj_lock( &rec->hdr );
883 ret = MSI_RecordReadStream( rec, iField, buf, sz );
884 msiobj_unlock( &rec->hdr );
885 msiobj_release( &rec->hdr );
886 return ret;
889 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
891 TRACE("%p %d %p\n", rec, iField, stm);
893 if( iField > rec->count )
894 return ERROR_INVALID_FIELD;
896 MSI_FreeField( &rec->fields[iField] );
898 rec->fields[iField].type = MSIFIELD_STREAM;
899 rec->fields[iField].u.stream = stm;
900 IStream_AddRef( stm );
902 return ERROR_SUCCESS;
905 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
907 TRACE("%p %d %p\n", rec, iField, pstm);
909 if( iField > rec->count )
910 return ERROR_INVALID_FIELD;
912 if( rec->fields[iField].type != MSIFIELD_STREAM )
913 return ERROR_INVALID_FIELD;
915 *pstm = rec->fields[iField].u.stream;
916 IStream_AddRef( *pstm );
918 return ERROR_SUCCESS;
921 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
923 ULARGE_INTEGER size;
924 LARGE_INTEGER pos;
925 IStream *out;
926 DWORD stgm;
927 HRESULT r;
929 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
930 r = SHCreateStreamOnFileW( name, stgm, &out );
931 if( FAILED( r ) )
932 return ERROR_FUNCTION_FAILED;
934 pos.QuadPart = 0;
935 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
936 if( FAILED( r ) )
937 goto end;
939 pos.QuadPart = 0;
940 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
941 if( FAILED( r ) )
942 goto end;
944 r = IStream_CopyTo( stm, out, size, NULL, NULL );
946 end:
947 IStream_Release( out );
948 if( FAILED( r ) )
949 return ERROR_FUNCTION_FAILED;
950 return ERROR_SUCCESS;
953 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
955 IStream *stm = NULL;
956 UINT r;
958 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
960 msiobj_lock( &rec->hdr );
962 r = MSI_RecordGetIStream( rec, iField, &stm );
963 if( r == ERROR_SUCCESS )
965 r = msi_dump_stream_to_file( stm, name );
966 IStream_Release( stm );
969 msiobj_unlock( &rec->hdr );
971 return r;
974 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
976 MSIRECORD *clone;
977 UINT r, i, count;
979 count = MSI_RecordGetFieldCount(rec);
980 clone = MSI_CreateRecord(count);
981 if (!clone)
982 return NULL;
984 for (i = 0; i <= count; i++)
986 if (rec->fields[i].type == MSIFIELD_STREAM)
988 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
989 &clone->fields[i].u.stream)))
991 msiobj_release(&clone->hdr);
992 return NULL;
994 clone->fields[i].type = MSIFIELD_STREAM;
996 else
998 r = MSI_RecordCopyField(rec, i, clone, i);
999 if (r != ERROR_SUCCESS)
1001 msiobj_release(&clone->hdr);
1002 return NULL;
1007 return clone;
1010 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
1012 if (a->fields[field].type != b->fields[field].type)
1013 return FALSE;
1015 switch (a->fields[field].type)
1017 case MSIFIELD_NULL:
1018 break;
1020 case MSIFIELD_INT:
1021 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
1022 return FALSE;
1023 break;
1025 case MSIFIELD_WSTR:
1026 if (a->fields[field].len != b->fields[field].len) return FALSE;
1027 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
1028 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
1029 break;
1031 case MSIFIELD_STREAM:
1032 default:
1033 return FALSE;
1035 return TRUE;
1039 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
1041 UINT i;
1043 if (a->count != b->count)
1044 return FALSE;
1046 for (i = 0; i <= a->count; i++)
1048 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1049 return FALSE;
1052 return TRUE;
1055 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1057 DWORD sz = 0;
1058 WCHAR *str;
1059 UINT r;
1061 if (MSI_RecordIsNull( rec, field )) return NULL;
1063 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1064 if (r != ERROR_SUCCESS)
1065 return NULL;
1067 sz++;
1068 str = msi_alloc( sz * sizeof(WCHAR) );
1069 if (!str) return NULL;
1070 str[0] = 0;
1071 r = MSI_RecordGetStringW( rec, field, str, &sz );
1072 if (r != ERROR_SUCCESS)
1074 ERR("failed to get string!\n");
1075 msi_free( str );
1076 return NULL;
1078 return str;
1081 void dump_record(MSIRECORD *rec)
1083 int i;
1084 if (!rec)
1086 TRACE("(null)\n");
1087 return;
1090 TRACE("[");
1091 for (i = 0; i <= rec->count; i++)
1093 switch(rec->fields[i].type)
1095 case MSIFIELD_NULL: TRACE("(null)"); break;
1096 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1097 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1098 case MSIFIELD_INTPTR: TRACE("%ld", rec->fields[i].u.pVal); break;
1099 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1101 if (i < rec->count) TRACE(", ");
1103 TRACE("]\n");