5d23ab6a2dc2ea00bcaee27285b6581b97f58813
[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 UINT ret = ERROR_FUNCTION_FAILED;
223 PROPERTYSETHEADER set_hdr;
224 FORMATIDOFFSET format_hdr;
225 PROPERTYSECTIONHEADER section_hdr;
226 LPBYTE data = NULL;
227 LARGE_INTEGER ofs;
228 ULONG count, sz;
229 HRESULT r;
230
231 TRACE("%p %p\n", si, stm);
232
233 /* read the header */
234 sz = sizeof set_hdr;
235 r = IStream_Read( stm, &set_hdr, sz, &count );
236 if( FAILED(r) || count != sz )
237 return ret;
238
239 if( set_hdr.wByteOrder != 0xfffe )
240 {
241 ERR("property set not big-endian %04X\n", set_hdr.wByteOrder);
242 return ret;
243 }
244
245 sz = sizeof format_hdr;
246 r = IStream_Read( stm, &format_hdr, sz, &count );
247 if( FAILED(r) || count != sz )
248 return ret;
249
250 /* check the format id is correct */
251 if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) )
252 return ret;
253
254 /* seek to the location of the section */
255 ofs.QuadPart = format_hdr.dwOffset;
256 r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL );
257 if( FAILED(r) )
258 return ret;
259
260 /* read the section itself */
261 sz = SECT_HDR_SIZE;
262 r = IStream_Read( stm, &section_hdr, sz, &count );
263 if( FAILED(r) || count != sz )
264 return ret;
265
266 if( section_hdr.cProperties > MSI_MAX_PROPS )
267 {
268 ERR("too many properties %d\n", section_hdr.cProperties);
269 return ret;
270 }
271
272 data = msi_alloc( section_hdr.cbSection);
273 if( !data )
274 return ret;
275
276 memcpy( data, &section_hdr, SECT_HDR_SIZE );
277
278 /* read all the data in one go */
279 sz = section_hdr.cbSection - SECT_HDR_SIZE;
280 r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count );
281 if( SUCCEEDED(r) && count == sz )
282 read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE );
283 else
284 ERR("failed to read properties %d %d\n", count, sz);
285
286 msi_free( data );
287 return ret;
288 }
289
290 static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val )
291 {
292 if( data )
293 {
294 data[ofs++] = val&0xff;
295 data[ofs++] = (val>>8)&0xff;
296 data[ofs++] = (val>>16)&0xff;
297 data[ofs++] = (val>>24)&0xff;
298 }
299 return 4;
300 }
301
302 static DWORD write_filetime( LPBYTE data, DWORD ofs, const FILETIME *ft )
303 {
304 write_dword( data, ofs, ft->dwLowDateTime );
305 write_dword( data, ofs + 4, ft->dwHighDateTime );
306 return 8;
307 }
308
309 static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str )
310 {
311 DWORD len = lstrlenA( str ) + 1;
312 write_dword( data, ofs, len );
313 if( data )
314 memcpy( &data[ofs + 4], str, len );
315 return (7 + len) & ~3;
316 }
317
318 static UINT write_property_to_data( const PROPVARIANT *prop, LPBYTE data )
319 {
320 DWORD sz = 0;
321
322 if( prop->vt == VT_EMPTY )
323 return sz;
324
325 /* add the type */
326 sz += write_dword( data, sz, prop->vt );
327 switch( prop->vt )
328 {
329 case VT_I2:
330 sz += write_dword( data, sz, prop->u.iVal );
331 break;
332 case VT_I4:
333 sz += write_dword( data, sz, prop->u.lVal );
334 break;
335 case VT_FILETIME:
336 sz += write_filetime( data, sz, &prop->u.filetime );
337 break;
338 case VT_LPSTR:
339 sz += write_string( data, sz, prop->u.pszVal );
340 break;
341 }
342 return sz;
343 }
344
345 static UINT save_summary_info( const MSISUMMARYINFO * si, IStream *stm )
346 {
347 UINT ret = ERROR_FUNCTION_FAILED;
348 PROPERTYSETHEADER set_hdr;
349 FORMATIDOFFSET format_hdr;
350 PROPERTYSECTIONHEADER section_hdr;
351 PROPERTYIDOFFSET idofs[MSI_MAX_PROPS];
352 LPBYTE data = NULL;
353 ULONG count, sz;
354 HRESULT r;
355 int i;
356
357 /* write the header */
358 sz = sizeof set_hdr;
359 memset( &set_hdr, 0, sz );
360 set_hdr.wByteOrder = 0xfffe;
361 set_hdr.wFormat = 0;
362 set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */
363 /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */
364 set_hdr.reserved = 1;
365 r = IStream_Write( stm, &set_hdr, sz, &count );
366 if( FAILED(r) || count != sz )
367 return ret;
368
369 /* write the format header */
370 sz = sizeof format_hdr;
371 format_hdr.fmtid = FMTID_SummaryInformation;
372 format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr;
373 r = IStream_Write( stm, &format_hdr, sz, &count );
374 if( FAILED(r) || count != sz )
375 return ret;
376
377 /* add up how much space the data will take and calculate the offsets */
378 section_hdr.cbSection = sizeof section_hdr;
379 section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]);
380 section_hdr.cProperties = 0;
381 for( i = 0; i < MSI_MAX_PROPS; i++ )
382 {
383 sz = write_property_to_data( &si->property[i], NULL );
384 if( !sz )
385 continue;
386 idofs[ section_hdr.cProperties ].propid = i;
387 idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection;
388 section_hdr.cProperties++;
389 section_hdr.cbSection += sz;
390 }
391
392 data = msi_alloc_zero( section_hdr.cbSection );
393
394 sz = 0;
395 memcpy( &data[sz], &section_hdr, sizeof section_hdr );
396 sz += sizeof section_hdr;
397
398 memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] );
399 sz += section_hdr.cProperties * sizeof idofs[0];
400
401 /* write out the data */
402 for( i = 0; i < MSI_MAX_PROPS; i++ )
403 sz += write_property_to_data( &si->property[i], &data[sz] );
404
405 r = IStream_Write( stm, data, sz, &count );
406 msi_free( data );
407 if( FAILED(r) || count != sz )
408 return ret;
409
410 return ERROR_SUCCESS;
411 }
412
413 MSISUMMARYINFO *MSI_GetSummaryInformationW( IStorage *stg, UINT uiUpdateCount )
414 {
415 IStream *stm = NULL;
416 MSISUMMARYINFO *si;
417 DWORD grfMode;
418 HRESULT r;
419
420 TRACE("%p %d\n", stg, uiUpdateCount );
421
422 si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
423 sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
424 if( !si )
425 return si;
426
427 si->update_count = uiUpdateCount;
428 IStorage_AddRef( stg );
429 si->storage = stg;
430
431 /* read the stream... if we fail, we'll start with an empty property set */
432 grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
433 r = IStorage_OpenStream( si->storage, szSumInfo, 0, grfMode, 0, &stm );
434 if( SUCCEEDED(r) )
435 {
436 load_summary_info( si, stm );
437 IStream_Release( stm );
438 }
439
440 return si;
441 }
442
443 UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
444 LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
445 {
446 MSISUMMARYINFO *si;
447 MSIDATABASE *db;
448 UINT ret = ERROR_FUNCTION_FAILED;
449
450 TRACE("%d %s %d %p\n", hDatabase, debugstr_w(szDatabase),
451 uiUpdateCount, pHandle);
452
453 if( !pHandle )
454 return ERROR_INVALID_PARAMETER;
455
456 if( szDatabase && szDatabase[0] )
457 {
458 LPCWSTR persist = uiUpdateCount ? MSIDBOPEN_TRANSACT : MSIDBOPEN_READONLY;
459
460 ret = MSI_OpenDatabaseW( szDatabase, persist, &db );
461 if( ret != ERROR_SUCCESS )
462 return ret;
463 }
464 else
465 {
466 db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
467 if( !db )
468 {
469 HRESULT hr;
470 IWineMsiRemoteDatabase *remote_database;
471
472 remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( hDatabase );
473 if ( !remote_database )
474 return ERROR_INVALID_HANDLE;
475
476 hr = IWineMsiRemoteDatabase_GetSummaryInformation( remote_database,
477 uiUpdateCount, pHandle );
478 IWineMsiRemoteDatabase_Release( remote_database );
479
480 if (FAILED(hr))
481 {
482 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
483 return HRESULT_CODE(hr);
484
485 return ERROR_FUNCTION_FAILED;
486 }
487
488 return ERROR_SUCCESS;
489 }
490 }
491
492 si = MSI_GetSummaryInformationW( db->storage, uiUpdateCount );
493 if (si)
494 {
495 *pHandle = alloc_msihandle( &si->hdr );
496 if( *pHandle )
497 ret = ERROR_SUCCESS;
498 else
499 ret = ERROR_NOT_ENOUGH_MEMORY;
500 msiobj_release( &si->hdr );
501 }
502
503 msiobj_release( &db->hdr );
504 return ret;
505 }
506
507 UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
508 LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
509 {
510 LPWSTR szwDatabase = NULL;
511 UINT ret;
512
513 TRACE("%d %s %d %p\n", hDatabase, debugstr_a(szDatabase),
514 uiUpdateCount, pHandle);
515
516 if( szDatabase )
517 {
518 szwDatabase = strdupAtoW( szDatabase );
519 if( !szwDatabase )
520 return ERROR_FUNCTION_FAILED;
521 }
522
523 ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle);
524
525 msi_free( szwDatabase );
526
527 return ret;
528 }
529
530 UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, PUINT pCount)
531 {
532 MSISUMMARYINFO *si;
533
534 TRACE("%d %p\n", hSummaryInfo, pCount);
535
536 si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
537 if( !si )
538 return ERROR_INVALID_HANDLE;
539
540 if( pCount )
541 *pCount = get_property_count( si->property );
542 msiobj_release( &si->hdr );
543
544 return ERROR_SUCCESS;
545 }
546
547 static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
548 INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf)
549 {
550 MSISUMMARYINFO *si;
551 PROPVARIANT *prop;
552 UINT ret = ERROR_SUCCESS;
553
554 TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
555 piValue, pftValue, str, pcchValueBuf);
556
557 if ( uiProperty >= MSI_MAX_PROPS )
558 {
559 if (puiDataType) *puiDataType = VT_EMPTY;
560 return ERROR_UNKNOWN_PROPERTY;
561 }
562
563 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
564 if( !si )
565 return ERROR_INVALID_HANDLE;
566
567 prop = &si->property[uiProperty];
568
569 if( puiDataType )
570 *puiDataType = prop->vt;
571
572 switch( prop->vt )
573 {
574 case VT_I2:
575 if( piValue )
576 *piValue = prop->u.iVal;
577 break;
578 case VT_I4:
579 if( piValue )
580 *piValue = prop->u.lVal;
581 break;
582 case VT_LPSTR:
583 if( pcchValueBuf )
584 {
585 DWORD len = 0;
586
587 if( str->unicode )
588 {
589 len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, NULL, 0 ) - 1;
590 MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, str->str.w, *pcchValueBuf );
591 }
592 else
593 {
594 len = lstrlenA( prop->u.pszVal );
595 if( str->str.a )
596 lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf );
597 }
598 if (len >= *pcchValueBuf)
599 ret = ERROR_MORE_DATA;
600 *pcchValueBuf = len;
601 }
602 break;
603 case VT_FILETIME:
604 if( pftValue )
605 *pftValue = prop->u.filetime;
606 break;
607 case VT_EMPTY:
608 break;
609 default:
610 FIXME("Unknown property variant type\n");
611 break;
612 }
613 msiobj_release( &si->hdr );
614 return ret;
615 }
616
617 LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
618 {
619 PROPVARIANT *prop;
620
621 if ( uiProperty >= MSI_MAX_PROPS )
622 return NULL;
623 prop = &si->property[uiProperty];
624 if( prop->vt != VT_LPSTR )
625 return NULL;
626 return strdupAtoW( prop->u.pszVal );
627 }
628
629 INT msi_suminfo_get_int32( MSISUMMARYINFO *si, UINT uiProperty )
630 {
631 PROPVARIANT *prop;
632
633 if ( uiProperty >= MSI_MAX_PROPS )
634 return -1;
635 prop = &si->property[uiProperty];
636 if( prop->vt != VT_I4 )
637 return -1;
638 return prop->u.lVal;
639 }
640
641 LPWSTR msi_get_suminfo_product( IStorage *stg )
642 {
643 MSISUMMARYINFO *si;
644 LPWSTR prod;
645
646 si = MSI_GetSummaryInformationW( stg, 0 );
647 if (!si)
648 {
649 ERR("no summary information!\n");
650 return NULL;
651 }
652 prod = msi_suminfo_dup_string( si, PID_REVNUMBER );
653 msiobj_release( &si->hdr );
654 return prod;
655 }
656
657 UINT WINAPI MsiSummaryInfoGetPropertyA(
658 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
659 FILETIME *pftValue, LPSTR szValueBuf, LPDWORD pcchValueBuf)
660 {
661 awstring str;
662
663 TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
664 piValue, pftValue, szValueBuf, pcchValueBuf );
665
666 str.unicode = FALSE;
667 str.str.a = szValueBuf;
668
669 return get_prop( handle, uiProperty, puiDataType, piValue,
670 pftValue, &str, pcchValueBuf );
671 }
672
673 UINT WINAPI MsiSummaryInfoGetPropertyW(
674 MSIHANDLE handle, UINT uiProperty, PUINT puiDataType, LPINT piValue,
675 FILETIME *pftValue, LPWSTR szValueBuf, LPDWORD pcchValueBuf)
676 {
677 awstring str;
678
679 TRACE("%d %d %p %p %p %p %p\n", handle, uiProperty, puiDataType,
680 piValue, pftValue, szValueBuf, pcchValueBuf );
681
682 str.unicode = TRUE;
683 str.str.w = szValueBuf;
684
685 return get_prop( handle, uiProperty, puiDataType, piValue,
686 pftValue, &str, pcchValueBuf );
687 }
688
689 static UINT set_prop( MSISUMMARYINFO *si, UINT uiProperty, UINT type,
690 INT iValue, FILETIME* pftValue, awcstring *str )
691 {
692 PROPVARIANT *prop;
693 UINT len;
694
695 TRACE("%p %u %u %i %p %p\n", si, uiProperty, type, iValue,
696 pftValue, str );
697
698 prop = &si->property[uiProperty];
699
700 if( prop->vt == VT_EMPTY )
701 {
702 if( !si->update_count )
703 return ERROR_FUNCTION_FAILED;
704
705 si->update_count--;
706 }
707 else if( prop->vt != type )
708 return ERROR_SUCCESS;
709
710 free_prop( prop );
711 prop->vt = type;
712 switch( type )
713 {
714 case VT_I4:
715 prop->u.lVal = iValue;
716 break;
717 case VT_I2:
718 prop->u.iVal = iValue;
719 break;
720 case VT_FILETIME:
721 prop->u.filetime = *pftValue;
722 break;
723 case VT_LPSTR:
724 if( str->unicode )
725 {
726 len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
727 NULL, 0, NULL, NULL );
728 prop->u.pszVal = msi_alloc( len );
729 WideCharToMultiByte( CP_ACP, 0, str->str.w, -1,
730 prop->u.pszVal, len, NULL, NULL );
731 }
732 else
733 {
734 len = lstrlenA( str->str.a ) + 1;
735 prop->u.pszVal = msi_alloc( len );
736 lstrcpyA( prop->u.pszVal, str->str.a );
737 }
738 break;
739 }
740
741 return ERROR_SUCCESS;
742 }
743
744 UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
745 UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
746 {
747 awcstring str;
748 MSISUMMARYINFO *si;
749 UINT type, ret;
750
751 TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
752 iValue, pftValue, debugstr_w(szValue) );
753
754 type = get_type( uiProperty );
755 if( type == VT_EMPTY || type != uiDataType )
756 return ERROR_DATATYPE_MISMATCH;
757
758 if( uiDataType == VT_LPSTR && !szValue )
759 return ERROR_INVALID_PARAMETER;
760
761 if( uiDataType == VT_FILETIME && !pftValue )
762 return ERROR_INVALID_PARAMETER;
763
764 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
765 if( !si )
766 return ERROR_INVALID_HANDLE;
767
768 str.unicode = TRUE;
769 str.str.w = szValue;
770 ret = set_prop( si, uiProperty, type, iValue, pftValue, &str );
771
772 msiobj_release( &si->hdr );
773 return ret;
774 }
775
776 UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
777 UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
778 {
779 awcstring str;
780 MSISUMMARYINFO *si;
781 UINT type, ret;
782
783 TRACE("%d %u %u %i %p %s\n", handle, uiProperty, uiDataType,
784 iValue, pftValue, debugstr_a(szValue) );
785
786 type = get_type( uiProperty );
787 if( type == VT_EMPTY || type != uiDataType )
788 return ERROR_DATATYPE_MISMATCH;
789
790 if( uiDataType == VT_LPSTR && !szValue )
791 return ERROR_INVALID_PARAMETER;
792
793 if( uiDataType == VT_FILETIME && !pftValue )
794 return ERROR_INVALID_PARAMETER;
795
796 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
797 if( !si )
798 return ERROR_INVALID_HANDLE;
799
800 str.unicode = FALSE;
801 str.str.a = szValue;
802 ret = set_prop( si, uiProperty, uiDataType, iValue, pftValue, &str );
803
804 msiobj_release( &si->hdr );
805 return ret;
806 }
807
808 static UINT suminfo_persist( MSISUMMARYINFO *si )
809 {
810 UINT ret = ERROR_FUNCTION_FAILED;
811 IStream *stm = NULL;
812 DWORD grfMode;
813 HRESULT r;
814
815 grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
816 r = IStorage_CreateStream( si->storage, szSumInfo, grfMode, 0, 0, &stm );
817 if( SUCCEEDED(r) )
818 {
819 ret = save_summary_info( si, stm );
820 IStream_Release( stm );
821 }
822 return ret;
823 }
824
825 static void parse_filetime( LPCWSTR str, FILETIME *ft )
826 {
827 SYSTEMTIME lt, utc;
828 const WCHAR *p = str;
829 WCHAR *end;
830
831 memset( &lt, 0, sizeof(lt) );
832
833 /* YYYY/MM/DD hh:mm:ss */
834
835 while (isspaceW( *p )) p++;
836
837 lt.wYear = strtolW( p, &end, 10 );
838 if (*end != '/') return;
839 p = end + 1;
840
841 lt.wMonth = strtolW( p, &end, 10 );
842 if (*end != '/') return;
843 p = end + 1;
844
845 lt.wDay = strtolW( p, &end, 10 );
846 if (*end != ' ') return;
847 p = end + 1;
848
849 while (isspaceW( *p )) p++;
850
851 lt.wHour = strtolW( p, &end, 10 );
852 if (*end != ':') return;
853 p = end + 1;
854
855 lt.wMinute = strtolW( p, &end, 10 );
856 if (*end != ':') return;
857 p = end + 1;
858
859 lt.wSecond = strtolW( p, &end, 10 );
860
861 TzSpecificLocalTimeToSystemTime( NULL, &lt, &utc );
862 SystemTimeToFileTime( &utc, ft );
863 }
864
865 static UINT parse_prop( LPCWSTR prop, LPCWSTR value, UINT *pid, INT *int_value,
866 FILETIME *ft_value, awcstring *str_value )
867 {
868 *pid = atoiW( prop );
869 switch (*pid)
870 {
871 case PID_CODEPAGE:
872 case PID_WORDCOUNT:
873 case PID_CHARCOUNT:
874 case PID_SECURITY:
875 case PID_PAGECOUNT:
876 *int_value = atoiW( value );
877 break;
878
879 case PID_LASTPRINTED:
880 case PID_CREATE_DTM:
881 case PID_LASTSAVE_DTM:
882 parse_filetime( value, ft_value );
883 break;
884
885 case PID_SUBJECT:
886 case PID_AUTHOR:
887 case PID_KEYWORDS:
888 case PID_COMMENTS:
889 case PID_TEMPLATE:
890 case PID_LASTAUTHOR:
891 case PID_REVNUMBER:
892 case PID_APPNAME:
893 case PID_TITLE:
894 str_value->str.w = value;
895 str_value->unicode = TRUE;
896 break;
897
898 default:
899 WARN("unhandled prop id %u\n", *pid);
900 return ERROR_FUNCTION_FAILED;
901 }
902
903 return ERROR_SUCCESS;
904 }
905
906 UINT msi_add_suminfo( MSIDATABASE *db, LPWSTR **records, int num_records, int num_columns )
907 {
908 UINT r = ERROR_FUNCTION_FAILED;
909 int i, j;
910 MSISUMMARYINFO *si;
911
912 si = MSI_GetSummaryInformationW( db->storage, num_records * (num_columns / 2) );
913 if (!si)
914 {
915 ERR("no summary information!\n");
916 return ERROR_FUNCTION_FAILED;
917 }
918
919 for (i = 0; i < num_records; i++)
920 {
921 for (j = 0; j < num_columns; j += 2)
922 {
923 UINT pid;
924 INT int_value = 0;
925 FILETIME ft_value;
926 awcstring str_value;
927
928 r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value );
929 if (r != ERROR_SUCCESS)
930 goto end;
931
932 r = set_prop( si, pid, get_type(pid), int_value, &ft_value, &str_value );
933 if (r != ERROR_SUCCESS)
934 goto end;
935 }
936 }
937
938 end:
939 if (r == ERROR_SUCCESS)
940 r = suminfo_persist( si );
941
942 msiobj_release( &si->hdr );
943 return r;
944 }
945
946 UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle )
947 {
948 MSISUMMARYINFO *si;
949 UINT ret;
950
951 TRACE("%d\n", handle );
952
953 si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
954 if( !si )
955 return ERROR_INVALID_HANDLE;
956
957 ret = suminfo_persist( si );
958
959 msiobj_release( &si->hdr );
960 return ret;
961 }
962
963 UINT WINAPI MsiCreateTransformSummaryInfoA( MSIHANDLE db, MSIHANDLE db_ref, LPCSTR transform, int error, int validation )
964 {
965 UINT r;
966 WCHAR *transformW = NULL;
967
968 TRACE("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_a(transform), error, validation);
969
970 if (transform && !(transformW = strdupAtoW( transform )))
971 return ERROR_OUTOFMEMORY;
972
973 r = MsiCreateTransformSummaryInfoW( db, db_ref, transformW, error, validation );
974 msi_free( transformW );
975 return r;
976 }
977
978 UINT WINAPI MsiCreateTransformSummaryInfoW( MSIHANDLE db, MSIHANDLE db_ref, LPCWSTR transform, int error, int validation )
979 {
980 FIXME("%u, %u, %s, %d, %d\n", db, db_ref, debugstr_w(transform), error, validation);
981 return ERROR_FUNCTION_FAILED;
982 }