gdi32: Store and return ABC metrics from get_glyph_outline.
[wine.git] / dlls / msi / record.c
blobdd097ea46e87131459cca0a311e5ae0702a7ab57
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;
82 UINT len;
84 TRACE("%d\n", cParams);
86 if( cParams>65535 )
87 return NULL;
89 len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
90 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
91 if( rec )
92 rec->count = cParams;
93 return rec;
96 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
98 MSIRECORD *rec;
99 MSIHANDLE ret = 0;
101 TRACE("%d\n", cParams);
103 rec = MSI_CreateRecord( cParams );
104 if( rec )
106 ret = alloc_msihandle( &rec->hdr );
107 msiobj_release( &rec->hdr );
109 return ret;
112 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
114 return rec->count;
117 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
119 MSIRECORD *rec;
120 UINT ret;
122 TRACE("%d\n", handle );
124 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
125 if( !rec )
126 return -1;
128 msiobj_lock( &rec->hdr );
129 ret = MSI_RecordGetFieldCount( rec );
130 msiobj_unlock( &rec->hdr );
131 msiobj_release( &rec->hdr );
133 return ret;
136 static BOOL string2intW( LPCWSTR str, int *out )
138 int x = 0;
139 LPCWSTR p = str;
141 if( *p == '-' ) /* skip the minus sign */
142 p++;
143 while ( *p )
145 if( (*p < '0') || (*p > '9') )
146 return FALSE;
147 x *= 10;
148 x += (*p - '0');
149 p++;
152 if( str[0] == '-' ) /* check if it's negative */
153 x = -x;
154 *out = x;
156 return TRUE;
159 WCHAR *msi_strdupW( const WCHAR *value, int len )
161 WCHAR *ret;
163 if (!value) return NULL;
164 if (!(ret = msi_alloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
165 memcpy( ret, value, len * sizeof(WCHAR) );
166 ret[len] = 0;
167 return ret;
170 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
171 MSIRECORD *out_rec, UINT out_n )
173 UINT r = ERROR_SUCCESS;
175 msiobj_lock( &in_rec->hdr );
177 if ( in_n > in_rec->count || out_n > out_rec->count )
178 r = ERROR_FUNCTION_FAILED;
179 else if ( in_rec != out_rec || in_n != out_n )
181 LPWSTR str;
182 MSIFIELD *in, *out;
184 in = &in_rec->fields[in_n];
185 out = &out_rec->fields[out_n];
187 switch ( in->type )
189 case MSIFIELD_NULL:
190 break;
191 case MSIFIELD_INT:
192 out->u.iVal = in->u.iVal;
193 break;
194 case MSIFIELD_INTPTR:
195 out->u.pVal = in->u.pVal;
196 break;
197 case MSIFIELD_WSTR:
198 if ((str = msi_strdupW( in->u.szwVal, in->len )))
200 out->u.szwVal = str;
201 out->len = in->len;
203 else r = ERROR_OUTOFMEMORY;
204 break;
205 case MSIFIELD_STREAM:
206 IStream_AddRef( in->u.stream );
207 out->u.stream = in->u.stream;
208 break;
209 default:
210 ERR("invalid field type %d\n", in->type);
212 if (r == ERROR_SUCCESS)
213 out->type = in->type;
216 msiobj_unlock( &in_rec->hdr );
217 return r;
220 INT_PTR MSI_RecordGetIntPtr( MSIRECORD *rec, UINT iField )
222 int ret;
224 TRACE( "%p %d\n", rec, iField );
226 if( iField > rec->count )
227 return MININT_PTR;
229 switch( rec->fields[iField].type )
231 case MSIFIELD_INT:
232 return rec->fields[iField].u.iVal;
233 case MSIFIELD_INTPTR:
234 return rec->fields[iField].u.pVal;
235 case MSIFIELD_WSTR:
236 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
237 return ret;
238 return MININT_PTR;
239 default:
240 break;
243 return MININT_PTR;
246 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
248 int ret = 0;
250 TRACE("%p %d\n", rec, iField );
252 if( iField > rec->count )
253 return MSI_NULL_INTEGER;
255 switch( rec->fields[iField].type )
257 case MSIFIELD_INT:
258 return rec->fields[iField].u.iVal;
259 case MSIFIELD_INTPTR:
260 return rec->fields[iField].u.pVal;
261 case MSIFIELD_WSTR:
262 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
263 return ret;
264 return MSI_NULL_INTEGER;
265 default:
266 break;
269 return MSI_NULL_INTEGER;
272 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
274 MSIRECORD *rec;
275 UINT ret;
277 TRACE("%d %d\n", handle, iField );
279 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
280 if( !rec )
281 return MSI_NULL_INTEGER;
283 msiobj_lock( &rec->hdr );
284 ret = MSI_RecordGetInteger( rec, iField );
285 msiobj_unlock( &rec->hdr );
286 msiobj_release( &rec->hdr );
288 return ret;
291 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
293 MSIRECORD *rec;
294 UINT i;
296 TRACE("%d\n", handle );
298 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
299 if( !rec )
300 return ERROR_INVALID_HANDLE;
302 msiobj_lock( &rec->hdr );
303 for( i=0; i<=rec->count; i++)
305 MSI_FreeField( &rec->fields[i] );
306 rec->fields[i].type = MSIFIELD_NULL;
307 rec->fields[i].u.iVal = 0;
309 msiobj_unlock( &rec->hdr );
310 msiobj_release( &rec->hdr );
312 return ERROR_SUCCESS;
315 UINT MSI_RecordSetIntPtr( MSIRECORD *rec, UINT iField, INT_PTR pVal )
317 TRACE("%p %u %ld\n", rec, iField, pVal);
319 if( iField > rec->count )
320 return ERROR_INVALID_PARAMETER;
322 MSI_FreeField( &rec->fields[iField] );
323 rec->fields[iField].type = MSIFIELD_INTPTR;
324 rec->fields[iField].u.pVal = pVal;
326 return ERROR_SUCCESS;
329 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
331 TRACE("%p %u %d\n", rec, iField, iVal);
333 if( iField > rec->count )
334 return ERROR_INVALID_PARAMETER;
336 MSI_FreeField( &rec->fields[iField] );
337 rec->fields[iField].type = MSIFIELD_INT;
338 rec->fields[iField].u.iVal = iVal;
340 return ERROR_SUCCESS;
343 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
345 MSIRECORD *rec;
346 UINT ret;
348 TRACE("%d %u %d\n", handle, iField, iVal);
350 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
351 if( !rec )
352 return ERROR_INVALID_HANDLE;
354 msiobj_lock( &rec->hdr );
355 ret = MSI_RecordSetInteger( rec, iField, iVal );
356 msiobj_unlock( &rec->hdr );
357 msiobj_release( &rec->hdr );
358 return ret;
361 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
363 BOOL r = TRUE;
365 TRACE("%p %d\n", rec, iField );
367 r = ( iField > rec->count ) ||
368 ( rec->fields[iField].type == MSIFIELD_NULL );
370 return r;
373 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
375 MSIRECORD *rec;
376 UINT ret;
378 TRACE("%d %d\n", handle, iField );
380 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
381 if( !rec )
382 return 0;
383 msiobj_lock( &rec->hdr );
384 ret = MSI_RecordIsNull( rec, iField );
385 msiobj_unlock( &rec->hdr );
386 msiobj_release( &rec->hdr );
387 return ret;
391 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
392 LPSTR szValue, LPDWORD pcchValue)
394 UINT len = 0, ret = ERROR_SUCCESS;
395 CHAR buffer[16];
397 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
399 if( iField > rec->count )
401 if ( szValue && *pcchValue > 0 )
402 szValue[0] = 0;
404 *pcchValue = 0;
405 return ERROR_SUCCESS;
408 switch( rec->fields[iField].type )
410 case MSIFIELD_INT:
411 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
412 len = lstrlenA( buffer );
413 if (szValue)
414 lstrcpynA(szValue, buffer, *pcchValue);
415 break;
416 case MSIFIELD_WSTR:
417 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
418 rec->fields[iField].len + 1, NULL, 0 , NULL, NULL );
419 if (szValue)
420 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal,
421 rec->fields[iField].len + 1, szValue, *pcchValue, NULL, NULL );
422 if( szValue && *pcchValue && len>*pcchValue )
423 szValue[*pcchValue-1] = 0;
424 if( len )
425 len--;
426 break;
427 case MSIFIELD_NULL:
428 if( szValue && *pcchValue > 0 )
429 szValue[0] = 0;
430 break;
431 default:
432 ret = ERROR_INVALID_PARAMETER;
433 break;
436 if( szValue && *pcchValue <= len )
437 ret = ERROR_MORE_DATA;
438 *pcchValue = len;
440 return ret;
443 UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
444 LPSTR szValue, LPDWORD pcchValue)
446 MSIRECORD *rec;
447 UINT ret;
449 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
451 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
452 if( !rec )
453 return ERROR_INVALID_HANDLE;
454 msiobj_lock( &rec->hdr );
455 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
456 msiobj_unlock( &rec->hdr );
457 msiobj_release( &rec->hdr );
458 return ret;
461 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
463 if (field > rec->count)
464 return NULL;
466 if (rec->fields[field].type != MSIFIELD_WSTR)
467 return NULL;
469 if (len) *len = rec->fields[field].len;
471 return rec->fields[field].u.szwVal;
474 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
476 return msi_record_get_string( rec, iField, NULL );
479 UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
480 LPWSTR szValue, LPDWORD pcchValue)
482 static const WCHAR szFormat[] = {'%','d',0};
483 UINT len = 0, ret = ERROR_SUCCESS;
484 WCHAR buffer[16];
486 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
488 if( iField > rec->count )
490 if ( szValue && *pcchValue > 0 )
491 szValue[0] = 0;
493 *pcchValue = 0;
494 return ERROR_SUCCESS;
497 switch( rec->fields[iField].type )
499 case MSIFIELD_INT:
500 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
501 len = lstrlenW( buffer );
502 if (szValue)
503 lstrcpynW(szValue, buffer, *pcchValue);
504 break;
505 case MSIFIELD_WSTR:
506 len = rec->fields[iField].len;
507 if (szValue)
508 memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
509 break;
510 case MSIFIELD_NULL:
511 if( szValue && *pcchValue > 0 )
512 szValue[0] = 0;
513 break;
514 default:
515 break;
518 if( szValue && *pcchValue <= len )
519 ret = ERROR_MORE_DATA;
520 *pcchValue = len;
522 return ret;
525 UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
526 LPWSTR szValue, LPDWORD pcchValue)
528 MSIRECORD *rec;
529 UINT ret;
531 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
533 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
534 if( !rec )
535 return ERROR_INVALID_HANDLE;
537 msiobj_lock( &rec->hdr );
538 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
539 msiobj_unlock( &rec->hdr );
540 msiobj_release( &rec->hdr );
541 return ret;
544 static UINT msi_get_stream_size( IStream *stm )
546 STATSTG stat;
547 HRESULT r;
549 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
550 if( FAILED(r) )
551 return 0;
552 return stat.cbSize.QuadPart;
555 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
557 TRACE("%p %d\n", rec, iField);
559 if( iField > rec->count )
560 return 0;
562 switch( rec->fields[iField].type )
564 case MSIFIELD_INT:
565 return sizeof (INT);
566 case MSIFIELD_WSTR:
567 return rec->fields[iField].len;
568 case MSIFIELD_NULL:
569 break;
570 case MSIFIELD_STREAM:
571 return msi_get_stream_size( rec->fields[iField].u.stream );
573 return 0;
576 UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
578 MSIRECORD *rec;
579 UINT ret;
581 TRACE("%d %d\n", handle, iField);
583 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
584 if( !rec )
585 return 0;
586 msiobj_lock( &rec->hdr );
587 ret = MSI_RecordDataSize( rec, iField);
588 msiobj_unlock( &rec->hdr );
589 msiobj_release( &rec->hdr );
590 return ret;
593 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
595 WCHAR *valueW = NULL;
596 MSIRECORD *rec;
597 UINT ret;
599 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
601 if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
603 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
604 if( !rec )
606 msi_free( valueW );
607 return ERROR_INVALID_HANDLE;
609 msiobj_lock( &rec->hdr );
610 ret = MSI_RecordSetStringW( rec, iField, valueW );
611 msiobj_unlock( &rec->hdr );
612 msiobj_release( &rec->hdr );
613 msi_free( valueW );
614 return ret;
617 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
619 if (field > rec->count)
620 return ERROR_INVALID_FIELD;
622 MSI_FreeField( &rec->fields[field] );
624 if (value && len < 0) len = strlenW( value );
626 if (value && len)
628 rec->fields[field].type = MSIFIELD_WSTR;
629 rec->fields[field].u.szwVal = msi_strdupW( value, len );
630 rec->fields[field].len = len;
632 else
634 rec->fields[field].type = MSIFIELD_NULL;
635 rec->fields[field].u.szwVal = NULL;
636 rec->fields[field].len = 0;
638 return 0;
641 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
643 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
645 return msi_record_set_string( rec, iField, szValue, -1 );
648 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
650 MSIRECORD *rec;
651 UINT ret;
653 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
655 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
656 if( !rec )
657 return ERROR_INVALID_HANDLE;
659 msiobj_lock( &rec->hdr );
660 ret = MSI_RecordSetStringW( rec, iField, szValue );
661 msiobj_unlock( &rec->hdr );
662 msiobj_release( &rec->hdr );
663 return ret;
666 /* read the data in a file into an IStream */
667 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
669 DWORD sz, szHighWord = 0, read;
670 HANDLE handle;
671 HGLOBAL hGlob = 0;
672 HRESULT hr;
673 ULARGE_INTEGER ulSize;
675 TRACE("reading %s\n", debugstr_w(szFile));
677 /* read the file into memory */
678 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
679 if( handle == INVALID_HANDLE_VALUE )
680 return GetLastError();
681 sz = GetFileSize(handle, &szHighWord);
682 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
684 hGlob = GlobalAlloc(GMEM_FIXED, sz);
685 if( hGlob )
687 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);
688 if( !r )
690 GlobalFree(hGlob);
691 hGlob = 0;
695 CloseHandle(handle);
696 if( !hGlob )
697 return ERROR_FUNCTION_FAILED;
699 /* make a stream out of it, and set the correct file size */
700 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
701 if( FAILED( hr ) )
703 GlobalFree(hGlob);
704 return ERROR_FUNCTION_FAILED;
707 /* set the correct size - CreateStreamOnHGlobal screws it up */
708 ulSize.QuadPart = sz;
709 IStream_SetSize(*pstm, ulSize);
711 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
713 return ERROR_SUCCESS;
716 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
718 if ( (iField == 0) || (iField > rec->count) )
719 return ERROR_INVALID_PARAMETER;
721 MSI_FreeField( &rec->fields[iField] );
722 rec->fields[iField].type = MSIFIELD_STREAM;
723 rec->fields[iField].u.stream = stream;
725 return ERROR_SUCCESS;
728 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
730 IStream *stm = NULL;
731 HRESULT r;
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 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
751 if( FAILED( r ) )
752 return ERROR_FUNCTION_FAILED;
754 else
756 /* read the file into a stream and save the stream in the record */
757 r = RECORD_StreamFromFile(szFilename, &stm);
758 if( r != ERROR_SUCCESS )
759 return r;
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;