hid: Rewrite HidP_MaxUsageListLength using enum_value_caps.
[wine.git] / dlls / msi / record.c
blob46c2d71f6f1893793f5d6e16de853088410fbc43
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 UINT len = 0, ret = ERROR_SUCCESS;
443 WCHAR buffer[16];
445 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
447 if( iField > rec->count )
449 if ( szValue && *pcchValue > 0 )
450 szValue[0] = 0;
452 *pcchValue = 0;
453 return ERROR_SUCCESS;
456 switch( rec->fields[iField].type )
458 case MSIFIELD_INT:
459 wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal);
460 len = lstrlenW( buffer );
461 if (szValue)
462 lstrcpynW(szValue, buffer, *pcchValue);
463 break;
464 case MSIFIELD_WSTR:
465 len = rec->fields[iField].len;
466 if (szValue)
467 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
468 break;
469 case MSIFIELD_NULL:
470 if( szValue && *pcchValue > 0 )
471 szValue[0] = 0;
472 break;
473 default:
474 break;
477 if( szValue && *pcchValue <= len )
478 ret = ERROR_MORE_DATA;
479 *pcchValue = len;
481 return ret;
484 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
485 LPWSTR szValue, LPDWORD pcchValue)
487 MSIRECORD *rec;
488 UINT ret;
490 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
492 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
493 if( !rec )
494 return ERROR_INVALID_HANDLE;
496 msiobj_lock( &rec->hdr );
497 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
498 msiobj_unlock( &rec->hdr );
499 msiobj_release( &rec->hdr );
500 return ret;
503 static UINT msi_get_stream_size( IStream *stm )
505 STATSTG stat;
506 HRESULT r;
508 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
509 if( FAILED(r) )
510 return 0;
511 return stat.cbSize.QuadPart;
514 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
516 TRACE("%p %d\n", rec, iField);
518 if( iField > rec->count )
519 return 0;
521 switch( rec->fields[iField].type )
523 case MSIFIELD_INT:
524 return sizeof (INT);
525 case MSIFIELD_WSTR:
526 return rec->fields[iField].len;
527 case MSIFIELD_NULL:
528 break;
529 case MSIFIELD_STREAM:
530 return msi_get_stream_size( rec->fields[iField].u.stream );
532 return 0;
535 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
537 MSIRECORD *rec;
538 UINT ret;
540 TRACE("%d %d\n", handle, iField);
542 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
543 if( !rec )
544 return 0;
545 msiobj_lock( &rec->hdr );
546 ret = MSI_RecordDataSize( rec, iField);
547 msiobj_unlock( &rec->hdr );
548 msiobj_release( &rec->hdr );
549 return ret;
552 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
554 WCHAR *valueW = NULL;
555 MSIRECORD *rec;
556 UINT ret;
558 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
560 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
562 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
563 if( !rec )
565 msi_free( valueW );
566 return ERROR_INVALID_HANDLE;
568 msiobj_lock( &rec->hdr );
569 ret = MSI_RecordSetStringW( rec, iField, valueW );
570 msiobj_unlock( &rec->hdr );
571 msiobj_release( &rec->hdr );
572 msi_free( valueW );
573 return ret;
576 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
578 if (field > rec->count)
579 return ERROR_INVALID_FIELD;
581 MSI_FreeField( &rec->fields[field] );
583 if (value && len < 0) len = lstrlenW( value );
585 if (value && len)
587 rec->fields[field].type = MSIFIELD_WSTR;
588 rec->fields[field].u.szwVal = msi_strdupW( value, len );
589 rec->fields[field].len = len;
591 else
593 rec->fields[field].type = MSIFIELD_NULL;
594 rec->fields[field].u.szwVal = NULL;
595 rec->fields[field].len = 0;
597 return 0;
600 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
602 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
604 return msi_record_set_string( rec, iField, szValue, -1 );
607 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
609 MSIRECORD *rec;
610 UINT ret;
612 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
614 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
615 if( !rec )
616 return ERROR_INVALID_HANDLE;
618 msiobj_lock( &rec->hdr );
619 ret = MSI_RecordSetStringW( rec, iField, szValue );
620 msiobj_unlock( &rec->hdr );
621 msiobj_release( &rec->hdr );
622 return ret;
625 /* read the data in a file into an IStream */
626 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
628 DWORD sz, szHighWord = 0, read;
629 HANDLE handle;
630 HGLOBAL hGlob = 0;
631 HRESULT hr;
632 ULARGE_INTEGER ulSize;
634 TRACE("reading %s\n", debugstr_w(szFile));
636 /* read the file into memory */
637 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
638 if( handle == INVALID_HANDLE_VALUE )
639 return GetLastError();
640 sz = GetFileSize(handle, &szHighWord);
641 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
643 hGlob = GlobalAlloc(GMEM_FIXED, sz);
644 if( hGlob )
646 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
647 if( !r )
649 GlobalFree(hGlob);
650 hGlob = 0;
654 CloseHandle(handle);
655 if( !hGlob )
656 return ERROR_FUNCTION_FAILED;
658 /* make a stream out of it, and set the correct file size */
659 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
660 if( FAILED( hr ) )
662 GlobalFree(hGlob);
663 return ERROR_FUNCTION_FAILED;
666 /* set the correct size - CreateStreamOnHGlobal screws it up */
667 ulSize.QuadPart = sz;
668 IStream_SetSize(*pstm, ulSize);
670 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
672 return ERROR_SUCCESS;
675 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
677 if ( (iField == 0) || (iField > rec->count) )
678 return ERROR_INVALID_PARAMETER;
680 MSI_FreeField( &rec->fields[iField] );
681 rec->fields[iField].type = MSIFIELD_STREAM;
682 rec->fields[iField].u.stream = stream;
684 return ERROR_SUCCESS;
687 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
689 IStream *stm = NULL;
690 HRESULT hr;
691 UINT ret;
693 if( (iField == 0) || (iField > rec->count) )
694 return ERROR_INVALID_PARAMETER;
696 /* no filename means we should seek back to the start of the stream */
697 if( !szFilename )
699 LARGE_INTEGER ofs;
700 ULARGE_INTEGER cur;
702 if( rec->fields[iField].type != MSIFIELD_STREAM )
703 return ERROR_INVALID_FIELD;
705 stm = rec->fields[iField].u.stream;
706 if( !stm )
707 return ERROR_INVALID_FIELD;
709 ofs.QuadPart = 0;
710 hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
711 if (FAILED( hr ))
712 return ERROR_FUNCTION_FAILED;
714 else
716 /* read the file into a stream and save the stream in the record */
717 ret = RECORD_StreamFromFile(szFilename, &stm);
718 if (ret != ERROR_SUCCESS)
719 return ret;
721 /* if all's good, store it in the record */
722 MSI_RecordSetStream(rec, iField, stm);
725 return ERROR_SUCCESS;
728 UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
730 LPWSTR wstr = NULL;
731 UINT ret;
733 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
735 if( szFilename )
737 wstr = strdupAtoW( szFilename );
738 if( !wstr )
739 return ERROR_OUTOFMEMORY;
741 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
742 msi_free(wstr);
744 return ret;
747 UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
749 MSIRECORD *rec;
750 UINT ret;
752 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
754 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
755 if( !rec )
756 return ERROR_INVALID_HANDLE;
758 msiobj_lock( &rec->hdr );
759 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
760 msiobj_unlock( &rec->hdr );
761 msiobj_release( &rec->hdr );
762 return ret;
765 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
767 ULONG count;
768 HRESULT r;
769 IStream *stm;
771 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
773 if( !sz )
774 return ERROR_INVALID_PARAMETER;
776 if( iField > rec->count)
777 return ERROR_INVALID_PARAMETER;
779 if ( rec->fields[iField].type == MSIFIELD_NULL )
781 *sz = 0;
782 return ERROR_INVALID_DATA;
785 if( rec->fields[iField].type != MSIFIELD_STREAM )
786 return ERROR_INVALID_DATATYPE;
788 stm = rec->fields[iField].u.stream;
789 if( !stm )
790 return ERROR_INVALID_PARAMETER;
792 /* if there's no buffer pointer, calculate the length to the end */
793 if( !buf )
795 LARGE_INTEGER ofs;
796 ULARGE_INTEGER end, cur;
798 ofs.QuadPart = cur.QuadPart = 0;
799 end.QuadPart = 0;
800 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
801 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
802 ofs.QuadPart = cur.QuadPart;
803 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
804 *sz = end.QuadPart - cur.QuadPart;
806 return ERROR_SUCCESS;
809 /* read the data */
810 count = 0;
811 r = IStream_Read( stm, buf, *sz, &count );
812 if( FAILED( r ) )
814 *sz = 0;
815 return ERROR_FUNCTION_FAILED;
818 *sz = count;
820 return ERROR_SUCCESS;
823 UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
825 MSIRECORD *rec;
826 UINT ret;
828 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
830 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
831 if( !rec )
832 return ERROR_INVALID_HANDLE;
833 msiobj_lock( &rec->hdr );
834 ret = MSI_RecordReadStream( rec, iField, buf, sz );
835 msiobj_unlock( &rec->hdr );
836 msiobj_release( &rec->hdr );
837 return ret;
840 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
842 TRACE("%p %d %p\n", rec, iField, stm);
844 if( iField > rec->count )
845 return ERROR_INVALID_FIELD;
847 MSI_FreeField( &rec->fields[iField] );
849 rec->fields[iField].type = MSIFIELD_STREAM;
850 rec->fields[iField].u.stream = stm;
851 IStream_AddRef( stm );
853 return ERROR_SUCCESS;
856 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
858 TRACE("%p %d %p\n", rec, iField, pstm);
860 if( iField > rec->count )
861 return ERROR_INVALID_FIELD;
863 if( rec->fields[iField].type != MSIFIELD_STREAM )
864 return ERROR_INVALID_FIELD;
866 *pstm = rec->fields[iField].u.stream;
867 IStream_AddRef( *pstm );
869 return ERROR_SUCCESS;
872 static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
874 ULARGE_INTEGER size;
875 LARGE_INTEGER pos;
876 IStream *out;
877 DWORD stgm;
878 HRESULT r;
880 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
881 r = SHCreateStreamOnFileW( name, stgm, &out );
882 if( FAILED( r ) )
883 return ERROR_FUNCTION_FAILED;
885 pos.QuadPart = 0;
886 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
887 if( FAILED( r ) )
888 goto end;
890 pos.QuadPart = 0;
891 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
892 if( FAILED( r ) )
893 goto end;
895 r = IStream_CopyTo( stm, out, size, NULL, NULL );
897 end:
898 IStream_Release( out );
899 if( FAILED( r ) )
900 return ERROR_FUNCTION_FAILED;
901 return ERROR_SUCCESS;
904 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
906 IStream *stm = NULL;
907 UINT r;
909 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
911 msiobj_lock( &rec->hdr );
913 r = MSI_RecordGetIStream( rec, iField, &stm );
914 if( r == ERROR_SUCCESS )
916 r = msi_dump_stream_to_file( stm, name );
917 IStream_Release( stm );
920 msiobj_unlock( &rec->hdr );
922 return r;
925 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
927 MSIRECORD *clone;
928 UINT r, i, count;
930 count = MSI_RecordGetFieldCount(rec);
931 clone = MSI_CreateRecord(count);
932 if (!clone)
933 return NULL;
935 for (i = 0; i <= count; i++)
937 if (rec->fields[i].type == MSIFIELD_STREAM)
939 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
940 &clone->fields[i].u.stream)))
942 msiobj_release(&clone->hdr);
943 return NULL;
945 clone->fields[i].type = MSIFIELD_STREAM;
947 else
949 r = MSI_RecordCopyField(rec, i, clone, i);
950 if (r != ERROR_SUCCESS)
952 msiobj_release(&clone->hdr);
953 return NULL;
958 return clone;
961 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
963 if (a->fields[field].type != b->fields[field].type)
964 return FALSE;
966 switch (a->fields[field].type)
968 case MSIFIELD_NULL:
969 break;
971 case MSIFIELD_INT:
972 if (a->fields[field].u.iVal != b->fields[field].u.iVal)
973 return FALSE;
974 break;
976 case MSIFIELD_WSTR:
977 if (a->fields[field].len != b->fields[field].len) return FALSE;
978 if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
979 a->fields[field].len * sizeof(WCHAR) )) return FALSE;
980 break;
982 case MSIFIELD_STREAM:
983 default:
984 return FALSE;
986 return TRUE;
990 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
992 UINT i;
994 if (a->count != b->count)
995 return FALSE;
997 for (i = 0; i <= a->count; i++)
999 if (!MSI_RecordsAreFieldsEqual( a, b, i ))
1000 return FALSE;
1003 return TRUE;
1006 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1008 DWORD sz = 0;
1009 WCHAR *str;
1010 UINT r;
1012 if (MSI_RecordIsNull( rec, field )) return NULL;
1014 r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1015 if (r != ERROR_SUCCESS)
1016 return NULL;
1018 sz++;
1019 str = msi_alloc( sz * sizeof(WCHAR) );
1020 if (!str) return NULL;
1021 str[0] = 0;
1022 r = MSI_RecordGetStringW( rec, field, str, &sz );
1023 if (r != ERROR_SUCCESS)
1025 ERR("failed to get string!\n");
1026 msi_free( str );
1027 return NULL;
1029 return str;
1032 void dump_record(MSIRECORD *rec)
1034 int i;
1035 if (!rec)
1037 TRACE("(null)\n");
1038 return;
1041 TRACE("[");
1042 for (i = 0; i <= rec->count; i++)
1044 switch(rec->fields[i].type)
1046 case MSIFIELD_NULL: TRACE("(null)"); break;
1047 case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1048 case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1049 case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1051 if (i < rec->count) TRACE(", ");
1053 TRACE("]\n");
1056 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
1058 MSIRECORD *rec;
1059 unsigned int i;
1060 UINT r = ERROR_SUCCESS;
1062 if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1063 return ERROR_INVALID_HANDLE;
1065 rec->cookie = in->cookie;
1066 for (i = 0; i <= in->count; i++)
1068 switch (in->fields[i].type)
1070 case MSIFIELD_NULL:
1071 MSI_FreeField(&rec->fields[i]);
1072 rec->fields[i].type = MSIFIELD_NULL;
1073 break;
1074 case MSIFIELD_INT:
1075 r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
1076 break;
1077 case MSIFIELD_WSTR:
1078 r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
1079 break;
1080 case MSIFIELD_STREAM:
1081 r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
1082 break;
1083 default:
1084 ERR("invalid field type %d\n", in->fields[i].type);
1085 break;
1088 if (r)
1090 msiobj_release(&rec->hdr);
1091 return r;
1095 msiobj_release(&rec->hdr);
1096 return ERROR_SUCCESS;
1099 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1101 if (!in)
1103 *out = 0;
1104 return ERROR_SUCCESS;
1107 *out = MsiCreateRecord(in->count);
1108 if (!*out) return ERROR_OUTOFMEMORY;
1110 return copy_remote_record(in, *out);
1113 struct wire_record *marshal_record(MSIHANDLE handle)
1115 struct wire_record *ret;
1116 unsigned int i;
1117 MSIRECORD *rec;
1119 if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1120 return NULL;
1122 ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
1123 ret->count = rec->count;
1124 ret->cookie = rec->cookie;
1126 for (i = 0; i <= rec->count; i++)
1128 switch (rec->fields[i].type)
1130 case MSIFIELD_NULL:
1131 break;
1132 case MSIFIELD_INT:
1133 ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1134 break;
1135 case MSIFIELD_WSTR:
1136 ret->fields[i].u.szwVal = strdupW(rec->fields[i].u.szwVal);
1137 break;
1138 case MSIFIELD_STREAM:
1139 IStream_AddRef(rec->fields[i].u.stream);
1140 ret->fields[i].u.stream = rec->fields[i].u.stream;
1141 break;
1142 default:
1143 ERR("invalid field type %d\n", rec->fields[i].type);
1144 break;
1146 ret->fields[i].type = rec->fields[i].type;
1149 msiobj_release(&rec->hdr);
1150 return ret;
1153 void free_remote_record(struct wire_record *rec)
1155 int i;
1157 for (i = 0; i <= rec->count; i++)
1159 if (rec->fields[i].type == MSIFIELD_WSTR)
1160 midl_user_free(rec->fields[i].u.szwVal);
1161 else if (rec->fields[i].type == MSIFIELD_STREAM)
1162 IStream_Release(rec->fields[i].u.stream);
1165 midl_user_free(rec);