summaryrefslogtreecommitdiffstats
path: root/libmsi/libmsi-summary-info.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2012-12-09 23:35:30 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2012-12-10 17:26:22 +0100
commit6b7407cb031cf245a4998d8c79009039ead38fc5 (patch)
tree510263de28a0319b9070ededaa2cc7c5b6d98ac0 /libmsi/libmsi-summary-info.c
parentada3b04b2246c13449e6b32b3857d7b86a8958f8 (diff)
downloadmsitools-6b7407cb031cf245a4998d8c79009039ead38fc5.tar.gz
msitools-6b7407cb031cf245a4998d8c79009039ead38fc5.tar.xz
msitools-6b7407cb031cf245a4998d8c79009039ead38fc5.zip
Split libmsi.h to be more gobject-like
Diffstat (limited to 'libmsi/libmsi-summary-info.c')
-rw-r--r--libmsi/libmsi-summary-info.c778
1 files changed, 778 insertions, 0 deletions
diff --git a/libmsi/libmsi-summary-info.c b/libmsi/libmsi-summary-info.c
new file mode 100644
index 0000000..4c0e77d
--- /dev/null
+++ b/libmsi/libmsi-summary-info.c
@@ -0,0 +1,778 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002, 2005 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <time.h>
+#include <assert.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "debug.h"
+#include "unicode.h"
+#include "libmsi.h"
+#include "msipriv.h"
+
+static const WCHAR szSumInfo[] = {5 ,'S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0};
+static const uint8_t fmtid_SummaryInformation[16] =
+ { 0xe0, 0x85, 0x9f, 0xf2, 0xf9, 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9};
+
+static void free_prop( LibmsiOLEVariant *prop )
+{
+ if (prop->vt == OLEVT_LPSTR)
+ msi_free( prop->strval );
+ prop->vt = OLEVT_EMPTY;
+}
+
+static void _libmsi_summary_info_destroy( LibmsiObject *arg )
+{
+ LibmsiSummaryInfo *si = (LibmsiSummaryInfo *) arg;
+ unsigned i;
+
+ for( i = 0; i < MSI_MAX_PROPS; i++ )
+ free_prop( &si->property[i] );
+ msiobj_release( &si->database->hdr );
+}
+
+static unsigned get_type( unsigned uiProperty )
+{
+ switch( uiProperty )
+ {
+ case MSI_PID_CODEPAGE:
+ return OLEVT_I2;
+
+ case MSI_PID_SUBJECT:
+ case MSI_PID_AUTHOR:
+ case MSI_PID_KEYWORDS:
+ case MSI_PID_COMMENTS:
+ case MSI_PID_TEMPLATE:
+ case MSI_PID_LASTAUTHOR:
+ case MSI_PID_REVNUMBER:
+ case MSI_PID_APPNAME:
+ case MSI_PID_TITLE:
+ return OLEVT_LPSTR;
+
+ case MSI_PID_LASTPRINTED:
+ case MSI_PID_CREATE_DTM:
+ case MSI_PID_LASTSAVE_DTM:
+ return OLEVT_FILETIME;
+
+ case MSI_PID_WORDCOUNT:
+ case MSI_PID_CHARCOUNT:
+ case MSI_PID_SECURITY:
+ case MSI_PID_PAGECOUNT:
+ return OLEVT_I4;
+ }
+ return OLEVT_EMPTY;
+}
+
+static unsigned get_property_count( const LibmsiOLEVariant *property )
+{
+ unsigned i, n = 0;
+
+ if( !property )
+ return n;
+ for( i = 0; i < MSI_MAX_PROPS; i++ )
+ if( property[i].vt != OLEVT_EMPTY )
+ n++;
+ return n;
+}
+
+static unsigned read_word( uint8_t *data, unsigned *ofs )
+{
+ unsigned val = 0;
+ val = data[*ofs];
+ val |= data[*ofs+1] << 8;
+ *ofs += 2;
+ return val;
+}
+
+static unsigned read_dword( uint8_t *data, unsigned *ofs )
+{
+ unsigned val = 0;
+ val = data[*ofs];
+ val |= data[*ofs+1] << 8;
+ val |= data[*ofs+2] << 16;
+ val |= data[*ofs+3] << 24;
+ *ofs += 4;
+ return val;
+}
+
+static void parse_filetime( const WCHAR *str, guint64 *ft )
+{
+ struct tm tm;
+ time_t t;
+ const WCHAR *p = str;
+ WCHAR *end;
+
+
+ /* YYYY/MM/DD hh:mm:ss */
+
+ while ( *p == ' ' || *p == '\t' ) p++;
+
+ tm.tm_year = strtolW( p, &end, 10 );
+ if (*end != '/') return;
+ p = end + 1;
+
+ tm.tm_mon = strtolW( p, &end, 10 ) - 1;
+ if (*end != '/') return;
+ p = end + 1;
+
+ tm.tm_mday = strtolW( p, &end, 10 );
+ if (*end != ' ') return;
+ p = end + 1;
+
+ while ( *p == ' ' || *p == '\t' ) p++;
+
+ tm.tm_hour = strtolW( p, &end, 10 );
+ if (*end != ':') return;
+ p = end + 1;
+
+ tm.tm_min = strtolW( p, &end, 10 );
+ if (*end != ':') return;
+ p = end + 1;
+
+ tm.tm_sec = strtolW( p, &end, 10 );
+
+ t = mktime(&tm);
+
+ /* Add number of seconds between 1601-01-01 and 1970-01-01,
+ * then convert to 100 ns units.
+ */
+ *ft = (t + 134774ULL * 86400ULL) * 10000000ULL;
+}
+
+/* FIXME: doesn't deal with endian conversion */
+static void read_properties_from_data( LibmsiOLEVariant *prop, uint8_t *data, unsigned sz, uint32_t cProperties )
+{
+ unsigned type;
+ unsigned i;
+ LibmsiOLEVariant *property;
+ uint32_t idofs, len;
+ char *str;
+
+ idofs = 8;
+
+ /* now set all the properties */
+ for( i = 0; i < cProperties; i++ )
+ {
+ int propid = read_dword(data, &idofs);
+ int dwOffset = read_dword(data, &idofs);
+ int proptype;
+
+ if( propid >= MSI_MAX_PROPS )
+ {
+ ERR("Unknown property ID %d\n", propid );
+ break;
+ }
+
+ type = get_type( propid );
+ if( type == OLEVT_EMPTY )
+ {
+ ERR("propid %d has unknown type\n", propid);
+ break;
+ }
+
+ property = &prop[ propid ];
+
+ if( dwOffset + 4 > sz )
+ {
+ ERR("not enough data for type %d %d \n", dwOffset, sz);
+ break;
+ }
+
+ proptype = read_dword(data, &dwOffset);
+ if( dwOffset + 4 > sz )
+ {
+ ERR("not enough data for type %d %d \n", dwOffset, sz);
+ break;
+ }
+
+ property->vt = proptype;
+ switch(proptype)
+ {
+ case OLEVT_I2:
+ case OLEVT_I4:
+ property->intval = read_dword(data, &dwOffset);
+ break;
+ case OLEVT_FILETIME:
+ if( dwOffset + 8 > sz )
+ {
+ ERR("not enough data for type %d %d \n", dwOffset, sz);
+ break;
+ }
+ property->filetime = read_dword(data, &dwOffset);
+ property->filetime |= (guint64)read_dword(data, &dwOffset) << 32;
+ break;
+ case OLEVT_LPSTR:
+ len = read_dword(data, &dwOffset);
+ if( dwOffset + len > sz )
+ {
+ ERR("not enough data for type %d %d %d \n", dwOffset, len, sz);
+ break;
+ }
+ str = msi_alloc( len );
+ memcpy( str, &data[dwOffset], len-1 );
+ str[ len - 1 ] = 0;
+ break;
+ }
+
+ /* check the type is the same as we expect */
+ if( type == OLEVT_LPSTR && proptype == OLEVT_LPSTR)
+ property->strval = str;
+ else if (type == proptype)
+ ;
+ else if( proptype == OLEVT_LPSTR) {
+ if( type == OLEVT_I2 || type == OLEVT_I4) {
+ property->intval = atoi( str );
+ } else if( type == OLEVT_FILETIME) {
+ WCHAR *wstr = strdupAtoW(str);
+ parse_filetime( wstr, &property->filetime );
+ msi_free (wstr);
+ }
+ msi_free (str);
+ }
+ else
+ {
+ ERR("invalid type \n");
+ break;
+ }
+ }
+}
+
+static unsigned load_summary_info( LibmsiSummaryInfo *si, IStream *stm )
+{
+ unsigned ret = LIBMSI_RESULT_FUNCTION_FAILED;
+ uint8_t *data = NULL;
+ unsigned ofs, dwOffset;
+ unsigned count, size, cbSection, cProperties;
+ HRESULT r;
+ STATSTG stat;
+
+ TRACE("%p %p\n", si, stm);
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME);
+ if (FAILED(r))
+ return r;
+
+ if (stat.cbSize.QuadPart >> 32)
+ {
+ ERR("Storage is too large\n");
+ return ret;
+ }
+
+ size = stat.cbSize.QuadPart;
+ data = msi_alloc(size);
+
+ ofs = 0;
+ r = IStream_Read( stm, data, size, &count );
+ if( FAILED(r) || count != size )
+ return ret;
+
+ /* process the set header */
+ if( read_word( data, &ofs) != 0xfffe )
+ {
+ ERR("property set not little-endian\n");
+ return ret;
+ }
+
+ /* process the format header */
+
+ /* check the format id is correct */
+ ofs = 28;
+ if( memcmp( &fmtid_SummaryInformation, &data[ofs], 16 ) )
+ return ret;
+
+ /* seek to the location of the section */
+ ofs += 16;
+ ofs = dwOffset = read_dword(data, &ofs);
+
+ /* read the section itself */
+ cbSection = read_dword( data, &ofs );
+ cProperties = read_dword( data, &ofs );
+
+ if( cProperties > MSI_MAX_PROPS )
+ {
+ ERR("too many properties %d\n", cProperties);
+ return ret;
+ }
+
+ /* read all the data in one go */
+ read_properties_from_data( si->property,
+ &data[dwOffset],
+ cbSection, cProperties );
+
+ msi_free( data );
+ return ret;
+}
+
+static unsigned write_word( uint8_t *data, unsigned ofs, unsigned val )
+{
+ if( data )
+ {
+ data[ofs++] = val&0xff;
+ data[ofs++] = (val>>8)&0xff;
+ }
+ return 2;
+}
+
+static unsigned write_dword( uint8_t *data, unsigned ofs, unsigned val )
+{
+ if( data )
+ {
+ data[ofs++] = val&0xff;
+ data[ofs++] = (val>>8)&0xff;
+ data[ofs++] = (val>>16)&0xff;
+ data[ofs++] = (val>>24)&0xff;
+ }
+ return 4;
+}
+
+static unsigned write_filetime( uint8_t *data, unsigned ofs, const guint64 *ft )
+{
+ write_dword( data, ofs, (*ft) & 0xFFFFFFFFUL );
+ write_dword( data, ofs + 4, (*ft) >> 32 );
+ return 8;
+}
+
+static unsigned write_string( uint8_t *data, unsigned ofs, const char *str )
+{
+ unsigned len = strlen( str ) + 1;
+ write_dword( data, ofs, len );
+ if( data )
+ memcpy( &data[ofs + 4], str, len );
+ return (7 + len) & ~3;
+}
+
+static unsigned write_property_to_data( const LibmsiOLEVariant *prop, uint8_t *data )
+{
+ unsigned sz = 0;
+
+ if( prop->vt == OLEVT_EMPTY )
+ return sz;
+
+ /* add the type */
+ sz += write_dword( data, sz, prop->vt );
+ switch( prop->vt )
+ {
+ case OLEVT_I2:
+ case OLEVT_I4:
+ sz += write_dword( data, sz, prop->intval );
+ break;
+ case OLEVT_FILETIME: {
+ sz += write_filetime( data, sz, &prop->filetime );
+ break;
+ }
+ case OLEVT_LPSTR:
+ sz += write_string( data, sz, prop->strval );
+ break;
+ }
+ return sz;
+}
+
+static unsigned suminfo_persist( LibmsiSummaryInfo *si )
+{
+ int cProperties, cbSection, dwOffset;
+ IStream *stm;
+ uint8_t *data = NULL;
+ unsigned r, sz;
+ int i;
+
+ /* add up how much space the data will take and calculate the offsets */
+ cProperties = get_property_count( si->property );
+ cbSection = 8 + cProperties * 8;
+ for( i = 0; i < MSI_MAX_PROPS; i++ )
+ cbSection += write_property_to_data( &si->property[i], NULL );
+
+ sz = 28 + 20 + cbSection;
+ data = msi_alloc_zero( sz );
+
+ /* write the set header */
+ sz = 0;
+ sz += write_word(data, sz, 0xfffe); /* wByteOrder */
+ sz += write_word(data, sz, 0); /* wFormat */
+ sz += write_dword(data, sz, 0x00020005); /* dwOSVer - build 5, platform id 2 */
+ sz += 16; /* clsID */
+ sz += write_dword(data, sz, 1); /* reserved */
+
+ /* write the format header */
+ memcpy( &data[sz], &fmtid_SummaryInformation, 16 );
+ sz += 16;
+
+ sz += write_dword(data, sz, 28 + 20); /* dwOffset */
+ assert(sz == 28 + 20);
+
+ /* write the section header */
+ sz += write_dword(data, sz, cbSection);
+ sz += write_dword(data, sz, cProperties);
+ assert(sz == 28 + 20 + 8);
+
+ dwOffset = 8 + cProperties * 8;
+ for( i = 0; i < MSI_MAX_PROPS; i++ )
+ {
+ int propsz = write_property_to_data( &si->property[i], NULL );
+ if( !propsz )
+ continue;
+ sz += write_dword(data, sz, i);
+ sz += write_dword(data, sz, dwOffset);
+ dwOffset += propsz;
+ }
+ assert(dwOffset == cbSection);
+
+ /* write out the data */
+ for( i = 0; i < MSI_MAX_PROPS; i++ )
+ sz += write_property_to_data( &si->property[i], &data[sz] );
+
+ assert(sz == 28 + 20 + cbSection);
+
+ r = write_raw_stream_data(si->database, szSumInfo, data, sz, &stm);
+ if (r == 0) {
+ IStream_Release( stm );
+ }
+ msi_free( data );
+ return r;
+}
+
+LibmsiSummaryInfo *_libmsi_get_summary_information( LibmsiDatabase *db, unsigned uiUpdateCount )
+{
+ IStream *stm = NULL;
+ LibmsiSummaryInfo *si;
+ unsigned grfMode;
+ unsigned r;
+
+ TRACE("%p %d\n", db, uiUpdateCount );
+
+ si = alloc_msiobject( sizeof (LibmsiSummaryInfo), _libmsi_summary_info_destroy );
+ if( !si )
+ return si;
+
+ si->update_count = uiUpdateCount;
+ msiobj_addref( &db->hdr );
+ si->database = db;
+
+ /* read the stream... if we fail, we'll start with an empty property set */
+ grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
+ r = msi_get_raw_stream( db, szSumInfo, &stm );
+ if( r == 0 )
+ {
+ load_summary_info( si, stm );
+ IStream_Release( stm );
+ }
+
+ return si;
+}
+
+LibmsiResult libmsi_database_get_summary_info( LibmsiDatabase *db,
+ unsigned uiUpdateCount, LibmsiSummaryInfo **psi )
+{
+ LibmsiSummaryInfo *si;
+ unsigned ret = LIBMSI_RESULT_FUNCTION_FAILED;
+
+ TRACE("%d %d %p\n", db, uiUpdateCount, psi);
+
+ if( !psi )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ if( !db )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref( &db->hdr);
+ si = _libmsi_get_summary_information( db, uiUpdateCount );
+ if (si)
+ {
+ *psi = si;
+ ret = LIBMSI_RESULT_SUCCESS;
+ }
+
+ msiobj_release( &db->hdr );
+ return ret;
+}
+
+LibmsiResult libmsi_summary_info_get_property_count(LibmsiSummaryInfo *si, unsigned *pCount)
+{
+ TRACE("%d %p\n", si, pCount);
+
+ if( !si )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref( &si->hdr );
+ if( pCount )
+ *pCount = get_property_count( si->property );
+ msiobj_release( &si->hdr );
+
+ return LIBMSI_RESULT_SUCCESS;
+}
+
+LibmsiResult libmsi_summary_info_get_property(
+ LibmsiSummaryInfo *si, unsigned uiProperty, unsigned *puiDataType, int *pintvalue,
+ guint64 *pftValue, char *szValueBuf, unsigned *pcchValueBuf)
+{
+ LibmsiOLEVariant *prop;
+ unsigned ret = LIBMSI_RESULT_SUCCESS;
+
+ TRACE("%d %d %p %p %p %p %p\n", si, uiProperty, puiDataType,
+ pintvalue, pftValue, szValueBuf, pcchValueBuf);
+
+ if ( uiProperty >= MSI_MAX_PROPS )
+ {
+ if (puiDataType) *puiDataType = LIBMSI_PROPERTY_TYPE_EMPTY;
+ return LIBMSI_RESULT_UNKNOWN_PROPERTY;
+ }
+
+ if( !si )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref( &si->hdr );
+ prop = &si->property[uiProperty];
+
+ switch( prop->vt )
+ {
+ case OLEVT_I2:
+ case OLEVT_I4:
+ if( puiDataType )
+ *puiDataType = LIBMSI_PROPERTY_TYPE_INT;
+
+ if( pintvalue )
+ *pintvalue = prop->intval;
+ break;
+ case OLEVT_LPSTR:
+ if( puiDataType )
+ *puiDataType = LIBMSI_PROPERTY_TYPE_STRING;
+
+ if( pcchValueBuf )
+ {
+ unsigned len = 0;
+
+ len = strlen( prop->strval );
+ if( szValueBuf )
+ strcpynA(szValueBuf, prop->strval, *pcchValueBuf );
+ if (len >= *pcchValueBuf)
+ ret = LIBMSI_RESULT_MORE_DATA;
+ *pcchValueBuf = len;
+ }
+ break;
+ case OLEVT_FILETIME:
+ if( puiDataType )
+ *puiDataType = LIBMSI_PROPERTY_TYPE_FILETIME;
+
+ if( pftValue )
+ *pftValue = prop->filetime;
+ break;
+ case OLEVT_EMPTY:
+ if( puiDataType )
+ *puiDataType = LIBMSI_PROPERTY_TYPE_EMPTY;
+
+ break;
+ default:
+ FIXME("Unknown property variant type\n");
+ break;
+ }
+ msiobj_release( &si->hdr );
+ return ret;
+}
+
+static LibmsiResult _libmsi_summary_info_set_property( LibmsiSummaryInfo *si, unsigned uiProperty,
+ unsigned type, int intvalue, guint64* pftValue, const char *szValue )
+{
+ LibmsiOLEVariant *prop;
+ unsigned len;
+ unsigned ret;
+
+ if( type == OLEVT_LPSTR && !szValue )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ if( type == OLEVT_FILETIME && !pftValue )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ msiobj_addref( &si->hdr);
+
+ prop = &si->property[uiProperty];
+
+ if( prop->vt == OLEVT_EMPTY )
+ {
+ ret = LIBMSI_RESULT_FUNCTION_FAILED;
+ if( !si->update_count )
+ goto end;
+
+ si->update_count--;
+ }
+ else if( prop->vt != type )
+ {
+ ret = LIBMSI_RESULT_SUCCESS;
+ goto end;
+ }
+
+ free_prop( prop );
+ prop->vt = type;
+ switch( type )
+ {
+ case OLEVT_I2:
+ case OLEVT_I4:
+ prop->intval = intvalue;
+ break;
+ case OLEVT_FILETIME:
+ prop->filetime = *pftValue;
+ break;
+ case OLEVT_LPSTR:
+ len = strlen( szValue ) + 1;
+ prop->strval = msi_alloc( len );
+ strcpy( prop->strval, szValue );
+ break;
+ }
+
+ ret = LIBMSI_RESULT_SUCCESS;
+end:
+ msiobj_release( &si->hdr );
+ return ret;
+}
+
+LibmsiResult libmsi_summary_info_set_property( LibmsiSummaryInfo *si, unsigned uiProperty,
+ unsigned uiDataType, int intvalue, guint64* pftValue, const char *szValue )
+{
+ int type;
+
+ TRACE("%p %u %u %i %p %p\n", si, uiProperty, type, intvalue,
+ pftValue, szValue );
+
+ if( !si )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ type = get_type( uiProperty );
+ switch (type) {
+ case OLEVT_EMPTY:
+ return LIBMSI_RESULT_DATATYPE_MISMATCH;
+ case OLEVT_I2:
+ case OLEVT_I4:
+ if (uiDataType != LIBMSI_PROPERTY_TYPE_INT) {
+ return LIBMSI_RESULT_DATATYPE_MISMATCH;
+ }
+ break;
+ case OLEVT_LPSTR:
+ if (uiDataType != LIBMSI_PROPERTY_TYPE_STRING) {
+ return LIBMSI_RESULT_DATATYPE_MISMATCH;
+ }
+ break;
+ case OLEVT_FILETIME:
+ if (uiDataType != LIBMSI_PROPERTY_TYPE_FILETIME) {
+ return LIBMSI_RESULT_DATATYPE_MISMATCH;
+ }
+ break;
+ }
+
+ return _libmsi_summary_info_set_property( si, uiProperty, type, intvalue, pftValue, szValue );
+}
+
+static unsigned parse_prop( const WCHAR *prop, const WCHAR *value, unsigned *pid, int *int_value,
+ guint64 *ft_value, char **str_value )
+{
+ *pid = atoiW( prop );
+ switch (*pid)
+ {
+ case MSI_PID_CODEPAGE:
+ case MSI_PID_WORDCOUNT:
+ case MSI_PID_CHARCOUNT:
+ case MSI_PID_SECURITY:
+ case MSI_PID_PAGECOUNT:
+ *int_value = atoiW( value );
+ break;
+
+ case MSI_PID_LASTPRINTED:
+ case MSI_PID_CREATE_DTM:
+ case MSI_PID_LASTSAVE_DTM:
+ parse_filetime( value, ft_value );
+ break;
+
+ case MSI_PID_SUBJECT:
+ case MSI_PID_AUTHOR:
+ case MSI_PID_KEYWORDS:
+ case MSI_PID_COMMENTS:
+ case MSI_PID_TEMPLATE:
+ case MSI_PID_LASTAUTHOR:
+ case MSI_PID_REVNUMBER:
+ case MSI_PID_APPNAME:
+ case MSI_PID_TITLE:
+ *str_value = strdupWtoA(value);
+ break;
+
+ default:
+ WARN("unhandled prop id %u\n", *pid);
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ }
+
+ return LIBMSI_RESULT_SUCCESS;
+}
+
+unsigned msi_add_suminfo( LibmsiDatabase *db, WCHAR ***records, int num_records, int num_columns )
+{
+ unsigned r = LIBMSI_RESULT_FUNCTION_FAILED;
+ unsigned i, j;
+ LibmsiSummaryInfo *si;
+
+ si = _libmsi_get_summary_information( db, num_records * (num_columns / 2) );
+ if (!si)
+ {
+ ERR("no summary information!\n");
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ }
+
+ for (i = 0; i < num_records; i++)
+ {
+ for (j = 0; j < num_columns; j += 2)
+ {
+ unsigned pid;
+ int int_value = 0;
+ guint64 ft_value;
+ char *str_value = NULL;
+
+ r = parse_prop( records[i][j], records[i][j + 1], &pid, &int_value, &ft_value, &str_value );
+ if (r != LIBMSI_RESULT_SUCCESS)
+ goto end;
+
+ assert( get_type(pid) != OLEVT_EMPTY );
+ r = _libmsi_summary_info_set_property( si, pid, get_type(pid), int_value, &ft_value, str_value );
+ if (r != LIBMSI_RESULT_SUCCESS)
+ goto end;
+
+ msi_free(str_value);
+ }
+ }
+
+end:
+ if (r == LIBMSI_RESULT_SUCCESS)
+ r = suminfo_persist( si );
+
+ msiobj_release( &si->hdr );
+ return r;
+}
+
+LibmsiResult libmsi_summary_info_persist( LibmsiSummaryInfo *si )
+{
+ unsigned ret;
+
+ TRACE("%d\n", si );
+
+ if( !si )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref( &si->hdr);
+ ret = suminfo_persist( si );
+ msiobj_release( &si->hdr );
+ return ret;
+}