msi: Add support for storing strings with embedded nulls in the string table.

This commit is contained in:
Hans Leidekker 2012-10-29 12:12:50 +01:00 committed by Alexandre Julliard
parent 652863f4d5
commit 6950ac1d1c
7 changed files with 66 additions and 50 deletions

View File

@ -754,9 +754,9 @@ enum StringPersistence
}; };
extern BOOL msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence ) DECLSPEC_HIDDEN; extern BOOL msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcount, enum StringPersistence persistence ) DECLSPEC_HIDDEN;
extern UINT msi_string2idW( const string_table *st, LPCWSTR buffer, UINT *id ) DECLSPEC_HIDDEN; extern UINT msi_string2id( const string_table *st, const WCHAR *data, int len, UINT *id ) DECLSPEC_HIDDEN;
extern VOID msi_destroy_stringtable( string_table *st ) DECLSPEC_HIDDEN; extern VOID msi_destroy_stringtable( string_table *st ) DECLSPEC_HIDDEN;
extern const WCHAR *msi_string_lookup_id( const string_table *st, UINT id ) DECLSPEC_HIDDEN; extern const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len ) DECLSPEC_HIDDEN;
extern HRESULT msi_init_string_table( IStorage *stg ) DECLSPEC_HIDDEN; extern HRESULT msi_init_string_table( IStorage *stg ) DECLSPEC_HIDDEN;
extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ) DECLSPEC_HIDDEN; extern string_table *msi_load_string_table( IStorage *stg, UINT *bytes_per_strref ) DECLSPEC_HIDDEN;
extern UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *bytes_per_strref ) DECLSPEC_HIDDEN; extern UINT msi_save_string_table( const string_table *st, IStorage *storage, UINT *bytes_per_strref ) DECLSPEC_HIDDEN;

View File

@ -347,7 +347,7 @@ UINT msi_view_get_row(MSIDATABASE *db, MSIVIEW *view, UINT row, MSIRECORD **rec)
{ {
LPCWSTR sval; LPCWSTR sval;
sval = msi_string_lookup_id(db->strings, ival); sval = msi_string_lookup(db->strings, ival, NULL);
MSI_RecordSetStringW(*rec, i, sval); MSI_RecordSetStringW(*rec, i, sval);
} }
else else

View File

@ -312,7 +312,7 @@ static UINT storages_find_row(MSISTORAGESVIEW *sv, MSIRECORD *rec, UINT *row)
UINT r, i, id, data; UINT r, i, id, data;
str = MSI_RecordGetString(rec, 1); str = MSI_RecordGetString(rec, 1);
r = msi_string2idW(sv->db->strings, str, &id); r = msi_string2id(sv->db->strings, str, -1, &id);
if (r != ERROR_SUCCESS) if (r != ERROR_SUCCESS)
return r; return r;

View File

@ -299,7 +299,7 @@ static UINT streams_find_row(MSISTREAMSVIEW *sv, MSIRECORD *rec, UINT *row)
UINT r, i, id, data; UINT r, i, id, data;
str = MSI_RecordGetString(rec, 1); str = MSI_RecordGetString(rec, 1);
r = msi_string2idW(sv->db->strings, str, &id); r = msi_string2id(sv->db->strings, str, -1, &id);
if (r != ERROR_SUCCESS) if (r != ERROR_SUCCESS)
return r; return r;

View File

