include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / msi / record.c
blob3671133ac4c17e218867e97d880a1584723e7b90
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
49 static void MSI_FreeField( MSIFIELD *field )
51 switch( field->type )
53 case MSIFIELD_NULL:
54 case MSIFIELD_INT:
55 break;
56 case MSIFIELD_WSTR:
57 free( field->u.szwVal);
58 break;
59 case MSIFIELD_STREAM:
60 IStream_Release( field->u.stream );
61 break;
62 default:
63 ERR("Invalid field type %d\n", field->type);
67 void MSI_CloseRecord( MSIOBJECTHDR *arg )
69 MSIRECORD *rec = (MSIRECORD *) arg;
70 UINT i;
72 for( i=0; i<=rec->count; i++ )
73 MSI_FreeField( &rec->fields[i] );
76 MSIRECORD *MSI_CreateRecord( UINT cParams )
78 MSIRECORD *rec;
80 TRACE("%d\n", cParams);
82 if( cParams>65535 )
83 return NULL;
85 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, FIELD_OFFSET(MSIRECORD, fields[cParams + 1]),
86 MSI_CloseRecord );
87 if( rec )
88 rec->count = cParams;
89 return rec;
92 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
94 MSIRECORD *rec;
95 MSIHANDLE ret = 0;
97 TRACE("%d\n", cParams);
99 rec = MSI_CreateRecord( cParams );
100 if( rec )
102 ret = alloc_msihandle( &rec->hdr );
103 msiobj_release( &rec->hdr );
105 return ret;
108 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
110 return rec->count;
113 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
115 MSIRECORD *rec;
116 UINT ret;
118 TRACE( "%lu\n", handle );
120 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
121 if( !rec )
122 return -1;
124 msiobj_lock( &rec->hdr );
125 ret = MSI_RecordGetFieldCount( rec );
126 msiobj_unlock( &rec->hdr );
127 msiobj_release( &rec->hdr );
129 return ret;
132 static BOOL string2intW( LPCWSTR str, int *out )
134 int x = 0;
135 LPCWSTR p = str;
137 if( *p == '-' ) /* skip the minus sign */
138 p++;
139 while ( *p )
141 if( (*p < '0') || (*p > '9') )
142 return FALSE;
143 x *= 10;
144 x += (*p - '0');
145 p++;
148 if( str[0] == '-' ) /* check if it's negative */
149 x = -x;
150 *out = x;
152 return TRUE;
155 WCHAR *msi_strdupW( const WCHAR *value, int len )
157 WCHAR *ret;
159 if (!value) return NULL;
160 if (!(ret = malloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
161 memcpy( ret, value, len * sizeof(WCHAR) );
162 ret[len] = 0;
163 return ret;
166 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
167 MSIRECORD *out_rec, UINT out_n )
169 UINT r = ERROR_SUCCESS;
171 msiobj_lock( &in_rec->hdr );
173 if ( in_n > in_rec->count || out_n > out_rec->count )
174 r = ERROR_FUNCTION_FAILED;
175 else if ( in_rec != out_rec || in_n != out_n )
177 LPWSTR str;
178 MSIFIELD *in, *out;
180 in = &in_rec->fields[in_n];
181 out = &out_rec->fields[out_n];
183 switch ( in->type )
185 case MSIFIELD_NULL:
186 break;
187 case MSIFIELD_INT:
188 out->u.iVal = in->u.iVal;
189 break;
190 case MSIFIELD_WSTR:
191 if ((str = msi_strdupW( in->u.szwVal, in->len )))
193 out->u.szwVal = str;
194 out->len = in->len;
196 else r = ERROR_OUTOFMEMORY;
197 break;
198 case MSIFIELD_STREAM:
199 IStream_AddRef( in->u.stream );
200 out->u.stream = in->u.stream;
201 break;
202 default:
203 ERR("invalid field type %d\n", in->type);
205 if (r == ERROR_SUCCESS)
206 out->type = in->type;
209 msiobj_unlock( &in_rec->hdr );
210 return r;
213 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
215 int ret = 0;
217 TRACE("%p %d\n", rec, iField );
219 if( iField > rec->count )
220 return MSI_NULL_INTEGER;
222 switch( rec->fields[iField].type )
224 case MSIFIELD_INT:
225 return rec->fields[iField].u.iVal;
226 case MSIFIELD_WSTR:
227 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
228 return ret;
229 return MSI_NULL_INTEGER;
230 default:
231 break;
234 return MSI_NULL_INTEGER;
237 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
239 MSIRECORD *rec;
240 UINT ret;
242 TRACE( "%lu, %u\n", handle, iField );
244 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
245 if( !rec )
246 return MSI_NULL_INTEGER;
248 msiobj_lock( &rec->hdr );
249 ret = MSI_RecordGetInteger( rec, iField );
250 msiobj_unlock( &rec->hdr );
251 msiobj_release( &rec->hdr );
253 return ret;
256 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
258 MSIRECORD *rec;
259 UINT i;
261 TRACE( "%lu\n", handle );
263 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
264 if( !rec )
265 return ERROR_INVALID_HANDLE;
267 msiobj_lock( &rec->hdr );
268 for( i=0; i<=rec->count; i++)
270 MSI_FreeField( &rec->fields[i] );
271 rec->fields[i].type = MSIFIELD_NULL;
272 rec->fields[i].u.iVal = 0;
274 msiobj_unlock( &rec->hdr );
275 msiobj_release( &rec->hdr );
277 return ERROR_SUCCESS;
280 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
282 TRACE("%p %u %d\n", rec, iField, iVal);
284 if( iField > rec->count )
285 return ERROR_INVALID_PARAMETER;
287 MSI_FreeField( &rec->fields[iField] );
289 if (iVal == MSI_NULL_INTEGER)
291 rec->fields[iField].type = MSIFIELD_NULL;
292 rec->fields[iField].u.szwVal = NULL;
294 else
296 rec->fields[iField].type = MSIFIELD_INT;
297 rec->fields[iField].u.iVal = iVal;
300 return ERROR_SUCCESS;
303 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
305 MSIRECORD *rec;
306 UINT ret;
308 TRACE( "%lu, %u, %d\n", handle, iField, iVal );
310 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
311 if( !rec )
312 return ERROR_INVALID_HANDLE;
314 msiobj_lock( &rec->hdr );
315 ret = MSI_RecordSetInteger( rec, iField, iVal );
316 msiobj_unlock( &rec->hdr );
317 msiobj_release( &rec->hdr );
318 return ret;
321 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
323 BOOL r = TRUE;
325 TRACE("%p %d\n", rec, iField );
327 r = ( iField > rec->count ) ||
328 ( rec->fields[iField].type == MSIFIELD_NULL );
330 return r;
333 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
335 MSIRECORD *rec;
336 UINT ret;
338 TRACE( "%lu, %u\n", handle, iField );
340 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
341 if( !rec )
342 return FALSE;
343 msiobj_lock( &rec->hdr );
344 ret = MSI_RecordIsNull( rec, iField );
345 msiobj_unlock( &rec->hdr );
346 msiobj_release( &rec->hdr );
347 return ret;
351 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
352 LPSTR szValue, LPDWORD pcchValue)
354 UINT len = 0, ret = ERROR_SUCCESS;
355 CHAR buffer[16];
357 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
359 if( iField > rec->count )
361 if ( szValue && *pcchValue > 0 )
362 szValue[0] = 0;
364 *pcchValue = 0;
365 return ERROR_SUCCESS;
368 switch( rec->fields[iField].type )
370 case MSIFIELD_INT:
371 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
372 len = lstrlenA( buffer );
373 if (szValue)
374 lstrcpynA(szValue, buffer, *pcchValue);
375 break;
376 case MSIFIELD_WSTR:
377 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
378 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
379 if (szValue)
380 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
381 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
382 if( szValue && *pcchValue && len>*pcchValue )
383 szValue[*pcchValue-1] = 0;
384 if( len )
385 len--;
386 break;
387 case MSIFIELD_NULL:
388 if( szValue && *pcchValue > 0 )
389 szValue[0] = 0;
390 break;
391 default:
392 ret = ERROR_INVALID_PARAMETER;
393 break;
396 if( szValue && *pcchValue <= len )
397 ret = ERROR_MORE_DATA;
398 *pcchValue = len;
400 return ret;
403 UINT WINAPI MsiRecordGetStringA( MSIHANDLE handle, UINT iField, char *szValue, DWORD *pcchValue )
405 MSIRECORD *rec;
406 UINT ret;
408 TRACE( "%lu, %d, %p, %p\n", handle, iField, szValue, pcchValue );
410 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
411 if( !rec )
412 return ERROR_INVALID_HANDLE;
413 msiobj_lock( &rec->hdr );
414 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
415 msiobj_unlock( &rec->hdr );
416 msiobj_release( &rec->hdr );
417 return ret;
420 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
422 if (field > rec->count)
423 return NULL;
425 if (rec->fields[field].type != MSIFIELD_WSTR)
426 return NULL;
428 if (len) *len = rec->fields[field].len;
430 return rec->fields[field].u.szwVal;
433 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
435 return msi_record_get_string( rec, iField, NULL );
438 UINT MSI_RecordGetStringW( MSIRECORD *rec, UINT iField, WCHAR *szValue, DWORD *pcchValue )
440 UINT len = 0, ret = ERROR_SUCCESS;
441 WCHAR buffer[16];
443 TRACE( "%p, %u, %p, %p\n", rec, iField, szValue, pcchValue );
445 if( iField > rec->count )
447 if ( szValue && *pcchValue > 0 )
448 szValue[0] = 0;
450 *pcchValue = 0;
451 return ERROR_SUCCESS;
454 switch( rec->fields[iField].type )
456 case MSIFIELD_INT:
457 wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal);
458 len = lstrlenW( buffer );
459 if (szValue)
460 lstrcpynW(szValue, buffer, *pcchValue);
461 break;
462 case MSIFIELD_WSTR:
463 len = rec->fields[iField].len;
464 if (szValue)
465 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
466 break;
467 case MSIFIELD_NULL:
468 if( szValue && *pcchValue > 0 )
469 szValue[0] = 0;
470 break;
471 default:
472 break;
475 if( szValue && *pcchValue <= len )
476 ret = ERROR_MORE_DATA;
477 *pcchValue = len;
479 return ret;
482 UINT WINAPI MsiRecordGetStringW( MSIHANDLE handle, UINT iField, WCHAR *szValue, DWORD *pcchValue )
484 MSIRECORD *rec;
485 UINT ret;
487 TRACE( "%lu, %u, %p, %p\n", handle, iField, szValue, pcchValue );
489 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
490 if( !rec )
491 return ERROR_INVALID_HANDLE;
493 msiobj_lock( &rec->hdr );
494 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
495 msiobj_unlock( &rec->hdr );
496 msiobj_release( &rec->hdr );
497 return ret;
500 static UINT get_stream_size( IStream *stm )
502 STATSTG stat;
503 HRESULT r;
505 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
506 if( FAILED(r) )
507 return 0;
508 return stat.cbSize.QuadPart;
511 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
513 TRACE("%p %d\n", rec, iField);
515 if( iField > rec->count )
516 return 0;
518 switch( rec->fields[iField].type )
520 case MSIFIELD_INT:
521 return sizeof (INT);
522 case MSIFIELD_WSTR:
523 return rec->fields[iField].len;
524 case MSIFIELD_NULL:
525 break;
526 case MSIFIELD_STREAM:
527 return get_stream_size( rec->fields[iField].u.stream );
529 return 0;
532 UINT WINAPI MsiRecordDataSize( MSIHANDLE handle, UINT iField )
534 MSIRECORD *rec;
535 UINT ret;
537 TRACE( "%lu, %u\n", handle, iField );
539 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
540 if( !rec )
541 return 0;
542 msiobj_lock( &rec->hdr );
543 ret = MSI_RecordDataSize( rec, iField);
544 msiobj_unlock( &rec->hdr );
545 msiobj_release( &rec->hdr );
546 return ret;
549 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, const char *szValue )
551 WCHAR *valueW = NULL;
552 MSIRECORD *rec;
553 UINT ret;
555 TRACE( "%lu, %u %s\n", handle, iField, debugstr_a(szValue) );
557 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
559 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
560 if( !rec )
562 free( valueW );
563 return ERROR_INVALID_HANDLE;
565 msiobj_lock( &rec->hdr );
566 ret = MSI_RecordSetStringW( rec, iField, valueW );
567 msiobj_unlock( &rec->hdr );
568 msiobj_release( &rec->hdr );
569 free( valueW );
570 return ret;
573 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
575 if (field > rec->count)
576 return ERROR_INVALID_FIELD;
578 MSI_FreeField( &rec->fields[field] );
580 if (value && len < 0) len = lstrlenW( value );
582 if (value && len)
584 rec->fields[field].type = MSIFIELD_WSTR;
585 rec->fields[field].u.szwVal = msi_strdupW( value, len );
586 rec->fields[field].len = len;
588 else
590 rec->fields[field].type = MSIFIELD_NULL;
591 rec->fields[field].u.szwVal = NULL;
592 rec->fields[field].len = 0;
594 return 0;
597 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
599 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
601 return msi_record_set_string( rec, iField, szValue, -1 );
604 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, const WCHAR *szValue )
606 MSIRECORD *rec;
607 UINT ret;
609 TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szValue) );
611 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
612 if( !rec )
613 return ERROR_INVALID_HANDLE;
615 msiobj_lock( &rec->hdr );
616 ret = MSI_RecordSetStringW( rec, iField, szValue );
617 msiobj_unlock( &rec->hdr );
618 msiobj_release( &rec->hdr );
619 return ret;
622 /* read the data in a file into an IStream */
623 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
625 DWORD sz, szHighWord = 0, read;
626 HANDLE handle;
627 HGLOBAL hGlob = 0;
628 HRESULT hr;
629 ULARGE_INTEGER ulSize;
631 TRACE("reading %s\n", debugstr_w(szFile));
633 /* read the file into memory */
634 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
635 if( handle == INVALID_HANDLE_VALUE )
636 return GetLastError();
637 sz = GetFileSize(handle, &szHighWord);
638 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
640 hGlob = GlobalAlloc(GMEM_FIXED, sz);
641 if( hGlob )
643 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
644 if( !r )
646 GlobalFree(hGlob);
647 hGlob = 0;
651 CloseHandle(handle);
652 if( !hGlob )
653 return ERROR_FUNCTION_FAILED;
655 /* make a stream out of it, and set the correct file size */
656 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
657 if( FAILED( hr ) )
659 GlobalFree(hGlob);
660 return ERROR_FUNCTION_FAILED;
663 /* set the correct size - CreateStreamOnHGlobal screws it up */
664 ulSize.QuadPart = sz;
665 IStream_SetSize(*pstm, ulSize);
667 TRACE( "read %s, %lu bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm );
668 return ERROR_SUCCESS;
671 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
673 if ( (iField == 0) || (iField > rec->count) )
674 return ERROR_INVALID_PARAMETER;
676 MSI_FreeField( &rec->fields[iField] );
677 rec->fields[iField].type = MSIFIELD_STREAM;
678 rec->fields[iField].u.stream = stream;
680 return ERROR_SUCCESS;
683 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
685 IStream *stm = NULL;
686 HRESULT hr;
687 UINT ret;
689 if( (iField == 0) || (iField > rec->count) )
690 return ERROR_INVALID_PARAMETER;
692 /* no filename means we should seek back to the start of the stream */
693 if( !szFilename )
695 LARGE_INTEGER ofs;
696 ULARGE_INTEGER cur;
698 if( rec->fields[iField].type != MSIFIELD_STREAM )
699 return ERROR_INVALID_FIELD;
701 stm = rec->fields[iField].u.stream;
702 if( !stm )
703 return ERROR_INVALID_FIELD;
705 ofs.QuadPart = 0;
706 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
707 if (FAILED( hr ))
708 return ERROR_FUNCTION_FAILED;
710 else
712 /* read the file into a stream and save the stream in the record */
713 ret = RECORD_StreamFromFile(szFilename, &stm);
714 if (ret != ERROR_SUCCESS)
715 return ret;
717 /* if all's good, store it in the record */
718 MSI_RecordSetStream(rec, iField, stm);
721 return ERROR_SUCCESS;
724 UINT WINAPI MsiRecordSetStreamA( MSIHANDLE hRecord, UINT iField, const char *szFilename )
726 WCHAR *wstr = NULL;
727 UINT ret;
729 TRACE( "%lu, %u, %s\n", hRecord, iField, debugstr_a(szFilename) );
731 if( szFilename )
733 wstr = strdupAtoW( szFilename );
734 if( !wstr )
735 return ERROR_OUTOFMEMORY;
737 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
738 free(wstr);
740 return ret;
743 UINT WINAPI MsiRecordSetStreamW( MSIHANDLE handle, UINT iField, const WCHAR *szFilename )
745 MSIRECORD *rec;
746 UINT ret;
748 TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szFilename) );
750 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
751 if( !rec )
752 return ERROR_INVALID_HANDLE;
754 msiobj_lock( &rec->hdr );
755 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
756 msiobj_unlock( &rec->hdr );
757 msiobj_release( &rec->hdr );
758 return ret;
761 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
763 ULONG count;
764 HRESULT r;
765 IStream *stm;
767 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
769 if( !sz )
770 return ERROR_INVALID_PARAMETER;
772 if( iField > rec->count)
773 return ERROR_INVALID_PARAMETER;
775 if ( rec->fields[iField].type == MSIFIELD_NULL )
777 *sz = 0;
778 return ERROR_INVALID_DATA;
781 if( rec->fields[iField].type != MSIFIELD_STREAM )
782 return ERROR_INVALID_DATATYPE;
784 stm = rec->fields[iField].u.stream;
785 if( !stm )
786 return ERROR_INVALID_PARAMETER;
788 /* if there's no buffer pointer, calculate the length to the end */
789 if( !buf )
791 LARGE_INTEGER ofs;
792 ULARGE_INTEGER end, cur;
794 ofs.QuadPart = cur.QuadPart = 0;
795 end.QuadPart = 0;
796 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
797 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
798 ofs.QuadPart = cur.QuadPart;
799 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
800 *sz = end.QuadPart - cur.QuadPart;
802 return ERROR_SUCCESS;
805 /* read the data */
806 count = 0;
807 r = IStream_Read( stm, buf, *sz, &count );
808 if( FAILED( r ) )
810 *sz = 0;
811 return ERROR_FUNCTION_FAILED;
814 *sz = count;
816 return ERROR_SUCCESS;
819 UINT WINAPI MsiRecordReadStream( MSIHANDLE handle, UINT iField, char *buf, DWORD *sz )
821 MSIRECORD *rec;
822 UINT ret;
824 TRACE( "%lu, %u, %p, %p\n", handle, iField, buf, sz );
826 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
827 if( !rec )
828 return ERROR_INVALID_HANDLE;
829 msiobj_lock( &rec->hdr );
830 ret = MSI_RecordReadStream( rec, iField, buf, sz );
831 msiobj_unlock( &rec->hdr );
832 msiobj_release( &rec->hdr );
833 return ret;
836 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
838 TRACE("%p %d %p\n", rec, iField, stm);
840 if( iField > rec->count )
841 return ERROR_INVALID_FIELD;
843 MSI_FreeField( &rec->fields[iField] );
845 rec->fields[iField].type = MSIFIELD_STREAM;
846 rec->fields[iField].u.stream = stm;
847 IStream_AddRef( stm );
849 return ERROR_SUCCESS;
852 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
854 TRACE("%p %d %p\n", rec, iField, pstm);
856 if( iField > rec->count )
857 return ERROR_INVALID_FIELD;
859 if( rec->fields[iField].type != MSIFIELD_STREAM )
860 return ERROR_INVALID_FIELD;
862 *pstm = rec->fields[iField].u.stream;
863 IStream_AddRef( *pstm );
865 return ERROR_SUCCESS;
868 static UINT dump_stream_to_file( IStream *stm, const WCHAR *name )
870 ULARGE_INTEGER size;
871 LARGE_INTEGER pos;
872 IStream *out;
873 DWORD stgm;
874 HRESULT r;
876 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
877 r = SHCreateStreamOnFileW( name, stgm, &out );
878 if( FAILED( r ) )
879 return ERROR_FUNCTION_FAILED;
881 pos.QuadPart = 0;
882 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
883 if( FAILED( r ) )
884 goto end;
886 pos.QuadPart = 0;
887 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
888 if( FAILED( r ) )
889 goto end;
891 r = IStream_CopyTo( stm, out, size, NULL, NULL );
893 end:
894 IStream_Release( out );
895 if( FAILED( r ) )
896 return ERROR_FUNCTION_FAILED;
897 return ERROR_SUCCESS;
900 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
902 IStream *stm = NULL;
903 UINT r;
905 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
907 msiobj_lock( &rec->hdr );
909 r = MSI_RecordGetIStream( rec, iField, &stm );
910 if( r == ERROR_SUCCESS )
912 r = dump_stream_to_file( stm, name );
913 IStream_Release( stm );
916 msiobj_unlock( &rec->hdr );
918 return r;
921 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
923 MSIRECORD *clone;
924 UINT r, i, count;
926 count = MSI_RecordGetFieldCount(rec);
927 clone = MSI_CreateRecord(count);
928 if (!clone)
929 return NULL;
931 for (i = 0; i <= count; i++)
933 if (rec->fields[i].type == MSIFIELD_STREAM)
935 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
936 &clone->fields[i].u.stream)))
938 msiobj_release(&clone->hdr);
939 return NULL;
941 clone->fields[i].type = MSIFIELD_STREAM;
943 else
945 r = MSI_RecordCopyField(rec, i, clone, i);
946 if (r != ERROR_SUCCESS)
948 msiobj_release(&clone->hdr);
949 return NULL;
954 return clone;
957 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
959 if (a->fields[field].type != b->fields[field].type)
960 return FALSE;
962 switch (a->fields[field].type)
964 case MSIFIELD_NULL:
965 break;
967 case MSIFIELD_INT:
968 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
969 return FALSE;
970 break;
972 case MSIFIELD_WSTR:
973 if (a->fields[field].len != b->fields[field].len) return FALSE;
974 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
975 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
976 break;
978 case MSIFIELD_STREAM:
979 default:
980 return FALSE;
982 return TRUE;
986 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
988 UINT i;
990 if (a->count != b->count)
991 return FALSE;
993 for (i = 0; i <= a->count; i++)
995 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
996 return FALSE;
999 return TRUE;
1002 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1004 DWORD sz = 0;
1005 WCHAR *str;
1006 UINT r;
1008 if (MSI_RecordIsNull( rec, field )) return NULL;
1010 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1011 if (r != ERROR_SUCCESS)
1012 return NULL;
1014 sz++;
1015 str = malloc( sz * sizeof(WCHAR) );
1016 if (!str) return NULL;
1017 str[0] = 0;
1018 r = MSI_RecordGetStringW( rec, field, str, &sz );
1019 if (r != ERROR_SUCCESS)
1021 ERR("failed to get string!\n");
1022 free( str );
1023 return NULL;
1025 return str;
1028 void dump_record(MSIRECORD *rec)
1030 int i;
1031 if (!rec)
1033 TRACE("(null)\n");
1034 return;
1037 TRACE("[");
1038 for (i = 0; i <= rec->count; i++)
1040 switch(rec->fields[i].type)
1042 case MSIFIELD_NULL: TRACE("(null)"); break;
1043 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1044 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1045 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1047 if (i < rec->count) TRACE(", ");
1049 TRACE("]\n");
1052 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
1054 MSIRECORD *rec;
1055 unsigned int i;
1056 UINT r = ERROR_SUCCESS;
1058 if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1059 return ERROR_INVALID_HANDLE;
1061 rec->cookie = in->cookie;
1062 for (i = 0; i <= in->count; i++)
1064 switch (in->fields[i].type)
1066 case MSIFIELD_NULL:
1067 MSI_FreeField(&rec->fields[i]);
1068 rec->fields[i].type = MSIFIELD_NULL;
1069 break;
1070 case MSIFIELD_INT:
1071 r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
1072 break;
1073 case MSIFIELD_WSTR:
1074 r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
1075 break;
1076 case MSIFIELD_STREAM:
1077 r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
1078 break;
1079 default:
1080 ERR("invalid field type %d\n", in->fields[i].type);
1081 break;
1084 if (r)
1086 msiobj_release(&rec->hdr);
1087 return r;
1091 msiobj_release(&rec->hdr);
1092 return ERROR_SUCCESS;
1095 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1097 if (!in)
1099 *out = 0;
1100 return ERROR_SUCCESS;
1103 *out = MsiCreateRecord(in->count);
1104 if (!*out) return ERROR_OUTOFMEMORY;
1106 return copy_remote_record(in, *out);
1109 struct wire_record *marshal_record(MSIHANDLE handle)
1111 struct wire_record *ret;
1112 unsigned int i;
1113 MSIRECORD *rec;
1115 if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1116 return NULL;
1118 ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
1119 ret->count = rec->count;
1120 ret->cookie = rec->cookie;
1122 for (i = 0; i <= rec->count; i++)
1124 switch (rec->fields[i].type)
1126 case MSIFIELD_NULL:
1127 break;
1128 case MSIFIELD_INT:
1129 ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1130 break;
1131 case MSIFIELD_WSTR:
1132 ret->fields[i].u.szwVal = wcsdup(rec->fields[i].u.szwVal);
1133 break;
1134 case MSIFIELD_STREAM:
1135 IStream_AddRef(rec->fields[i].u.stream);
1136 ret->fields[i].u.stream = rec->fields[i].u.stream;
1137 break;
1138 default:
1139 ERR("invalid field type %d\n", rec->fields[i].type);
1140 break;
1142 ret->fields[i].type = rec->fields[i].type;
1145 msiobj_release(&rec->hdr);
1146 return ret;
1149 void free_remote_record(struct wire_record *rec)
1151 int i;
1153 for (i = 0; i <= rec->count; i++)
1155 if (rec->fields[i].type == MSIFIELD_WSTR)
1156 midl_user_free(rec->fields[i].u.szwVal);
1157 else if (rec->fields[i].type == MSIFIELD_STREAM)
1158 IStream_Release(rec->fields[i].u.stream);
1161 midl_user_free(rec);