msi: Add support for exporting binary streams (Binary/Icon tables).

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.

Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Erich E. Hoover 2019-03-15 10:03:59 +01:00 committed by Alexandre Julliard
parent b08d999863
commit f1d8218169
1 changed files with 79 additions and 6 deletions

View File

@ -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 );
}