@ -45,7 +45,8 @@ struct msistring
{ {
USHORT persistent_refcount; USHORT persistent_refcount;
USHORT nonpersistent_refcount; USHORT nonpersistent_refcount;
LPWSTR str; WCHAR *data;
int len;
}; };
struct string_table struct string_table
@ -112,7 +113,7 @@ VOID msi_destroy_stringtable( string_table *st )
{ {
if( st->strings[i].persistent_refcount || if( st->strings[i].persistent_refcount ||
st->strings[i].nonpersistent_refcount ) st->strings[i].nonpersistent_refcount )
msi_free( st->strings[i].str ); msi_free( st->strings[i].data );
} }
msi_free( st->strings ); msi_free( st->strings );
msi_free( st->sorted ); msi_free( st->sorted );
@ -162,6 +163,19 @@ static int st_find_free_entry( string_table *st )
return st->freeslot; return st->freeslot;
} }
static inline int cmp_string( const WCHAR *str1, int len1, const WCHAR *str2, int len2 )
{
if (len1 < len2) return -1;
else if (len1 > len2) return 1;
while (len1)
{
if (*str1 == *str2) { str1++; str2++; }
else return *str1 - *str2;
len1--;
}
return 0;
}
static int find_insert_index( const string_table *st, UINT string_id ) static int find_insert_index( const string_table *st, UINT string_id )
{ {
int i, c, low = 0, high = st->sortcount - 1; int i, c, low = 0, high = st->sortcount - 1;
@ -169,8 +183,8 @@ static int find_insert_index( const string_table *st, UINT string_id )
while (low <= high) while (low <= high)
{ {
i = (low + high) / 2; i = (low + high) / 2;
c = strcmpW( st->strings[string_id].str, st->strings[st->sorted[i]].str ); c = cmp_string( st->strings[string_id].data, st->strings[string_id].len,
st->strings[st->sorted[i]].data, st->strings[st->sorted[i]].len );
if (c < 0) if (c < 0)
high = i - 1; high = i - 1;
else if (c > 0) else if (c > 0)
@ -194,7 +208,8 @@ static void insert_string_sorted( string_table *st, UINT string_id )
st->sortcount++; st->sortcount++;
} }
static void set_st_entry( string_table *st, UINT n, LPWSTR str, USHORT refcount, enum StringPersistence persistence ) static void set_st_entry( string_table *st, UINT n, WCHAR *str, int len, USHORT refcount,
enum StringPersistence persistence )
{ {
if (persistence == StringPersistent) if (persistence == StringPersistent)
{ {
@ -207,7 +222,8 @@ static void set_st_entry( string_table *st, UINT n, LPWSTR str, USHORT refcount,
st->strings[n].nonpersistent_refcount = refcount; st->strings[n].nonpersistent_refcount = refcount;
} }
st->strings[n].str = str; st->strings[n].data = str;
st->strings[n].len = len;
insert_string_sorted( st, n ); insert_string_sorted( st, n );
@ -237,9 +253,8 @@ static UINT msi_string2idA( const string_table *st, LPCSTR buffer, UINT *id )
return ERROR_NOT_ENOUGH_MEMORY; return ERROR_NOT_ENOUGH_MEMORY;
MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz ); MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
r = msi_string2idW( st, str, id ); r = msi_string2id( st, str, sz - 1, id );
msi_free( str ); msi_free( str );
return r; return r;
} }
@ -289,7 +304,7 @@ static int msi_addstring( string_table *st, UINT n, const CHAR *data, int len, U
MultiByteToWideChar( st->codepage, 0, data, len, str, sz ); MultiByteToWideChar( st->codepage, 0, data, len, str, sz );
str[sz] = 0; str[sz] = 0;
set_st_entry( st, n, str, refcount, persistence ); set_st_entry( st, n, str, sz, refcount, persistence );
return n; return n;
} }
@ -301,10 +316,10 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun
if( !data ) if( !data )
return 0; return 0;
if( !data[0] ) if( !data[0] && !len )
return 0; return 0;
if( msi_string2idW( st, data, &n ) == ERROR_SUCCESS ) if (msi_string2id( st, data, len, &n) == ERROR_SUCCESS )
{ {
if (persistence == StringPersistent) if (persistence == StringPersistent)
st->strings[n].persistent_refcount += refcount; st->strings[n].persistent_refcount += refcount;
@ -320,7 +335,7 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun
/* allocate a new string */ /* allocate a new string */
if(len<0) if(len<0)
len = strlenW(data); len = strlenW(data);
TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len ); TRACE( "%s, n = %d len = %d\n", debugstr_wn(data, len), n, len );
str = msi_alloc( (len+1)*sizeof(WCHAR) ); str = msi_alloc( (len+1)*sizeof(WCHAR) );
if( !str ) if( !str )
@ -328,13 +343,13 @@ int msi_addstringW( string_table *st, const WCHAR *data, int len, USHORT refcoun
memcpy( str, data, len*sizeof(WCHAR) ); memcpy( str, data, len*sizeof(WCHAR) );
str[len] = 0; str[len] = 0;
set_st_entry( st, n, str, refcount, persistence ); set_st_entry( st, n, str, len, refcount, persistence );
return n; return n;
} }
/* find the string identified by an id - return null if there's none */ /* find the string identified by an id - return null if there's none */
const WCHAR *msi_string_lookup_id( const string_table *st, UINT id ) const WCHAR *msi_string_lookup( const string_table *st, UINT id, int *len )
{ {
if( id == 0 ) if( id == 0 )
return szEmpty; return szEmpty;
@ -345,7 +360,9 @@ const WCHAR *msi_string_lookup_id( const string_table *st, UINT id )
if( id && !st->strings[id].persistent_refcount && !st->strings[id].nonpersistent_refcount) if( id && !st->strings[id].persistent_refcount && !st->strings[id].nonpersistent_refcount)
return NULL; return NULL;
return st->strings[id].str; if (len) *len = st->strings[id].len;
return st->strings[id].data;
} }
/* /*
@ -361,16 +378,15 @@ const WCHAR *msi_string_lookup_id( const string_table *st, UINT id )
*/ */
static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT *sz ) static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT *sz )
{ {
UINT len, lenW; int len, lenW;
const WCHAR *str; const WCHAR *str;
TRACE("Finding string %d of %d\n", id, st->maxcount); TRACE("Finding string %d of %d\n", id, st->maxcount);
str = msi_string_lookup_id( st, id ); str = msi_string_lookup( st, id, &lenW );
if( !str ) if( !str )
return ERROR_FUNCTION_FAILED; return ERROR_FUNCTION_FAILED;
lenW = strlenW( str );
len = WideCharToMultiByte( st->codepage, 0, str, lenW, NULL, 0, NULL, NULL ); len = WideCharToMultiByte( st->codepage, 0, str, lenW, NULL, 0, NULL, NULL );
if( *sz < len ) if( *sz < len )
{ {
@ -382,20 +398,22 @@ static UINT msi_id2stringA( const string_table *st, UINT id, LPSTR buffer, UINT
} }
/* /*
* msi_string2idW * msi_string2id
* *
* [in] st - pointer to the string table * [in] st - pointer to the string table
* [in] str - string to find in the string table * [in] str - string to find in the string table
* [out] id - id of the string, if found * [out] id - id of the string, if found
*/ */
UINT msi_string2idW( const string_table *st, LPCWSTR str, UINT *id ) UINT msi_string2id( const string_table *st, const WCHAR *str, int len, UINT *id )
{ {
int i, c, low = 0, high = st->sortcount - 1; int i, c, low = 0, high = st->sortcount - 1;
if (len < 0) len = strlenW( str );
while (low <= high) while (low <= high)
{ {
i = (low + high) / 2; i = (low + high) / 2;
c = strcmpW( str, st->strings[st->sorted[i]].str ); c = cmp_string( str, len, st->strings[st->sorted[i]].data, st->strings[st->sorted[i]].len );
if (c < 0) if (c < 0)
high = i - 1; high = i - 1;
@ -407,7 +425,6 @@ UINT msi_string2idW( const string_table *st, LPCWSTR str, UINT *id )
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
} }
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
} }
@ -415,7 +432,7 @@ static void string_totalsize( const string_table *st, UINT *datasize, UINT *pool
{ {
UINT i, len, holesize; UINT i, len, holesize;
if( st->strings[0].str || st->strings[0].persistent_refcount || st->strings[0].nonpersistent_refcount) if( st->strings[0].data || st->strings[0].persistent_refcount || st->strings[0].nonpersistent_refcount)
ERR("oops. element 0 has a string\n"); ERR("oops. element 0 has a string\n");
*poolsize = 4; *poolsize = 4;
@ -425,14 +442,14 @@ static void string_totalsize( const string_table *st, UINT *datasize, UINT *pool
{ {
if( !st->strings[i].persistent_refcount ) if( !st->strings[i].persistent_refcount )
{ {
TRACE("[%u] nonpersistent = %s\n", i, debugstr_w(st->strings[i].str)); TRACE("[%u] nonpersistent = %s\n", i, debugstr_wn(st->strings[i].data, st->strings[i].len));
(*poolsize) += 4; (*poolsize) += 4;
} }
else if( st->strings[i].str ) else if( st->strings[i].data )
{ {
TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str)); TRACE("[%u] = %s\n", i, debugstr_wn(st->strings[i].data, st->strings[i].len));
len = WideCharToMultiByte( st->codepage, 0, len = WideCharToMultiByte( st->codepage, 0, st->strings[i].data, st->strings[i].len + 1,
st->strings[i].str, -1, NULL, 0, NULL, NULL); NULL, 0, NULL, NULL);
if( len ) if( len )
len--; len--;
(*datasize) += len; (*datasize) += len;

View File

@ -660,7 +660,7 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINF
} }
/* convert table and column names to IDs from the string table */ /* convert table and column names to IDs from the string table */
r = msi_string2idW( db->strings, szTableName, &table_id ); r = msi_string2id( db->strings, szTableName, -1, &table_id );
if (r != ERROR_SUCCESS) if (r != ERROR_SUCCESS)
{ {
WARN("Couldn't find id for %s\n", debugstr_w(szTableName)); WARN("Couldn't find id for %s\n", debugstr_w(szTableName));
@ -693,9 +693,9 @@ static UINT get_tablecolumns( MSIDATABASE *db, LPCWSTR szTableName, MSICOLUMNINF
ERR("duplicate column %d\n", col); ERR("duplicate column %d\n", col);
continue; continue;
} }
colinfo[col - 1].tablename = msi_string_lookup_id( db->strings, table_id ); colinfo[col - 1].tablename = msi_string_lookup( db->strings, table_id, NULL );
colinfo[col - 1].number = col; colinfo[col - 1].number = col;
colinfo[col - 1].colname = msi_string_lookup_id( db->strings, id ); colinfo[col - 1].colname = msi_string_lookup( db->strings, id, NULL );
colinfo[col - 1].type = read_table_int( table->data, i, table->colinfo[3].offset, colinfo[col - 1].type = read_table_int( table->data, i, table->colinfo[3].offset,
sizeof(USHORT) ) - (1 << 15); sizeof(USHORT) ) - (1 << 15);
colinfo[col - 1].offset = 0; colinfo[col - 1].offset = 0;
@ -763,9 +763,9 @@ UINT msi_create_table( MSIDATABASE *db, LPCWSTR name, column_info *col_info,
UINT table_id = msi_addstringW( db->strings, col->table, -1, 1, string_persistence ); UINT table_id = msi_addstringW( db->strings, col->table, -1, 1, string_persistence );
UINT col_id = msi_addstringW( db->strings, col->column, -1, 1, string_persistence ); UINT col_id = msi_addstringW( db->strings, col->column, -1, 1, string_persistence );
table->colinfo[ i ].tablename = msi_string_lookup_id( db->strings, table_id ); table->colinfo[ i ].tablename = msi_string_lookup( db->strings, table_id, NULL );
table->colinfo[ i ].number = i + 1; table->colinfo[ i ].number = i + 1;
table->colinfo[ i ].colname = msi_string_lookup_id( db->strings, col_id ); table->colinfo[ i ].colname = msi_string_lookup( db->strings, col_id, NULL );
table->colinfo[ i ].type = col->type; table->colinfo[ i ].type = col->type;
table->colinfo[ i ].offset = 0; table->colinfo[ i ].offset = 0;
table->colinfo[ i ].ref_count = 0; table->colinfo[ i ].ref_count = 0;
@ -981,7 +981,7 @@ BOOL TABLE_Exists( MSIDATABASE *db, LPCWSTR name )
!strcmpW( name, szStreams ) || !strcmpW( name, szStorages ) ) !strcmpW( name, szStreams ) || !strcmpW( name, szStorages ) )
return TRUE; return TRUE;
r = msi_string2idW( db->strings, name, &table_id ); r = msi_string2id( db->strings, name, -1, &table_id );
if( r != ERROR_SUCCESS ) if( r != ERROR_SUCCESS )
{ {
TRACE("Couldn't find id for %s\n", debugstr_w(name)); TRACE("Couldn't find id for %s\n", debugstr_w(name));
@ -1087,7 +1087,7 @@ static UINT msi_stream_name( const MSITABLEVIEW *tv, UINT row, LPWSTR *pstname )
if ( tv->columns[i].type & MSITYPE_STRING ) if ( tv->columns[i].type & MSITYPE_STRING )
{ {
sval = msi_string_lookup_id( tv->db->strings, ival ); sval = msi_string_lookup( tv->db->strings, ival, NULL );
if ( !sval ) if ( !sval )
{ {
r = ERROR_INVALID_PARAMETER; r = ERROR_INVALID_PARAMETER;
@ -1276,7 +1276,7 @@ static UINT get_table_value_from_record( MSITABLEVIEW *tv, MSIRECORD *rec, UINT
LPCWSTR sval = MSI_RecordGetString( rec, iField ); LPCWSTR sval = MSI_RecordGetString( rec, iField );
if (sval) if (sval)
{ {
r = msi_string2idW(tv->db->strings, sval, pvalue); r = msi_string2id(tv->db->strings, sval, -1, pvalue);
if (r != ERROR_SUCCESS) if (r != ERROR_SUCCESS)
return ERROR_NOT_FOUND; return ERROR_NOT_FOUND;
} }
@ -2343,7 +2343,7 @@ static MSIRECORD *msi_get_transform_record( const MSITABLEVIEW *tv, const string
LPCWSTR sval; LPCWSTR sval;
val = read_raw_int(rawdata, ofs, bytes_per_strref); val = read_raw_int(rawdata, ofs, bytes_per_strref);
sval = msi_string_lookup_id( st, val ); sval = msi_string_lookup( st, val, NULL );
MSI_RecordSetStringW( rec, i+1, sval ); MSI_RecordSetStringW( rec, i+1, sval );
TRACE(" field %d [%s]\n", i+1, debugstr_w(sval)); TRACE(" field %d [%s]\n", i+1, debugstr_w(sval));
ofs += bytes_per_strref; ofs += bytes_per_strref;
@ -2395,13 +2395,12 @@ static void dump_record( MSIRECORD *rec )
static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize ) static void dump_table( const string_table *st, const USHORT *rawdata, UINT rawsize )
{ {
LPCWSTR sval;
UINT i; UINT i;
for (i = 0; i < rawsize / 2; i++)
for( i=0; i<(rawsize/2); i++ )
{ {
sval = msi_string_lookup_id( st, rawdata[i] ); int len;
MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) ); const WCHAR *sval = msi_string_lookup( st, rawdata[i], &len );
MESSAGE(" %04x %s\n", rawdata[i], debugstr_wn(sval, len) );
} }
} }
@ -2425,7 +2424,7 @@ static UINT* msi_record_to_row( const MSITABLEVIEW *tv, MSIRECORD *rec )
str = MSI_RecordGetString( rec, i+1 ); str = MSI_RecordGetString( rec, i+1 );
if (str) if (str)
{ {
r = msi_string2idW( tv->db->strings, str, &data[i] ); r = msi_string2id( tv->db->strings, str, -1, &data[i] );
/* if there's no matching string in the string table, /* if there's no matching string in the string table,
these keys can't match any record, so fail now. */ these keys can't match any record, so fail now. */

View File

@ -494,7 +494,7 @@ static UINT STRING_evaluate( MSIWHEREVIEW *wv, const UINT rows[],
case EXPR_COL_NUMBER_STRING: case EXPR_COL_NUMBER_STRING:
r = expr_fetch_value(&expr->u.column, rows, &val); r = expr_fetch_value(&expr->u.column, rows, &val);
if (r == ERROR_SUCCESS) if (r == ERROR_SUCCESS)
*str = msi_string_lookup_id(wv->db->strings, val); *str = msi_string_lookup(wv->db->strings, val, NULL);
else else
*str = NULL; *str = NULL;
break; break;
@ -883,7 +883,7 @@ static UINT join_find_row( MSIWHEREVIEW *wv, MSIRECORD *rec, UINT *row )
UINT r, i, id, data; UINT r, i, id, data;
str = MSI_RecordGetString( rec, 1 ); str = MSI_RecordGetString( rec, 1 );
r = msi_string2idW( wv->db->strings, str, &id ); r = msi_string2id( wv->db->strings, str, -1, &id );
if (r != ERROR_SUCCESS) if (r != ERROR_SUCCESS)
return r; return r;