msi: Handle embedded nulls in text archives.
This commit is contained in:
parent
b55cbe8d11
commit
e2ba5dce06
|
@ -509,7 +509,7 @@ end:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LPWSTR msi_read_text_archive(LPCWSTR path)
|
static LPWSTR msi_read_text_archive(LPCWSTR path, DWORD *len)
|
||||||
{
|
{
|
||||||
HANDLE file;
|
HANDLE file;
|
||||||
LPSTR data = NULL;
|
LPSTR data = NULL;
|
||||||
|
@ -521,15 +521,17 @@ static LPWSTR msi_read_text_archive(LPCWSTR path)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
size = GetFileSize( file, NULL );
|
size = GetFileSize( file, NULL );
|
||||||
data = msi_alloc( size + 1 );
|
if (!(data = msi_alloc( size ))) goto done;
|
||||||
if (!data)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (!ReadFile( file, data, size, &read, NULL ))
|
if (!ReadFile( file, data, size, &read, NULL ) || read != size) goto done;
|
||||||
goto done;
|
|
||||||
|
|
||||||
data[size] = '\0';
|
while (!data[size - 1]) size--;
|
||||||
wdata = strdupAtoW( data );
|
*len = MultiByteToWideChar( CP_ACP, 0, data, size, NULL, 0 );
|
||||||
|
if ((wdata = msi_alloc( (*len + 1) * sizeof(WCHAR) )))
|
||||||
|
{
|
||||||
|
MultiByteToWideChar( CP_ACP, 0, data, size, wdata, *len );
|
||||||
|
wdata[*len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
CloseHandle( file );
|
CloseHandle( file );
|
||||||
|
@ -537,21 +539,22 @@ done:
|
||||||
return wdata;
|
return wdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
|
static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries, DWORD *len)
|
||||||
{
|
{
|
||||||
LPWSTR ptr = *line, save;
|
LPWSTR ptr = *line, save;
|
||||||
DWORD i, count = 1;
|
DWORD i, count = 1, chars_left = *len;
|
||||||
|
|
||||||
*entries = NULL;
|
*entries = NULL;
|
||||||
|
|
||||||
/* stay on this line */
|
/* stay on this line */
|
||||||
while (*ptr && *ptr != '\n')
|
while (chars_left && *ptr != '\n')
|
||||||
{
|
{
|
||||||
/* entries are separated by tabs */
|
/* entries are separated by tabs */
|
||||||
if (*ptr == '\t')
|
if (*ptr == '\t')
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
|
chars_left--;
|
||||||
}
|
}
|
||||||
|
|
||||||
*entries = msi_alloc(count * sizeof(LPWSTR));
|
*entries = msi_alloc(count * sizeof(LPWSTR));
|
||||||
|
@ -559,28 +562,43 @@ static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* store pointers into the data */
|
/* store pointers into the data */
|
||||||
|
chars_left = *len;
|
||||||
for (i = 0, ptr = *line; i < count; i++)
|
for (i = 0, ptr = *line; i < count; i++)
|
||||||
{
|
{
|
||||||
while (*ptr && *ptr == '\r') ptr++;
|
while (chars_left && *ptr == '\r')
|
||||||
|
{
|
||||||
|
ptr++;
|
||||||
|
chars_left--;
|
||||||
|
}
|
||||||
save = ptr;
|
save = ptr;
|
||||||
|
|
||||||
while (*ptr && *ptr != '\t' && *ptr != '\n' && *ptr != '\r') ptr++;
|
while (chars_left && *ptr != '\t' && *ptr != '\n' && *ptr != '\r')
|
||||||
|
{
|
||||||
|
if (!*ptr) *ptr = '\n'; /* convert embedded nulls to \n */
|
||||||
|
ptr++;
|
||||||
|
chars_left--;
|
||||||
|
}
|
||||||
|
|
||||||
/* NULL-separate the data */
|
/* NULL-separate the data */
|
||||||
if (*ptr == '\n' || *ptr == '\r')
|
if (*ptr == '\n' || *ptr == '\r')
|
||||||
{
|
{
|
||||||
while (*ptr == '\n' || *ptr == '\r')
|
while (chars_left && (*ptr == '\n' || *ptr == '\r'))
|
||||||
*(ptr++) = '\0';
|
{
|
||||||
|
*(ptr++) = 0;
|
||||||
|
chars_left--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (*ptr)
|
else if (*ptr)
|
||||||
*ptr++ = '\0';
|
{
|
||||||
|
*(ptr++) = 0;
|
||||||
|
chars_left--;
|
||||||
|
}
|
||||||
(*entries)[i] = save;
|
(*entries)[i] = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move to the next line if there's more, else EOF */
|
/* move to the next line if there's more, else EOF */
|
||||||
*line = ptr;
|
*line = ptr;
|
||||||
|
*len = chars_left;
|
||||||
if (num_entries)
|
if (num_entries)
|
||||||
*num_entries = count;
|
*num_entries = count;
|
||||||
}
|
}
|
||||||
|
@ -916,12 +934,12 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
|
||||||
lstrcatW( path, szBackSlash );
|
lstrcatW( path, szBackSlash );
|
||||||
lstrcatW( path, file );
|
lstrcatW( path, file );
|
||||||
|
|
||||||
data = msi_read_text_archive( path );
|
data = msi_read_text_archive( path, &len );
|
||||||
|
|
||||||
ptr = data;
|
ptr = data;
|
||||||
msi_parse_line( &ptr, &columns, &num_columns );
|
msi_parse_line( &ptr, &columns, &num_columns, &len );
|
||||||
msi_parse_line( &ptr, &types, &num_types );
|
msi_parse_line( &ptr, &types, &num_types, &len );
|
||||||
msi_parse_line( &ptr, &labels, &num_labels );
|
msi_parse_line( &ptr, &labels, &num_labels, &len );
|
||||||
|
|
||||||
if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
|
if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
|
||||||
num_types == 2 && !strcmpW( types[1], forcecodepage ))
|
num_types == 2 && !strcmpW( types[1], forcecodepage ))
|
||||||
|
@ -944,9 +962,9 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read in the table records */
|
/* read in the table records */
|
||||||
while (*ptr)
|
while (len)
|
||||||
{
|
{
|
||||||
msi_parse_line( &ptr, &records[num_records], NULL );
|
msi_parse_line( &ptr, &records[num_records], NULL, &len );
|
||||||
|
|
||||||
num_records++;
|
num_records++;
|
||||||
temp_records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *));
|
temp_records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *));
|
||||||
|
|
|
@ -9253,6 +9253,39 @@ static void test_createtable(void)
|
||||||
DeleteFileA(msifile);
|
DeleteFileA(msifile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_embedded_nulls(void)
|
||||||
|
{
|
||||||
|
static const char control_table[] =
|
||||||
|
"Dialog\tText\n"
|
||||||
|
"s72\tL0\n"
|
||||||
|
"Control\tDialog\n"
|
||||||
|
"LicenseAgreementDlg\ttext\0text";
|
||||||
|
UINT r, sz;
|
||||||
|
MSIHANDLE hdb, hrec;
|
||||||
|
char buffer[32];
|
||||||
|
|
||||||
|
r = MsiOpenDatabaseA( msifile, MSIDBOPEN_CREATE, &hdb );
|
||||||
|
ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
|
||||||
|
|
||||||
|
GetCurrentDirectoryA( MAX_PATH, CURR_DIR );
|
||||||
|
write_file( "temp_file", control_table, sizeof(control_table) );
|
||||||
|
r = MsiDatabaseImportA( hdb, CURR_DIR, "temp_file" );
|
||||||
|
ok( r == ERROR_SUCCESS, "failed to import table %u\n", r );
|
||||||
|
DeleteFileA( "temp_file" );
|
||||||
|
|
||||||
|
r = do_query( hdb, "SELECT `Text` FROM `Control` WHERE `Dialog` = 'LicenseAgreementDlg'", &hrec );
|
||||||
|
ok( r == ERROR_SUCCESS, "query failed %u\n", r );
|
||||||
|
|
||||||
|
buffer[0] = 0;
|
||||||
|
sz = sizeof(buffer);
|
||||||
|
r = MsiRecordGetStringA( hrec, 1, buffer, &sz );
|
||||||
|
ok( r == ERROR_SUCCESS, "failed to get string %u\n", r );
|
||||||
|
ok( !memcmp( "text\ntext", buffer, sizeof("text\ntext") - 1 ), "wrong buffer contents \"%s\"\n", buffer );
|
||||||
|
|
||||||
|
MsiCloseHandle( hrec );
|
||||||
|
MsiCloseHandle( hdb );
|
||||||
|
DeleteFileA( msifile );
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(db)
|
START_TEST(db)
|
||||||
{
|
{
|
||||||
|
@ -9307,4 +9340,5 @@ START_TEST(db)
|
||||||
test_suminfo_import();
|
test_suminfo_import();
|
||||||
test_createtable();
|
test_createtable();
|
||||||
test_collation();
|
test_collation();
|
||||||
|
test_embedded_nulls();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue