Load a table's column information separately from the table itself.

This commit is contained in:
Mike McCormack 2005-09-22 10:34:07 +00:00 committed by Alexandre Julliard
parent 75658d7aaa
commit 1c5967c48c
1 changed files with 68 additions and 67 deletions

View File

@ -1,7 +1,7 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 Mike McCormack for CodeWeavers
* 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
@ -41,9 +41,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMSICOLUMNINFO
{
LPWSTR tablename;
LPCWSTR tablename;
UINT number;
LPWSTR colname;
LPCWSTR colname;
UINT type;
UINT offset;
} MSICOLUMNINFO;
@ -63,7 +63,7 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
static UINT get_tablecolumns( MSIDATABASE *db,
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
static inline UINT bytes_per_column( MSICOLUMNINFO *col )
static inline UINT bytes_per_column( const MSICOLUMNINFO *col )
{
if( col->type & MSITYPE_STRING )
return 2;
@ -404,12 +404,14 @@ static void free_table( MSITABLE *table )
msi_free( table );
}
static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
/* add this table to the list of cached tables in the database */
static MSITABLE *read_table_from_storage( IStorage *stg, LPCWSTR name,
const MSICOLUMNINFO *cols, UINT num_cols )
{
MSITABLE *t;
USHORT *rawdata = NULL;
UINT rawsize = 0, r, i, j, row_size = 0, num_cols = 0;
MSICOLUMNINFO *cols = NULL, *last_col;
UINT rawsize = 0, i, j, row_size = 0;
const MSICOLUMNINFO *last_col;
TRACE("%s\n",debugstr_w(name));
@ -418,10 +420,6 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
if( !t )
return t;
r = table_get_column_info( db, name, &cols, &num_cols );
if( r != ERROR_SUCCESS )
goto err;
last_col = &cols[num_cols-1];
row_size = last_col->offset + bytes_per_column( last_col );
@ -430,7 +428,7 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
lstrcpyW( t->name, name );
/* if we can't read the table, just assume that it's empty */
read_stream_data( db->storage, name, &rawdata, &rawsize );
read_stream_data( stg, name, &rawdata, &rawsize );
if( !rawdata )
return t;
@ -476,13 +474,9 @@ static MSITABLE *read_table_from_storage( MSIDATABASE *db, LPCWSTR name )
}
}
msi_free( cols );
msi_free( rawdata );
return t;
err:
msi_free( cols );
msi_free( rawdata );
free_table( t );
return NULL;
@ -499,7 +493,7 @@ void free_cached_tables( MSIDATABASE *db )
}
}
static MSITABLE *find_cached_table(MSIDATABASE *db, LPCWSTR name )
static MSITABLE *find_cached_table( MSIDATABASE *db, LPCWSTR name )
{
MSITABLE *t;
@ -512,7 +506,7 @@ static MSITABLE *find_cached_table(MSIDATABASE *db, LPCWSTR name )
static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
{
UINT r, column_count;
UINT r, column_count = 0;
MSICOLUMNINFO *columns;
/* get the number of columns in this table */
@ -527,7 +521,7 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
TRACE("Table %s found\n", debugstr_w(name) );
columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO));
columns = msi_alloc( column_count*sizeof (MSICOLUMNINFO) );
if( !columns )
return ERROR_FUNCTION_FAILED;
@ -544,7 +538,8 @@ static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO
return r;
}
static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name )
static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name,
const MSICOLUMNINFO *cols, UINT num_cols )
{
MSITABLE *table;
@ -553,7 +548,7 @@ static MSITABLE *get_table( MSIDATABASE *db, LPCWSTR name )
if( table )
return table;
table = read_table_from_storage( db, name );
table = read_table_from_storage( db->storage, name, cols, num_cols );
if( table )
list_add_head( &db->tables, &table->entry );
@ -809,53 +804,63 @@ static const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 };
static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
static const WCHAR szType[] = { 'T','y','p','e',0 };
struct standard_table {
LPCWSTR tablename;
LPCWSTR columnname;
UINT number;
UINT type;
} MSI_standard_tables[] =
{
{ szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szNumber, 2, MSITYPE_VALID | 2},
{ szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szType, 4, MSITYPE_VALID | 2},
static const MSICOLUMNINFO _Columns_cols[4] = {
{ szColumns, 1, szTable, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
{ szColumns, 2, szNumber, MSITYPE_VALID | 2, 2 },
{ szColumns, 3, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 4 },
{ szColumns, 4, szType, MSITYPE_VALID | 2, 6 },
};
static const MSICOLUMNINFO _Tables_cols[1] = {
{ szTables, 1, szName, MSITYPE_VALID | MSITYPE_STRING | 32, 0 },
};
#define STANDARD_TABLE_COUNT \
(sizeof(MSI_standard_tables)/sizeof(struct standard_table))
static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
static UINT get_defaulttablecolumns( LPCWSTR name, MSICOLUMNINFO *colinfo, UINT *sz)
{
DWORD i, n=0;
const MSICOLUMNINFO *p;
DWORD i, n;
for(i=0; i<STANDARD_TABLE_COUNT; i++)
TRACE("%s\n", debugstr_w(name));
if (!lstrcmpW( name, szTables ))
{
if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) )
continue;
if(colinfo && (n < *sz) )
p = _Tables_cols;
n = 1;
}
else if (!lstrcmpW( name, szColumns ))
{
p = _Columns_cols;
n = 4;
}
else
return ERROR_FUNCTION_FAILED;
/* duplicate the string data so we can free it in msi_free_colinfo */
for (i=0; i<n; i++)
{
if (colinfo && (i < *sz) )
{
colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename);
colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname);
colinfo[n].number = MSI_standard_tables[i].number;
colinfo[n].type = MSI_standard_tables[i].type;
/* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename),
debugstr_w(colinfo[n].colname)); */
if( n )
colinfo[n].offset = colinfo[n-1].offset
+ bytes_per_column( &colinfo[n-1] );
else
colinfo[n].offset = 0;
memcpy( &colinfo[i], &p[i], sizeof(MSICOLUMNINFO) );
colinfo[i].tablename = strdupW( p[i].tablename );
colinfo[i].colname = strdupW( p[i].colname );
}
n++;
if( colinfo && (n >= *sz) )
if( colinfo && (i >= *sz) )
break;
}
*sz = n;
return ERROR_SUCCESS;
}
static void msi_free_colinfo( MSICOLUMNINFO *colinfo, UINT count )
{
UINT i;
for( i=0; i<count; i++ )
{
msi_free( (LPWSTR) colinfo[i].tablename );
msi_free( (LPWSTR) colinfo[i].colname );
}
}
LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
{
UINT sz=0, r;
@ -885,10 +890,10 @@ static UINT get_tablecolumns( MSIDATABASE *db,
if( ( r == ERROR_SUCCESS ) && *sz )
return r;
table = get_table( db, szColumns );
table = get_table( db, szColumns, _Columns_cols, 4 );
if( !table )
{
WARN("table %s not available\n", debugstr_w(szColumns));
ERR("couldn't load _Columns table\n");
return ERROR_FUNCTION_FAILED;
}
@ -958,7 +963,7 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name )
return FALSE;
}
table = get_table( db, szTables );
table = get_table( db, szTables, _Tables_cols, 1 );
if( !table )
{
TRACE("table %s not available\n", debugstr_w(szTables));
@ -1167,7 +1172,8 @@ static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
TRACE("%p %p\n", tv, record);
tv->table = get_table( tv->db, tv->name );
TRACE("There are %d columns\n", tv->num_cols );
tv->table = get_table( tv->db, tv->name, tv->columns, tv->num_cols );
if( !tv->table )
return ERROR_FUNCTION_FAILED;
@ -1401,12 +1407,7 @@ static UINT TABLE_delete( struct tagMSIVIEW *view )
if( tv->columns )
{
UINT i;
for( i=0; i<tv->num_cols; i++)
{
msi_free( tv->columns[i].colname );
msi_free( tv->columns[i].tablename );
}
msi_free_colinfo( tv->columns, tv->num_cols );
msi_free( tv->columns );
}
tv->columns = NULL;
@ -1434,7 +1435,7 @@ MSIVIEWOPS table_ops =
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
{
MSITABLEVIEW *tv ;
UINT r, sz, column_count = 0;
UINT r, sz, column_count;
MSICOLUMNINFO *columns, *last_col;
TRACE("%p %s %p\n", db, debugstr_w(name), view );
@ -1483,7 +1484,7 @@ UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
tv->table = NULL;
tv->row_size = last_col->offset + bytes_per_column( last_col );
TRACE("one row is %d bytes\n", tv->row_size );
TRACE("%s one row is %d bytes\n", debugstr_w(name), tv->row_size );
*view = (MSIVIEW*) tv;
lstrcpyW( tv->name, name );