From 51bd884384da29872faf878fc41b4572da634aa4 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 11 Jul 2017 00:18:34 -0500 Subject: [PATCH] msi: Properly parse empty format strings. Signed-off-by: Zebediah Figura Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/msi/format.c | 87 ++++++++++++++++++----------------------- dlls/msi/tests/format.c | 27 +++++++++++++ 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/dlls/msi/format.c b/dlls/msi/format.c index 581dd55f383..4297fbc7406 100644 --- a/dlls/msi/format.c +++ b/dlls/msi/format.c @@ -276,7 +276,7 @@ static WCHAR *deformat_environment( FORMAT *format, FORMSTR *str, int *ret_len ) } static WCHAR *deformat_literal( FORMAT *format, FORMSTR *str, BOOL *propfound, - BOOL *nonprop, int *type, int *len ) + int *type, int *len ) { LPCWSTR data = get_formstr_data(format, str); WCHAR *replaced = NULL; @@ -343,58 +343,24 @@ static LPWSTR build_default_format(const MSIRECORD* record) { int i; int count; - LPWSTR rc, buf; - static const WCHAR fmt[] = {'%','i',':',' ','%','s',' ',0}; - static const WCHAR fmt_null[] = {'%','i',':',' ',' ',0}; - static const WCHAR fmt_index[] = {'%','i',0}; - LPCWSTR str; - WCHAR index[10]; - DWORD size, max_len, len; + WCHAR *rc, buf[26]; + static const WCHAR fmt[] = {'%','i',':',' ','[','%','i',']',' ',0}; + DWORD size; count = MSI_RecordGetFieldCount(record); - max_len = MAX_PATH; - buf = msi_alloc((max_len + 1) * sizeof(WCHAR)); - - rc = NULL; + rc = msi_alloc(1); + rc[0] = 0; size = 1; + for (i = 1; i <= count; i++) { - sprintfW(index, fmt_index, i); - str = MSI_RecordGetString(record, i); - len = (str) ? lstrlenW(str) : 0; - len += (sizeof(fmt_null)/sizeof(fmt_null[0]) - 3) + lstrlenW(index); - size += len; - - if (len > max_len) - { - max_len = len; - buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR)); - if (!buf) - { - msi_free(rc); - return NULL; - } - } - - if (str) - sprintfW(buf, fmt, i, str); - else - sprintfW(buf, fmt_null, i); - - if (!rc) - { - rc = msi_alloc(size * sizeof(WCHAR)); - lstrcpyW(rc, buf); - } - else - { - rc = msi_realloc(rc, size * sizeof(WCHAR)); - lstrcatW(rc, buf); - } + sprintfW(buf, fmt, i, i); + size += lstrlenW(buf); + rc = msi_realloc(rc, size * sizeof(WCHAR)); + lstrcatW(rc, buf); } - msi_free(buf); return rc; } @@ -685,7 +651,7 @@ static WCHAR *replace_stack_prop( FORMAT *format, STACK *values, content->len = *oldsize - 2; content->type = *type; - if (*type == FORMAT_NUMBER) + if (*type == FORMAT_NUMBER && format->record) { replaced = deformat_index( format, content, len ); if (replaced) @@ -699,7 +665,7 @@ static WCHAR *replace_stack_prop( FORMAT *format, STACK *values, } else if (format->package) { - replaced = deformat_literal( format, content, propfound, nonprop, type, len ); + replaced = deformat_literal( format, content, propfound, type, len ); } else { @@ -791,7 +757,7 @@ static BOOL verify_format(LPWSTR data) static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data, DWORD *len, - MSIRECORD* record, INT* failcount) + MSIRECORD* record) { FORMAT format; FORMSTR *str = NULL; @@ -877,15 +843,34 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, WCHAR *format, *deformated; UINT rc = ERROR_INVALID_PARAMETER; DWORD len; + MSIRECORD *record_deformated; + int field_count, i; TRACE("%p %p %p %p\n", package, record, buffer, size); + dump_record(record); if (!(format = msi_dup_record_field( record, 0 ))) format = build_default_format( record ); - TRACE("%s\n", debugstr_w(format)); + field_count = MSI_RecordGetFieldCount(record); + record_deformated = MSI_CloneRecord(record); + if (!record_deformated) + { + rc = ERROR_OUTOFMEMORY; + goto end; + } + MSI_RecordSetStringW(record_deformated, 0, format); + for (i = 1; i <= field_count; i++) + { + if (MSI_RecordGetString(record, i)) + { + deformat_string_internal(package, MSI_RecordGetString(record, i), &deformated, &len, NULL); + MSI_RecordSetStringW(record_deformated, i, deformated); + msi_free(deformated); + } + } - deformat_string_internal( package, format, &deformated, &len, record, NULL ); + deformat_string_internal(package, format, &deformated, &len, record_deformated); if (buffer) { if (*size>len) @@ -907,6 +892,8 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, else rc = ERROR_SUCCESS; *size = len; + msiobj_release(&record_deformated->hdr); +end: msi_free( format ); msi_free( deformated ); return rc; diff --git a/dlls/msi/tests/format.c b/dlls/msi/tests/format.c index 6209399855f..b476c6b2906 100644 --- a/dlls/msi/tests/format.c +++ b/dlls/msi/tests/format.c @@ -494,6 +494,15 @@ static void test_formatrecord(void) ok( sz == 7, "size wrong\n"); ok( 0 == strcmp(buffer,"boo hoo"), "wrong output\n"); + /* self-referential format field */ + r = MsiRecordSetStringA(hrec, 0, "[1] test [0]"); + ok( r == ERROR_SUCCESS, "set string failed\n"); + sz = sizeof buffer; + r = MsiFormatRecordA(0, hrec, buffer, &sz); + ok( r == ERROR_SUCCESS, "format failed\n"); + ok( sz == 21, "size wrong\n"); + ok( 0 == strcmp(buffer,"boo test [1] test [0]"), "wrong output\n"); + /* empty string */ r = MsiRecordSetStringA(hrec, 0, ""); ok( r == ERROR_SUCCESS, "set string failed\n"); @@ -504,6 +513,18 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"1: boo 2: hoo 3: 4: 5: 6: "), "wrong output(%s)\n",buffer); + /* empty string with numbers */ + r = MsiRecordSetStringA(hrec, 1, "123"); + ok( r == ERROR_SUCCESS, "set string failed\n"); + r = MsiRecordSetInteger(hrec, 2, 4567); + ok( r == ERROR_SUCCESS, "set string failed\n"); + sz = sizeof buffer; + r = MsiFormatRecordA(0, hrec, buffer, &sz); + ok( r == ERROR_SUCCESS, "format failed\n"); + ok( sz == 31, "size wrong %i\n",sz); + ok( 0 == strcmp(buffer,"1: 123 2: 4567 3: 4: 5: 6: "), + "wrong output(%s)\n",buffer); + /* play games with recursive lookups */ r = MsiRecordSetStringA(hrec, 0, "[[1]] [2]"); ok( r == ERROR_SUCCESS, "set string failed\n"); @@ -2575,6 +2596,12 @@ static void test_formatrecord_tables(void) ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); ok( !lstrcmpA( buf, "1: ringer " ), "Expected '1: ringer ', got %s\n", buf ); + size = MAX_PATH; + MsiRecordSetStringA( hrec, 0, "1: [1] " ); + r = MsiFormatRecordA( hpkg, hrec, buf, &size ); + ok( r == ERROR_SUCCESS, "format record failed: %d\n", r); + ok( !lstrcmpA( buf, "1: ringer " ), "Expected '1: ringer ', got %s\n", buf ); + /* environment variable doesn't exist */ size = MAX_PATH; MsiRecordSetStringA( hrec, 1, "[%idontexist]" );