xref: /reactos/dll/win32/msi/record.c (revision f4be6dc3)
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002-2004 Mike McCormack for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 
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"
36 
37 #include "winreg.h"
38 #include "shlwapi.h"
39 
40 #include "query.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
43 
44 #define MSIFIELD_NULL   0
45 #define MSIFIELD_INT    1
46 #define MSIFIELD_WSTR   3
47 #define MSIFIELD_STREAM 4
48 
MSI_FreeField(MSIFIELD * field)49 static void MSI_FreeField( MSIFIELD *field )
50 {
51     switch( field->type )
52     {
53     case MSIFIELD_NULL:
54     case MSIFIELD_INT:
55         break;
56     case MSIFIELD_WSTR:
57         free( field->u.szwVal);
58         break;
59     case MSIFIELD_STREAM:
60         IStream_Release( field->u.stream );
61         break;
62     default:
63         ERR("Invalid field type %d\n", field->type);
64     }
65 }
66 
MSI_CloseRecord(MSIOBJECTHDR * arg)67 void MSI_CloseRecord( MSIOBJECTHDR *arg )
68 {
69     MSIRECORD *rec = (MSIRECORD *) arg;
70     UINT i;
71 
72     for( i=0; i<=rec->count; i++ )
73         MSI_FreeField( &rec->fields[i] );
74 }
75 
MSI_CreateRecord(UINT cParams)76 MSIRECORD *MSI_CreateRecord( UINT cParams )
77 {
78     MSIRECORD *rec;
79 
80     TRACE("%d\n", cParams);
81 
82     if( cParams>65535 )
83         return NULL;
84 
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;
90 }
91 
MsiCreateRecord(UINT cParams)92 MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
93 {
94     MSIRECORD *rec;
95     MSIHANDLE ret = 0;
96 
97     TRACE("%d\n", cParams);
98 
99     rec = MSI_CreateRecord( cParams );
100     if( rec )
101     {
102         ret = alloc_msihandle( &rec->hdr );
103         msiobj_release( &rec->hdr );
104     }
105     return ret;
106 }
107 
MSI_RecordGetFieldCount(const MSIRECORD * rec)108 UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
109 {
110     return rec->count;
111 }
112 
MsiRecordGetFieldCount(MSIHANDLE handle)113 UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
114 {
115     MSIRECORD *rec;
116     UINT ret;
117 
118     TRACE( "%lu\n", handle );
119 
120     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
121     if( !rec )
122         return -1;
123 
124     msiobj_lock( &rec->hdr );
125     ret = MSI_RecordGetFieldCount( rec );
126     msiobj_unlock( &rec->hdr );
127     msiobj_release( &rec->hdr );
128 
129     return ret;
130 }
131 
string2intW(LPCWSTR str,int * out)132 static BOOL string2intW( LPCWSTR str, int *out )
133 {
134     int x = 0;
135     LPCWSTR p = str;
136 
137     if( *p == '-' ) /* skip the minus sign */
138         p++;
139     while ( *p )
140     {
141         if( (*p < '0') || (*p > '9') )
142             return FALSE;
143         x *= 10;
144         x += (*p - '0');
145         p++;
146     }
147 
148     if( str[0] == '-' ) /* check if it's negative */
149         x = -x;
150     *out = x;
151 
152     return TRUE;
153 }
154 
msi_strdupW(const WCHAR * value,int len)155 WCHAR *msi_strdupW( const WCHAR *value, int len )
156 {
157     WCHAR *ret;
158 
159     if (!value) return NULL;
160     if (!(ret = malloc( (len + 1) * sizeof(WCHAR) ))) return NULL;
161     memcpy( ret, value, len * sizeof(WCHAR) );
162     ret[len] = 0;
163     return ret;
164 }
165 
MSI_RecordCopyField(MSIRECORD * in_rec,UINT in_n,MSIRECORD * out_rec,UINT out_n)166 UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
167                           MSIRECORD *out_rec, UINT out_n )
168 {
169     UINT r = ERROR_SUCCESS;
170 
171     msiobj_lock( &in_rec->hdr );
172 
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 )
176     {
177         LPWSTR str;
178         MSIFIELD *in, *out;
179 
180         in = &in_rec->fields[in_n];
181         out = &out_rec->fields[out_n];
182 
183         switch ( in->type )
184         {
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 )))
192             {
193                 out->u.szwVal = str;
194                 out->len = in->len;
195             }
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);
204         }
205         if (r == ERROR_SUCCESS)
206             out->type = in->type;
207     }
208 
209     msiobj_unlock( &in_rec->hdr );
210     return r;
211 }
212 
MSI_RecordGetInteger(MSIRECORD * rec,UINT iField)213 int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
214 {
215     int ret = 0;
216 
217     TRACE("%p %d\n", rec, iField );
218 
219     if( iField > rec->count )
220         return MSI_NULL_INTEGER;
221 
222     switch( rec->fields[iField].type )
223     {
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;
232     }
233 
234     return MSI_NULL_INTEGER;
235 }
236 
MsiRecordGetInteger(MSIHANDLE handle,UINT iField)237 int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
238 {
239     MSIRECORD *rec;
240     UINT ret;
241 
242     TRACE( "%lu, %u\n", handle, iField );
243 
244     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
245     if( !rec )
246         return MSI_NULL_INTEGER;
247 
248     msiobj_lock( &rec->hdr );
249     ret = MSI_RecordGetInteger( rec, iField );
250     msiobj_unlock( &rec->hdr );
251     msiobj_release( &rec->hdr );
252 
253     return ret;
254 }
255 
MsiRecordClearData(MSIHANDLE handle)256 UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
257 {
258     MSIRECORD *rec;
259     UINT i;
260 
261     TRACE( "%lu\n", handle );
262 
263     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
264     if( !rec )
265         return ERROR_INVALID_HANDLE;
266 
267     msiobj_lock( &rec->hdr );
268     for( i=0; i<=rec->count; i++)
269     {
270         MSI_FreeField( &rec->fields[i] );
271         rec->fields[i].type = MSIFIELD_NULL;
272         rec->fields[i].u.iVal = 0;
273     }
274     msiobj_unlock( &rec->hdr );
275     msiobj_release( &rec->hdr );
276 
277     return ERROR_SUCCESS;
278 }
279 
MSI_RecordSetInteger(MSIRECORD * rec,UINT iField,int iVal)280 UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
281 {
282     TRACE("%p %u %d\n", rec, iField, iVal);
283 
284     if( iField > rec->count )
285         return ERROR_INVALID_PARAMETER;
286 
287     MSI_FreeField( &rec->fields[iField] );
288 
289     if (iVal == MSI_NULL_INTEGER)
290     {
291         rec->fields[iField].type = MSIFIELD_NULL;
292         rec->fields[iField].u.szwVal = NULL;
293     }
294     else
295     {
296         rec->fields[iField].type = MSIFIELD_INT;
297         rec->fields[iField].u.iVal = iVal;
298     }
299 
300     return ERROR_SUCCESS;
301 }
302 
MsiRecordSetInteger(MSIHANDLE handle,UINT iField,int iVal)303 UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
304 {
305     MSIRECORD *rec;
306     UINT ret;
307 
308     TRACE( "%lu, %u, %d\n", handle, iField, iVal );
309 
310     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
311     if( !rec )
312         return ERROR_INVALID_HANDLE;
313 
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;
319 }
320 
MSI_RecordIsNull(MSIRECORD * rec,UINT iField)321 BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
322 {
323     BOOL r = TRUE;
324 
325     TRACE("%p %d\n", rec, iField );
326 
327     r = ( iField > rec->count ) ||
328         ( rec->fields[iField].type == MSIFIELD_NULL );
329 
330     return r;
331 }
332 
MsiRecordIsNull(MSIHANDLE handle,UINT iField)333 BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
334 {
335     MSIRECORD *rec;
336     UINT ret;
337 
338     TRACE( "%lu, %u\n", handle, iField );
339 
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;
348 
349 }
350 
MSI_RecordGetStringA(MSIRECORD * rec,UINT iField,LPSTR szValue,LPDWORD pcchValue)351 UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
352                LPSTR szValue, LPDWORD pcchValue)
353 {
354     UINT len = 0, ret = ERROR_SUCCESS;
355     CHAR buffer[16];
356 
357     TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
358 
359     if( iField > rec->count )
360     {
361         if ( szValue && *pcchValue > 0 )
362             szValue[0] = 0;
363 
364         *pcchValue = 0;
365         return ERROR_SUCCESS;
366     }
367 
368     switch( rec->fields[iField].type )
369     {
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;
394     }
395 
396     if( szValue && *pcchValue <= len )
397         ret = ERROR_MORE_DATA;
398     *pcchValue = len;
399 
400     return ret;
401 }
402 
MsiRecordGetStringA(MSIHANDLE handle,UINT iField,char * szValue,DWORD * pcchValue)403 UINT WINAPI MsiRecordGetStringA( MSIHANDLE handle, UINT iField, char *szValue, DWORD *pcchValue )
404 {
405     MSIRECORD *rec;
406     UINT ret;
407 
408     TRACE( "%lu, %d, %p, %p\n", handle, iField, szValue, pcchValue );
409 
410     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
411     if( !rec )
412         return ERROR_INVALID_HANDLE;
413     msiobj_lock( &rec->hdr );
414     ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
415     msiobj_unlock( &rec->hdr );
416     msiobj_release( &rec->hdr );
417     return ret;
418 }
419 
msi_record_get_string(const MSIRECORD * rec,UINT field,int * len)420 const WCHAR *msi_record_get_string( const MSIRECORD *rec, UINT field, int *len )
421 {
422     if (field > rec->count)
423         return NULL;
424 
425     if (rec->fields[field].type != MSIFIELD_WSTR)
426         return NULL;
427 
428     if (len) *len = rec->fields[field].len;
429 
430     return rec->fields[field].u.szwVal;
431 }
432 
MSI_RecordGetString(const MSIRECORD * rec,UINT iField)433 const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
434 {
435     return msi_record_get_string( rec, iField, NULL );
436 }
437 
MSI_RecordGetStringW(MSIRECORD * rec,UINT iField,WCHAR * szValue,DWORD * pcchValue)438 UINT MSI_RecordGetStringW( MSIRECORD *rec, UINT iField, WCHAR *szValue, DWORD *pcchValue )
439 {
440     UINT len = 0, ret = ERROR_SUCCESS;
441     WCHAR buffer[16];
442 
443     TRACE( "%p, %u, %p, %p\n", rec, iField, szValue, pcchValue );
444 
445     if( iField > rec->count )
446     {
447         if ( szValue && *pcchValue > 0 )
448             szValue[0] = 0;
449 
450         *pcchValue = 0;
451         return ERROR_SUCCESS;
452     }
453 
454     switch( rec->fields[iField].type )
455     {
456     case MSIFIELD_INT:
457         wsprintfW(buffer, L"%d", rec->fields[iField].u.iVal);
458         len = lstrlenW( buffer );
459         if (szValue)
460             lstrcpynW(szValue, buffer, *pcchValue);
461         break;
462     case MSIFIELD_WSTR:
463         len = rec->fields[iField].len;
464         if (szValue)
465             memcpy( szValue, rec->fields[iField].u.szwVal, min(len + 1, *pcchValue) * sizeof(WCHAR) );
466         break;
467     case MSIFIELD_NULL:
468         if( szValue && *pcchValue > 0 )
469             szValue[0] = 0;
470         break;
471     default:
472         break;
473     }
474 
475     if( szValue && *pcchValue <= len )
476         ret = ERROR_MORE_DATA;
477     *pcchValue = len;
478 
479     return ret;
480 }
481 
MsiRecordGetStringW(MSIHANDLE handle,UINT iField,WCHAR * szValue,DWORD * pcchValue)482 UINT WINAPI MsiRecordGetStringW( MSIHANDLE handle, UINT iField, WCHAR *szValue, DWORD *pcchValue )
483 {
484     MSIRECORD *rec;
485     UINT ret;
486 
487     TRACE( "%lu, %u, %p, %p\n", handle, iField, szValue, pcchValue );
488 
489     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
490     if( !rec )
491         return ERROR_INVALID_HANDLE;
492 
493     msiobj_lock( &rec->hdr );
494     ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
495     msiobj_unlock( &rec->hdr );
496     msiobj_release( &rec->hdr );
497     return ret;
498 }
499 
get_stream_size(IStream * stm)500 static UINT get_stream_size( IStream *stm )
501 {
502     STATSTG stat;
503     HRESULT r;
504 
505     r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
506     if( FAILED(r) )
507         return 0;
508     return stat.cbSize.QuadPart;
509 }
510 
MSI_RecordDataSize(MSIRECORD * rec,UINT iField)511 static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
512 {
513     TRACE("%p %d\n", rec, iField);
514 
515     if( iField > rec->count )
516         return 0;
517 
518     switch( rec->fields[iField].type )
519     {
520     case MSIFIELD_INT:
521         return sizeof (INT);
522     case MSIFIELD_WSTR:
523         return rec->fields[iField].len;
524     case MSIFIELD_NULL:
525         break;
526     case MSIFIELD_STREAM:
527         return get_stream_size( rec->fields[iField].u.stream );
528     }
529     return 0;
530 }
531 
MsiRecordDataSize(MSIHANDLE handle,UINT iField)532 UINT WINAPI MsiRecordDataSize( MSIHANDLE handle, UINT iField )
533 {
534     MSIRECORD *rec;
535     UINT ret;
536 
537     TRACE( "%lu, %u\n", handle, iField );
538 
539     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
540     if( !rec )
541         return 0;
542     msiobj_lock( &rec->hdr );
543     ret = MSI_RecordDataSize( rec, iField);
544     msiobj_unlock( &rec->hdr );
545     msiobj_release( &rec->hdr );
546     return ret;
547 }
548 
MsiRecordSetStringA(MSIHANDLE handle,UINT iField,const char * szValue)549 UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, const char *szValue )
550 {
551     WCHAR *valueW = NULL;
552     MSIRECORD *rec;
553     UINT ret;
554 
555     TRACE( "%lu, %u %s\n", handle, iField, debugstr_a(szValue) );
556 
557     if (szValue && !(valueW = strdupAtoW( szValue ))) return ERROR_OUTOFMEMORY;
558 
559     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
560     if( !rec )
561     {
562         free( valueW );
563         return ERROR_INVALID_HANDLE;
564     }
565     msiobj_lock( &rec->hdr );
566     ret = MSI_RecordSetStringW( rec, iField, valueW );
567     msiobj_unlock( &rec->hdr );
568     msiobj_release( &rec->hdr );
569     free( valueW );
570     return ret;
571 }
572 
msi_record_set_string(MSIRECORD * rec,UINT field,const WCHAR * value,int len)573 UINT msi_record_set_string( MSIRECORD *rec, UINT field, const WCHAR *value, int len )
574 {
575     if (field > rec->count)
576         return ERROR_INVALID_FIELD;
577 
578     MSI_FreeField( &rec->fields[field] );
579 
580     if (value && len < 0) len = lstrlenW( value );
581 
582     if (value && len)
583     {
584         rec->fields[field].type = MSIFIELD_WSTR;
585         rec->fields[field].u.szwVal = msi_strdupW( value, len );
586         rec->fields[field].len = len;
587     }
588     else
589     {
590         rec->fields[field].type = MSIFIELD_NULL;
591         rec->fields[field].u.szwVal = NULL;
592         rec->fields[field].len = 0;
593     }
594     return 0;
595 }
596 
MSI_RecordSetStringW(MSIRECORD * rec,UINT iField,LPCWSTR szValue)597 UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
598 {
599     TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
600 
601     return msi_record_set_string( rec, iField, szValue, -1 );
602 }
603 
MsiRecordSetStringW(MSIHANDLE handle,UINT iField,const WCHAR * szValue)604 UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, const WCHAR *szValue )
605 {
606     MSIRECORD *rec;
607     UINT ret;
608 
609     TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szValue) );
610 
611     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
612     if( !rec )
613         return ERROR_INVALID_HANDLE;
614 
615     msiobj_lock( &rec->hdr );
616     ret = MSI_RecordSetStringW( rec, iField, szValue );
617     msiobj_unlock( &rec->hdr );
618     msiobj_release( &rec->hdr );
619     return ret;
620 }
621 
622 /* read the data in a file into an IStream */
RECORD_StreamFromFile(LPCWSTR szFile,IStream ** pstm)623 static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
624 {
625     DWORD sz, szHighWord = 0, read;
626     HANDLE handle;
627     HGLOBAL hGlob = 0;
628     HRESULT hr;
629     ULARGE_INTEGER ulSize;
630 
631     TRACE("reading %s\n", debugstr_w(szFile));
632 
633     /* read the file into memory */
634     handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
635     if( handle == INVALID_HANDLE_VALUE )
636         return GetLastError();
637     sz = GetFileSize(handle, &szHighWord);
638     if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
639     {
640         hGlob = GlobalAlloc(GMEM_FIXED, sz);
641         if( hGlob )
642         {
643             BOOL r = ReadFile(handle, hGlob, sz, &read, NULL) && read == sz;
644             if( !r )
645             {
646                 GlobalFree(hGlob);
647                 hGlob = 0;
648             }
649         }
650     }
651     CloseHandle(handle);
652     if( !hGlob )
653         return ERROR_FUNCTION_FAILED;
654 
655     /* make a stream out of it, and set the correct file size */
656     hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
657     if( FAILED( hr ) )
658     {
659         GlobalFree(hGlob);
660         return ERROR_FUNCTION_FAILED;
661     }
662 
663     /* set the correct size - CreateStreamOnHGlobal screws it up */
664     ulSize.QuadPart = sz;
665     IStream_SetSize(*pstm, ulSize);
666 
667     TRACE( "read %s, %lu bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm );
668     return ERROR_SUCCESS;
669 }
670 
MSI_RecordSetStream(MSIRECORD * rec,UINT iField,IStream * stream)671 UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
672 {
673     if ( (iField == 0) || (iField > rec->count) )
674         return ERROR_INVALID_PARAMETER;
675 
676     MSI_FreeField( &rec->fields[iField] );
677     rec->fields[iField].type = MSIFIELD_STREAM;
678     rec->fields[iField].u.stream = stream;
679 
680     return ERROR_SUCCESS;
681 }
682 
MSI_RecordSetStreamFromFileW(MSIRECORD * rec,UINT iField,LPCWSTR szFilename)683 UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
684 {
685     IStream *stm = NULL;
686     HRESULT hr;
687     UINT ret;
688 
689     if( (iField == 0) || (iField > rec->count) )
690         return ERROR_INVALID_PARAMETER;
691 
692     /* no filename means we should seek back to the start of the stream */
693     if( !szFilename )
694     {
695         LARGE_INTEGER ofs;
696         ULARGE_INTEGER cur;
697 
698         if( rec->fields[iField].type != MSIFIELD_STREAM )
699             return ERROR_INVALID_FIELD;
700 
701         stm = rec->fields[iField].u.stream;
702         if( !stm )
703             return ERROR_INVALID_FIELD;
704 
705         ofs.QuadPart = 0;
706         hr = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
707         if (FAILED( hr ))
708             return ERROR_FUNCTION_FAILED;
709     }
710     else
711     {
712         /* read the file into a stream and save the stream in the record */
713         ret = RECORD_StreamFromFile(szFilename, &stm);
714         if (ret != ERROR_SUCCESS)
715             return ret;
716 
717         /* if all's good, store it in the record */
718         MSI_RecordSetStream(rec, iField, stm);
719     }
720 
721     return ERROR_SUCCESS;
722 }
723 
MsiRecordSetStreamA(MSIHANDLE hRecord,UINT iField,const char * szFilename)724 UINT WINAPI MsiRecordSetStreamA( MSIHANDLE hRecord, UINT iField, const char *szFilename )
725 {
726     WCHAR *wstr = NULL;
727     UINT ret;
728 
729     TRACE( "%lu, %u, %s\n", hRecord, iField, debugstr_a(szFilename) );
730 
731     if( szFilename )
732     {
733         wstr = strdupAtoW( szFilename );
734         if( !wstr )
735              return ERROR_OUTOFMEMORY;
736     }
737     ret = MsiRecordSetStreamW(hRecord, iField, wstr);
738     free(wstr);
739 
740     return ret;
741 }
742 
MsiRecordSetStreamW(MSIHANDLE handle,UINT iField,const WCHAR * szFilename)743 UINT WINAPI MsiRecordSetStreamW( MSIHANDLE handle, UINT iField, const WCHAR *szFilename )
744 {
745     MSIRECORD *rec;
746     UINT ret;
747 
748     TRACE( "%lu, %u, %s\n", handle, iField, debugstr_w(szFilename) );
749 
750     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
751     if( !rec )
752         return ERROR_INVALID_HANDLE;
753 
754     msiobj_lock( &rec->hdr );
755     ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
756     msiobj_unlock( &rec->hdr );
757     msiobj_release( &rec->hdr );
758     return ret;
759 }
760 
MSI_RecordReadStream(MSIRECORD * rec,UINT iField,char * buf,LPDWORD sz)761 UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
762 {
763     ULONG count;
764     HRESULT r;
765     IStream *stm;
766 
767     TRACE("%p %d %p %p\n", rec, iField, buf, sz);
768 
769     if( !sz )
770         return ERROR_INVALID_PARAMETER;
771 
772     if( iField > rec->count)
773         return ERROR_INVALID_PARAMETER;
774 
775     if ( rec->fields[iField].type == MSIFIELD_NULL )
776     {
777         *sz = 0;
778         return ERROR_INVALID_DATA;
779     }
780 
781     if( rec->fields[iField].type != MSIFIELD_STREAM )
782         return ERROR_INVALID_DATATYPE;
783 
784     stm = rec->fields[iField].u.stream;
785     if( !stm )
786         return ERROR_INVALID_PARAMETER;
787 
788     /* if there's no buffer pointer, calculate the length to the end */
789     if( !buf )
790     {
791         LARGE_INTEGER ofs;
792         ULARGE_INTEGER end, cur;
793 
794         ofs.QuadPart = cur.QuadPart = 0;
795         end.QuadPart = 0;
796         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
797         IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
798         ofs.QuadPart = cur.QuadPart;
799         IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
800         *sz = end.QuadPart - cur.QuadPart;
801 
802         return ERROR_SUCCESS;
803     }
804 
805     /* read the data */
806     count = 0;
807     r = IStream_Read( stm, buf, *sz, &count );
808     if( FAILED( r ) )
809     {
810         *sz = 0;
811         return ERROR_FUNCTION_FAILED;
812     }
813 
814     *sz = count;
815 
816     return ERROR_SUCCESS;
817 }
818 
MsiRecordReadStream(MSIHANDLE handle,UINT iField,char * buf,DWORD * sz)819 UINT WINAPI MsiRecordReadStream( MSIHANDLE handle, UINT iField, char *buf, DWORD *sz )
820 {
821     MSIRECORD *rec;
822     UINT ret;
823 
824     TRACE( "%lu, %u, %p, %p\n", handle, iField, buf, sz );
825 
826     rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
827     if( !rec )
828         return ERROR_INVALID_HANDLE;
829     msiobj_lock( &rec->hdr );
830     ret = MSI_RecordReadStream( rec, iField, buf, sz );
831     msiobj_unlock( &rec->hdr );
832     msiobj_release( &rec->hdr );
833     return ret;
834 }
835 
MSI_RecordSetIStream(MSIRECORD * rec,UINT iField,IStream * stm)836 UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
837 {
838     TRACE("%p %d %p\n", rec, iField, stm);
839 
840     if( iField > rec->count )
841         return ERROR_INVALID_FIELD;
842 
843     MSI_FreeField( &rec->fields[iField] );
844 
845     rec->fields[iField].type = MSIFIELD_STREAM;
846     rec->fields[iField].u.stream = stm;
847     IStream_AddRef( stm );
848 
849     return ERROR_SUCCESS;
850 }
851 
MSI_RecordGetIStream(MSIRECORD * rec,UINT iField,IStream ** pstm)852 UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
853 {
854     TRACE("%p %d %p\n", rec, iField, pstm);
855 
856     if( iField > rec->count )
857         return ERROR_INVALID_FIELD;
858 
859     if( rec->fields[iField].type != MSIFIELD_STREAM )
860         return ERROR_INVALID_FIELD;
861 
862     *pstm = rec->fields[iField].u.stream;
863     IStream_AddRef( *pstm );
864 
865     return ERROR_SUCCESS;
866 }
867 
dump_stream_to_file(IStream * stm,const WCHAR * name)868 static UINT dump_stream_to_file( IStream *stm, const WCHAR *name )
869 {
870     ULARGE_INTEGER size;
871     LARGE_INTEGER pos;
872     IStream *out;
873     DWORD stgm;
874     HRESULT r;
875 
876     stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
877     r = SHCreateStreamOnFileW( name, stgm, &out );
878     if( FAILED( r ) )
879         return ERROR_FUNCTION_FAILED;
880 
881     pos.QuadPart = 0;
882     r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
883     if( FAILED( r ) )
884         goto end;
885 
886     pos.QuadPart = 0;
887     r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
888     if( FAILED( r ) )
889         goto end;
890 
891     r = IStream_CopyTo( stm, out, size, NULL, NULL );
892 
893 end:
894     IStream_Release( out );
895     if( FAILED( r ) )
896         return ERROR_FUNCTION_FAILED;
897     return ERROR_SUCCESS;
898 }
899 
MSI_RecordStreamToFile(MSIRECORD * rec,UINT iField,LPCWSTR name)900 UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
901 {
902     IStream *stm = NULL;
903     UINT r;
904 
905     TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
906 
907     msiobj_lock( &rec->hdr );
908 
909     r = MSI_RecordGetIStream( rec, iField, &stm );
910     if( r == ERROR_SUCCESS )
911     {
912         r = dump_stream_to_file( stm, name );
913         IStream_Release( stm );
914     }
915 
916     msiobj_unlock( &rec->hdr );
917 
918     return r;
919 }
920 
MSI_CloneRecord(MSIRECORD * rec)921 MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
922 {
923     MSIRECORD *clone;
924     UINT r, i, count;
925 
926     count = MSI_RecordGetFieldCount(rec);
927     clone = MSI_CreateRecord(count);
928     if (!clone)
929         return NULL;
930 
931     for (i = 0; i <= count; i++)
932     {
933         if (rec->fields[i].type == MSIFIELD_STREAM)
934         {
935             if (FAILED(IStream_Clone(rec->fields[i].u.stream,
936                                      &clone->fields[i].u.stream)))
937             {
938                 msiobj_release(&clone->hdr);
939                 return NULL;
940             }
941             clone->fields[i].type = MSIFIELD_STREAM;
942         }
943         else
944         {
945             r = MSI_RecordCopyField(rec, i, clone, i);
946             if (r != ERROR_SUCCESS)
947             {
948                 msiobj_release(&clone->hdr);
949                 return NULL;
950             }
951         }
952     }
953 
954     return clone;
955 }
956 
MSI_RecordsAreFieldsEqual(MSIRECORD * a,MSIRECORD * b,UINT field)957 BOOL MSI_RecordsAreFieldsEqual(MSIRECORD *a, MSIRECORD *b, UINT field)
958 {
959     if (a->fields[field].type != b->fields[field].type)
960         return FALSE;
961 
962     switch (a->fields[field].type)
963     {
964         case MSIFIELD_NULL:
965             break;
966 
967         case MSIFIELD_INT:
968             if (a->fields[field].u.iVal != b->fields[field].u.iVal)
969                 return FALSE;
970             break;
971 
972         case MSIFIELD_WSTR:
973             if (a->fields[field].len != b->fields[field].len) return FALSE;
974             if (memcmp( a->fields[field].u.szwVal, b->fields[field].u.szwVal,
975                         a->fields[field].len * sizeof(WCHAR) )) return FALSE;
976             break;
977 
978         case MSIFIELD_STREAM:
979         default:
980             return FALSE;
981     }
982     return TRUE;
983 }
984 
985 
MSI_RecordsAreEqual(MSIRECORD * a,MSIRECORD * b)986 BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
987 {
988     UINT i;
989 
990     if (a->count != b->count)
991         return FALSE;
992 
993     for (i = 0; i <= a->count; i++)
994     {
995         if (!MSI_RecordsAreFieldsEqual( a, b, i ))
996             return FALSE;
997     }
998 
999     return TRUE;
1000 }
1001 
msi_dup_record_field(MSIRECORD * rec,INT field)1002 WCHAR *msi_dup_record_field( MSIRECORD *rec, INT field )
1003 {
1004     DWORD sz = 0;
1005     WCHAR *str;
1006     UINT r;
1007 
1008     if (MSI_RecordIsNull( rec, field )) return NULL;
1009 
1010     r = MSI_RecordGetStringW( rec, field, NULL, &sz );
1011     if (r != ERROR_SUCCESS)
1012         return NULL;
1013 
1014     sz++;
1015     str = malloc( sz * sizeof(WCHAR) );
1016     if (!str) return NULL;
1017     str[0] = 0;
1018     r = MSI_RecordGetStringW( rec, field, str, &sz );
1019     if (r != ERROR_SUCCESS)
1020     {
1021         ERR("failed to get string!\n");
1022         free( str );
1023         return NULL;
1024     }
1025     return str;
1026 }
1027 
dump_record(MSIRECORD * rec)1028 void dump_record(MSIRECORD *rec)
1029 {
1030     int i;
1031     if (!rec)
1032     {
1033         TRACE("(null)\n");
1034         return;
1035     }
1036 
1037     TRACE("[");
1038     for (i = 0; i <= rec->count; i++)
1039     {
1040         switch(rec->fields[i].type)
1041         {
1042         case MSIFIELD_NULL: TRACE("(null)"); break;
1043         case MSIFIELD_INT: TRACE("%d", rec->fields[i].u.iVal); break;
1044         case MSIFIELD_WSTR: TRACE("%s", debugstr_w(rec->fields[i].u.szwVal)); break;
1045         case MSIFIELD_STREAM: TRACE("%p", rec->fields[i].u.stream); break;
1046         }
1047         if (i < rec->count) TRACE(", ");
1048     }
1049     TRACE("]\n");
1050 }
1051 
copy_remote_record(const struct wire_record * in,MSIHANDLE out)1052 UINT copy_remote_record(const struct wire_record *in, MSIHANDLE out)
1053 {
1054     MSIRECORD *rec;
1055     unsigned int i;
1056     UINT r = ERROR_SUCCESS;
1057 
1058     if (!(rec = msihandle2msiinfo(out, MSIHANDLETYPE_RECORD)))
1059         return ERROR_INVALID_HANDLE;
1060 
1061     rec->cookie = in->cookie;
1062     for (i = 0; i <= in->count; i++)
1063     {
1064         switch (in->fields[i].type)
1065         {
1066         case MSIFIELD_NULL:
1067             MSI_FreeField(&rec->fields[i]);
1068             rec->fields[i].type = MSIFIELD_NULL;
1069             break;
1070         case MSIFIELD_INT:
1071             r = MSI_RecordSetInteger(rec, i, in->fields[i].u.iVal);
1072             break;
1073         case MSIFIELD_WSTR:
1074             r = MSI_RecordSetStringW(rec, i, in->fields[i].u.szwVal);
1075             break;
1076         case MSIFIELD_STREAM:
1077             r = MSI_RecordSetIStream(rec, i, in->fields[i].u.stream);
1078             break;
1079         default:
1080             ERR("invalid field type %d\n", in->fields[i].type);
1081             break;
1082         }
1083 
1084         if (r)
1085         {
1086             msiobj_release(&rec->hdr);
1087             return r;
1088         }
1089     }
1090 
1091     msiobj_release(&rec->hdr);
1092     return ERROR_SUCCESS;
1093 }
1094 
unmarshal_record(const struct wire_record * in,MSIHANDLE * out)1095 UINT unmarshal_record(const struct wire_record *in, MSIHANDLE *out)
1096 {
1097     if (!in)
1098     {
1099         *out = 0;
1100         return ERROR_SUCCESS;
1101     }
1102 
1103     *out = MsiCreateRecord(in->count);
1104     if (!*out) return ERROR_OUTOFMEMORY;
1105 
1106     return copy_remote_record(in, *out);
1107 }
1108 
marshal_record(MSIHANDLE handle)1109 struct wire_record *marshal_record(MSIHANDLE handle)
1110 {
1111     struct wire_record *ret;
1112     unsigned int i;
1113     MSIRECORD *rec;
1114 
1115     if (!(rec = msihandle2msiinfo(handle, MSIHANDLETYPE_RECORD)))
1116         return NULL;
1117 
1118     ret = midl_user_allocate(sizeof(*ret) + rec->count * sizeof(ret->fields[0]));
1119     ret->count = rec->count;
1120     ret->cookie = rec->cookie;
1121 
1122     for (i = 0; i <= rec->count; i++)
1123     {
1124         switch (rec->fields[i].type)
1125         {
1126         case MSIFIELD_NULL:
1127             break;
1128         case MSIFIELD_INT:
1129             ret->fields[i].u.iVal = rec->fields[i].u.iVal;
1130             break;
1131         case MSIFIELD_WSTR:
1132             ret->fields[i].u.szwVal = wcsdup(rec->fields[i].u.szwVal);
1133             break;
1134         case MSIFIELD_STREAM:
1135             IStream_AddRef(rec->fields[i].u.stream);
1136             ret->fields[i].u.stream = rec->fields[i].u.stream;
1137             break;
1138         default:
1139             ERR("invalid field type %d\n", rec->fields[i].type);
1140             break;
1141         }
1142         ret->fields[i].type = rec->fields[i].type;
1143     }
1144 
1145     msiobj_release(&rec->hdr);
1146     return ret;
1147 }
1148 
free_remote_record(struct wire_record * rec)1149 void free_remote_record(struct wire_record *rec)
1150 {
1151     int i;
1152 
1153     for (i = 0; i <= rec->count; i++)
1154     {
1155         if (rec->fields[i].type == MSIFIELD_WSTR)
1156             midl_user_free(rec->fields[i].u.szwVal);
1157         else if (rec->fields[i].type == MSIFIELD_STREAM)
1158             IStream_Release(rec->fields[i].u.stream);
1159     }
1160 
1161     midl_user_free(rec);
1162 }
1163