ntdll: Convert PE header to 64-bit when loading a 32-bit IL-only module.
[wine.git] / dlls / msi / record.c
blobcca63083d1802406febce62b35a854cd9a792f10
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
50 static void MSI_FreeField( MSIFIELD *field )
52 switch( field->type )
54 case MSIFIELD_NULL:
55 case MSIFIELD_INT:
56 break;
57 case MSIFIELD_WSTR:
58 msi_free( field->u.szwVal);
59 break;
60 case MSIFIELD_STREAM:
61 IStream_Release( field->u.stream );
62 break;
63 default:
64 ERR("Invalid field type %d\n", field->type);
68 void MSI_CloseRecord( MSIOBJECTHDR *arg )
70 MSIRECORD *rec = (MSIRECORD *) arg;
71 UINT i;
73 for( i=0; i<=rec->count; i++ )
74 MSI_FreeField( &rec->fields[i] );
77 MSIRECORD *MSI_CreateRecord( UINT cParams )
79 MSIRECORD *rec;
81 TRACE("%d\n", cParams);
83 if( cParams>65535 )
84 return NULL;
86 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]),
87 MSI_CloseRecord );
88 if( rec )
89 rec->count = cParams;
90 return rec;
93 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
95 MSIRECORD *rec;
96 MSIHANDLE ret = 0;
98 TRACE("%d\n", cParams);
100 rec = MSI_CreateRecord( cParams );
101 if( rec )
103 ret = alloc_msihandle( &rec->hdr );
104 msiobj_release( &rec->hdr );
106 return ret;
109 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
111 return rec->count;
114 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
116 MSIRECORD *rec;
117 UINT ret;
119 TRACE("%d\n", handle );
121 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
122 if( !rec )
123 return -1;
125 msiobj_lock( &rec->hdr );
126 ret = MSI_RecordGetFieldCount( rec );
127 msiobj_unlock( &rec->hdr );
128 msiobj_release( &rec->hdr );
130 return ret;
133 static BOOL string2intW( LPCWSTR str, int *out )
135 int x = 0;
136 LPCWSTR p = str;
138 if( *p == '-' ) /* skip the minus sign */
139 p++;
140 while ( *p )
142 if( (*p < '0') || (*p > '9') )
143 return FALSE;
144 x *= 10;
145 x += (*p - '0');
146 p++;
149 if( str[0] == '-' ) /* check if it's negative */
150 x = -x;
151 *out = x;
153 return TRUE;
156 WCHAR *msi_strdupW( const WCHAR *value, int len )
158 WCHAR *ret;
160 if (!value) return NULL;
161 if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
162 memcpy( ret, value, len * sizeof(WCHAR) );
163 ret[len] = 0;
164 return ret;
167 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
168 MSIRECORD *out_rec, UINT out_n )
170 UINT r = ERROR_SUCCESS;
172 msiobj_lock( &in_rec->hdr );
174 if ( in_n > in_rec->count || out_n > out_rec->count )
175 r = ERROR_FUNCTION_FAILED;
176 else if ( in_rec != out_rec || in_n != out_n )
178 LPWSTR str;
179 MSIFIELD *in, *out;
181 in = &in_rec->fields[in_n];
182 out = &out_rec->fields[out_n];
184 switch ( in->type )
186 case MSIFIELD_NULL:
187 break;
188 case MSIFIELD_INT:
189 out->u.iVal = in->u.iVal;
190 break;
191 case MSIFIELD_WSTR:
192 if ((str = msi_strdupW( in->u.szwVal, in->len )))
194 out->u.szwVal = str;
195 out->len = in->len;
197 else r = ERROR_OUTOFMEMORY;
198 break;
199 case MSIFIELD_STREAM:
200 IStream_AddRef( in->u.stream );
201 out->u.stream = in->u.stream;
202 break;
203 default:
204 ERR("invalid field type %d\n", in->type);
206 if (r == ERROR_SUCCESS)
207 out->type = in->type;
210 msiobj_unlock( &in_rec->hdr );
211 return r;
214 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
216 int ret = 0;
218 TRACE("%p %d\n", rec, iField );
220 if( iField > rec->count )
221 return MSI_NULL_INTEGER;
223 switch( rec->fields[iField].type )
225 case MSIFIELD_INT:
226 return rec->fields[iField].u.iVal;
227 case MSIFIELD_WSTR:
228 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
229 return ret;
230 return MSI_NULL_INTEGER;
231 default:
232 break;
235 return MSI_NULL_INTEGER;
238 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
240 MSIRECORD *rec;
241 UINT ret;
243 TRACE("%d %d\n", handle, iField );
245 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
246 if( !rec )
247 return MSI_NULL_INTEGER;
249 msiobj_lock( &rec->hdr );
250 ret = MSI_RecordGetInteger( rec, iField );
251 msiobj_unlock( &rec->hdr );
252 msiobj_release( &rec->hdr );
254 return ret;
257 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
259 MSIRECORD *rec;
260 UINT i;
262 TRACE("%d\n", handle );
264 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
265 if( !rec )
266 return ERROR_INVALID_HANDLE;
268 msiobj_lock( &rec->hdr );
269 for( i=0; i<=rec->count; i++)
271 MSI_FreeField( &rec->fields[i] );
272 rec->fields[i].type = MSIFIELD_NULL;
273 rec->fields[i].u.iVal = 0;
275 msiobj_unlock( &rec->hdr );
276 msiobj_release( &rec->hdr );
278 return ERROR_SUCCESS;
281 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
283 TRACE("%p %u %d\n", rec, iField, iVal);
285 if( iField > rec->count )
286 return ERROR_INVALID_PARAMETER;
288 MSI_FreeField( &rec->fields[iField] );
290 if (iVal == MSI_NULL_INTEGER)
292 rec->fields[iField].type = MSIFIELD_NULL;
293 rec->fields[iField].u.szwVal = NULL;
295 else
297 rec->fields[iField].type = MSIFIELD_INT;
298 rec->fields[iField].u.iVal = iVal;
301 return ERROR_SUCCESS;
304 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
306 MSIRECORD *rec;
307 UINT ret;
309 TRACE("%d %u %d\n", handle, iField, iVal);
311 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
312 if( !rec )
313 return ERROR_INVALID_HANDLE;
315 msiobj_lock( &rec->hdr );
316 ret = MSI_RecordSetInteger( rec, iField, iVal );
317 msiobj_unlock( &rec->hdr );
318 msiobj_release( &rec->hdr );
319 return ret;
322 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
324 BOOL r = TRUE;
326 TRACE("%p %d\n", rec, iField );
328 r = ( iField > rec->count ) ||
329 ( rec->fields[iField].type == MSIFIELD_NULL );
331 return r;
334 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
336 MSIRECORD *rec;
337 UINT ret;
339 TRACE("%d %d\n", handle, iField );
341 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
342 if( !rec )
343 return FALSE;
344 msiobj_lock( &rec->hdr );
345 ret = MSI_RecordIsNull( rec, iField );
346 msiobj_unlock( &rec->hdr );
347 msiobj_release( &rec->hdr );
348 return ret;
352 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
353 LPSTR szValue, LPDWORD pcchValue)
355 UINT len = 0, ret = ERROR_SUCCESS;
356 CHAR buffer[16];
358 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
360 if( iField > rec->count )
362 if ( szValue && *pcchValue > 0 )
363 szValue[0] = 0;
365 *pcchValue = 0;
366 return ERROR_SUCCESS;
369 switch( rec->fields[iField].type )
371 case MSIFIELD_INT:
372 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
373 len = lstrlenA( buffer );
374 if (szValue)
375 lstrcpynA(szValue, buffer, *pcchValue);
376 break;
377 case MSIFIELD_WSTR:
378 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
379 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
380 if (szValue)
381 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
382 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
383 if( szValue && *pcchValue && len>*pcchValue )
384 szValue[*pcchValue-1] = 0;
385 if( len )
386 len--;
387 break;
388 case MSIFIELD_NULL:
389 if( szValue && *pcchValue > 0 )
390 szValue[0] = 0;
391 break;
392 default:
393 ret = ERROR_INVALID_PARAMETER;
394 break;
397 if( szValue && *pcchValue <= len )
398 ret = ERROR_MORE_DATA;
399 *pcchValue = len;
401 return ret;
404 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
405 LPSTR szValue, LPDWORD pcchValue)
407 MSIRECORD *rec;
408 UINT ret;
410 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
412 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
413 if( !rec )
414 return ERROR_INVALID_HANDLE;
415 msiobj_lock( &rec->hdr );
416 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
417 msiobj_unlock( &rec->hdr );
418 msiobj_release( &rec->hdr );
419 return ret;
422 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
424 if (field > rec->count)
425 return NULL;
427 if (rec->fields[field].type != MSIFIELD_WSTR)
428 return NULL;
430 if (len) *len = rec->fields[field].len;
432 return rec->fields[field].u.szwVal;
435 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
437 return msi_record_get_string( rec, iField, NULL );
440 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
441 LPWSTR szValue, LPDWORD pcchValue)
443 static const WCHAR szFormat[] = {'%','d',0};
444 UINT len = 0, ret = ERROR_SUCCESS;
445 WCHAR buffer[16];
447 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
449 if( iField > rec->count )
451 if ( szValue && *pcchValue > 0 )
452 szValue[0] = 0;
454 *pcchValue = 0;
455 return ERROR_SUCCESS;
458 switch( rec->fields[iField].type )
460 case MSIFIELD_INT:
461 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
462 len = lstrlenW( buffer );
463 if (szValue)
464 lstrcpynW(szValue, buffer, *pcchValue);
465 break;
466 case MSIFIELD_WSTR:
467 len = rec->fields[iField].len;
468 if (szValue)
469 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
470 break;
471 case MSIFIELD_NULL:
472 if( szValue && *pcchValue > 0 )
473 szValue[0] = 0;
474 break;
475 default:
476 break;
479 if( szValue && *pcchValue <= len )
480 ret = ERROR_MORE_DATA;
481 *pcchValue = len;
483 return ret;
486 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
487 LPWSTR szValue, LPDWORD pcchValue)
489 MSIRECORD *rec;
490 UINT ret;
492 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
494 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
495 if( !rec )
496 return ERROR_INVALID_HANDLE;
498 msiobj_lock( &rec->hdr );
499 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
500 msiobj_unlock( &rec->hdr );
501 msiobj_release( &rec->hdr );
502 return ret;
505 static UINT msi_get_stream_size( IStream *stm )
507 STATSTG stat;
508 HRESULT r;
510 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
511 if( FAILED(r) )
512 return 0;
513 return stat.cbSize.QuadPart;
516 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
518 TRACE("%p %d\n", rec, iField);
520 if( iField > rec->count )
521 return 0;
523 switch( rec->fields[iField].type )
525 case MSIFIELD_INT:
526 return sizeof (INT);
527 case MSIFIELD_WSTR:
528 return rec->fields[iField].len;
529 case MSIFIELD_NULL:
530 break;
531 case MSIFIELD_STREAM:
532 return msi_get_stream_size( rec->fields[iField].u.stream );
534 return 0;
537 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
539 MSIRECORD *rec;
540 UINT ret;
542 TRACE("%d %d\n", handle, iField);
544 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
545 if( !rec )
546 return 0;
547 msiobj_lock( &rec->hdr );
548 ret = MSI_RecordDataSize( rec, iField);
549 msiobj_unlock( &rec->hdr );
550 msiobj_release( &rec->hdr );
551 return ret;
554 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
556 WCHAR *valueW = NULL;
557 MSIRECORD *rec;
558 UINT ret;
560 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
562 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
564 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
565 if( !rec )
567 msi_free( valueW );
568 return ERROR_INVALID_HANDLE;
570 msiobj_lock( &rec->hdr );
571 ret = MSI_RecordSetStringW( rec, iField, valueW );
572 msiobj_unlock( &rec->hdr );
573 msiobj_release( &rec->hdr );
574 msi_free( valueW );
575 return ret;
578 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
580 if (field > rec->count)
581 return ERROR_INVALID_FIELD;
583 MSI_FreeField( &rec->fields[field] );
585 if (value && len < 0) len = strlenW( value );
587 if (value && len)
589 rec->fields[field].type = MSIFIELD_WSTR;
590 rec->fields[field].u.szwVal = msi_strdupW( value, len );
591 rec->fields[field].len = len;
593 else
595 rec->fields[field].type = MSIFIELD_NULL;
596 rec->fields[field].u.szwVal = NULL;
597 rec->fields[field].len = 0;
599 return 0;
602 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
604 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
606 return msi_record_set_string( rec, iField, szValue, -1 );
609 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
611 MSIRECORD *rec;
612 UINT ret;
614 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
616 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
617 if( !rec )
618 return ERROR_INVALID_HANDLE;
620 msiobj_lock( &rec->hdr );
621 ret = MSI_RecordSetStringW( rec, iField, szValue );
622 msiobj_unlock( &rec->hdr );
623 msiobj_release( &rec->hdr );
624 return ret;
627 /* read the data in a file into an IStream */
628 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
630 DWORD sz, szHighWord = 0, read;
631 HANDLE handle;
632 HGLOBAL hGlob = 0;
633 HRESULT hr;
634 ULARGE_INTEGER ulSize;
636 TRACE("reading %s\n", debugstr_w(szFile));
638 /* read the file into memory */
639 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
640 if( handle == INVALID_HANDLE_VALUE )
641 return GetLastError();
642 sz = GetFileSize(handle, &szHighWord);
643 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
645 hGlob = GlobalAlloc(GMEM_FIXED, sz);
646 if( hGlob )
648 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
649 if( !r )
651 GlobalFree(hGlob);
652 hGlob = 0;
656 CloseHandle(handle);
657 if( !hGlob )
658 return ERROR_FUNCTION_FAILED;
660 /* make a stream out of it, and set the correct file size */
661 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
662 if( FAILED( hr ) )
664 GlobalFree(hGlob);
665 return ERROR_FUNCTION_FAILED;
668 /* set the correct size - CreateStreamOnHGlobal screws it up */
669 ulSize.QuadPart = sz;
670 IStream_SetSize(*pstm, ulSize);
672 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
674 return ERROR_SUCCESS;
677 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
679 if ( (iField == 0) || (iField > rec->count) )
680 return ERROR_INVALID_PARAMETER;
682 MSI_FreeField( &rec->fields[iField] );
683 rec->fields[iField].type = MSIFIELD_STREAM;
684 rec->fields[iField].u.stream = stream;
686 return ERROR_SUCCESS;
689 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
691 IStream *stm = NULL;
692 HRESULT hr;
693 UINT ret;
695 if( (iField == 0) || (iField > rec->count) )
696 return ERROR_INVALID_PARAMETER;
698 /* no filename means we should seek back to the start of the stream */
699 if( !szFilename )
701 LARGE_INTEGER ofs;
702 ULARGE_INTEGER cur;
704 if( rec->fields[iField].type != MSIFIELD_STREAM )
705 return ERROR_INVALID_FIELD;
707 stm = rec->fields[iField].u.stream;
708 if( !stm )
709 return ERROR_INVALID_FIELD;
711 ofs.QuadPart = 0;
712 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
713 if (FAILED( hr ))
714 return ERROR_FUNCTION_FAILED;
716 else
718 /* read the file into a stream and save the stream in the record */
719 ret = RECORD_StreamFromFile(szFilename, &stm);
720 if (ret != ERROR_SUCCESS)
721 return ret;
723 /* if all's good, store it in the record */
724 MSI_RecordSetStream(rec, iField, stm);
727 return ERROR_SUCCESS;
730 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
732 LPWSTR wstr = NULL;
733 UINT ret;
735 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
737 if( szFilename )
739 wstr = strdupAtoW( szFilename );
740 if( !wstr )
741 return ERROR_OUTOFMEMORY;
743 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
744 msi_free(wstr);
746 return ret;
749 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
751 MSIRECORD *rec;
752 UINT ret;
754 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
756 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
757 if( !rec )
758 return ERROR_INVALID_HANDLE;
760 msiobj_lock( &rec->hdr );
761 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
762 msiobj_unlock( &rec->hdr );
763 msiobj_release( &rec->hdr );
764 return ret;
767 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
769 ULONG count;
770 HRESULT r;
771 IStream *stm;
773 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
775 if( !sz )
776 return ERROR_INVALID_PARAMETER;
778 if( iField > rec->count)
779 return ERROR_INVALID_PARAMETER;
781 if ( rec->fields[iField].type == MSIFIELD_NULL )
783 *sz = 0;
784 return ERROR_INVALID_DATA;
787 if( rec->fields[iField].type != MSIFIELD_STREAM )
788 return ERROR_INVALID_DATATYPE;
790 stm = rec->fields[iField].u.stream;
791 if( !stm )
792 return ERROR_INVALID_PARAMETER;
794 /* if there's no buffer pointer, calculate the length to the end */
795 if( !buf )
797 LARGE_INTEGER ofs;
798 ULARGE_INTEGER end, cur;
800 ofs.QuadPart = cur.QuadPart = 0;
801 end.QuadPart = 0;
802 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
803 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
804 ofs.QuadPart = cur.QuadPart;
805 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
806 *sz = end.QuadPart - cur.QuadPart;
808 return ERROR_SUCCESS;
811 /* read the data */
812 count = 0;
813 r = IStream_Read( stm, buf, *sz, &count );
814 if( FAILED( r ) )
816 *sz = 0;
817 return ERROR_FUNCTION_FAILED;
820 *sz = count;
822 return ERROR_SUCCESS;
825 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
827 MSIRECORD *rec;
828 UINT ret;
830 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
832 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
833 if( !rec )
834 return ERROR_INVALID_HANDLE;
835 msiobj_lock( &rec->hdr );
836 ret = MSI_RecordReadStream( rec, iField, buf, sz );
837 msiobj_unlock( &rec->hdr );
838 msiobj_release( &rec->hdr );
839 return ret;
842 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
844 TRACE("%p %d %p\n", rec, iField, stm);
846 if( iField > rec->count )
847 return ERROR_INVALID_FIELD;
849 MSI_FreeField( &rec->fields[iField] );
851 rec->fields[iField].type = MSIFIELD_STREAM;
852 rec->fields[iField].u.stream = stm;
853 IStream_AddRef( stm );
855 return ERROR_SUCCESS;
858 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
860 TRACE("%p %d %p\n", rec, iField, pstm);
862 if( iField > rec->count )
863 return ERROR_INVALID_FIELD;
865 if( rec->fields[iField].type != MSIFIELD_STREAM )
866 return ERROR_INVALID_FIELD;
868 *pstm = rec->fields[iField].u.stream;
869 IStream_AddRef( *pstm );
871 return ERROR_SUCCESS;
874 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
876 ULARGE_INTEGER size;
877 LARGE_INTEGER pos;
878 IStream *out;
879 DWORD stgm;
880 HRESULT r;
882 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
883 r = SHCreateStreamOnFileW( name, stgm, &out );
884 if( FAILED( r ) )
885 return ERROR_FUNCTION_FAILED;
887 pos.QuadPart = 0;
888 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
889 if( FAILED( r ) )
890 goto end;
892 pos.QuadPart = 0;
893 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
894 if( FAILED( r ) )
895 goto end;
897 r = IStream_CopyTo( stm, out, size, NULL, NULL );
899 end:
900 IStream_Release( out );
901 if( FAILED( r ) )
902 return ERROR_FUNCTION_FAILED;
903 return ERROR_SUCCESS;
906 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
908 IStream *stm = NULL;
909 UINT r;
911 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
913 msiobj_lock( &rec->hdr );
915 r = MSI_RecordGetIStream( rec, iField, &stm );
916 if( r == ERROR_SUCCESS )
918 r = msi_dump_stream_to_file( stm, name );
919 IStream_Release( stm );
922 msiobj_unlock( &rec->hdr );
924 return r;
927 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
929 MSIRECORD *clone;
930 UINT r, i, count;
932 count = MSI_RecordGetFieldCount(rec);
933 clone = MSI_CreateRecord(count);
934 if (!clone)
935 return NULL;
937 for (i = 0; i <= count; i++)
939 if (rec->fields[i].type == MSIFIELD_STREAM)
941 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
942 &clone->fields[i].u.stream)))
944 msiobj_release(&clone->hdr);
945 return NULL;
947 clone->fields[i].type = MSIFIELD_STREAM;
949 else
951 r = MSI_RecordCopyField(rec, i, clone, i);
952 if (r != ERROR_SUCCESS)
954 msiobj_release(&clone->hdr);
955 return NULL;
960 return clone;
963 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
965 if (a->fields[field].type != b->fields[field].type)
966 return FALSE;
968 switch (a->fields[field].type)
970 case MSIFIELD_NULL:
971 break;
973 case MSIFIELD_INT:
974 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
975 return FALSE;
976 break;
978 case MSIFIELD_WSTR:
979 if (a->fields[field].len != b->fields[field].len) return FALSE;
980 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
981 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
982 break;
984 case MSIFIELD_STREAM:
985 default:
986 return FALSE;
988 return TRUE;
992 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
994 UINT i;
996 if (a->count != b->count)
997 return FALSE;
999 for (i = 0; i <= a->count; i++)
1001 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1002 return FALSE;
1005 return TRUE;
1008 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1010 DWORD sz = 0;
1011 WCHAR *str;
1012 UINT r;
1014 if (MSI_RecordIsNull( rec, field )) return NULL;
1016 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1017 if (r != ERROR_SUCCESS)
1018 return NULL;
1020 sz++;
1021 str = msi_alloc( sz * sizeof(WCHAR) );
1022 if (!str) return NULL;
1023 str[0] = 0;
1024 r = MSI_RecordGetStringW( rec, field, str, &sz );
1025 if (r != ERROR_SUCCESS)
1027 ERR("failed to get string!\n");
1028 msi_free( str );
1029 return NULL;
1031 return str;
1034 void dump_record(MSIRECORD *rec)
1036 int i;
1037 if (!rec)
1039 TRACE("(null)\n");
1040 return;
1043 TRACE("[");
1044 for (i = 0; i <= rec->count; i++)
1046 switch(rec->fields[i].type)
1048 case MSIFIELD_NULL: TRACE("(null)"); break;
1049 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1050 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1051 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1053 if (i < rec->count) TRACE(", ");
1055 TRACE("]\n");
1058 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
1060 MSIRECORD *rec;
1061 unsigned int i;
1062 UINT r = ERROR_SUCCESS;
1064 if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1065 return ERROR_INVALID_HANDLE;
1067 rec->cookie = in->cookie;
1068 for (i = 0; i <= in->count; i++)
1070 switch (in->fields[i].type)
1072 case MSIFIELD_NULL:
1073 MSI_FreeField(&rec->fields[i]);
1074 rec->fields[i].type = MSIFIELD_NULL;
1075 break;
1076 case MSIFIELD_INT:
1077 r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
1078 break;
1079 case MSIFIELD_WSTR:
1080 r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
1081 break;
1082 case MSIFIELD_STREAM:
1083 r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
1084 break;
1085 default:
1086 ERR("invalid field type %d\n", in->fields[i].type);
1087 break;
1090 if (r)
1092 msiobj_release(&rec->hdr);
1093 return r;
1097 msiobj_release(&rec->hdr);
1098 return ERROR_SUCCESS;
1101 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1103 if (!in)
1105 *out = 0;
1106 return ERROR_SUCCESS;
1109 *out = MsiCreateRecord(in->count);
1110 if (!*out) return ERROR_OUTOFMEMORY;
1112 return copy_remote_record(in, *out);
1115 struct wire_record *marshal_record(MSIHANDLE handle)
1117 struct wire_record *ret;
1118 unsigned int i;
1119 MSIRECORD *rec;
1121 if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1122 return NULL;
1124 ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
1125 ret->count = rec->count;
1126 ret->cookie = rec->cookie;
1128 for (i = 0; i <= rec->count; i++)
1130 switch (rec->fields[i].type)
1132 case MSIFIELD_NULL:
1133 break;
1134 case MSIFIELD_INT:
1135 ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1136 break;
1137 case MSIFIELD_WSTR:
1138 ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal);
1139 break;
1140 case MSIFIELD_STREAM:
1141 IStream_AddRef(rec->fields[i].u.stream);
1142 ret->fields[i].u.stream = rec->fields[i].u.stream;
1143 break;
1144 default:
1145 ERR("invalid field type %d\n", rec->fields[i].type);
1146 break;
1148 ret->fields[i].type = rec->fields[i].type;
1151 msiobj_release(&rec->hdr);
1152 return ret;
1155 void free_remote_record(struct wire_record *rec)
1157 int i;
1159 for (i = 0; i <= rec->count; i++)
1161 if (rec->fields[i].type == MSIFIELD_WSTR)
1162 midl_user_free(rec->fields[i].u.szwVal);
1163 else if (rec->fields[i].type == MSIFIELD_STREAM)
1164 IStream_Release(rec->fields[i].u.stream);
1167 midl_user_free(rec);