[PATCH 4/9] msi: Add support for exporting binary streams (Binary/Icon tables).
Hans Leidekker
hans at codeweavers.com
Fri Mar 15 04:03:59 CDT 2019
From: "Erich E. Hoover" <erich.e.hoover at gmail.com>
The Binary and Icon tables store their data in a different format from
other tables, one column of the data is stored as a "stream" instead
of a normal text field. With this patch those tables can now be
exported properly by the MSI export functionality.
v2: Avoid fixed size path buffers.
Signed-off-by: Erich E. Hoover <erich.e.hoover at gmail.com>
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/msi/database.c | 85 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 79 insertions(+), 6 deletions(-)
diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index f302610771..4537ed5836 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -961,8 +961,68 @@ static UINT msi_export_field( HANDLE handle, MSIRECORD *row, UINT field )
return ret ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
}
-static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start )
+static UINT msi_export_stream( const WCHAR *folder, const WCHAR *table, MSIRECORD *row, UINT field, UINT start )
{
+ static const WCHAR fmt[] = {'%','s','\\','%','s',0};
+ WCHAR stream[MAX_STREAM_NAME_LEN + 1], *path;
+ DWORD sz, read_size, write_size;
+ char buffer[1024];
+ HANDLE file;
+ UINT len, r;
+
+ sz = ARRAY_SIZE( stream );
+ r = MSI_RecordGetStringW( row, start, stream, &sz );
+ if (r != ERROR_SUCCESS)
+ return r;
+
+ len = (sz + strlenW( folder ) + strlenW( table ) + ARRAY_SIZE( fmt ) + 1) * sizeof(WCHAR);
+ if (!(path = msi_alloc( len )))
+ return ERROR_OUTOFMEMORY;
+
+ len = sprintfW( path, fmt, folder, table );
+ if (!CreateDirectoryW( path, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ msi_free( path );
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ path[len++] = '\\';
+ strcpyW( path + len, stream );
+ file = CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+ msi_free( path );
+ if (file == INVALID_HANDLE_VALUE)
+ return ERROR_FUNCTION_FAILED;
+
+ read_size = sizeof(buffer);
+ while (read_size == sizeof(buffer))
+ {
+ r = MSI_RecordReadStream( row, field, buffer, &read_size );
+ if (r != ERROR_SUCCESS)
+ {
+ CloseHandle( file );
+ return r;
+ }
+ if (!WriteFile( file, buffer, read_size, &write_size, NULL ) || read_size != write_size)
+ {
+ CloseHandle( file );
+ return ERROR_WRITE_FAULT;
+ }
+ }
+ CloseHandle( file );
+ return r;
+}
+
+struct row_export_info
+{
+ HANDLE handle;
+ const WCHAR *folder;
+ const WCHAR *table;
+};
+
+static UINT msi_export_record( struct row_export_info *row_export_info, MSIRECORD *row, UINT start )
+{
+ HANDLE handle = row_export_info->handle;
UINT i, count, r = ERROR_SUCCESS;
const char *sep;
DWORD sz;
@@ -971,7 +1031,18 @@ static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start )
for (i = start; i <= count; i++)
{
r = msi_export_field( handle, row, i );
- if (r != ERROR_SUCCESS)
+ if (r == ERROR_INVALID_PARAMETER)
+ {
+ r = msi_export_stream( row_export_info->folder, row_export_info->table, row, i, start );
+ if (r != ERROR_SUCCESS)
+ return r;
+
+ /* exporting a binary stream, repeat the "Name" field */
+ r = msi_export_field( handle, row, start );
+ if (r != ERROR_SUCCESS)
+ return r;
+ }
+ else if (r != ERROR_SUCCESS)
return r;
sep = (i < count) ? "\t" : "\r\n";
@@ -1062,11 +1133,13 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, LPCWSTR folder,
r = MSI_OpenQuery( db, &view, query, table );
if (r == ERROR_SUCCESS)
{
+ struct row_export_info row_export_info = { handle, folder, table };
+
/* write out row 1, the column names */
r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
if (r == ERROR_SUCCESS)
{
- msi_export_record( handle, rec, 1 );
+ msi_export_record( &row_export_info, rec, 1 );
msiobj_release( &rec->hdr );
}
@@ -1074,7 +1147,7 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, LPCWSTR folder,
r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
if (r == ERROR_SUCCESS)
{
- msi_export_record( handle, rec, 1 );
+ msi_export_record( &row_export_info, rec, 1 );
msiobj_release( &rec->hdr );
}
@@ -1083,12 +1156,12 @@ static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, LPCWSTR folder,
if (r == ERROR_SUCCESS)
{
MSI_RecordSetStringW( rec, 0, table );
- msi_export_record( handle, rec, 0 );
+ msi_export_record( &row_export_info, rec, 0 );
msiobj_release( &rec->hdr );
}
/* write out row 4 onwards, the data */
- r = MSI_IterateRecords( view, 0, msi_export_row, handle );
+ r = MSI_IterateRecords( view, 0, msi_export_row, &row_export_info );
msiobj_release( &view->hdr );
}
--
2.20.1
More information about the wine-devel
mailing list