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