dmime: Free list when Tempo track is destroyed.
[wine.git] / dlls / msi / record.c
blob0a352adcd87aab50b8df6b79802f80dcab8f51ae
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 msi_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("%d\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 = msi_alloc( (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("%d %d\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("%d\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("%d %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("%d %d\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,
404 LPSTR szValue, LPDWORD pcchValue)
406 MSIRECORD *rec;
407 UINT ret;
409 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
411 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
412 if( !rec )
413 return ERROR_INVALID_HANDLE;
414 msiobj_lock( &rec->hdr );
415 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
416 msiobj_unlock( &rec->hdr );
417 msiobj_release( &rec->hdr );
418 return ret;
421 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
423 if (field > rec->count)
424 return NULL;
426 if (rec->fields[field].type != MSIFIELD_WSTR)
427 return NULL;
429 if (len) *len = rec->fields[field].len;
431 return rec->fields[field].u.szwVal;
434 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
436 return msi_record_get_string( rec, iField, NULL );
439 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
440 LPWSTR szValue, LPDWORD pcchValue)
442 static const WCHAR szFormat[] = {'%','d',0};
443 UINT len = 0, ret = ERROR_SUCCESS;
444 WCHAR buffer[16];
446 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
448 if( iField > rec->count )
450 if ( szValue && *pcchValue > 0 )
451 szValue[0] = 0;
453 *pcchValue = 0;
454 return ERROR_SUCCESS;
457 switch( rec->fields[iField].type )
459 case MSIFIELD_INT:
460 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
461 len = lstrlenW( buffer );
462 if (szValue)
463 lstrcpynW(szValue, buffer, *pcchValue);
464 break;
465 case MSIFIELD_WSTR:
466 len = rec->fields[iField].len;
467 if (szValue)
468 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
469 break;
470 case MSIFIELD_NULL:
471 if( szValue && *pcchValue > 0 )
472 szValue[0] = 0;
473 break;
474 default:
475 break;
478 if( szValue && *pcchValue <= len )
479 ret = ERROR_MORE_DATA;
480 *pcchValue = len;
482 return ret;
485 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
486 LPWSTR szValue, LPDWORD pcchValue)
488 MSIRECORD *rec;
489 UINT ret;
491 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
493 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
494 if( !rec )
495 return ERROR_INVALID_HANDLE;
497 msiobj_lock( &rec->hdr );
498 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
499 msiobj_unlock( &rec->hdr );
500 msiobj_release( &rec->hdr );
501 return ret;
504 static UINT msi_get_stream_size( IStream *stm )
506 STATSTG stat;
507 HRESULT r;
509 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
510 if( FAILED(r) )
511 return 0;
512 return stat.cbSize.QuadPart;
515 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
517 TRACE("%p %d\n", rec, iField);
519 if( iField > rec->count )
520 return 0;
522 switch( rec->fields[iField].type )
524 case MSIFIELD_INT:
525 return sizeof (INT);
526 case MSIFIELD_WSTR:
527 return rec->fields[iField].len;
528 case MSIFIELD_NULL:
529 break;
530 case MSIFIELD_STREAM:
531 return msi_get_stream_size( rec->fields[iField].u.stream );
533 return 0;
536 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
538 MSIRECORD *rec;
539 UINT ret;
541 TRACE("%d %d\n", handle, iField);
543 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
544 if( !rec )
545 return 0;
546 msiobj_lock( &rec->hdr );
547 ret = MSI_RecordDataSize( rec, iField);
548 msiobj_unlock( &rec->hdr );
549 msiobj_release( &rec->hdr );
550 return ret;
553 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
555 WCHAR *valueW = NULL;
556 MSIRECORD *rec;
557 UINT ret;
559 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
561 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
563 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
564 if( !rec )
566 msi_free( valueW );
567 return ERROR_INVALID_HANDLE;
569 msiobj_lock( &rec->hdr );
570 ret = MSI_RecordSetStringW( rec, iField, valueW );
571 msiobj_unlock( &rec->hdr );
572 msiobj_release( &rec->hdr );
573 msi_free( valueW );
574 return ret;
577 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
579 if (field > rec->count)
580 return ERROR_INVALID_FIELD;
582 MSI_FreeField( &rec->fields[field] );
584 if (value && len < 0) len = lstrlenW( value );
586 if (value && len)
588 rec->fields[field].type = MSIFIELD_WSTR;
589 rec->fields[field].u.szwVal = msi_strdupW( value, len );
590 rec->fields[field].len = len;
592 else
594 rec->fields[field].type = MSIFIELD_NULL;
595 rec->fields[field].u.szwVal = NULL;
596 rec->fields[field].len = 0;
598 return 0;
601 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
603 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
605 return msi_record_set_string( rec, iField, szValue, -1 );
608 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
610 MSIRECORD *rec;
611 UINT ret;
613 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
615 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
616 if( !rec )
617 return ERROR_INVALID_HANDLE;
619 msiobj_lock( &rec->hdr );
620 ret = MSI_RecordSetStringW( rec, iField, szValue );
621 msiobj_unlock( &rec->hdr );
622 msiobj_release( &rec->hdr );
623 return ret;
626 /* read the data in a file into an IStream */
627 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
629 DWORD sz, szHighWord = 0, read;
630 HANDLE handle;
631 HGLOBAL hGlob = 0;
632 HRESULT hr;
633 ULARGE_INTEGER ulSize;
635 TRACE("reading %s\n", debugstr_w(szFile));
637 /* read the file into memory */
638 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
639 if( handle == INVALID_HANDLE_VALUE )
640 return GetLastError();
641 sz = GetFileSize(handle, &szHighWord);
642 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
644 hGlob = GlobalAlloc(GMEM_FIXED, sz);
645 if( hGlob )
647 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
648 if( !r )
650 GlobalFree(hGlob);
651 hGlob = 0;
655 CloseHandle(handle);
656 if( !hGlob )
657 return ERROR_FUNCTION_FAILED;
659 /* make a stream out of it, and set the correct file size */
660 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
661 if( FAILED( hr ) )
663 GlobalFree(hGlob);
664 return ERROR_FUNCTION_FAILED;
667 /* set the correct size - CreateStreamOnHGlobal screws it up */
668 ulSize.QuadPart = sz;
669 IStream_SetSize(*pstm, ulSize);
671 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
673 return ERROR_SUCCESS;
676 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
678 if ( (iField == 0) || (iField > rec->count) )
679 return ERROR_INVALID_PARAMETER;
681 MSI_FreeField( &rec->fields[iField] );
682 rec->fields[iField].type = MSIFIELD_STREAM;
683 rec->fields[iField].u.stream = stream;
685 return ERROR_SUCCESS;
688 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
690 IStream *stm = NULL;
691 HRESULT hr;
692 UINT ret;
694 if( (iField == 0) || (iField > rec->count) )
695 return ERROR_INVALID_PARAMETER;
697 /* no filename means we should seek back to the start of the stream */
698 if( !szFilename )
700 LARGE_INTEGER ofs;
701 ULARGE_INTEGER cur;
703 if( rec->fields[iField].type != MSIFIELD_STREAM )
704 return ERROR_INVALID_FIELD;
706 stm = rec->fields[iField].u.stream;
707 if( !stm )
708 return ERROR_INVALID_FIELD;
710 ofs.QuadPart = 0;
711 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
712 if (FAILED( hr ))
713 return ERROR_FUNCTION_FAILED;
715 else
717 /* read the file into a stream and save the stream in the record */
718 ret = RECORD_StreamFromFile(szFilename, &stm);
719 if (ret != ERROR_SUCCESS)
720 return ret;
722 /* if all's good, store it in the record */
723 MSI_RecordSetStream(rec, iField, stm);
726 return ERROR_SUCCESS;
729 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
731 LPWSTR wstr = NULL;
732 UINT ret;
734 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
736 if( szFilename )
738 wstr = strdupAtoW( szFilename );
739 if( !wstr )
740 return ERROR_OUTOFMEMORY;
742 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
743 msi_free(wstr);
745 return ret;
748 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
750 MSIRECORD *rec;
751 UINT ret;
753 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
755 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
756 if( !rec )
757 return ERROR_INVALID_HANDLE;
759 msiobj_lock( &rec->hdr );
760 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
761 msiobj_unlock( &rec->hdr );
762 msiobj_release( &rec->hdr );
763 return ret;
766 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
768 ULONG count;
769 HRESULT r;
770 IStream *stm;
772 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
774 if( !sz )
775 return ERROR_INVALID_PARAMETER;
777 if( iField > rec->count)
778 return ERROR_INVALID_PARAMETER;
780 if ( rec->fields[iField].type == MSIFIELD_NULL )
782 *sz = 0;
783 return ERROR_INVALID_DATA;
786 if( rec->fields[iField].type != MSIFIELD_STREAM )
787 return ERROR_INVALID_DATATYPE;
789 stm = rec->fields[iField].u.stream;
790 if( !stm )
791 return ERROR_INVALID_PARAMETER;
793 /* if there's no buffer pointer, calculate the length to the end */
794 if( !buf )
796 LARGE_INTEGER ofs;
797 ULARGE_INTEGER end, cur;
799 ofs.QuadPart = cur.QuadPart = 0;
800 end.QuadPart = 0;
801 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
802 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
803 ofs.QuadPart = cur.QuadPart;
804 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
805 *sz = end.QuadPart - cur.QuadPart;
807 return ERROR_SUCCESS;
810 /* read the data */
811 count = 0;
812 r = IStream_Read( stm, buf, *sz, &count );
813 if( FAILED( r ) )
815 *sz = 0;
816 return ERROR_FUNCTION_FAILED;
819 *sz = count;
821 return ERROR_SUCCESS;
824 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
826 MSIRECORD *rec;
827 UINT ret;
829 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
831 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
832 if( !rec )
833 return ERROR_INVALID_HANDLE;
834 msiobj_lock( &rec->hdr );
835 ret = MSI_RecordReadStream( rec, iField, buf, sz );
836 msiobj_unlock( &rec->hdr );
837 msiobj_release( &rec->hdr );
838 return ret;
841 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
843 TRACE("%p %d %p\n", rec, iField, stm);
845 if( iField > rec->count )
846 return ERROR_INVALID_FIELD;
848 MSI_FreeField( &rec->fields[iField] );
850 rec->fields[iField].type = MSIFIELD_STREAM;
851 rec->fields[iField].u.stream = stm;
852 IStream_AddRef( stm );
854 return ERROR_SUCCESS;
857 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
859 TRACE("%p %d %p\n", rec, iField, pstm);
861 if( iField > rec->count )
862 return ERROR_INVALID_FIELD;
864 if( rec->fields[iField].type != MSIFIELD_STREAM )
865 return ERROR_INVALID_FIELD;
867 *pstm = rec->fields[iField].u.stream;
868 IStream_AddRef( *pstm );
870 return ERROR_SUCCESS;
873 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
875 ULARGE_INTEGER size;
876 LARGE_INTEGER pos;
877 IStream *out;
878 DWORD stgm;
879 HRESULT r;
881 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
882 r = SHCreateStreamOnFileW( name, stgm, &out );
883 if( FAILED( r ) )
884 return ERROR_FUNCTION_FAILED;
886 pos.QuadPart = 0;
887 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
888 if( FAILED( r ) )
889 goto end;
891 pos.QuadPart = 0;
892 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
893 if( FAILED( r ) )
894 goto end;
896 r = IStream_CopyTo( stm, out, size, NULL, NULL );
898 end:
899 IStream_Release( out );
900 if( FAILED( r ) )
901 return ERROR_FUNCTION_FAILED;
902 return ERROR_SUCCESS;
905 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
907 IStream *stm = NULL;
908 UINT r;
910 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
912 msiobj_lock( &rec->hdr );
914 r = MSI_RecordGetIStream( rec, iField, &stm );
915 if( r == ERROR_SUCCESS )
917 r = msi_dump_stream_to_file( stm, name );
918 IStream_Release( stm );
921 msiobj_unlock( &rec->hdr );
923 return r;
926 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
928 MSIRECORD *clone;
929 UINT r, i, count;
931 count = MSI_RecordGetFieldCount(rec);
932 clone = MSI_CreateRecord(count);
933 if (!clone)
934 return NULL;
936 for (i = 0; i <= count; i++)
938 if (rec->fields[i].type == MSIFIELD_STREAM)
940 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
941 &clone->fields[i].u.stream)))
943 msiobj_release(&clone->hdr);
944 return NULL;
946 clone->fields[i].type = MSIFIELD_STREAM;
948 else
950 r = MSI_RecordCopyField(rec, i, clone, i);
951 if (r != ERROR_SUCCESS)
953 msiobj_release(&clone->hdr);
954 return NULL;
959 return clone;
962 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
964 if (a->fields[field].type != b->fields[field].type)
965 return FALSE;
967 switch (a->fields[field].type)
969 case MSIFIELD_NULL:
970 break;
972 case MSIFIELD_INT:
973 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
974 return FALSE;
975 break;
977 case MSIFIELD_WSTR:
978 if (a->fields[field].len != b->fields[field].len) return FALSE;
979 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
980 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
981 break;
983 case MSIFIELD_STREAM:
984 default:
985 return FALSE;
987 return TRUE;
991 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
993 UINT i;
995 if (a->count != b->count)
996 return FALSE;
998 for (i = 0; i <= a->count; i++)
1000 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1001 return FALSE;
1004 return TRUE;
1007 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1009 DWORD sz = 0;
1010 WCHAR *str;
1011 UINT r;
1013 if (MSI_RecordIsNull( rec, field )) return NULL;
1015 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1016 if (r != ERROR_SUCCESS)
1017 return NULL;
1019 sz++;
1020 str = msi_alloc( sz * sizeof(WCHAR) );
1021 if (!str) return NULL;
1022 str[0] = 0;
1023 r = MSI_RecordGetStringW( rec, field, str, &sz );
1024 if (r != ERROR_SUCCESS)
1026 ERR("failed to get string!\n");
1027 msi_free( str );
1028 return NULL;
1030 return str;
1033 void dump_record(MSIRECORD *rec)
1035 int i;
1036 if (!rec)
1038 TRACE("(null)\n");
1039 return;
1042 TRACE("[");
1043 for (i = 0; i <= rec->count; i++)
1045 switch(rec->fields[i].type)
1047 case MSIFIELD_NULL: TRACE("(null)"); break;
1048 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1049 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1050 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1052 if (i < rec->count) TRACE(", ");
1054 TRACE("]\n");
1057 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
1059 MSIRECORD *rec;
1060 unsigned int i;
1061 UINT r = ERROR_SUCCESS;
1063 if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1064 return ERROR_INVALID_HANDLE;
1066 rec->cookie = in->cookie;
1067 for (i = 0; i <= in->count; i++)
1069 switch (in->fields[i].type)
1071 case MSIFIELD_NULL:
1072 MSI_FreeField(&rec->fields[i]);
1073 rec->fields[i].type = MSIFIELD_NULL;
1074 break;
1075 case MSIFIELD_INT:
1076 r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
1077 break;
1078 case MSIFIELD_WSTR:
1079 r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
1080 break;
1081 case MSIFIELD_STREAM:
1082 r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
1083 break;
1084 default:
1085 ERR("invalid field type %d\n", in->fields[i].type);
1086 break;
1089 if (r)
1091 msiobj_release(&rec->hdr);
1092 return r;
1096 msiobj_release(&rec->hdr);
1097 return ERROR_SUCCESS;
1100 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1102 if (!in)
1104 *out = 0;
1105 return ERROR_SUCCESS;
1108 *out = MsiCreateRecord(in->count);
1109 if (!*out) return ERROR_OUTOFMEMORY;
1111 return copy_remote_record(in, *out);
1114 struct wire_record *marshal_record(MSIHANDLE handle)
1116 struct wire_record *ret;
1117 unsigned int i;
1118 MSIRECORD *rec;
1120 if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1121 return NULL;
1123 ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
1124 ret->count = rec->count;
1125 ret->cookie = rec->cookie;
1127 for (i = 0; i <= rec->count; i++)
1129 switch (rec->fields[i].type)
1131 case MSIFIELD_NULL:
1132 break;
1133 case MSIFIELD_INT:
1134 ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1135 break;
1136 case MSIFIELD_WSTR:
1137 ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal);
1138 break;
1139 case MSIFIELD_STREAM:
1140 IStream_AddRef(rec->fields[i].u.stream);
1141 ret->fields[i].u.stream = rec->fields[i].u.stream;
1142 break;
1143 default:
1144 ERR("invalid field type %d\n", rec->fields[i].type);
1145 break;
1147 ret->fields[i].type = rec->fields[i].type;
1150 msiobj_release(&rec->hdr);
1151 return ret;
1154 void free_remote_record(struct wire_record *rec)
1156 int i;
1158 for (i = 0; i <= rec->count; i++)
1160 if (rec->fields[i].type == MSIFIELD_WSTR)
1161 midl_user_free(rec->fields[i].u.szwVal);
1162 else if (rec->fields[i].type == MSIFIELD_STREAM)
1163 IStream_Release(rec->fields[i].u.stream);
1166 midl_user_free(rec);