Hans Leidekker : msi: Handle embedded nulls in text archives.

Alexandre Julliard julliard at winehq.org
Thu May 12 13:57:53 CDT 2011


Module: wine
Branch: master
Commit: e2ba5dce06b80a38ee763081ee4348cf7c28bde0
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e2ba5dce06b80a38ee763081ee4348cf7c28bde0

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Thu May 12 17:23:27 2011 +0200

msi: Handle embedded nulls in text archives.

---

 dlls/msi/database.c |   66 ++++++++++++++++++++++++++++++++------------------
 dlls/msi/tests/db.c |   34 ++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 24 deletions(-)

diff --git a/dlls/msi/database.c b/dlls/msi/database.c
index 02fc007..e7164e5 100644
--- a/dlls/msi/database.c
+++ b/dlls/msi/database.c
@@ -509,7 +509,7 @@ end:
     return r;
 }
 
-static LPWSTR msi_read_text_archive(LPCWSTR path)
+static LPWSTR msi_read_text_archive(LPCWSTR path, DWORD *len)
 {
     HANDLE file;
     LPSTR data = NULL;
@@ -521,15 +521,17 @@ static LPWSTR msi_read_text_archive(LPCWSTR path)
         return NULL;
 
     size = GetFileSize( file, NULL );
-    data = msi_alloc( size + 1 );
-    if (!data)
-        goto done;
+    if (!(data = msi_alloc( size ))) goto done;
 
-    if (!ReadFile( file, data, size, &read, NULL ))
-        goto done;
+    if (!ReadFile( file, data, size, &read, NULL ) || read != size) goto done;
 
-    data[size] = '\0';
-    wdata = strdupAtoW( data );
+    while (!data[size - 1]) size--;
+    *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:
     CloseHandle( file );
@@ -537,21 +539,22 @@ done:
     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;
-    DWORD i, count = 1;
+    DWORD i, count = 1, chars_left = *len;
 
     *entries = NULL;
 
     /* stay on this line */
-    while (*ptr && *ptr != '\n')
+    while (chars_left && *ptr != '\n')
     {
         /* entries are separated by tabs */
         if (*ptr == '\t')
             count++;
 
         ptr++;
+        chars_left--;
     }
 
     *entries = msi_alloc(count * sizeof(LPWSTR));
@@ -559,28 +562,43 @@ static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
         return;
 
     /* store pointers into the data */
+    chars_left = *len;
     for (i = 0, ptr = *line; i < count; i++)
     {
-        while (*ptr && *ptr == '\r') ptr++;
+        while (chars_left && *ptr == '\r')
+        {
+            ptr++;
+            chars_left--;
+        }
         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 */
         if (*ptr == '\n' || *ptr == '\r')
         {
-            while (*ptr == '\n' || *ptr == '\r')
-                *(ptr++) = '\0';
+            while (chars_left && (*ptr == '\n' || *ptr == '\r'))
+            {
+                *(ptr++) = 0;
+                chars_left--;
+            }
         }
         else if (*ptr)
-            *ptr++ = '\0';
-
+        {
+            *(ptr++) = 0;
+            chars_left--;
+        }
         (*entries)[i] = save;
     }
 
     /* move to the next line if there's more, else EOF */
     *line = ptr;
-
+    *len = chars_left;
     if (num_entries)
         *num_entries = count;
 }
@@ -916,12 +934,12 @@ static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
     lstrcatW( path, szBackSlash );
     lstrcatW( path, file );
 
-    data = msi_read_text_archive( path );
+    data = msi_read_text_archive( path, &len );
 
     ptr = data;
-    msi_parse_line( &ptr, &columns, &num_columns );
-    msi_parse_line( &ptr, &types, &num_types );
-    msi_parse_line( &ptr, &labels, &num_labels );
+    msi_parse_line( &ptr, &columns, &num_columns, &len );
+    msi_parse_line( &ptr, &types, &num_types, &len );
+    msi_parse_line( &ptr, &labels, &num_labels, &len );
 
     if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
         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 */
-    while (*ptr)
+    while (len)
     {
-        msi_parse_line( &ptr, &records[num_records], NULL );
+        msi_parse_line( &ptr, &records[num_records], NULL, &len );
 
         num_records++;
         temp_records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *));
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index 342157e..08b84bf 100644
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -9253,6 +9253,39 @@ static void test_createtable(void)
     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)
 {
@@ -9307,4 +9340,5 @@ START_TEST(db)
     test_suminfo_import();
     test_createtable();
     test_collation();
+    test_embedded_nulls();
 }




More information about the wine-cvs mailing list