Release 2.9.
[wine.git] / dlls / msi / record.c
blob51e7a23a45cdc021f883b9bb53dfda7c6d1d09b4
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 hr;
731 UINT ret;
733 if( (iField == 0) || (iField > rec->count) )
734 return ERROR_INVALID_PARAMETER;
736 /* no filename means we should seek back to the start of the stream */
737 if( !szFilename )
739 LARGE_INTEGER ofs;
740 ULARGE_INTEGER cur;
742 if( rec->fields[iField].type != MSIFIELD_STREAM )
743 return ERROR_INVALID_FIELD;
745 stm = rec->fields[iField].u.stream;
746 if( !stm )
747 return ERROR_INVALID_FIELD;
749 ofs.QuadPart = 0;
750 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
751 if (FAILED( hr ))
752 return ERROR_FUNCTION_FAILED;
754 else
756 /* read the file into a stream and save the stream in the record */
757 ret = RECORD_StreamFromFile(szFilename, &stm);
758 if (ret != ERROR_SUCCESS)
759 return ret;
761 /* if all's good, store it in the record */
762 MSI_RecordSetStream(rec, iField, stm);
765 return ERROR_SUCCESS;
768 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
770 LPWSTR wstr = NULL;
771 UINT ret;
773 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
775 if( szFilename )
777 wstr = strdupAtoW( szFilename );
778 if( !wstr )
779 return ERROR_OUTOFMEMORY;
781 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
782 msi_free(wstr);
784 return ret;
787 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
789 MSIRECORD *rec;
790 UINT ret;
792 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
794 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
795 if( !rec )
796 return ERROR_INVALID_HANDLE;
798 msiobj_lock( &rec->hdr );
799 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
800 msiobj_unlock( &rec->hdr );
801 msiobj_release( &rec->hdr );
802 return ret;
805 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
807 ULONG count;
808 HRESULT r;
809 IStream *stm;
811 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
813 if( !sz )
814 return ERROR_INVALID_PARAMETER;
816 if( iField > rec->count)
817 return ERROR_INVALID_PARAMETER;
819 if ( rec->fields[iField].type == MSIFIELD_NULL )
821 *sz = 0;
822 return ERROR_INVALID_DATA;
825 if( rec->fields[iField].type != MSIFIELD_STREAM )
826 return ERROR_INVALID_DATATYPE;
828 stm = rec->fields[iField].u.stream;
829 if( !stm )
830 return ERROR_INVALID_PARAMETER;
832 /* if there's no buffer pointer, calculate the length to the end */
833 if( !buf )
835 LARGE_INTEGER ofs;
836 ULARGE_INTEGER end, cur;
838 ofs.QuadPart = cur.QuadPart = 0;
839 end.QuadPart = 0;
840 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
841 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
842 ofs.QuadPart = cur.QuadPart;
843 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
844 *sz = end.QuadPart - cur.QuadPart;
846 return ERROR_SUCCESS;
849 /* read the data */
850 count = 0;
851 r = IStream_Read( stm, buf, *sz, &count );
852 if( FAILED( r ) )
854 *sz = 0;
855 return ERROR_FUNCTION_FAILED;
858 *sz = count;
860 return ERROR_SUCCESS;
863 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
865 MSIRECORD *rec;
866 UINT ret;
868 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
870 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
871 if( !rec )
872 return ERROR_INVALID_HANDLE;
873 msiobj_lock( &rec->hdr );
874 ret = MSI_RecordReadStream( rec, iField, buf, sz );
875 msiobj_unlock( &rec->hdr );
876 msiobj_release( &rec->hdr );
877 return ret;
880 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
882 TRACE("%p %d %p\n", rec, iField, stm);
884 if( iField > rec->count )
885 return ERROR_INVALID_FIELD;
887 MSI_FreeField( &rec->fields[iField] );
889 rec->fields[iField].type = MSIFIELD_STREAM;
890 rec->fields[iField].u.stream = stm;
891 IStream_AddRef( stm );
893 return ERROR_SUCCESS;
896 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
898 TRACE("%p %d %p\n", rec, iField, pstm);
900 if( iField > rec->count )
901 return ERROR_INVALID_FIELD;
903 if( rec->fields[iField].type != MSIFIELD_STREAM )
904 return ERROR_INVALID_FIELD;
906 *pstm = rec->fields[iField].u.stream;
907 IStream_AddRef( *pstm );
909 return ERROR_SUCCESS;
912 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
914 ULARGE_INTEGER size;
915 LARGE_INTEGER pos;
916 IStream *out;
917 DWORD stgm;
918 HRESULT r;
920 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
921 r = SHCreateStreamOnFileW( name, stgm, &out );
922 if( FAILED( r ) )
923 return ERROR_FUNCTION_FAILED;
925 pos.QuadPart = 0;
926 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
927 if( FAILED( r ) )
928 goto end;
930 pos.QuadPart = 0;
931 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
932 if( FAILED( r ) )
933 goto end;
935 r = IStream_CopyTo( stm, out, size, NULL, NULL );
937 end:
938 IStream_Release( out );
939 if( FAILED( r ) )
940 return ERROR_FUNCTION_FAILED;
941 return ERROR_SUCCESS;
944 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
946 IStream *stm = NULL;
947 UINT r;
949 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
951 msiobj_lock( &rec->hdr );
953 r = MSI_RecordGetIStream( rec, iField, &stm );
954 if( r == ERROR_SUCCESS )
956 r = msi_dump_stream_to_file( stm, name );
957 IStream_Release( stm );
960 msiobj_unlock( &rec->hdr );
962 return r;
965 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
967 MSIRECORD *clone;
968 UINT r, i, count;
970 count = MSI_RecordGetFieldCount(rec);
971 clone = MSI_CreateRecord(count);
972 if (!clone)
973 return NULL;
975 for (i = 0; i <= count; i++)
977 if (rec->fields[i].type == MSIFIELD_STREAM)
979 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
980 &clone->fields[i].u.stream)))
982 msiobj_release(&clone->hdr);
983 return NULL;
985 clone->fields[i].type = MSIFIELD_STREAM;
987 else
989 r = MSI_RecordCopyField(rec, i, clone, i);
990 if (r != ERROR_SUCCESS)
992 msiobj_release(&clone->hdr);
993 return NULL;
998 return clone;
1001 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
1003 if (a->fields[field].type != b->fields[field].type)
1004 return FALSE;
1006 switch (a->fields[field].type)
1008 case MSIFIELD_NULL:
1009 break;
1011 case MSIFIELD_INT:
1012 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
1013 return FALSE;
1014 break;
1016 case MSIFIELD_WSTR:
1017 if (a->fields[field].len != b->fields[field].len) return FALSE;
1018 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
1019 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
1020 break;
1022 case MSIFIELD_STREAM:
1023 default:
1024 return FALSE;
1026 return TRUE;
1030 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
1032 UINT i;
1034 if (a->count != b->count)
1035 return FALSE;
1037 for (i = 0; i <= a->count; i++)
1039 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1040 return FALSE;
1043 return TRUE;
1046 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1048 DWORD sz = 0;
1049 WCHAR *str;
1050 UINT r;
1052 if (MSI_RecordIsNull( rec, field )) return NULL;
1054 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1055 if (r != ERROR_SUCCESS)
1056 return NULL;
1058 sz++;
1059 str = msi_alloc( sz * sizeof(WCHAR) );
1060 if (!str) return NULL;
1061 str[0] = 0;
1062 r = MSI_RecordGetStringW( rec, field, str, &sz );
1063 if (r != ERROR_SUCCESS)
1065 ERR("failed to get string!\n");
1066 msi_free( str );
1067 return NULL;
1069 return str;