table.c
来自「一个类似windows」· C语言 代码 · 共 1,862 行 · 第 1/4 页
C
1,862 行
TRACE("Table id is %d\n", table_id);
count = table->row_count;
for( i=0; i<count; i++ )
{
if( table->data[ i ][ 0 ] != table_id )
continue;
if( colinfo )
{
UINT id = table->data[ i ] [ 2 ];
colinfo[n].tablename = MSI_makestring( db, table_id );
colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
colinfo[n].colname = MSI_makestring( db, id );
colinfo[n].type = table->data[ i ] [ 3 ] ^ 0x8000;
/* this assumes that columns are in order in the table */
if( n )
colinfo[n].offset = colinfo[n-1].offset
+ bytes_per_column( &colinfo[n-1] );
else
colinfo[n].offset = 0;
TRACE("table %s column %d is [%s] (%d) with type %08x "
"offset %d at row %d\n", debugstr_w(szTableName),
colinfo[n].number, debugstr_w(colinfo[n].colname),
id, colinfo[n].type, colinfo[n].offset, i);
if( n != (colinfo[n].number-1) )
{
ERR("oops. data in the _Columns table isn't in the right "
"order for table %s\n", debugstr_w(szTableName));
return ERROR_FUNCTION_FAILED;
}
}
n++;
if( colinfo && ( n >= maxcount ) )
break;
}
*sz = n;
return ERROR_SUCCESS;
}
/* try to find the table name in the _Tables table */
BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name )
{
UINT r, table_id = 0, i, count;
MSITABLE *table = NULL;
if( !lstrcmpW( name, szTables ) )
return TRUE;
if( !lstrcmpW( name, szColumns ) )
return TRUE;
r = msi_string2idW( db->strings, name, &table_id );
if( r != ERROR_SUCCESS )
{
TRACE("Couldn't find id for %s\n", debugstr_w(name));
return FALSE;
}
table = get_table( db, szTables, _Tables_cols, 1 );
if( !table )
{
TRACE("table %s not available\n", debugstr_w(szTables));
return FALSE;
}
/* count = table->size/2; */
count = table->row_count;
for( i=0; i<count; i++ )
if( table->data[ i ][ 0 ] == table_id )
break;
if (i!=count)
return TRUE;
TRACE("Searched %d tables, but %d was not found\n", count, table_id );
return FALSE;
}
/* below is the query interface to a table */
typedef struct tagMSITABLEVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSITABLE *table;
MSICOLUMNINFO *columns;
UINT num_cols;
UINT row_size;
WCHAR name[1];
} MSITABLEVIEW;
static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT offset, num_rows, n;
if( !tv->table )
return ERROR_INVALID_PARAMETER;
if( (col==0) || (col>tv->num_cols) )
return ERROR_INVALID_PARAMETER;
/* how many rows are there ? */
num_rows = tv->table->row_count;
if( row >= num_rows )
return ERROR_NO_MORE_ITEMS;
if( tv->columns[col-1].offset >= tv->row_size )
{
ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
ERR("%p %p\n", tv, tv->columns );
return ERROR_FUNCTION_FAILED;
}
offset = row + (tv->columns[col-1].offset/2) * num_rows;
n = bytes_per_column( &tv->columns[col-1] );
switch( n )
{
case 4:
offset = tv->columns[col-1].offset/2;
*val = tv->table->data[row][offset] +
(tv->table->data[row][offset + 1] << 16);
break;
case 2:
offset = tv->columns[col-1].offset/2;
*val = tv->table->data[row][offset];
break;
default:
ERR("oops! what is %d bytes per column?\n", n );
return ERROR_FUNCTION_FAILED;
}
/* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
return ERROR_SUCCESS;
}
/*
* We need a special case for streams, as we need to reference column with
* the name of the stream in the same table, and the table name
* which may not be available at higher levels of the query
*/
static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT ival = 0, refcol = 0, r;
LPWSTR sval;
LPWSTR full_name;
DWORD len;
static const WCHAR szDot[] = { '.', 0 };
if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER;
/*
* The column marked with the type stream data seems to have a single number
* which references the column containing the name of the stream data
*
* Fetch the column to reference first.
*/
r = view->ops->fetch_int( view, row, col, &ival );
if( r != ERROR_SUCCESS )
return r;
/* now get the column with the name of the stream */
r = view->ops->fetch_int( view, row, ival, &refcol );
if( r != ERROR_SUCCESS )
return r;
/* lookup the string value from the string table */
sval = MSI_makestring( tv->db, refcol );
if( !sval )
return ERROR_INVALID_PARAMETER;
len = lstrlenW( tv->name ) + 2 + lstrlenW( sval );
full_name = msi_alloc( len*sizeof(WCHAR) );
lstrcpyW( full_name, tv->name );
lstrcatW( full_name, szDot );
lstrcatW( full_name, sval );
r = db_get_raw_stream( tv->db, full_name, stm );
if( r )
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
msi_free( full_name );
msi_free( sval );
return r;
}
static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT offset, n;
if( !tv->table )
return ERROR_INVALID_PARAMETER;
if( (col==0) || (col>tv->num_cols) )
return ERROR_INVALID_PARAMETER;
if( tv->columns[col-1].offset >= tv->row_size )
{
ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
ERR("%p %p\n", tv, tv->columns );
return ERROR_FUNCTION_FAILED;
}
n = bytes_per_column( &tv->columns[col-1] );
switch( n )
{
case 4:
offset = tv->columns[col-1].offset/2;
tv->table->data[row][offset] = val & 0xffff;
tv->table->data[row][offset + 1] = (val>>16)&0xffff;
break;
case 2:
offset = tv->columns[col-1].offset/2;
tv->table->data[row][offset] = val;
break;
default:
ERR("oops! what is %d bytes per column?\n", n );
return ERROR_FUNCTION_FAILED;
}
return ERROR_SUCCESS;
}
static UINT table_create_new_row( struct tagMSIVIEW *view, UINT *num )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
USHORT **p, *row;
UINT sz;
TRACE("%p\n", view);
if( !tv->table )
return ERROR_INVALID_PARAMETER;
row = msi_alloc_zero( tv->row_size );
if( !row )
return ERROR_NOT_ENOUGH_MEMORY;
sz = (tv->table->row_count + 1) * sizeof (UINT*);
if( tv->table->data )
p = msi_realloc( tv->table->data, sz );
else
p = msi_alloc( sz );
if( !p )
{
msi_free( row );
return ERROR_NOT_ENOUGH_MEMORY;
}
tv->table->data = p;
tv->table->data[tv->table->row_count] = row;
*num = tv->table->row_count;
tv->table->row_count++;
return ERROR_SUCCESS;
}
static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p %p\n", tv, record);
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;
return ERROR_SUCCESS;
}
static UINT TABLE_close( struct tagMSIVIEW *view )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p\n", view );
if( !tv->table )
return ERROR_FUNCTION_FAILED;
tv->table = NULL;
return ERROR_SUCCESS;
}
static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols)
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p %p %p\n", view, rows, cols );
if( cols )
*cols = tv->num_cols;
if( rows )
{
if( !tv->table )
return ERROR_INVALID_PARAMETER;
*rows = tv->table->row_count;
}
return ERROR_SUCCESS;
}
static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p %d %p %p\n", tv, n, name, type );
if( ( n == 0 ) || ( n > tv->num_cols ) )
return ERROR_INVALID_PARAMETER;
if( name )
{
*name = strdupW( tv->columns[n-1].colname );
if( !*name )
return ERROR_FUNCTION_FAILED;
}
if( type )
*type = tv->columns[n-1].type;
return ERROR_SUCCESS;
}
static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
{
UINT r, row;
r = msi_table_find_row( tv, rec, &row );
if (r != ERROR_SUCCESS)
return ERROR_SUCCESS;
return ERROR_INVALID_DATA;
}
static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
UINT row, UINT mask )
{
UINT i, val, r = ERROR_SUCCESS;
TRACE("%p %p %u %08x\n", tv, rec, row, mask );
for( i = 0; i < tv->num_cols; i++ )
{
/* set keys or values specified in the mask */
if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<<i)) )
continue;
if( (tv->columns[i].type & MSITYPE_STRING) &&
! MSITYPE_IS_BINARY(tv->columns[i].type) )
{
const WCHAR *str = MSI_RecordGetString( rec, i+1 );
val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
}
else
{
val = MSI_RecordGetInteger( rec, i+1 );
if ( 2 == bytes_per_column( &tv->columns[i] ) )
val ^= 0x8000;
}
r = TABLE_set_int( &tv->view, row, i+1, val );
if( r )
break;
}
return r;
}
static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r, row = -1;
TRACE("%p %p\n", tv, rec );
r = table_create_new_row( view, &row );
TRACE("insert_row returned %08x\n", r);
if( r != ERROR_SUCCESS )
return r;
return msi_table_modify_row( tv, rec, row, ~0 );
}
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec)
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r;
TRACE("%p %d %p\n", view, eModifyMode, rec );
if (!tv->table)
{
r = TABLE_execute( view, NULL );
if( r )
return r;
}
switch (eModifyMode)
{
case MSIMODIFY_VALIDATE_NEW:
r = table_validate_new( tv, rec );
break;
case MSIMODIFY_INSERT_TEMPORARY:
r = table_validate_new( tv, rec );
if (r != ERROR_SUCCESS)
break;
r = TABLE_insert_row( view, rec );
break;
case MSIMODIFY_REFRESH:
case MSIMODIFY_INSERT:
case MSIMODIFY_UPDATE:
case MSIMODIFY_ASSIGN:
case MSIMODIFY_REPLACE:
case MSIMODIFY_MERGE:
case MSIMODIFY_DELETE:
case MSIMODIFY_VALIDATE:
case MSIMODIFY_VALIDATE_FIELD:
case MSIMODIFY_VALIDATE_DELETE:
FIXME("%p %d %p - mode not implemented\n", view, eModifyMode, rec );
r = ERROR_CALL_NOT_IMPLEMENTED;
break;
default:
r = ERROR_INVALID_DATA;
}
return r;
}
static UINT TABLE_delete( struct tagMSIVIEW *view )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p\n", view );
tv->table = NULL;
if( tv->columns )
{
msi_free_colinfo( tv->columns, tv->num_cols );
msi_free( tv->columns );
}
tv->columns = NULL;
msi_free( tv );
return ERROR_SUCCESS;
}
MSIVIEWOPS table_ops =
{
TABLE_fetch_int,
TABLE_fetch_stream,
TABLE_set_int,
TABLE_insert_row,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?