[MSI] Sync with Wine Staging 1.7.47. CORE-9924
[reactos.git] / reactos / dll / win32 / msi / suminfo.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2002, 2005 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 "msipriv.h"
22
23 #include <propvarutil.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(msi);
26
27 #include <pshpack1.h>
28
29 typedef struct {
30 WORD wByteOrder;
31 WORD wFormat;
32 DWORD dwOSVer;
33 CLSID clsID;
34 DWORD reserved;
35 } PROPERTYSETHEADER;
36
37 typedef struct {
38 FMTID fmtid;
39 DWORD dwOffset;
40 } FORMATIDOFFSET;
41
42 typedef struct {
43 DWORD cbSection;
44 DWORD cProperties;
45 } PROPERTYSECTIONHEADER;
46
47 typedef struct {
48 DWORD propid;
49 DWORD dwOffset;
50 } PROPERTYIDOFFSET;
51
52 typedef struct {
53 DWORD type;
54 union {
55 INT i4;
56 SHORT i2;
57 FILETIME ft;
58 struct {
59 DWORD len;
60 BYTE str[1];
61 } str;
62 } u;
63 } PROPERTY_DATA;
64
65 #include <poppack.h>
66
67 static HRESULT (WINAPI *pPropVariantChangeType)
68 (PROPVARIANT *ppropvarDest, REFPROPVARIANT propvarSrc,
69 PROPVAR_CHANGE_FLAGS flags, VARTYPE vt);
70
71 #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
72
73 static void free_prop( PROPVARIANT *prop )
74 {
75 if (prop->vt == VT_LPSTR )
76 msi_free( prop->u.pszVal );
77 prop->vt = VT_EMPTY;
78 }
79
80 static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
81 {
82 MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg;
83 DWORD i;
84
85 for( i = 0; i < MSI_MAX_PROPS; i++ )
86 free_prop( &si->property[i] );
87 IStorage_Release( si->storage );
88 }
89
90 static UINT get_type( UINT uiProperty )
91 {
92 switch( uiProperty )
93 {
94 case PID_CODEPAGE:
95 return VT_I2;
96
97 case PID_SUBJECT:
98 case PID_AUTHOR:
99 case PID_KEYWORDS:
100 case PID_COMMENTS:
101 case PID_TEMPLATE:
102 case PID_LASTAUTHOR:
103 case PID_REVNUMBER:
104 case PID_APPNAME:
105 case PID_TITLE:
106 return VT_LPSTR;
107
108 case PID_LASTPRINTED:
109 case PID_CREATE_DTM:
110 case PID_LASTSAVE_DTM:
111 return VT_FILETIME;
112
113 case PID_WORDCOUNT:
114 case PID_CHARCOUNT:
115 case PID_SECURITY:
116 case PID_PAGECOUNT:
117 return VT_I4;
118 }
119 return VT_EMPTY;
120 }
121
122 static UINT get_property_count( const PROPVARIANT *property )
123 {
124 UINT i, n = 0;
125
126 if( !property )
127 return n;
128 for( i = 0; i < MSI_MAX_PROPS; i++ )
129 if( property[i].vt != VT_EMPTY )
130 n++;
131 return n;
132 }
133
134 static UINT propvar_changetype(PROPVARIANT *changed, PROPVARIANT *property, VARTYPE vt)
135 {
136 HRESULT hr;
137 HMODULE propsys = LoadLibraryA("propsys.dll");
138 pPropVariantChangeType = (void *)GetProcAddress(propsys, "PropVariantChangeType");
139
140 if (!pPropVariantChangeType)
141 {
142 ERR("PropVariantChangeType function missing!\n");
143 return ERROR_FUNCTION_FAILED;
144 }
145
146 hr = pPropVariantChangeType(changed, property, 0, vt);
147 return (hr == S_OK) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
148 }
149
150 /* FIXME: doesn't deal with endian conversion */
151 static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz )
152 {
153 UINT type;
154 DWORD i, size;
155 PROPERTY_DATA *propdata;
156 PROPVARIANT property, *ptr;
157 PROPVARIANT changed;
158 PROPERTYIDOFFSET *idofs;
159 PROPERTYSECTIONHEADER *section_hdr;
160
161 section_hdr = (PROPERTYSECTIONHEADER*) &data[0];
162 idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE];
163
164 /* now set all the properties */
165 for( i = 0; i < section_hdr->cProperties; i++ )
166 {
167 if( idofs[i].propid >= MSI_MAX_PROPS )
168 {
169 ERR("Unknown property ID %d\n", idofs[i].propid );
170 break;
171 }
172
173 type = get_type( idofs[i].propid );
174 if( type == VT_EMPTY )
175 {
176 ERR("propid %d has unknown type\n", idofs[i].propid);
177 break;
178 }
179
180 propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ];
181
182 /* check we don't run off the end of the data */
183 size = sz - idofs[i].dwOffset - sizeof(DWORD);
184 if( sizeof(DWORD) > size ||
185 ( propdata->type == VT_FILETIME && sizeof(FILETIME) > size ) ||
186 ( propdata->type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) )
187 {
188 ERR("not enough data\n");
189 break;
190 }
191
192 property.vt = propdata->type;
193 if( propdata->type == VT_LPSTR )
194 {
195 LPSTR str = msi_alloc( propdata->u.str.len );
196 memcpy( str, propdata->u.str.str, propdata->u.str.len );
197 str[ propdata->u.str.len - 1 ] = 0;
198 property.u.pszVal = str;
199 }
200 else if( propdata->type == VT_FILETIME )
201 property.u.filetime = propdata->u.ft;
202 else if( propdata->type == VT_I2 )
203 property.u.iVal = propdata->u.i2;
204 else if( propdata->type == VT_I4 )
205 property.u.lVal = propdata->u.i4;
206
207 /* check the type is the same as we expect */
208 if( type != propdata->type )
209 {
210 propvar_changetype(&changed, &property, type);
211 ptr = &changed;
212 }
213 else
214 ptr = &property;
215
216 prop[ idofs[i].propid ] = *ptr;
217 }
218 }
219
220 static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm )
221 {
222 PROPERTYSETHEADER set_hdr;
223 FORMATIDOFFSET format_hdr;
224 PROPERTYSECTIONHEADER section_hdr;
225 LPBYTE data = NULL;
226 LARGE_INTEGER ofs;
227 ULONG count, sz;
228 HRESULT r;
229
230 TRACE("%p %p\n", si, stm);
231
232 /* read the header */
233 sz = sizeof set_hdr;
234 r = IStream_Read( stm, &set_hdr, sz, &count );
235 if( FAILED(r) || count != sz )
236 return ERROR_FUNCTION_FAILED;
237
238 if( set_hdr.wByteOrder != 0xfffe )
239 {
240 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
241 return ERROR_FUNCTION_FAILED;
242 }
243
244 sz = sizeof format_hdr;
245 r = IStream_Read( stm, &format_hdr, sz, &count );
246 if( FAILED(r) || count != sz )
247 return ERROR_FUNCTION_FAILED;
248
249 /* check the format id is correct */
250 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
251 return ERROR_FUNCTION_FAILED;
252
253 /* seek to the location of the section */
254 ofs.QuadPart = format_hdr.dwOffset;
255 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
256 if( FAILED(r) )
257 return ERROR_FUNCTION_FAILED;
258
259 /* read the section itself */
260 sz = SECT_HDR_SIZE;
261 r = IStream_Read( stm, &section_hdr, sz, &count );
262 if( FAILED(r) || count != sz )
263 return ERROR_FUNCTION_FAILED;
264
265 if( section_hdr.cProperties > MSI_MAX_PROPS )
266 {
267 ERR("too many properties %d\n", section_hdr.cProperties);
268 return ERROR_FUNCTION_FAILED;
269 }
270
271 data = msi_alloc( section_hdr.cbSection);
272 if( !data )
273 return ERROR_FUNCTION_FAILED;
274
275 memcpy( data, &section_hdr, SECT_HDR_SIZE );
276
277 /* read all the data in one go */
278 sz = section_hdr.cbSection - SECT_HDR_SIZE;
279 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
280 if( SUCCEEDED(r) && count == sz )
281 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
282 else
283 ERR("failed to read properties %d %d\n", count, sz);
284
285 msi_free( data );
286 return ERROR_SUCCESS;
287 }
288
289 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
290 {
291 if( data )
292 {
293 data[ofs++] = val&0xff;
294 data[ofs++] = (val>>8)&0xff;
295 data[ofs++] = (val>>16)&0xff;
296 data[ofs++] = (val>>24)&0xff;
297 }
298 return 4;
299 }
300
301 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
302 {
303 write_dword( data, ofs, ft->dwLowDateTime );
304 write_dword( data, ofs + 4, ft->dwHighDateTime );
305 return 8;
306 }
307
308 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
309 {
310 DWORD len = lstrlenA( str ) + 1;
311 write_dword( data, ofs, len );
312 if( data )
313 memcpy( &data[ofs + 4], str, len );
314 return (7 + len) & ~3;
315 }
316
317 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
318 {
319 DWORD sz = 0;
320
321 if( prop->vt == VT_EMPTY )
322 return sz;
323
324 /* add the type */
325 sz += write_dword( data, sz, prop->vt );
326 switch( prop->vt )
327 {
328 case VT_I2:
329 sz += write_dword( data, sz, prop->u.iVal );
330 break;
331 case VT_I4:
332 sz += write_dword( data, sz, prop->u.lVal );
333 break;
334 case VT_FILETIME:
335 sz += write_filetime( data, sz, &prop->u.filetime );
336 break;
337 case VT_LPSTR:
338 sz += write_string( data, sz, prop->u.pszVal );
339 break;
340 }
341 return sz;
342 }
343
344 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
345 {
346 UINT ret = ERROR_FUNCTION_FAILED;
347 PROPERTYSETHEADER set_hdr;
348 FORMATIDOFFSET format_hdr;
349 PROPERTYSECTIONHEADER section_hdr;
350 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
351 LPBYTE data = NULL;
352 ULONG count, sz;
353 HRESULT r;
354 int i;
355
356 /* write the header */
357 sz = sizeof set_hdr;
358 memset( &set_hdr, 0, sz );
359 set_hdr.wByteOrder = 0xfffe;
360 set_hdr.wFormat = 0;
361 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
362 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
363 set_hdr.reserved = 1;
364 r = IStream_Write( stm, &set_hdr, sz, &count );
365 if( FAILED(r) || count != sz )
366 return ret;
367
368 /* write the format header */
369 sz = sizeof format_hdr;
370 format_hdr.fmtid = FMTID_SummaryInformation;
371 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
372 r = IStream_Write( stm, &format_hdr, sz, &count );
373 if( FAILED(r) || count != sz )
374 return ret;
375
376 /* add up how much space the data will take and calculate the offsets */
377 section_hdr.cbSection = sizeof section_hdr;
378 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
379 section_hdr.cProperties = 0;
380 for( i = 0; i < MSI_MAX_PROPS; i++ )
381 {
382 sz = write_property_to_data( &si->property[i], NULL );
383 if( !sz )
384 continue;
385 idofs[ section_hdr.cProperties ].propid = i;
386 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
387 section_hdr.cProperties++;
388 section_hdr.cbSection += sz;
389 }
390
391 data = msi_alloc_zero( section_hdr.cbSection );
392
393 sz = 0;
394 memcpy( &data[sz], &section_hdr, sizeof section_hdr );
395 sz += sizeof section_hdr;
396
397 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
398 sz += section_hdr.cProperties * sizeof idofs[0];
399
400 /* write out the data */
401 for( i = 0; i < MSI_MAX_PROPS; i++ )
402 sz += write_property_to_data( &si->property[i], &data[sz] );
403
404 r = IStream_Write( stm, data, sz, &count );
405 msi_free( data );
406 if( FAILED(r) || count != sz )
407 return ret;
408
409 return ERROR_SUCCESS;
410 }
411
412 static MSISUMMARYINFO *create_suminfo( IStorage *stg, UINT update_count )
413 {
414 MSISUMMARYINFO *si;
415
416 if (!(si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof(MSISUMMARYINFO), MSI_CloseSummaryInfo )))
417 return NULL;
418
419 si->update_count = update_count;
420 IStorage_AddRef( stg );
421 si->storage = stg;
422
423 return si;
424 }
425
426 UINT msi_get_suminfo( IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **ret )
427 {
428 IStream *stm;
429 MSISUMMARYINFO *si;
430 HRESULT hr;
431 UINT r;
432
433 TRACE("%p, %u\n", stg, uiUpdateCount);
434
435 if (!(si = create_suminfo( stg, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
436
437 hr = IStorage_OpenStream( si->storage, szSumInfo, 0, STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm );
438 if (FAILED( hr ))
439 {
440 msiobj_release( &si->hdr );
441 return ERROR_FUNCTION_FAILED;
442 }
443
444 r = load_summary_info( si, stm );
445 IStream_Release( stm );
446 if (r != ERROR_SUCCESS)
447 {
448 msiobj_release( &si->hdr );
449 return r;
450 }
451
452 *ret = si;
453 return ERROR_SUCCESS;
454 }
455
456 UINT msi_get_db_suminfo( MSIDATABASE *db, UINT uiUpdateCount, MSISUMMARYINFO **ret )
457 {
458 IStream *stm;
459 MSISUMMARYINFO *si;
460 UINT r;
461
462 if (!(si = create_suminfo( db->storage, uiUpdateCount ))) return ERROR_OUTOFMEMORY;
463
464 r = msi_get_stream( db, szSumInfo, &stm );
465 if (r != ERROR_SUCCESS)
466 {
467 msiobj_release( &si->hdr );
468 return r;
469 }
470
471 r = load_summary_info( si, stm );
472 IStream_Release( stm );
473 if (r != ERROR_SUCCESS)
474 {
475 msiobj_release( &si->hdr );
476 return r;
477 }
478
479 *ret = si;
480 return ERROR_SUCCESS;
481 }
482
483 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
484 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
485 {
486 MSISUMMARYINFO *si;
487 MSIDATABASE *db;
488 UINT ret;
489
490 TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase),
491 uiUpdateCount, pHandle);
492
493 if( !pHandle )
494 return ERROR_INVALID_PARAMETER;
495
496 if( szDatabase && szDatabase[0] )
497 {
498 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY;
499
500 ret = MSI_OpenDatabaseW( szDatabase, persist, &db );
501 if( ret != ERROR_SUCCESS )
502 return ret;
503 }
504 else
505 {
506 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
507 if( !db )
508 {
509 HRESULT hr;
510 IWineMsiRemoteDatabase *remote_database;
511
512 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
513 if ( !remote_database )
514 return ERROR_INVALID_HANDLE;
515
516 hr = IWineMsiRemoteDatabase_GetSummaryInformation( remote_database,
517 uiUpdateCount, pHandle );
518 IWineMsiRemoteDatabase_Release( remote_database );
519
520 if (FAILED(hr))
521 {
522 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
523 return HRESULT_CODE(hr);
524
525 return ERROR_FUNCTION_FAILED;
526 }
527
528 return ERROR_SUCCESS;
529 }
530 }
531
532 ret = msi_get_suminfo( db->storage, uiUpdateCount, &si );
533 if (ret != ERROR_SUCCESS)
534 ret = msi_get_db_suminfo( db, uiUpdateCount, &si );
535 if (ret != ERROR_SUCCESS)
536 {
537 if ((si = create_suminfo( db->storage, uiUpdateCount )))
538 ret = ERROR_SUCCESS;
539 }
540
541 if (ret == ERROR_SUCCESS)
542 {
543 *pHandle = alloc_msihandle( &si->hdr );
544 if( *pHandle )
545 ret = ERROR_SUCCESS;
546 else
547 ret = ERROR_NOT_ENOUGH_MEMORY;
548 msiobj_release( &si->hdr );
549 }
550
551 msiobj_release( &db->hdr );
552 return ret;
553 }
554
555 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
556 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
557 {
558 LPWSTR szwDatabase = NULL;
559 UINT ret;
560
561 TRACE("%d %s %d %p\n", hDatabase, debugstr_a(szDatabase),
562 uiUpdateCount, pHandle);
563
564 if( szDatabase )
565 {
566 szwDatabase = strdupAtoW( szDatabase );
567 if( !szwDatabase )
568 return ERROR_FUNCTION_FAILED;
569 }
570
571 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
572
573 msi_free( szwDatabase );
574
575 return ret;
576 }
577
578 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
579 {
580 MSISUMMARYINFO *si;
581
582 TRACE("%d %p\n", hSummaryInfo, pCount);
583
584 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
585 if( !si )
586 return ERROR_INVALID_HANDLE;
587
588 if( pCount )
589 *pCount = get_property_count( si->property );
590 msiobj_release( &si->hdr );
591
592 return ERROR_SUCCESS;
593 }
594
595 static UINT get_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT *puiDataType, INT *piValue,
596 FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
597 {
598 PROPVARIANT *prop;
599 UINT ret = ERROR_SUCCESS;
600
601 prop = &si->property[uiProperty];
602
603 if( puiDataType )
604 *puiDataType = prop->vt;
605
606 switch( prop->vt )
607 {
608 case VT_I2:
609 if( piValue )
610 *piValue = prop->u.iVal;
611 break;
612 case VT_I4:
613 if( piValue )
614 *piValue = prop->u.lVal;
615 break;
616 case VT_LPSTR:
617 if( pcchValueBuf )
618 {
619 DWORD len = 0;
620
621 if( str->unicode )
622 {
623 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, NULL, 0 ) - 1;
624 MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, str->str.w, *pcchValueBuf );
625 }
626 else
627 {
628 len = lstrlenA( prop->u.pszVal );
629 if( str->str.a )
630 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
631 }
632 if (len >= *pcchValueBuf)
633 ret = ERROR_MORE_DATA;
634 *pcchValueBuf = len;
635 }
636 break;
637 case VT_FILETIME:
638 if( pftValue )
639 *pftValue = prop->u.filetime;
640 break;
641 case VT_EMPTY:
642 break;
643 default:
644 FIXME("Unknown property variant type\n");
645 break;
646 }
647 return ret;
648 }
649
650 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
651 {
652 PROPVARIANT *prop;
653
654 if ( uiProperty >= MSI_MAX_PROPS )
655 return NULL;
656 prop = &si->property[uiProperty];
657 if( prop->vt != VT_LPSTR )
658 return NULL;
659 return strdupAtoW( prop->u.pszVal );
660 }
661
662 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty )
663 {
664 PROPVARIANT *prop;
665
666 if ( uiProperty >= MSI_MAX_PROPS )
667 return -1;
668 prop = &si->property[uiProperty];
669 if( prop->vt != VT_I4 )
670 return -1;
671 return prop->u.lVal;
672 }
673
674 LPWSTR msi_get_suminfo_product( IStorage *stg )
675 {
676 MSISUMMARYINFO *si;
677 LPWSTR prod;
678 UINT r;
679
680 r = msi_get_suminfo( stg, 0, &si );
681 if (r != ERROR_SUCCESS)
682 {
683 ERR("no summary information!\n");
684 return NULL;
685 }
686 prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
687 msiobj_release( &si->hdr );
688 return prod;
689 }
690
691 UINT WINAPI MsiSummaryInfoGetPropertyA(
692 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
693 FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
694 {
695 MSISUMMARYINFO *si;
696 awstring str;
697 UINT r;
698
699 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
700 piValue, pftValue, szValueBuf, pcchValueBuf );
701
702 if (uiProperty >= MSI_MAX_PROPS)
703 {
704 if (puiDataType) *puiDataType = VT_EMPTY;
705 return ERROR_UNKNOWN_PROPERTY;
706 }
707
708 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
709 return ERROR_INVALID_HANDLE;
710
711 str.unicode = FALSE;
712 str.str.a = szValueBuf;
713
714 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
715 msiobj_release( &si->hdr );
716 return r;
717 }
718
719 UINT WINAPI MsiSummaryInfoGetPropertyW(
720 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
721 FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
722 {
723 MSISUMMARYINFO *si;
724 awstring str;
725 UINT r;
726
727 TRACE("%u, %u, %p, %p, %p, %p, %p\n", handle, uiProperty, puiDataType,
728 piValue, pftValue, szValueBuf, pcchValueBuf );
729
730 if (uiProperty >= MSI_MAX_PROPS)
731 {
732 if (puiDataType) *puiDataType = VT_EMPTY;
733 return ERROR_UNKNOWN_PROPERTY;
734 }
735
736 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
737 return ERROR_INVALID_HANDLE;
738
739 str.unicode = TRUE;
740 str.str.w = szValueBuf;
741
742 r = get_prop( si, uiProperty, puiDataType, piValue, pftValue, &str, pcchValueBuf );
743 msiobj_release( &si->hdr );
744 return r;
745 }
746
747 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
748 INT iValue, FILETIME *pftValue, awcstring *str )
749 {
750 PROPVARIANT *prop;
751 UINT len;
752
753 TRACE("%p, %u, %u, %d, %p, %p\n", si, uiProperty, type, iValue, pftValue, str );
754
755 prop = &si->property[uiProperty];
756
757 if( prop->vt == VT_EMPTY )
758 {
759 if( !si->update_count )
760 return ERROR_FUNCTION_FAILED;
761
762 si->update_count--;
763 }
764 else if( prop->vt != type )
765 return ERROR_SUCCESS;
766
767 free_prop( prop );
768 prop->vt = type;
769 switch( type )
770 {
771 case VT_I4:
772 prop->u.lVal = iValue;
773 break;
774 case VT_I2:
775 prop->u.iVal = iValue;
776 break;
777 case VT_FILETIME:
778 prop->u.filetime = *pftValue;
779 break;
780 case VT_LPSTR:
781 if( str->unicode )
782 {
783 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
784 NULL, 0, NULL, NULL );
785 prop->u.pszVal = msi_alloc( len );
786 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
787 prop->u.pszVal, len, NULL, NULL );
788 }
789 else
790 {
791 len = lstrlenA( str->str.a ) + 1;
792 prop->u.pszVal = msi_alloc( len );
793 lstrcpyA( prop->u.pszVal, str->str.a );
794 }
795 break;
796 }
797
798 return ERROR_SUCCESS;
799 }
800
801 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
802 INT iValue, FILETIME *pftValue, LPCWSTR szValue )
803 {
804 awcstring str;
805 MSISUMMARYINFO *si;
806 UINT type, ret;
807
808 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
809 debugstr_w(szValue) );
810
811 type = get_type( uiProperty );
812 if( type == VT_EMPTY || type != uiDataType )
813 return ERROR_DATATYPE_MISMATCH;
814
815 if( uiDataType == VT_LPSTR && !szValue )
816 return ERROR_INVALID_PARAMETER;
817
818 if( uiDataType == VT_FILETIME && !pftValue )
819 return ERROR_INVALID_PARAMETER;
820
821 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
822 return ERROR_INVALID_HANDLE;
823
824 str.unicode = TRUE;
825 str.str.w = szValue;
826
827 ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
828 msiobj_release( &si->hdr );
829 return ret;
830 }
831
832 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
833 INT iValue, FILETIME *pftValue, LPCSTR szValue )
834 {
835 awcstring str;
836 MSISUMMARYINFO *si;
837 UINT type, ret;
838
839 TRACE("%u, %u, %u, %d, %p, %s\n", handle, uiProperty, uiDataType, iValue, pftValue,
840 debugstr_a(szValue) );
841
842 type = get_type( uiProperty );
843 if( type == VT_EMPTY || type != uiDataType )
844 return ERROR_DATATYPE_MISMATCH;
845
846 if( uiDataType == VT_LPSTR && !szValue )
847 return ERROR_INVALID_PARAMETER;
848
849 if( uiDataType == VT_FILETIME && !pftValue )
850 return ERROR_INVALID_PARAMETER;
851
852 if (!(si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO )))
853 return ERROR_INVALID_HANDLE;
854
855 str.unicode = FALSE;
856 str.str.a = szValue;
857
858 ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
859 msiobj_release( &si->hdr );
860 return ret;
861 }
862
863 static UINT suminfo_persist( MSISUMMARYINFO *si )
864 {
865 UINT ret = ERROR_FUNCTION_FAILED;
866 IStream *stm = NULL;
867 DWORD grfMode;
868 HRESULT r;
869
870 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
871 r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
872 if( SUCCEEDED(r) )
873 {
874 ret = save_summary_info( si, stm );
875 IStream_Release( stm );
876 }
877 return ret;
878 }
879
880 static void parse_filetime( LPCWSTR str, FILETIME *ft )
881 {
882 SYSTEMTIME lt, utc;
883 const WCHAR *p = str;
884 WCHAR *end;
885
886 memset( &lt, 0, sizeof(lt) );
887
888 /* YYYY/MM/DD hh:mm:ss */
889
890 while (isspaceW( *p )) p++;
891
892 lt.wYear = strtolW( p, &end, 10 );
893 if (*end != '/') return;
894 p = end + 1;
895
896 lt.wMonth = strtolW( p, &end, 10 );
897 if (*end != '/') return;
898 p = end + 1;
899
900 lt.wDay = strtolW( p, &end, 10 );
901 if (*end != ' ') return;
902 p = end + 1;
903
904 while (isspaceW( *p )) p++;
905
906 lt.wHour = strtolW( p, &end, 10 );
907 if (*end != ':') return;
908 p = end + 1;
909
910 lt.wMinute = strtolW( p, &end, 10 );
911 if (*end != ':') return;
912 p = end + 1;
913
914 lt.wSecond = strtolW( p, &end, 10 );
915
916 TzSpecificLocalTimeToSystemTime( NULL, &lt, &utc );
917 SystemTimeToFileTime( &utc, ft );
918 }
919
920 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
921 FILETIME *ft_value, awcstring *str_value )
922 {
923 *pid = atoiW( prop );
924 switch (*pid)
925 {
926 case PID_CODEPAGE:
927 case PID_WORDCOUNT:
928 case PID_CHARCOUNT:
929 case PID_SECURITY:
930 case PID_PAGECOUNT:
931 *int_value = atoiW( value );
932 break;
933
934 case PID_LASTPRINTED:
935 case PID_CREATE_DTM:
936 case PID_LASTSAVE_DTM:
937 parse_filetime( value, ft_value );
938 break;
939
940 case PID_SUBJECT:
941 case PID_AUTHOR:
942 case PID_KEYWORDS:
943 case PID_COMMENTS:
944 case PID_TEMPLATE:
945 case PID_LASTAUTHOR:
946 case PID_REVNUMBER:
947 case PID_APPNAME:
948 case PID_TITLE:
949 str_value->str.w = value;
950 str_value->unicode = TRUE;
951 break;
952
953 default:
954 WARN("unhandled prop id %u\n", *pid);
955 return ERROR_FUNCTION_FAILED;
956 }
957
958 return ERROR_SUCCESS;
959 }
960
961 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
962 {
963 UINT r;
964 int i, j;
965 MSISUMMARYINFO *si;
966
967 r = msi_get_suminfo( db->storage, num_records * (num_columns / 2), &si );
968 if (r != ERROR_SUCCESS)
969 {
970 if (!(si = create_suminfo( db->storage, num_records * (num_columns / 2) )))
971 return ERROR_OUTOFMEMORY;
972 r = ERROR_SUCCESS;
973 }
974
975 for (i = 0; i < num_records; i++)
976 {
977 for (j = 0; j < num_columns; j += 2)
978 {
979 UINT pid;
980 INT int_value = 0;
981 FILETIME ft_value;
982 awcstring str_value;
983
984 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value );
985 if (r != ERROR_SUCCESS)
986 goto end;
987
988 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value );
989 if (r != ERROR_SUCCESS)
990 goto end;
991 }
992 }
993
994 end:
995 if (r == ERROR_SUCCESS)
996 r = suminfo_persist( si );
997
998 msiobj_release( &si->hdr );
999 return r;
1000 }
1001
1002 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
1003 {
1004 MSISUMMARYINFO *si;
1005 UINT ret;
1006
1007 TRACE("%d\n", handle );
1008
1009 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
1010 if( !si )
1011 return ERROR_INVALID_HANDLE;
1012
1013 ret = suminfo_persist( si );
1014
1015 msiobj_release( &si->hdr );
1016 return ret;
1017 }
1018
1019 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, LPCSTR transform, int error, int validation )
1020 {
1021 UINT r;
1022 WCHAR *transformW = NULL;
1023
1024 TRACE("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation);
1025
1026 if (transform && !(transformW = strdupAtoW( transform )))
1027 return ERROR_OUTOFMEMORY;
1028
1029 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation );
1030 msi_free( transformW );
1031 return r;
1032 }
1033
1034 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCWSTR transform, int error, int validation )
1035 {
1036 FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation);
1037 return ERROR_FUNCTION_FAILED;
1038 }
1039
1040 UINT msi_load_suminfo_properties( MSIPACKAGE *package )
1041 {
1042 static const WCHAR packagecodeW[] = {'P','a','c','k','a','g','e','C','o','d','e',0};
1043 MSISUMMARYINFO *si;
1044 WCHAR *package_code;
1045 UINT r, len;
1046 awstring str;
1047 INT count;
1048
1049 r = msi_get_suminfo( package->db->storage, 0, &si );
1050 if (r != ERROR_SUCCESS)
1051 {
1052 r = msi_get_db_suminfo( package->db, 0, &si );
1053 if (r != ERROR_SUCCESS)
1054 {
1055 ERR("Unable to open summary information stream %u\n", r);
1056 return r;
1057 }
1058 }
1059
1060 str.unicode = TRUE;
1061 str.str.w = NULL;
1062 len = 0;
1063 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1064 if (r != ERROR_MORE_DATA)
1065 {
1066 WARN("Unable to query revision number %u\n", r);
1067 msiobj_release( &si->hdr );
1068 return ERROR_FUNCTION_FAILED;
1069 }
1070
1071 len++;
1072 if (!(package_code = msi_alloc( len * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY;
1073 str.str.w = package_code;
1074
1075 r = get_prop( si, PID_REVNUMBER, NULL, NULL, NULL, &str, &len );
1076 if (r != ERROR_SUCCESS)
1077 {
1078 msi_free( package_code );
1079 msiobj_release( &si->hdr );
1080 return r;
1081 }
1082
1083 r = msi_set_property( package->db, packagecodeW, package_code, len );
1084 msi_free( package_code );
1085
1086 count = 0;
1087 get_prop( si, PID_WORDCOUNT, NULL, &count, NULL, NULL, NULL );
1088 package->WordCount = count;
1089
1090 msiobj_release( &si->hdr );
1091 return r;
1092 }