d3d9: Also copy the AutoDepthStencilFormat field in GetPresentParameters().
[wine] / dlls / msi / record.c
CommitLineData
6386edc5
MM
1/*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
a7a6f5f3 4 * Copyright 2002-2004 Mike McCormack for CodeWeavers
6386edc5
MM
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
360a3f91 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
6386edc5
MM
19 */
20
e37c6e18
AJ
21#include <stdarg.h>
22
bf72af30
FG
23#define COBJMACROS
24
6386edc5
MM
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"
921be0a8 35#include "ole2.h"
6386edc5 36
7e3918d5
MM
37#include "winreg.h"
38#include "shlwapi.h"
39
6386edc5
MM
40#include "query.h"
41
50684c15 42WINE_DEFAULT_DEBUG_CHANNEL(msidb);
6386edc5
MM
43
44#define MSIFIELD_NULL 0
45#define MSIFIELD_INT 1
6386edc5
MM
46#define MSIFIELD_WSTR 3
47#define MSIFIELD_STREAM 4
48
64de949c 49static void MSI_FreeField( MSIFIELD *field )
6386edc5
MM
50{
51 switch( field->type )
52 {
53 case MSIFIELD_NULL:
54 case MSIFIELD_INT:
55 break;
6386edc5 56 case MSIFIELD_WSTR:
8dc28d53 57 msi_free( field->u.szwVal);
6386edc5
MM
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
64de949c 67static void MSI_CloseRecord( MSIOBJECTHDR *arg )
6386edc5
MM
68{
69 MSIRECORD *rec = (MSIRECORD *) arg;
70 UINT i;
71
7e168ee7 72 for( i=0; i<=rec->count; i++ )
6386edc5
MM
73 MSI_FreeField( &rec->fields[i] );
74}
75
57717000 76MSIRECORD *MSI_CreateRecord( UINT cParams )
6386edc5 77{
6386edc5 78 MSIRECORD *rec;
a7a6f5f3 79 UINT len;
6386edc5
MM
80
81 TRACE("%d\n", cParams);
82
aaa4b42c
MM
83 if( cParams>65535 )
84 return NULL;
85
a7a6f5f3
AJ
86 len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
87 rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
88 if( rec )
aaa4b42c 89 rec->count = cParams;
a7a6f5f3
AJ
90 return rec;
91}
92
57717000 93MSIHANDLE WINAPI MsiCreateRecord( UINT cParams )
a7a6f5f3
AJ
94{
95 MSIRECORD *rec;
96 MSIHANDLE ret = 0;
97
98 TRACE("%d\n", cParams);
99
100 rec = MSI_CreateRecord( cParams );
101 if( rec )
ed580a1d 102 {
a7a6f5f3 103 ret = alloc_msihandle( &rec->hdr );
ed580a1d
MM
104 msiobj_release( &rec->hdr );
105 }
a7a6f5f3
AJ
106 return ret;
107}
6386edc5 108
57717000 109UINT MSI_RecordGetFieldCount( const MSIRECORD *rec )
a7a6f5f3
AJ
110{
111 return rec->count;
6386edc5
MM
112}
113
57717000 114UINT WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
6386edc5
MM
115{
116 MSIRECORD *rec;
a7a6f5f3 117 UINT ret;
6386edc5 118
6bd893a9 119 TRACE("%d\n", handle );
6386edc5
MM
120
121 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
122 if( !rec )
aaa4b42c 123 return -1;
6386edc5 124
0f0b6c8c 125 msiobj_lock( &rec->hdr );
a7a6f5f3 126 ret = MSI_RecordGetFieldCount( rec );
0f0b6c8c 127 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
128 msiobj_release( &rec->hdr );
129
130 return ret;
6386edc5
MM
131}
132
6386edc5
MM
133static BOOL string2intW( LPCWSTR str, int *out )
134{
135 int x = 0;
136 LPCWSTR p = str;
137
138 if( *p == '-' ) /* skip the minus sign */
139 p++;
140 while ( *p )
141 {
142 if( (*p < '0') || (*p > '9') )
143 return FALSE;
144 x *= 10;
145 x += (*p - '0');
146 p++;
147 }
148
149 if( str[0] == '-' ) /* check if it's negative */
150 x = -x;
151 *out = x;
152
153 return TRUE;
154}
155
57717000
FG
156UINT MSI_RecordCopyField( MSIRECORD *in_rec, UINT in_n,
157 MSIRECORD *out_rec, UINT out_n )
71d8f4eb
MM
158{
159 UINT r = ERROR_SUCCESS;
160
161 msiobj_lock( &in_rec->hdr );
162
163 if ( in_n > in_rec->count || out_n > out_rec->count )
164 r = ERROR_FUNCTION_FAILED;
165 else if ( in_rec != out_rec || in_n != out_n )
166 {
167 LPWSTR str;
168 MSIFIELD *in, *out;
169
170 in = &in_rec->fields[in_n];
171 out = &out_rec->fields[out_n];
172
173 switch ( in->type )
174 {
175 case MSIFIELD_NULL:
176 break;
177 case MSIFIELD_INT:
178 out->u.iVal = in->u.iVal;
179 break;
180 case MSIFIELD_WSTR:
181 str = strdupW( in->u.szwVal );
182 if ( !str )
183 r = ERROR_OUTOFMEMORY;
184 else
185 out->u.szwVal = str;
186 break;
187 case MSIFIELD_STREAM:
188 IStream_AddRef( in->u.stream );
189 out->u.stream = in->u.stream;
190 break;
191 default:
192 ERR("invalid field type %d\n", in->type);
193 }
194 if (r == ERROR_SUCCESS)
195 out->type = in->type;
196 }
197
198 msiobj_unlock( &in_rec->hdr );
199
200 return r;
201}
202
57717000 203int MSI_RecordGetInteger( MSIRECORD *rec, UINT iField)
6386edc5 204{
6386edc5
MM
205 int ret = 0;
206
a7a6f5f3 207 TRACE("%p %d\n", rec, iField );
6386edc5
MM
208
209 if( iField > rec->count )
210 return MSI_NULL_INTEGER;
211
212 switch( rec->fields[iField].type )
213 {
214 case MSIFIELD_INT:
215 return rec->fields[iField].u.iVal;
6386edc5
MM
216 case MSIFIELD_WSTR:
217 if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
218 return ret;
219 return MSI_NULL_INTEGER;
220 default:
221 break;
222 }
223
224 return MSI_NULL_INTEGER;
225}
226
57717000 227int WINAPI MsiRecordGetInteger( MSIHANDLE handle, UINT iField)
a7a6f5f3
AJ
228{
229 MSIRECORD *rec;
230 UINT ret;
231
6bd893a9 232 TRACE("%d %d\n", handle, iField );
a7a6f5f3
AJ
233
234 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
235 if( !rec )
236 return MSI_NULL_INTEGER;
237
0f0b6c8c 238 msiobj_lock( &rec->hdr );
a7a6f5f3 239 ret = MSI_RecordGetInteger( rec, iField );
0f0b6c8c 240 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
241 msiobj_release( &rec->hdr );
242
243 return ret;
244}
245
6386edc5
MM
246UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
247{
248 MSIRECORD *rec;
249 UINT i;
250
6bd893a9 251 TRACE("%d\n", handle );
6386edc5
MM
252
253 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
254 if( !rec )
255 return ERROR_INVALID_HANDLE;
256
0f0b6c8c 257 msiobj_lock( &rec->hdr );
6386edc5
MM
258 for( i=0; i<=rec->count; i++)
259 {
260 MSI_FreeField( &rec->fields[i] );
261 rec->fields[i].type = MSIFIELD_NULL;
262 rec->fields[i].u.iVal = 0;
263 }
0f0b6c8c 264 msiobj_unlock( &rec->hdr );
5ebd4e93 265 msiobj_release( &rec->hdr );
6386edc5
MM
266
267 return ERROR_SUCCESS;
268}
269
57717000 270UINT MSI_RecordSetInteger( MSIRECORD *rec, UINT iField, int iVal )
6386edc5 271{
a7a6f5f3 272 TRACE("%p %u %d\n", rec, iField, iVal);
6386edc5 273
aaa4b42c
MM
274 if( iField > rec->count )
275 return ERROR_INVALID_PARAMETER;
8f207560 276
aaa4b42c
MM
277 MSI_FreeField( &rec->fields[iField] );
278 rec->fields[iField].type = MSIFIELD_INT;
279 rec->fields[iField].u.iVal = iVal;
6386edc5
MM
280
281 return ERROR_SUCCESS;
282}
283
57717000 284UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, UINT iField, int iVal )
6386edc5
MM
285{
286 MSIRECORD *rec;
a7a6f5f3 287 UINT ret;
6386edc5 288
6bd893a9 289 TRACE("%d %u %d\n", handle, iField, iVal);
6386edc5
MM
290
291 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
292 if( !rec )
293 return ERROR_INVALID_HANDLE;
294
0f0b6c8c 295 msiobj_lock( &rec->hdr );
a7a6f5f3 296 ret = MSI_RecordSetInteger( rec, iField, iVal );
0f0b6c8c 297 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
298 msiobj_release( &rec->hdr );
299 return ret;
300}
301
57717000 302BOOL MSI_RecordIsNull( MSIRECORD *rec, UINT iField )
a7a6f5f3
AJ
303{
304 BOOL r = TRUE;
305
306 TRACE("%p %d\n", rec, iField );
307
943a71e4
MM
308 r = ( iField > rec->count ) ||
309 ( rec->fields[iField].type == MSIFIELD_NULL );
6386edc5 310
943a71e4 311 return r;
6386edc5
MM
312}
313
57717000 314BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, UINT iField )
6386edc5
MM
315{
316 MSIRECORD *rec;
a7a6f5f3 317 UINT ret;
6386edc5 318
6bd893a9 319 TRACE("%d %d\n", handle, iField );
6386edc5
MM
320
321 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
322 if( !rec )
aaa4b42c 323 return 0;
0f0b6c8c 324 msiobj_lock( &rec->hdr );
a7a6f5f3 325 ret = MSI_RecordIsNull( rec, iField );
0f0b6c8c 326 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
327 msiobj_release( &rec->hdr );
328 return ret;
329
330}
331
57717000
FG
332UINT MSI_RecordGetStringA(MSIRECORD *rec, UINT iField,
333 LPSTR szValue, LPDWORD pcchValue)
a7a6f5f3
AJ
334{
335 UINT len=0, ret;
336 CHAR buffer[16];
337
338 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
6386edc5
MM
339
340 if( iField > rec->count )
0d56df21
JH
341 {
342 if ( szValue && *pcchValue > 0 )
343 szValue[0] = 0;
344
345 *pcchValue = 0;
346 return ERROR_SUCCESS;
347 }
6386edc5
MM
348
349 ret = ERROR_SUCCESS;
350 switch( rec->fields[iField].type )
351 {
352 case MSIFIELD_INT:
353 wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
354 len = lstrlenA( buffer );
8f207560
MM
355 if (szValue)
356 lstrcpynA(szValue, buffer, *pcchValue);
6386edc5 357 break;
6386edc5
MM
358 case MSIFIELD_WSTR:
359 len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
360 NULL, 0 , NULL, NULL);
17ffb562
AS
361 if (szValue)
362 WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
363 szValue, *pcchValue, NULL, NULL);
b9d6ec3b 364 if( szValue && *pcchValue && len>*pcchValue )
aaa4b42c
MM
365 szValue[*pcchValue-1] = 0;
366 if( len )
367 len--;
6386edc5 368 break;
d3239926 369 case MSIFIELD_NULL:
17ffb562 370 if( szValue && *pcchValue > 0 )
d3239926 371 szValue[0] = 0;
47c94c0e 372 break;
6386edc5
MM
373 default:
374 ret = ERROR_INVALID_PARAMETER;
375 break;
376 }
377
b9d6ec3b 378 if( szValue && *pcchValue <= len )
6386edc5
MM
379 ret = ERROR_MORE_DATA;
380 *pcchValue = len;
381
382 return ret;
383}
384
57717000
FG
385UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, UINT iField,
386 LPSTR szValue, LPDWORD pcchValue)
ab519f2a
MM
387{
388 MSIRECORD *rec;
a7a6f5f3
AJ
389 UINT ret;
390
6bd893a9 391 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
ab519f2a
MM
392
393 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
394 if( !rec )
a7a6f5f3 395 return ERROR_INVALID_HANDLE;
0f0b6c8c 396 msiobj_lock( &rec->hdr );
a7a6f5f3 397 ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
0f0b6c8c 398 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
399 msiobj_release( &rec->hdr );
400 return ret;
401}
ab519f2a 402
57717000 403const WCHAR *MSI_RecordGetString( const MSIRECORD *rec, UINT iField )
a7a6f5f3 404{
ab519f2a
MM
405 if( iField > rec->count )
406 return NULL;
407
de8674ec
MM
408 if( rec->fields[iField].type != MSIFIELD_WSTR )
409 return NULL;
410
ab519f2a
MM
411 return rec->fields[iField].u.szwVal;
412}
413
57717000
FG
414UINT MSI_RecordGetStringW(MSIRECORD *rec, UINT iField,
415 LPWSTR szValue, LPDWORD pcchValue)
6386edc5 416{
6386edc5
MM
417 UINT len=0, ret;
418 WCHAR buffer[16];
6a6c85c6 419 static const WCHAR szFormat[] = { '%','d',0 };
6386edc5 420
a7a6f5f3 421 TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
6386edc5
MM
422
423 if( iField > rec->count )
0d56df21
JH
424 {
425 if ( szValue && *pcchValue > 0 )
426 szValue[0] = 0;
427
428 *pcchValue = 0;
429 return ERROR_SUCCESS;
430 }
6386edc5
MM
431
432 ret = ERROR_SUCCESS;
433 switch( rec->fields[iField].type )
434 {
435 case MSIFIELD_INT:
436 wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
437 len = lstrlenW( buffer );
8f207560
MM
438 if (szValue)
439 lstrcpynW(szValue, buffer, *pcchValue);
6386edc5
MM
440 break;
441 case MSIFIELD_WSTR:
442 len = lstrlenW( rec->fields[iField].u.szwVal );
8f207560
MM
443 if (szValue)
444 lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
6386edc5 445 break;
d3239926
MM
446 case MSIFIELD_NULL:
447 len = 1;
b9d6ec3b 448 if( szValue && *pcchValue > 0 )
d3239926 449 szValue[0] = 0;
6386edc5
MM
450 default:
451 break;
452 }
453
b9d6ec3b 454 if( szValue && *pcchValue <= len )
6386edc5
MM
455 ret = ERROR_MORE_DATA;
456 *pcchValue = len;
457
458 return ret;
459}
460
57717000
FG
461UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, UINT iField,
462 LPWSTR szValue, LPDWORD pcchValue)
a7a6f5f3
AJ
463{
464 MSIRECORD *rec;
465 UINT ret;
466
6bd893a9 467 TRACE("%d %d %p %p\n", handle, iField, szValue, pcchValue);
a7a6f5f3
AJ
468
469 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
470 if( !rec )
471 return ERROR_INVALID_HANDLE;
472
0f0b6c8c 473 msiobj_lock( &rec->hdr );
a7a6f5f3 474 ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
0f0b6c8c 475 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
476 msiobj_release( &rec->hdr );
477 return ret;
478}
479
018bc9a0
MM
480static UINT msi_get_stream_size( IStream *stm )
481{
482 STATSTG stat;
483 HRESULT r;
484
485 r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
486 if( FAILED(r) )
487 return 0;
488 return stat.cbSize.QuadPart;
489}
490
668197a8 491static UINT MSI_RecordDataSize(MSIRECORD *rec, UINT iField)
6386edc5 492{
aaa4b42c
MM
493 TRACE("%p %d\n", rec, iField);
494
495 if( iField > rec->count )
496 return 0;
497
498 switch( rec->fields[iField].type )
499 {
500 case MSIFIELD_INT:
501 return sizeof (INT);
502 case MSIFIELD_WSTR:
503 return lstrlenW( rec->fields[iField].u.szwVal );
504 case MSIFIELD_NULL:
505 break;
018bc9a0
MM
506 case MSIFIELD_STREAM:
507 return msi_get_stream_size( rec->fields[iField].u.stream );
aaa4b42c 508 }
6386edc5
MM
509 return 0;
510}
511
57717000 512UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, UINT iField)
aaa4b42c
MM
513{
514 MSIRECORD *rec;
515 UINT ret;
516
6bd893a9 517 TRACE("%d %d\n", handle, iField);
aaa4b42c
MM
518
519 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
520 if( !rec )
521 return 0;
522 msiobj_lock( &rec->hdr );
523 ret = MSI_RecordDataSize( rec, iField);
524 msiobj_unlock( &rec->hdr );
525 msiobj_release( &rec->hdr );
526 return ret;
527}
528
668197a8 529static UINT MSI_RecordSetStringA( MSIRECORD *rec, UINT iField, LPCSTR szValue )
6386edc5 530{
ab519f2a 531 LPWSTR str;
6386edc5 532
a7a6f5f3 533 TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
6386edc5
MM
534
535 if( iField > rec->count )
536 return ERROR_INVALID_FIELD;
537
6386edc5 538 MSI_FreeField( &rec->fields[iField] );
e495e7e3 539 if( szValue && szValue[0] )
e5f2ed4c 540 {
30e388af 541 str = strdupAtoW( szValue );
e5f2ed4c
MM
542 rec->fields[iField].type = MSIFIELD_WSTR;
543 rec->fields[iField].u.szwVal = str;
544 }
545 else
546 {
547 rec->fields[iField].type = MSIFIELD_NULL;
548 rec->fields[iField].u.szwVal = NULL;
549 }
6386edc5
MM
550
551 return 0;
552}
553
57717000 554UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, UINT iField, LPCSTR szValue )
6386edc5
MM
555{
556 MSIRECORD *rec;
a7a6f5f3 557 UINT ret;
6386edc5 558
6bd893a9 559 TRACE("%d %d %s\n", handle, iField, debugstr_a(szValue));
6386edc5
MM
560
561 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
562 if( !rec )
563 return ERROR_INVALID_HANDLE;
0f0b6c8c 564 msiobj_lock( &rec->hdr );
a7a6f5f3 565 ret = MSI_RecordSetStringA( rec, iField, szValue );
0f0b6c8c 566 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
567 msiobj_release( &rec->hdr );
568 return ret;
569}
570
57717000 571UINT MSI_RecordSetStringW( MSIRECORD *rec, UINT iField, LPCWSTR szValue )
a7a6f5f3
AJ
572{
573 LPWSTR str;
a7a6f5f3
AJ
574
575 TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
6386edc5
MM
576
577 if( iField > rec->count )
578 return ERROR_INVALID_FIELD;
579
6386edc5 580 MSI_FreeField( &rec->fields[iField] );
e5f2ed4c 581
e495e7e3 582 if( szValue && szValue[0] )
e5f2ed4c 583 {
30e388af 584 str = strdupW( szValue );
e5f2ed4c
MM
585 rec->fields[iField].type = MSIFIELD_WSTR;
586 rec->fields[iField].u.szwVal = str;
587 }
588 else
589 {
590 rec->fields[iField].type = MSIFIELD_NULL;
591 rec->fields[iField].u.szwVal = NULL;
592 }
6386edc5
MM
593
594 return 0;
595}
596
57717000 597UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, UINT iField, LPCWSTR szValue )
a7a6f5f3
AJ
598{
599 MSIRECORD *rec;
600 UINT ret;
601
6bd893a9 602 TRACE("%d %d %s\n", handle, iField, debugstr_w(szValue));
a7a6f5f3
AJ
603
604 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
605 if( !rec )
606 return ERROR_INVALID_HANDLE;
607
0f0b6c8c 608 msiobj_lock( &rec->hdr );
a7a6f5f3 609 ret = MSI_RecordSetStringW( rec, iField, szValue );
0f0b6c8c 610 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
611 msiobj_release( &rec->hdr );
612 return ret;
613}
614
921be0a8 615/* read the data in a file into an IStream */
64de949c 616static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
921be0a8
MM
617{
618 DWORD sz, szHighWord = 0, read;
619 HANDLE handle;
620 HGLOBAL hGlob = 0;
621 HRESULT hr;
622 ULARGE_INTEGER ulSize;
623
624 TRACE("reading %s\n", debugstr_w(szFile));
625
626 /* read the file into memory */
627 handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
628 if( handle == INVALID_HANDLE_VALUE )
629 return GetLastError();
630 sz = GetFileSize(handle, &szHighWord);
631 if( sz != INVALID_FILE_SIZE && szHighWord == 0 )
632 {
633 hGlob = GlobalAlloc(GMEM_FIXED, sz);
634 if( hGlob )
635 {
636 BOOL r = ReadFile(handle, hGlob, sz, &read, NULL);
637 if( !r )
638 {
639 GlobalFree(hGlob);
640 hGlob = 0;
641 }
642 }
643 }
644 CloseHandle(handle);
645 if( !hGlob )
646 return ERROR_FUNCTION_FAILED;
647
648 /* make a stream out of it, and set the correct file size */
649 hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm);
650 if( FAILED( hr ) )
651 {
652 GlobalFree(hGlob);
653 return ERROR_FUNCTION_FAILED;
654 }
655
656 /* set the correct size - CreateStreamOnHGlobal screws it up */
657 ulSize.QuadPart = sz;
658 IStream_SetSize(*pstm, ulSize);
659
f1d4646a 660 TRACE("read %s, %d bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm);
921be0a8
MM
661
662 return ERROR_SUCCESS;
663}
664
668197a8 665static UINT MSI_RecordSetStream(MSIRECORD *rec, UINT iField, IStream *stream)
7d3162e6
JH
666{
667 if ( (iField == 0) || (iField > rec->count) )
668 return ERROR_INVALID_PARAMETER;
669
670 MSI_FreeField( &rec->fields[iField] );
671 rec->fields[iField].type = MSIFIELD_STREAM;
672 rec->fields[iField].u.stream = stream;
673
674 return ERROR_SUCCESS;
675}
676
4439e0b5 677static UINT MSI_RecordSetStreamFromFileW(MSIRECORD *rec, UINT iField, LPCWSTR szFilename)
921be0a8
MM
678{
679 IStream *stm = NULL;
680 HRESULT r;
681
682 if( (iField == 0) || (iField > rec->count) )
683 return ERROR_INVALID_PARAMETER;
684
685 /* no filename means we should seek back to the start of the stream */
686 if( !szFilename )
687 {
688 LARGE_INTEGER ofs;
689 ULARGE_INTEGER cur;
690
691 if( rec->fields[iField].type != MSIFIELD_STREAM )
692 return ERROR_INVALID_FIELD;
693
694 stm = rec->fields[iField].u.stream;
695 if( !stm )
696 return ERROR_INVALID_FIELD;
697
698 ofs.QuadPart = 0;
699 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
700 if( FAILED( r ) )
701 return ERROR_FUNCTION_FAILED;
702 }
703 else
704 {
705 /* read the file into a stream and save the stream in the record */
706 r = RECORD_StreamFromFile(szFilename, &stm);
707 if( r != ERROR_SUCCESS )
708 return r;
709
710 /* if all's good, store it in the record */
7d3162e6 711 MSI_RecordSetStream(rec, iField, stm);
921be0a8
MM
712 }
713
714 return ERROR_SUCCESS;
715}
716
57717000 717UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, UINT iField, LPCSTR szFilename)
6386edc5 718{
921be0a8 719 LPWSTR wstr = NULL;
30e388af 720 UINT ret;
921be0a8 721
6bd893a9 722 TRACE("%d %d %s\n", hRecord, iField, debugstr_a(szFilename));
921be0a8
MM
723
724 if( szFilename )
725 {
30e388af
MM
726 wstr = strdupAtoW( szFilename );
727 if( !wstr )
728 return ERROR_OUTOFMEMORY;
921be0a8
MM
729 }
730 ret = MsiRecordSetStreamW(hRecord, iField, wstr);
8dc28d53 731 msi_free(wstr);
921be0a8
MM
732
733 return ret;
6386edc5
MM
734}
735
57717000 736UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, UINT iField, LPCWSTR szFilename)
6386edc5 737{
921be0a8
MM
738 MSIRECORD *rec;
739 UINT ret;
740
6bd893a9 741 TRACE("%d %d %s\n", handle, iField, debugstr_w(szFilename));
921be0a8
MM
742
743 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
744 if( !rec )
745 return ERROR_INVALID_HANDLE;
746
747 msiobj_lock( &rec->hdr );
7d3162e6 748 ret = MSI_RecordSetStreamFromFileW( rec, iField, szFilename );
921be0a8
MM
749 msiobj_unlock( &rec->hdr );
750 msiobj_release( &rec->hdr );
751 return ret;
6386edc5
MM
752}
753
57717000 754UINT MSI_RecordReadStream(MSIRECORD *rec, UINT iField, char *buf, LPDWORD sz)
6386edc5 755{
0eecfdef
MM
756 ULONG count;
757 HRESULT r;
758 IStream *stm;
759
a7a6f5f3 760 TRACE("%p %d %p %p\n", rec, iField, buf, sz);
0eecfdef 761
921be0a8
MM
762 if( !sz )
763 return ERROR_INVALID_PARAMETER;
764
765 if( iField > rec->count)
766 return ERROR_INVALID_PARAMETER;
0eecfdef
MM
767
768 if( rec->fields[iField].type != MSIFIELD_STREAM )
921be0a8 769 return ERROR_INVALID_DATATYPE;
0eecfdef
MM
770
771 stm = rec->fields[iField].u.stream;
772 if( !stm )
921be0a8 773 return ERROR_INVALID_PARAMETER;
0eecfdef
MM
774
775 /* if there's no buffer pointer, calculate the length to the end */
776 if( !buf )
777 {
778 LARGE_INTEGER ofs;
779 ULARGE_INTEGER end, cur;
780
781 ofs.QuadPart = cur.QuadPart = 0;
782 end.QuadPart = 0;
783 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
784 IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
785 ofs.QuadPart = cur.QuadPart;
786 IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
787 *sz = end.QuadPart - cur.QuadPart;
788
789 return ERROR_SUCCESS;
790 }
791
792 /* read the data */
793 count = 0;
794 r = IStream_Read( stm, buf, *sz, &count );
795 if( FAILED( r ) )
63d757f0
UC
796 {
797 *sz = 0;
0eecfdef 798 return ERROR_FUNCTION_FAILED;
63d757f0 799 }
0eecfdef
MM
800
801 *sz = count;
802
803 return ERROR_SUCCESS;
804}
805
57717000 806UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, UINT iField, char *buf, LPDWORD sz)
0eecfdef
MM
807{
808 MSIRECORD *rec;
a7a6f5f3 809 UINT ret;
0eecfdef 810
6bd893a9 811 TRACE("%d %d %p %p\n", handle, iField, buf, sz);
0eecfdef
MM
812
813 rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
814 if( !rec )
815 return ERROR_INVALID_HANDLE;
0f0b6c8c 816 msiobj_lock( &rec->hdr );
a7a6f5f3 817 ret = MSI_RecordReadStream( rec, iField, buf, sz );
0f0b6c8c 818 msiobj_unlock( &rec->hdr );
a7a6f5f3
AJ
819 msiobj_release( &rec->hdr );
820 return ret;
821}
822
57717000 823UINT MSI_RecordSetIStream( MSIRECORD *rec, UINT iField, IStream *stm )
a7a6f5f3
AJ
824{
825 TRACE("%p %d %p\n", rec, iField, stm);
0eecfdef
MM
826
827 if( iField > rec->count )
828 return ERROR_INVALID_FIELD;
829
830 MSI_FreeField( &rec->fields[iField] );
831
832 rec->fields[iField].type = MSIFIELD_STREAM;
833 rec->fields[iField].u.stream = stm;
834 IStream_AddRef( stm );
835
836 return ERROR_SUCCESS;
6386edc5 837}
499a887d 838
57717000 839UINT MSI_RecordGetIStream( MSIRECORD *rec, UINT iField, IStream **pstm)
499a887d
MM
840{
841 TRACE("%p %d %p\n", rec, iField, pstm);
842
843 if( iField > rec->count )
844 return ERROR_INVALID_FIELD;
845
846 if( rec->fields[iField].type != MSIFIELD_STREAM )
847 return ERROR_INVALID_FIELD;
848
849 *pstm = rec->fields[iField].u.stream;
850 IStream_AddRef( *pstm );
851
852 return ERROR_SUCCESS;
853}
7e3918d5
MM
854
855static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
856{
857 ULARGE_INTEGER size;
858 LARGE_INTEGER pos;
859 IStream *out;
860 DWORD stgm;
861 HRESULT r;
862
863 stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
864 r = SHCreateStreamOnFileW( name, stgm, &out );
865 if( FAILED( r ) )
866 return ERROR_FUNCTION_FAILED;
867
868 pos.QuadPart = 0;
869 r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
870 if( FAILED( r ) )
871 goto end;
872
873 pos.QuadPart = 0;
874 r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
875 if( FAILED( r ) )
876 goto end;
877
878 r = IStream_CopyTo( stm, out, size, NULL, NULL );
879
880end:
881 IStream_Release( out );
882 if( FAILED( r ) )
883 return ERROR_FUNCTION_FAILED;
884 return ERROR_SUCCESS;
885}
886
57717000 887UINT MSI_RecordStreamToFile( MSIRECORD *rec, UINT iField, LPCWSTR name )
7e3918d5
MM
888{
889 IStream *stm = NULL;
890 UINT r;
891
892 TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
893
894 msiobj_lock( &rec->hdr );
895
896 r = MSI_RecordGetIStream( rec, iField, &stm );
897 if( r == ERROR_SUCCESS )
898 {
899 r = msi_dump_stream_to_file( stm, name );
900 IStream_Release( stm );
901 }
902
903 msiobj_unlock( &rec->hdr );
904
905 return r;
906}
f03889ae
JH
907
908MSIRECORD *MSI_CloneRecord(MSIRECORD *rec)
909{
910 MSIRECORD *clone;
911 UINT r, i, count;
912
913 count = MSI_RecordGetFieldCount(rec);
914 clone = MSI_CreateRecord(count);
915 if (!clone)
916 return NULL;
917
918 for (i = 0; i <= count; i++)
919 {
920 if (rec->fields[i].type == MSIFIELD_STREAM)
921 {
922 if (FAILED(IStream_Clone(rec->fields[i].u.stream,
923 &clone->fields[i].u.stream)))
924 {
925 msiobj_release(&clone->hdr);
926 return NULL;
927 }
928 }
929 else
930 {
931 r = MSI_RecordCopyField(rec, i, clone, i);
932 if (r != ERROR_SUCCESS)
933 {
934 msiobj_release(&clone->hdr);
935 return NULL;
936 }
937 }
938 }
939
940 return clone;
941}
942
943BOOL MSI_RecordsAreEqual(MSIRECORD *a, MSIRECORD *b)
944{
945 UINT i;
946
947 if (a->count != b->count)
948 return FALSE;
949
950 for (i = 0; i <= a->count; i++)
951 {
952 if (a->fields[i].type != b->fields[i].type)
953 return FALSE;
954
955 switch (a->fields[i].type)
956 {
957 case MSIFIELD_NULL:
958 break;
959
960 case MSIFIELD_INT:
961 if (a->fields[i].u.iVal != b->fields[i].u.iVal)
962 return FALSE;
963 break;
964
965 case MSIFIELD_WSTR:
966 if (lstrcmpW(a->fields[i].u.szwVal, b->fields[i].u.szwVal))
967 return FALSE;
968 break;
969
970 case MSIFIELD_STREAM:
971 default:
972 return FALSE;
973 }
974 }
975
976 return TRUE;
977}