From 5a0d459cc4fe6315d63ab5f270772d2793c8e0a2 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Mon, 4 Feb 2008 15:59:21 -0600 Subject: [PATCH] msi: Reimplement MsiFormatRecord. --- dlls/msi/format.c | 1822 +++++++++++++++++++++++++++-------------------- dlls/msi/tests/format.c | 307 ++++---- 2 files changed, 1178 insertions(+), 951 deletions(-) rewrite dlls/msi/format.c (62%) diff --git a/dlls/msi/format.c b/dlls/msi/format.c dissimilarity index 62% index f56702d35f3..4a31f74dd31 100644 --- a/dlls/msi/format.c +++ b/dlls/msi/format.c @@ -1,787 +1,1035 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Mike McCormack for CodeWeavers - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* -http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiformatrecord.asp - */ - -#include -#include - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "winnls.h" -#include "objbase.h" -#include "oleauto.h" - -#include "msipriv.h" -#include "msiserver.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, - WCHAR** data, DWORD len, MSIRECORD* record, - BOOL* in_group); - - -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; - - count = MSI_RecordGetFieldCount(record); - - max_len = MAX_PATH; - buf = msi_alloc((max_len + 1) * sizeof(WCHAR)); - - rc = NULL; - 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) - 3) + lstrlenW(index); - size += len; - - if (len > max_len) - { - max_len = len; - buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR)); - if (!buf) 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); - } - } - msi_free(buf); - return rc; -} - -static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len) -{ - DWORD i; - for (i = 0; i < len; i++) - if (buf[i] == token) - return &buf[i]; - return NULL; -} - -/* break out helper functions for deformating */ -static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) -{ - LPWSTR value = NULL; - MSICOMPONENT *comp; - BOOL source; - - *sz = 0; - if (!package) - return NULL; - - comp = get_loaded_component(package,key); - if (comp) - { - source = (comp->Action == INSTALLSTATE_SOURCE) ? TRUE : FALSE; - value = resolve_folder(package, comp->Directory, source, FALSE, TRUE, NULL); - *sz = (strlenW(value)) * sizeof(WCHAR); - } - - return value; -} - -static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz, - BOOL shortname) -{ - LPWSTR value = NULL; - MSIFILE *file; - - *sz = 0; - - if (!package) - return NULL; - - file = get_loaded_file( package, key ); - if (file) - { - if (!shortname) - { - value = strdupW( file->TargetPath ); - *sz = (strlenW(value)) * sizeof(WCHAR); - } - else - { - DWORD size = 0; - size = GetShortPathNameW( file->TargetPath, NULL, 0 ); - - if (size > 0) - { - *sz = (size-1) * sizeof (WCHAR); - size ++; - value = msi_alloc(size * sizeof(WCHAR)); - GetShortPathNameW( file->TargetPath, value, size ); - } - else - { - value = strdupW( file->TargetPath ); - *sz = (lstrlenW(value)) * sizeof(WCHAR); - } - } - } - - return value; -} - -static LPWSTR deformat_environment(MSIPACKAGE* package, LPCWSTR key, - DWORD* chunk) -{ - LPWSTR value = NULL; - DWORD sz; - - sz = GetEnvironmentVariableW(key,NULL,0); - if (sz > 0) - { - sz++; - value = msi_alloc(sz * sizeof(WCHAR)); - GetEnvironmentVariableW(key,value,sz); - *chunk = (strlenW(value)) * sizeof(WCHAR); - } - else - { - WARN("Unknown environment variable %s\n", debugstr_w(key)); - *chunk = 0; - value = NULL; - } - return value; -} - - -static LPWSTR deformat_NULL(DWORD* chunk) -{ - LPWSTR value; - - value = msi_alloc(sizeof(WCHAR)*2); - value[0] = 0; - *chunk = sizeof(WCHAR); - return value; -} - -static LPWSTR deformat_escape(LPCWSTR key, DWORD* chunk) -{ - LPWSTR value; - - value = msi_alloc(sizeof(WCHAR)*2); - value[0] = key[0]; - *chunk = sizeof(WCHAR); - - return value; -} - - -static BOOL is_key_number(LPCWSTR key) -{ - INT index = 0; - if (key[0] == 0) - return FALSE; - - while (isdigitW(key[index])) index++; - if (key[index] == 0) - return TRUE; - else - return FALSE; -} - -static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk ) -{ - INT index; - LPWSTR value; - - index = atoiW(key); - TRACE("record index %i\n",index); - value = msi_dup_record_field(record,index); - if (value) - *chunk = strlenW(value) * sizeof(WCHAR); - else - { - value = NULL; - *chunk = 0; - } - return value; -} - -static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk) -{ - LPWSTR value; - - if (!package) - return NULL; - - value = msi_dup_property( package, key ); - - if (value) - *chunk = (strlenW(value)) * sizeof(WCHAR); - - return value; -} - -/* - * Groups cannot be nested. They are just treated as from { to next } - */ -static BOOL find_next_group(LPCWSTR source, DWORD len_remaining, - LPWSTR *group, LPCWSTR *mark, - LPCWSTR* mark2) -{ - int i; - BOOL found = FALSE; - - *mark = scanW(source,'{',len_remaining); - if (!*mark) - return FALSE; - - for (i = 1; (*mark - source) + i < len_remaining; i++) - { - if ((*mark)[i] == '}') - { - found = TRUE; - break; - } - } - if (! found) - return FALSE; - - *mark2 = &(*mark)[i]; - - i = *mark2 - *mark; - *group = msi_alloc(i*sizeof(WCHAR)); - - i -= 1; - memcpy(*group,&(*mark)[1],i*sizeof(WCHAR)); - (*group)[i] = 0; - - TRACE("Found group %s\n",debugstr_w(*group)); - return TRUE; -} - - -static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, - LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2, - BOOL *nested) -{ - INT count = 0; - INT total_count = 0; - int i; - - *nested = FALSE; - *mark = scanW(source,'[',len_remaining); - if (!*mark) - return FALSE; - - count = 1; - total_count = 1; - for (i = 1; (*mark - source) + i < len_remaining && count > 0; i++) - { - if ((*mark)[i] == '[' && (*mark)[i-1] != '\\') - { - count ++; - total_count ++; - *nested = TRUE; - } - else if ((*mark)[i] == ']' && (*mark)[i-1] != '\\') - { - count --; - } - } - - if (count > 0) - return FALSE; - - *mark2 = &(*mark)[i-1]; - - i = *mark2 - *mark; - *key = msi_alloc(i*sizeof(WCHAR)); - /* do not have the [] in the key */ - i -= 1; - memcpy(*key,&(*mark)[1],i*sizeof(WCHAR)); - (*key)[i] = 0; - - TRACE("Found Key %s\n",debugstr_w(*key)); - return TRUE; -} - -static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len, - MSIRECORD* record, DWORD* size) -{ - LPWSTR value = NULL; - LPCWSTR mark, mark2; - LPWSTR key; - BOOL nested; - INT failcount; - static const WCHAR fmt[] = {'{','%','s','}',0}; - UINT sz; - - if (!group || group[0] == 0) - { - *size = 0; - return NULL; - } - /* if no [] then group is returned as is */ - - if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested)) - { - *size = (len+2)*sizeof(WCHAR); - value = msi_alloc(*size); - sprintfW(value,fmt,group); - /* do not return size of the null at the end */ - *size = (len+1)*sizeof(WCHAR); - return value; - } - - msi_free(key); - failcount = 0; - sz = deformat_string_internal(package, group, &value, strlenW(group), - record, &failcount); - if (failcount==0) - { - *size = sz * sizeof(WCHAR); - return value; - } - else if (failcount < 0) - { - LPWSTR v2; - - v2 = msi_alloc((sz+2)*sizeof(WCHAR)); - v2[0] = '{'; - memcpy(&v2[1],value,sz*sizeof(WCHAR)); - v2[sz+1]='}'; - msi_free(value); - - *size = (sz+2)*sizeof(WCHAR); - return v2; - } - else - { - msi_free(value); - *size = 0; - return NULL; - } -} - - -/* - * len is in WCHARs - * return is also in WCHARs - */ -static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, - WCHAR** data, DWORD len, MSIRECORD* record, - INT* failcount) -{ - LPCWSTR mark = NULL; - LPCWSTR mark2 = NULL; - DWORD size=0; - DWORD chunk=0; - LPWSTR key; - LPWSTR value = NULL; - DWORD sz; - LPBYTE newdata = NULL; - const WCHAR* progress = NULL; - BOOL nested = FALSE; - - if (ptr==NULL) - { - TRACE("Deformatting NULL string\n"); - *data = NULL; - return 0; - } - - TRACE("Starting with %s\n",debugstr_wn(ptr,len)); - - /* scan for special characters... fast exit */ - if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) && - (scanW(ptr,'{',len) && !scanW(ptr,'}',len))) - { - /* not formatted */ - *data = msi_alloc((len*sizeof(WCHAR))); - memcpy(*data,ptr,len*sizeof(WCHAR)); - TRACE("Returning %s\n",debugstr_wn(*data,len)); - return len; - } - - progress = ptr; - - while (progress - ptr < len) - { - /* seek out first group if existing */ - if (find_next_group(progress, len - (progress - ptr), &key, - &mark, &mark2)) - { - value = deformat_group(package, key, strlenW(key)+1, record, - &chunk); - msi_free( key ); - key = NULL; - nested = FALSE; - } - /* formatted string located */ - else if (!find_next_outermost_key(progress, len - (progress - ptr), - &key, &mark, &mark2, &nested)) - { - LPBYTE nd2; - - TRACE("after value %s\n", debugstr_wn((LPWSTR)newdata, - size/sizeof(WCHAR))); - chunk = (len - (progress - ptr)) * sizeof(WCHAR); - TRACE("after chunk is %i + %i\n",size,chunk); - if (size) - nd2 = msi_realloc(newdata,(size+chunk)); - else - nd2 = msi_alloc(chunk); - - newdata = nd2; - memcpy(&newdata[size],progress,chunk); - size+=chunk; - break; - } - - if (mark != progress) - { - LPBYTE tgt; - DWORD old_size = size; - INT cnt = (mark - progress); - TRACE("%i (%i) characters before marker\n",cnt,(mark-progress)); - size += cnt * sizeof(WCHAR); - if (!old_size) - tgt = msi_alloc(size); - else - tgt = msi_realloc(newdata,size); - newdata = tgt; - memcpy(&newdata[old_size],progress,(cnt * sizeof(WCHAR))); - } - - progress = mark; - - if (nested) - { - TRACE("Nested key... %s\n",debugstr_w(key)); - deformat_string_internal(package, key, &value, strlenW(key)+1, - record, failcount); - - msi_free(key); - key = value; - } - - TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata, - size/sizeof(WCHAR)),debugstr_w(key)); - - if (!package) - { - /* only deformat number indexs */ - if (key && is_key_number(key)) - { - value = deformat_index(record,key,&chunk); - if (!chunk && failcount && *failcount >= 0) - (*failcount)++; - } - else - { - if (failcount) - *failcount = -1; - if(key) - { - DWORD keylen = strlenW(key); - chunk = (keylen + 2)*sizeof(WCHAR); - value = msi_alloc(chunk); - value[0] = '['; - memcpy(&value[1],key,keylen*sizeof(WCHAR)); - value[1+keylen] = ']'; - } - } - } - else - { - sz = 0; - if (key) switch (key[0]) - { - case '~': - value = deformat_NULL(&chunk); - break; - case '$': - value = deformat_component(package,&key[1],&chunk); - break; - case '#': - value = deformat_file(package,&key[1], &chunk, FALSE); - break; - case '!': /* should be short path */ - value = deformat_file(package,&key[1], &chunk, TRUE); - break; - case '\\': - value = deformat_escape(&key[1],&chunk); - break; - case '%': - value = deformat_environment(package,&key[1],&chunk); - break; - default: - /* index keys cannot be nested */ - if (is_key_number(key)) - if (!nested) - value = deformat_index(record,key,&chunk); - else - { - static const WCHAR fmt[] = {'[','%','s',']',0}; - value = msi_alloc(10); - sprintfW(value,fmt,key); - chunk = strlenW(value)*sizeof(WCHAR); - } - else - value = deformat_property(package,key,&chunk); - break; - } - } - - msi_free(key); - - if (value!=NULL) - { - LPBYTE nd2; - TRACE("value %s, chunk %i size %i\n",debugstr_w(value), - chunk, size); - if (size) - nd2= msi_realloc(newdata,(size + chunk)); - else - nd2= msi_alloc(chunk); - newdata = nd2; - memcpy(&newdata[size],value,chunk); - size+=chunk; - msi_free(value); - } - else if (failcount && *failcount >=0 ) - (*failcount)++; - - progress = mark2+1; - } - - TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata, - size/sizeof(WCHAR))); - - *data = (LPWSTR)newdata; - return size / sizeof(WCHAR); -} - - -UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, - LPDWORD size ) -{ - LPWSTR deformated; - LPWSTR rec; - DWORD len; - UINT rc = ERROR_INVALID_PARAMETER; - - TRACE("%p %p %p %i\n", package, record ,buffer, *size); - - rec = msi_dup_record_field(record,0); - if (!rec) - rec = build_default_format(record); - - TRACE("(%s)\n",debugstr_w(rec)); - - len = deformat_string_internal(package,rec,&deformated, - rec ? strlenW(rec) : 0, record, NULL); - - if (buffer) - { - if (*size>len) - { - memcpy(buffer,deformated,len*sizeof(WCHAR)); - rc = ERROR_SUCCESS; - buffer[len] = 0; - } - else - { - if (*size > 0) - { - memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); - buffer[(*size)-1] = 0; - } - rc = ERROR_MORE_DATA; - } - } - else - rc = ERROR_SUCCESS; - - *size = len; - - msi_free(rec); - msi_free(deformated); - return rc; -} - -UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, - LPWSTR szResult, LPDWORD sz ) -{ - UINT r = ERROR_INVALID_HANDLE; - MSIPACKAGE *package; - MSIRECORD *record; - - TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - { - HRESULT hr; - IWineMsiRemotePackage *remote_package; - BSTR value = NULL; - DWORD len; - awstring wstr; - - remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall ); - if (remote_package) - { - len = 0; - hr = IWineMsiRemotePackage_FormatRecord( remote_package, hRecord, - NULL, &len ); - if (FAILED(hr)) - goto done; - - len++; - value = SysAllocStringLen( NULL, len ); - if (!value) - { - r = ERROR_OUTOFMEMORY; - goto done; - } - - hr = IWineMsiRemotePackage_FormatRecord( remote_package, hRecord, - value, &len ); - if (FAILED(hr)) - goto done; - - wstr.unicode = TRUE; - wstr.str.w = szResult; - r = msi_strcpy_to_awstring( value, &wstr, sz ); - -done: - IWineMsiRemotePackage_Release( remote_package ); - SysFreeString( value ); - - if (FAILED(hr)) - { - if (HRESULT_FACILITY(hr) == FACILITY_WIN32) - return HRESULT_CODE(hr); - - return ERROR_FUNCTION_FAILED; - } - - return r; - } - } - - record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - - if (!record) - return ERROR_INVALID_HANDLE; - if (!sz) - { - msiobj_release( &record->hdr ); - if (szResult) - return ERROR_INVALID_PARAMETER; - else - return ERROR_SUCCESS; - } - - r = MSI_FormatRecordW( package, record, szResult, sz ); - msiobj_release( &record->hdr ); - if (package) - msiobj_release( &package->hdr ); - return r; -} - -UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, - LPSTR szResult, LPDWORD sz ) -{ - UINT r; - DWORD len, save; - LPWSTR value; - - TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); - - if (!hRecord) - return ERROR_INVALID_HANDLE; - - if (!sz) - { - if (szResult) - return ERROR_INVALID_PARAMETER; - else - return ERROR_SUCCESS; - } - - r = MsiFormatRecordW( hInstall, hRecord, NULL, &len ); - if (r != ERROR_SUCCESS) - return r; - - value = msi_alloc(++len * sizeof(WCHAR)); - if (!value) - return ERROR_OUTOFMEMORY; - - r = MsiFormatRecordW( hInstall, hRecord, value, &len ); - if (r != ERROR_SUCCESS) - goto done; - - save = len + 1; - len = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, value, -1, szResult, *sz, NULL, NULL); - - if (szResult && len > *sz) - { - if (*sz) szResult[*sz - 1] = '\0'; - r = ERROR_MORE_DATA; - } - - *sz = save - 1; - -done: - msi_free(value); - return r; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Mike McCormack for CodeWeavers + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "winnls.h" +#include "objbase.h" +#include "oleauto.h" + +#include "msipriv.h" +#include "msiserver.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* types arranged by precedence */ +#define FORMAT_NULL 0x0001 +#define FORMAT_LITERAL 0x0002 +#define FORMAT_NUMBER 0x0004 +#define FORMAT_LBRACK 0x0010 +#define FORMAT_LBRACE 0x0020 +#define FORMAT_RBRACK 0x0011 +#define FORMAT_RBRACE 0x0021 +#define FORMAT_ESCAPE 0x0040 +#define FORMAT_PROPNULL 0x0080 +#define FORMAT_ERROR 0x1000 +#define FORMAT_FAIL 0x2000 + +#define left_type(x) (x & 0xF0) + +typedef struct _tagFORMAT +{ + MSIPACKAGE *package; + MSIRECORD *record; + LPWSTR deformatted; + int len; + int n; + BOOL propfailed; + BOOL groupfailed; + int groups; +} FORMAT; + +typedef struct _tagFORMSTR +{ + struct list entry; + int n; + int len; + int type; + BOOL propfound; + BOOL nonprop; +} FORMSTR; + +typedef struct _tagSTACK +{ + struct list items; +} STACK; + +static STACK *create_stack(void) +{ + STACK *stack = msi_alloc(sizeof(STACK)); + list_init(&stack->items); + return stack; +} + +static void free_stack(STACK *stack) +{ + while (!list_empty(&stack->items)) + { + FORMSTR *str = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); + list_remove(&str->entry); + msi_free(str); + } + + msi_free(stack); +} + +static void stack_push(STACK *stack, FORMSTR *str) +{ + list_add_head(&stack->items, &str->entry); +} + +static FORMSTR *stack_pop(STACK *stack) +{ + FORMSTR *ret; + + if (list_empty(&stack->items)) + return NULL; + + ret = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); + list_remove(&ret->entry); + return ret; +} + +static FORMSTR *stack_find(STACK *stack, int type) +{ + FORMSTR *str; + + LIST_FOR_EACH_ENTRY(str, &stack->items, FORMSTR, entry) + { + if (str->type == type) + return str; + } + + return NULL; +} + +static FORMSTR *stack_peek(STACK *stack) +{ + return LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); +} + +static LPCWSTR get_formstr_data(FORMAT *format, FORMSTR *str) +{ + return &format->deformatted[str->n]; +} + +static LPWSTR dup_formstr(FORMAT *format, FORMSTR *str) +{ + LPWSTR val; + LPCWSTR data; + + if (str->len == 0) + return NULL; + + val = msi_alloc((str->len + 1) * sizeof(WCHAR)); + data = get_formstr_data(format, str); + lstrcpynW(val, data, str->len + 1); + + return val; +} + +static LPWSTR deformat_index(FORMAT *format, FORMSTR *str) +{ + LPWSTR val, ret; + + val = msi_alloc((str->len + 1) * sizeof(WCHAR)); + lstrcpynW(val, get_formstr_data(format, str), str->len + 1); + + ret = msi_dup_record_field(format->record, atoiW(val)); + + msi_free(val); + return ret; +} + +static LPWSTR deformat_property(FORMAT *format, FORMSTR *str) +{ + LPWSTR val, ret; + + val = msi_alloc((str->len + 1) * sizeof(WCHAR)); + lstrcpynW(val, get_formstr_data(format, str), str->len + 1); + + ret = msi_dup_property(format->package, val); + + msi_free(val); + return ret; +} + +static LPWSTR deformat_component(FORMAT *format, FORMSTR *str) +{ + LPWSTR key, ret = NULL; + MSICOMPONENT *comp; + BOOL source; + + key = msi_alloc((str->len + 1) * sizeof(WCHAR)); + lstrcpynW(key, get_formstr_data(format, str), str->len + 1); + + comp = get_loaded_component(format->package, key); + if (!comp) + goto done; + + source = (comp->Action == INSTALLSTATE_SOURCE) ? TRUE : FALSE; + ret = resolve_folder(format->package, comp->Directory, source, FALSE, TRUE, NULL); + +done: + msi_free(key); + return ret; +} + +static LPWSTR deformat_file(FORMAT *format, FORMSTR *str, BOOL shortname) +{ + LPWSTR key, ret = NULL; + MSIFILE *file; + DWORD size; + + key = msi_alloc((str->len + 1) * sizeof(WCHAR)); + lstrcpynW(key, get_formstr_data(format, str), str->len + 1); + + file = get_loaded_file(format->package, key); + if (!file) + goto done; + + if (!shortname) + { + ret = strdupW(file->TargetPath); + goto done; + } + + size = GetShortPathNameW(file->TargetPath, NULL, 0); + if (size <= 0) + { + ret = strdupW(file->TargetPath); + goto done; + } + + size++; + ret = msi_alloc(size * sizeof(WCHAR)); + GetShortPathNameW(file->TargetPath, ret, size); + +done: + msi_free(key); + return ret; +} + +static LPWSTR deformat_environment(FORMAT *format, FORMSTR *str) +{ + LPWSTR key, ret = NULL; + DWORD sz; + + key = msi_alloc((str->len + 1) * sizeof(WCHAR)); + lstrcpynW(key, get_formstr_data(format, str), str->len + 1); + + sz = GetEnvironmentVariableW(key, NULL ,0); + if (sz <= 0) + goto done; + + sz++; + ret = msi_alloc(sz * sizeof(WCHAR)); + GetEnvironmentVariableW(key, ret, sz); + +done: + msi_free(key); + return ret; +} + +static LPWSTR deformat_literal(FORMAT *format, FORMSTR *str, BOOL *propfound, + BOOL *nonprop, int *type) +{ + LPCWSTR data = get_formstr_data(format, str); + LPWSTR replaced = NULL; + char ch = data[0]; + + if (ch == '\\') + { + str->n++; + if (str->len == 1) + { + str->len = 0; + replaced = NULL; + } + else + { + str->len = 1; + replaced = dup_formstr(format, str); + } + } + else if (ch == '~') + { + if (str->len != 1) + replaced = NULL; + else + { + replaced = msi_alloc(sizeof(WCHAR)); + *replaced = '\0'; + } + } + else if (ch == '%' || ch == '#' || ch == '!' || ch == '$') + { + str->n++; + str->len--; + + switch (ch) + { + case '%': + replaced = deformat_environment(format, str); break; + case '#': + replaced = deformat_file(format, str, FALSE); break; + case '!': + replaced = deformat_file(format, str, TRUE); break; + case '$': + replaced = deformat_component(format, str); break; + } + + *type = FORMAT_LITERAL; + } + else + { + replaced = deformat_property(format, str); + *type = FORMAT_LITERAL; + + if (replaced) + *propfound = TRUE; + else + format->propfailed = TRUE; + } + + return replaced; +} + +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; + + count = MSI_RecordGetFieldCount(record); + + max_len = MAX_PATH; + buf = msi_alloc((max_len + 1) * sizeof(WCHAR)); + + rc = NULL; + 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) - 3) + lstrlenW(index); + size += len; + + if (len > max_len) + { + max_len = len; + buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR)); + if (!buf) 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); + } + } + + msi_free(buf); + return rc; +} + +static BOOL format_is_number(WCHAR x) +{ + return ((x >= '0') && (x <= '9')); +} + +static BOOL format_str_is_number(LPWSTR str) +{ + LPWSTR ptr; + + for (ptr = str; *ptr; ptr++) + if (!format_is_number(*ptr)) + return FALSE; + + return TRUE; +} + +static BOOL format_is_alpha(x) +{ + return (!format_is_number(x) && x != '\0' && + x != '[' && x != ']' && x != '{' && x != '}'); +} + +static BOOL format_is_literal(x) +{ + return (format_is_alpha(x) || format_is_number(x)); +} + +static int format_lex(FORMAT *format, FORMSTR **out) +{ + int type, len = 1; + FORMSTR *str; + LPCWSTR data; + WCHAR ch; + + *out = NULL; + + if (!format->deformatted) + return FORMAT_NULL; + + *out = msi_alloc_zero(sizeof(FORMSTR)); + if (!*out) + return FORMAT_FAIL; + + str = *out; + str->n = format->n; + str->len = 1; + data = get_formstr_data(format, str); + + ch = data[0]; + switch (ch) + { + case '{': type = FORMAT_LBRACE; break; + case '}': type = FORMAT_RBRACE; break; + case '[': type = FORMAT_LBRACK; break; + case ']': type = FORMAT_RBRACK; break; + case '~': type = FORMAT_PROPNULL; break; + case '\0': type = FORMAT_NULL; break; + + default: + type = 0; + } + + if (type) + { + str->type = type; + format->n++; + return type; + } + + if (ch == '\\') + { + while (data[len] && data[len] != ']') + len++; + + type = FORMAT_ESCAPE; + } + else if (format_is_alpha(ch)) + { + while (format_is_literal(data[len])) + len++; + + type = FORMAT_LITERAL; + } + else if (format_is_number(ch)) + { + while (format_is_number(data[len])) + len++; + + type = FORMAT_NUMBER; + + if (data[len] != ']') + { + while (format_is_literal(data[len])) + len++; + + type = FORMAT_LITERAL; + } + } + else + { + ERR("Got unknown character %c(%x)\n", ch, ch); + return FORMAT_ERROR; + } + + format->n += len; + str->len = len; + str->type = type; + + return type; +} + +static FORMSTR *format_replace(FORMAT *format, BOOL propfound, BOOL nonprop, + int oldsize, int type, LPWSTR replace) +{ + FORMSTR *ret; + LPWSTR str, ptr; + DWORD size = 0; + int n; + + if (replace) + { + if (!*replace) + size = 1; + else + size = lstrlenW(replace); + } + + size -= oldsize; + size = format->len + size + 1; + + if (size <= 1) + { + msi_free(format->deformatted); + format->deformatted = NULL; + format->len = 0; + return NULL; + } + + str = msi_alloc(size * sizeof(WCHAR)); + if (!str) + return NULL; + + str[0] = '\0'; + memcpy(str, format->deformatted, format->n * sizeof(WCHAR)); + n = format->n; + + if (replace) + { + if (!*replace) + { + str[n] = '\0'; + n++; + } + else + { + lstrcpyW(&str[n], replace); + n += lstrlenW(replace); + } + } + + ptr = &format->deformatted[format->n + oldsize]; + memcpy(&str[n], ptr, (lstrlenW(ptr) + 1) * sizeof(WCHAR)); + + msi_free(format->deformatted); + format->deformatted = str; + format->len = size - 1; + + if (!replace) + return NULL; + + ret = msi_alloc_zero(sizeof(FORMSTR)); + if (!ret) + return NULL; + + ret->len = lstrlenW(replace); + ret->type = type; + ret->n = format->n; + ret->propfound = propfound; + ret->nonprop = nonprop; + + return ret; +} + +static LPWSTR replace_stack_group(FORMAT *format, STACK *values, + BOOL *propfound, BOOL *nonprop, + int *oldsize, int *type) +{ + LPWSTR replaced = NULL; + FORMSTR *content; + FORMSTR *node; + int n; + + *nonprop = FALSE; + *propfound = FALSE; + + node = stack_pop(values); + n = node->n; + *oldsize = node->len; + msi_free(node); + + while ((node = stack_pop(values))) + { + *oldsize += node->len; + + if (node->nonprop) + *nonprop = TRUE; + + if (node->propfound) + *propfound = TRUE; + + msi_free(node); + } + + content = msi_alloc_zero(sizeof(FORMSTR)); + content->n = n; + content->len = *oldsize; + content->type = FORMAT_LITERAL; + + if (!format->groupfailed && (*oldsize == 2 || + (format->propfailed && !*nonprop))) + { + msi_free(content); + return NULL; + } + else if (format->deformatted[content->n + 1] == '{' && + format->deformatted[content->n + content->len - 2] == '}') + { + format->groupfailed = FALSE; + content->len = 0; + } + else if (*propfound && !*nonprop && + !format->groupfailed && format->groups == 0) + { + content->n++; + content->len -= 2; + } + else + { + if (format->groups != 0) + format->groupfailed = TRUE; + + *nonprop = TRUE; + } + + replaced = dup_formstr(format, content); + *type = content->type; + msi_free(content); + + if (format->groups == 0) + format->propfailed = FALSE; + + return replaced; +} + +static LPWSTR replace_stack_prop(FORMAT *format, STACK *values, + BOOL *propfound, BOOL *nonprop, + int *oldsize, int *type) +{ + LPWSTR replaced = NULL; + FORMSTR *content; + FORMSTR *node; + int n; + + *propfound = FALSE; + *nonprop = FALSE; + + node = stack_pop(values); + n = node->n; + *oldsize = node->len; + *type = stack_peek(values)->type; + msi_free(node); + + while ((node = stack_pop(values))) + { + *oldsize += node->len; + + if (*type != FORMAT_ESCAPE && + stack_peek(values) && node->type != *type) + *type = FORMAT_LITERAL; + + msi_free(node); + } + + content = msi_alloc_zero(sizeof(FORMSTR)); + content->n = n + 1; + content->len = *oldsize - 2; + content->type = *type; + + if (*type == FORMAT_NUMBER) + { + replaced = deformat_index(format, content); + if (replaced) + *propfound = TRUE; + else + format->propfailed = TRUE; + + if (replaced) + *type = format_str_is_number(replaced) ? + FORMAT_NUMBER : FORMAT_LITERAL; + } + else if (format->package) + { + replaced = deformat_literal(format, content, propfound, nonprop, type); + } + else + { + *nonprop = TRUE; + content->n--; + content->len += 2; + replaced = dup_formstr(format, content); + } + + msi_free(content); + return replaced; +} + +static UINT replace_stack(FORMAT *format, STACK *stack, STACK *values) +{ + LPWSTR replaced = NULL; + FORMSTR *beg; + FORMSTR *top; + FORMSTR *node; + BOOL propfound = FALSE; + BOOL nonprop = FALSE; + BOOL group = FALSE; + int oldsize = 0; + int type, n; + + node = stack_peek(values); + type = node->type; + n = node->n; + + if (type == FORMAT_LBRACK) + replaced = replace_stack_prop(format, values, &propfound, + &nonprop, &oldsize, &type); + else if (type == FORMAT_LBRACE) + { + replaced = replace_stack_group(format, values, &propfound, + &nonprop, &oldsize, &type); + group = TRUE; + } + + format->n = n; + beg = format_replace(format, propfound, nonprop, oldsize, type, replaced); + if (!beg) + return ERROR_SUCCESS; + + msi_free(replaced); + format->n = beg->n + beg->len; + + if (type == FORMAT_PROPNULL) + format->n++; + + top = stack_peek(stack); + if (top) + { + type = top->type; + + if ((type == FORMAT_LITERAL || type == FORMAT_NUMBER) && + type == beg->type) + { + top->len += beg->len; + + if (group) + top->nonprop = FALSE; + + if (type == FORMAT_LITERAL) + top->nonprop = beg->nonprop; + + if (beg->propfound) + top->propfound = TRUE; + + msi_free(beg); + return ERROR_SUCCESS; + } + } + + stack_push(stack, beg); + return ERROR_SUCCESS; +} + +static BOOL verify_format(LPWSTR data) +{ + int count = 0; + + while (*data) + { + if (*data == '[' && *(data - 1) != '\\') + count++; + else if (*data == ']') + count--; + + data++; + } + + if (count > 0) + return FALSE; + + return TRUE; +} + +static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, + WCHAR** data, DWORD *len, + MSIRECORD* record, INT* failcount) +{ + FORMAT format; + FORMSTR *str = NULL; + STACK *stack, *temp; + FORMSTR *node; + int type; + + if (!ptr) + { + *data = NULL; + *len = 0; + return ERROR_SUCCESS; + } + + *data = strdupW(ptr); + *len = lstrlenW(ptr); + + ZeroMemory(&format, sizeof(FORMAT)); + format.package = package; + format.record = record; + format.deformatted = *data; + format.len = *len; + + stack = create_stack(); + temp = create_stack(); + + if (!verify_format(*data)) + return ERROR_SUCCESS; + + while ((type = format_lex(&format, &str)) != FORMAT_NULL) + { + if (type == FORMAT_LBRACK || type == FORMAT_LBRACE || + type == FORMAT_LITERAL || type == FORMAT_NUMBER || + type == FORMAT_ESCAPE || type == FORMAT_PROPNULL) + { + if (type == FORMAT_LBRACE) + { + format.propfailed = FALSE; + format.groups++; + } + else if (type == FORMAT_ESCAPE && + !stack_find(stack, FORMAT_LBRACK)) + { + format.n -= str->len - 1; + str->len = 1; + } + + stack_push(stack, str); + } + else if (type == FORMAT_RBRACK || type == FORMAT_RBRACE) + { + if (type == FORMAT_RBRACE) + format.groups--; + + stack_push(stack, str); + + if (stack_find(stack, left_type(type))) + { + do + { + node = stack_pop(stack); + stack_push(temp, node); + } while (node->type != left_type(type)); + + replace_stack(&format, stack, temp); + } + } + } + + *data = format.deformatted; + *len = format.len; + + msi_free(str); + free_stack(stack); + free_stack(temp); + + return ERROR_SUCCESS; +} + +UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, + LPDWORD size ) +{ + LPWSTR deformated; + LPWSTR rec; + DWORD len; + UINT rc = ERROR_INVALID_PARAMETER; + + TRACE("%p %p %p %i\n", package, record ,buffer, *size); + + rec = msi_dup_record_field(record,0); + if (!rec) + rec = build_default_format(record); + + TRACE("(%s)\n",debugstr_w(rec)); + + deformat_string_internal(package, rec, &deformated, &len, record, NULL); + if (buffer) + { + if (*size>len) + { + memcpy(buffer,deformated,len*sizeof(WCHAR)); + rc = ERROR_SUCCESS; + buffer[len] = 0; + } + else + { + if (*size > 0) + { + memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); + buffer[(*size)-1] = 0; + } + rc = ERROR_MORE_DATA; + } + } + else + rc = ERROR_SUCCESS; + + *size = len; + + msi_free(rec); + msi_free(deformated); + return rc; +} + +UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, + LPWSTR szResult, LPDWORD sz ) +{ + UINT r = ERROR_INVALID_HANDLE; + MSIPACKAGE *package; + MSIRECORD *record; + + TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); + if (!package) + { + HRESULT hr; + IWineMsiRemotePackage *remote_package; + BSTR value = NULL; + DWORD len; + awstring wstr; + + remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall ); + if (remote_package) + { + len = 0; + hr = IWineMsiRemotePackage_FormatRecord( remote_package, hRecord, + NULL, &len ); + if (FAILED(hr)) + goto done; + + len++; + value = SysAllocStringLen( NULL, len ); + if (!value) + { + r = ERROR_OUTOFMEMORY; + goto done; + } + + hr = IWineMsiRemotePackage_FormatRecord( remote_package, hRecord, + value, &len ); + if (FAILED(hr)) + goto done; + + wstr.unicode = TRUE; + wstr.str.w = szResult; + r = msi_strcpy_to_awstring( value, &wstr, sz ); + +done: + IWineMsiRemotePackage_Release( remote_package ); + SysFreeString( value ); + + if (FAILED(hr)) + { + if (HRESULT_FACILITY(hr) == FACILITY_WIN32) + return HRESULT_CODE(hr); + + return ERROR_FUNCTION_FAILED; + } + + return r; + } + } + + record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + + if (!record) + return ERROR_INVALID_HANDLE; + if (!sz) + { + msiobj_release( &record->hdr ); + if (szResult) + return ERROR_INVALID_PARAMETER; + else + return ERROR_SUCCESS; + } + + r = MSI_FormatRecordW( package, record, szResult, sz ); + msiobj_release( &record->hdr ); + if (package) + msiobj_release( &package->hdr ); + return r; +} + +UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, + LPSTR szResult, LPDWORD sz ) +{ + UINT r; + DWORD len, save; + LPWSTR value; + + TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); + + if (!hRecord) + return ERROR_INVALID_HANDLE; + + if (!sz) + { + if (szResult) + return ERROR_INVALID_PARAMETER; + else + return ERROR_SUCCESS; + } + + r = MsiFormatRecordW( hInstall, hRecord, NULL, &len ); + if (r != ERROR_SUCCESS) + return r; + + value = msi_alloc(++len * sizeof(WCHAR)); + if (!value) + return ERROR_OUTOFMEMORY; + + r = MsiFormatRecordW( hInstall, hRecord, value, &len ); + if (r != ERROR_SUCCESS) + goto done; + + save = len + 1; + len = WideCharToMultiByte(CP_ACP, 0, value, len + 1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, value, len, szResult, *sz, NULL, NULL); + + if (szResult && len > *sz) + { + if (*sz) szResult[*sz - 1] = '\0'; + r = ERROR_MORE_DATA; + } + + *sz = save - 1; + +done: + msi_free(value); + return r; +} diff --git a/dlls/msi/tests/format.c b/dlls/msi/tests/format.c index be3a0255fd8..aec347dad73 100644 --- a/dlls/msi/tests/format.c +++ b/dlls/msi/tests/format.c @@ -517,7 +517,6 @@ static void test_formatrecord(void) ok( sz == 7, "size wrong\n"); ok( 0 == strcmp(buffer,"boo hoo"), "wrong output\n"); - /* empty string */ r = MsiRecordSetString(hrec, 0, ""); sz = sizeof buffer; @@ -734,11 +733,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - - todo_wine{ ok( sz == 16, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"{{2hey}1[dummy]}"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{{[1][2]}[3]{[4][dummy]}}"); r = MsiRecordSetString(hrec, 1, "2"); @@ -750,10 +746,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 0, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{{[1][2]}[3]} {[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -765,10 +759,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 12, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"{{12}3} {12}"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{[1][2]} {{[1][2]}[3]} {[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -780,10 +772,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 15, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"12 {{12}3} {12}"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{[4]}{[1][2]} {{[1][2]}[3]} {[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -795,11 +785,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 15, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"12 {{12}3} {12}"), "wrong output (%s)\n",buffer); - } - r = MsiRecordSetString(hrec, 0, "{blah} {[4]}{[1][2]} {{[1][2]}[3]} {[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -811,10 +798,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 22, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"{blah} 12 {{12}3} {12}"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{{[1]}[2]} {[4]}{[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -826,10 +811,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 13, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer,"{{1}2} {}{12}"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{{[1]}} {[4]}{[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -841,10 +824,8 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine{ ok( sz == 3, "size wrong,(%i)\n",sz); ok( 0 == strcmp(buffer," 12"), "wrong output (%s)\n",buffer); - } r = MsiRecordSetString(hrec, 0, "{{{[1]}} {[4]}{[1][2]}"); r = MsiRecordSetString(hrec, 1, "1"); @@ -1015,61 +996,54 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"boo hoo"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{[1]}}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{ {[1]}}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( 0 == strcmp(buffer," {hoo}"), "wrong output\n"); - ok( sz == 6, "size wrong\n"); + todo_wine + { + ok( 0 == strcmp(buffer," {hoo}"), "wrong output\n"); + ok( sz == 6, "size wrong\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{[1]} }"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 8, "size wrong\n"); ok( 0 == strcmp(buffer,"{{hoo} }"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{ [1]}}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{[1] }}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{a}{b}{c }{ d}{any text}}"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{{a} }"); @@ -1079,13 +1053,11 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"{{a} }"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{a} {b}}"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); todo_wine { @@ -1097,13 +1069,11 @@ static void test_formatrecord(void) } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{a b}}"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 0, "size wrong\n"); ok( 0 == strcmp(buffer,""), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{ }"); @@ -1113,13 +1083,11 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"{ }"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, " {{a}}}"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 2, "size wrong\n"); ok( 0 == strcmp(buffer," }"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); todo_wine { @@ -1174,6 +1142,14 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"[\\[]"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); + MsiRecordSetString(hrec, 0, "[\\[]"); + MsiRecordSetString(hrec, 1, "hoo"); + sz = sizeof(buffer); + r = MsiFormatRecord(0, hrec, buffer, &sz); + ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); + ok(sz == 4, "Expected 4, got %d\n", sz); + ok(!lstrcmpA(buffer, "[\\[]"), "Expected \"[\\[]\", got \"%s\"\n", buffer); + r = MsiRecordSetString(hrec, 0, "[foo]"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; @@ -1198,44 +1174,36 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"[%FOO]"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 6, "size wrong\n"); ok( 0 == strcmp(buffer,"{{hoo}"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{ {[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 8, "size wrong\n"); ok( 0 == strcmp(buffer,"{{ {hoo}"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{ {[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 8, "size wrong\n"); ok( 0 == strcmp(buffer,"{{ {hoo}"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{ {{[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 9, "size wrong\n"); ok( 0 == strcmp(buffer,"{{ {{hoo}"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "[1]}"); @@ -1264,24 +1232,33 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 19, "size wrong\n"); - ok( 0 == strcmp(buffer,"01{2{3{4hoo56}7}8}9"), "wrong output\n"); + todo_wine + { + ok( sz == 19, "size wrong\n"); + ok( 0 == strcmp(buffer,"01{2{3{4hoo56}7}8}9"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "0{1{2[1]3}4"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 9, "size wrong\n"); - ok( 0 == strcmp(buffer,"01{2hoo34"), "wrong output\n"); + todo_wine + { + ok( sz == 9, "size wrong\n"); + ok( 0 == strcmp(buffer,"01{2hoo34"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "0{1{2[1]3}4"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 9, "size wrong\n"); - ok( 0 == strcmp(buffer,"01{2hoo34"), "wrong output\n"); + todo_wine + { + ok( sz == 9, "size wrong\n"); + ok( 0 == strcmp(buffer,"01{2hoo34"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[1.} [1]"); @@ -1289,7 +1266,10 @@ static void test_formatrecord(void) sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 9, "size wrong\n"); - ok( 0 == strcmp(buffer,"{[1.} hoo"), "wrong output\n"); + todo_wine + { + ok( 0 == strcmp(buffer,"{[1.} hoo"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[{[1]}]}"); @@ -1297,8 +1277,11 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 2, "foo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 9, "size wrong\n"); - ok( 0 == strcmp(buffer,"{[{[1]}]}"), "wrong output\n"); + todo_wine + { + ok( sz == 9, "size wrong\n"); + ok( 0 == strcmp(buffer,"{[{[1]}]}"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[1][}"); @@ -1306,8 +1289,11 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 2, "foo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 2, "size wrong\n"); - ok( 0 == strcmp(buffer,"2["), "wrong output\n"); + todo_wine + { + ok( sz == 2, "size wrong\n"); + ok( 0 == strcmp(buffer,"2["), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "[1]"); @@ -1319,17 +1305,17 @@ static void test_formatrecord(void) ok( 0 == strcmp(buffer,"[2]"), "wrong output\n"); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "[{{boo}}1]"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); + ok( r == ERROR_SUCCESS, "format failed\n"); ok( sz == 3, "size wrong\n"); - ok( 0 == strcmp(buffer,"[1]"), "wrong output\n"); + todo_wine + { + ok( 0 == strcmp(buffer,"[1]"), "wrong output: %s\n", buffer); } - ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "[{{boo}}1]"); r = MsiRecordSetString(hrec, 0, "[1{{boo}}]"); r = MsiRecordSetString(hrec, 1, "hoo"); @@ -1337,33 +1323,36 @@ static void test_formatrecord(void) r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 3, "size wrong\n"); ok( 0 == strcmp(buffer,"[1]"), "wrong output\n"); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[1]{{boo} }}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 11, "size wrong\n"); - ok( 0 == strcmp(buffer,"hoo{{boo }}"), "wrong output\n"); + todo_wine + { + ok( sz == 11, "size wrong\n"); + ok( 0 == strcmp(buffer,"hoo{{boo }}"), "wrong output\n"); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[1{{boo}}]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 12, "size wrong: got %u, expected 12\n", sz); - ok( 0 == strcmp(buffer,"{[1{{boo}}]}"), "wrong output: got %s, expected [1]\n", buffer); + todo_wine + { + ok( sz == 12, "size wrong: got %u, expected 12\n", sz); + ok( 0 == strcmp(buffer,"{[1{{boo}}]}"), "wrong output: got %s, expected [1]\n", buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine { r = MsiRecordSetString(hrec, 0, "{{[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); ok( sz == 6, "size wrong: got %u, expected 3\n", sz); ok( 0 == strcmp(buffer,"{{hoo}"), "wrong output: got %s, expected [1]\n", buffer); - } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{[1{{bo}o}}]}"); @@ -1377,16 +1366,22 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 0, "{[1{{b{o}o}}]}"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 14, "size wrong\n"); - ok( 0 == strcmp(buffer,"{[1{{b{o}o}}]}"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 14, "size wrong\n"); + ok( 0 == strcmp(buffer,"{[1{{b{o}o}}]}"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "{ {[1]}"); r = MsiRecordSetString(hrec, 1, "hoo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 5, "size wrong\n"); - ok( 0 == strcmp(buffer," {hoo"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 5, "size wrong\n"); + ok( 0 == strcmp(buffer," {hoo"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); /* {} inside a substitution does strange things... */ @@ -1394,24 +1389,33 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 1, "2"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 5, "size wrong\n"); - ok( 0 == strcmp(buffer,"[[1]]"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 5, "size wrong\n"); + ok( 0 == strcmp(buffer,"[[1]]"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "[[1]{}[1]]"); r = MsiRecordSetString(hrec, 1, "2"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 6, "size wrong\n"); - ok( 0 == strcmp(buffer,"[[1]2]"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 6, "size wrong\n"); + ok( 0 == strcmp(buffer,"[[1]2]"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "[a[1]b[1]c{}d[1]e]"); r = MsiRecordSetString(hrec, 1, "2"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 14, "size wrong\n"); - ok( 0 == strcmp(buffer,"[a[1]b[1]cd2e]"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 14, "size wrong\n"); + ok( 0 == strcmp(buffer,"[a[1]b[1]cd2e]"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); r = MsiRecordSetString(hrec, 0, "[a[1]b"); @@ -1489,8 +1493,11 @@ static void test_formatrecord(void) r = MsiRecordSetString(hrec, 1, "foo"); sz = sizeof buffer; r = MsiFormatRecord(0, hrec, buffer, &sz); - ok( sz == 12, "size wrong\n"); - ok( 0 == strcmp(buffer,"{foo[-1]foo}"), "wrong output %s\n",buffer); + todo_wine + { + ok( sz == 12, "size wrong\n"); + ok( 0 == strcmp(buffer,"{foo[-1]foo}"), "wrong output %s\n",buffer); + } ok( r == ERROR_SUCCESS, "format failed\n"); /* nested braces */ @@ -1540,31 +1547,22 @@ static void test_formatrecord(void) MsiRecordSetString(hrec, 0, "{abc}{{def}hi{j[one]k}}"); r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 5, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"{abc}"), "wrong output (%s)\n",buffer); - } + ok( sz == 5, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"{abc}"), "wrong output (%s)\n",buffer); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{{def}hi{j[one]k}}"); r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 0, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } + ok( sz == 0, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{{def}hi{jk}}"); r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 0, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } + ok( sz == 0, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{{{def}}hi{jk}}"); @@ -1590,21 +1588,15 @@ static void test_formatrecord(void) MsiRecordSetString(hrec, 0, "{{def}{jk}}"); r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 0, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } + ok( sz == 0, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{{def}}"); r = MsiFormatRecord(0, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 0, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } + ok( sz == 0, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{a{b}c}"); @@ -1652,11 +1644,8 @@ static void test_formatrecord(void) r = MsiFormatRecord(0, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 33, "Expected 33, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one {[noprop] [twoprop]} {abcdef}"), - "Expected \"one {[noprop] [twoprop]} {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one {[noprop] [twoprop]} {abcdef}"), + "Expected \"one {[noprop] [twoprop]} {abcdef}\", got \"%s\"\n", buffer); sz = sizeof(buffer); MsiRecordSetString(hrec, 0, "[1] {[noprop] [one]} {abcdef}"); @@ -1664,11 +1653,8 @@ static void test_formatrecord(void) r = MsiFormatRecord(0, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 29, "Expected 29, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one {[noprop] [one]} {abcdef}"), - "Expected \"one {[noprop] [one]} {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one {[noprop] [one]} {abcdef}"), + "Expected \"one {[noprop] [one]} {abcdef}\", got \"%s\"\n", buffer); sz = sizeof(buffer); MsiRecordSetString(hrec, 0, "[1] {[one]} {abcdef}"); @@ -1676,11 +1662,8 @@ static void test_formatrecord(void) r = MsiFormatRecord(0, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 20, "Expected 20, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one {[one]} {abcdef}"), - "Expected \"one {[one]} {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one {[one]} {abcdef}"), + "Expected \"one {[one]} {abcdef}\", got \"%s\"\n", buffer); MsiCloseHandle( hrec ); } @@ -1742,7 +1725,9 @@ static void test_formatrecord_package(void) todo_wine { ok( sz == 66, "size wrong (%i)\n",sz); - ok( 0 == strcmp(buffer,"1: [2] 2: stuff 3: prop 4: val 5: 6: 7: 8: 9: 10: 11: 12: "), "wrong output(%s)\n",buffer); + ok( !lstrcmpA(buffer, + "1: [2] 2: stuff 3: prop 4: val 5: 6: 7: 8: 9: 10: 11: 12: "), + "wrong output(%s)\n",buffer); } /* now put play games with escaping */ @@ -1904,8 +1889,10 @@ static void test_formatrecord_package(void) sz = sizeof buffer; r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - ok( sz == 9, "size wrong\n"); - ok( 0 == strcmp(buffer,"boo "), "wrong output\n"); + ok( sz == 9, "size wrong: %d\n", sz); + ok( 0 == strcmp(buffer,"boo "), "wrong output: %s\n", buffer); + ok(!lstrcmpA(&buffer[5], " hoo"), + "Expected \" hoo\", got \"%s\"\n", &buffer[5]); MsiRecordSetString(hrec, 0, "[1] [~abc] [2]"); MsiRecordSetString(hrec, 1, "boo"); @@ -1913,12 +1900,8 @@ static void test_formatrecord_package(void) sz = sizeof(buffer); r = MsiFormatRecord(package, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); - todo_wine - { - ok(sz == 8, "Expected 8, got %d\n", sz); - ok(!lstrcmpA(buffer, "boo hoo"), - "Expected \"boo hoo\", got \"%s\"\n", buffer); - } + ok(sz == 8, "Expected 8, got %d\n", sz); + ok(!lstrcmpA(buffer, "boo hoo"), "Expected \"boo hoo\", got \"%s\"\n", buffer); /* properties */ r = MsiSetProperty(package,"dummy","Bork"); @@ -1943,7 +1926,6 @@ static void test_formatrecord_package(void) ok( sz == 8, "size wrong\n"); ok( 0 == strcmp(buffer,"boo hoo"), "wrong output\n"); - /* nesting tests */ r = MsiSetProperty(package,"dummya","foo"); r = MsiSetProperty(package,"dummyb","baa"); @@ -1960,7 +1942,6 @@ static void test_formatrecord_package(void) ok( sz == 12, "size wrong(%i)\n",sz); ok( 0 == strcmp(buffer,"foo baa whoa"), "wrong output (%s)\n",buffer); - r = MsiSetProperty(package,"dummya","1"); r = MsiSetProperty(package,"dummyb","[2]"); ok( r == ERROR_SUCCESS, "set property failed\n"); @@ -1972,8 +1953,11 @@ static void test_formatrecord_package(void) sz = sizeof buffer; r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - ok( sz == 9, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"1 [1] [2]"), "wrong output (%s)\n",buffer); + todo_wine + { + ok( sz == 9, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"1 [1] [2]"), "wrong output (%s)\n",buffer); + } r = MsiSetProperty(package,"dummya","1"); r = MsiSetProperty(package,"dummyb","a"); @@ -1999,8 +1983,11 @@ static void test_formatrecord_package(void) sz = sizeof buffer; r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - ok( sz == 11, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"boo hoo [3]"), "wrong output (%s)\n",buffer); + todo_wine + { + ok( sz == 11, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"boo hoo [3]"), "wrong output (%s)\n",buffer); + } r = MsiRecordSetString(hrec, 0, "[1] [2] [[3]]"); r = MsiRecordSetString(hrec, 1, "boo"); @@ -2087,7 +2074,7 @@ static void test_formatrecord_package(void) sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{a[one]bc[two]de[one]f}"); r = MsiFormatRecord(package, hrec, buffer, &sz); - ok( r == ERROR_SUCCESS, "format failed\n"); + ok( r == ERROR_SUCCESS, "format failed: %d\n", r); ok( sz == 25, "size wrong(%i)\n",sz); ok( 0 == strcmp(buffer,"amercurybcvenusdemercuryf"), "wrong output (%s)\n",buffer); @@ -2114,38 +2101,39 @@ static void test_formatrecord_package(void) MsiRecordSetString(hrec, 0, "{abc{d[one]ef}"); /* missing final brace */ r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - ok( sz == 14, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"abc{dmercuryef"), "wrong output (%s)\n",buffer); + todo_wine + { + ok( sz == 14, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"abc{dmercuryef"), "wrong output (%s)\n",buffer); + } MsiSetProperty(package, "one", "mercury"); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{abc{d[one]ef}}"); r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - ok( sz == 15, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"abc{dmercuryef}"), "wrong output (%s)\n",buffer); + todo_wine + { + ok( sz == 15, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"abc{dmercuryef}"), "wrong output (%s)\n",buffer); + } MsiSetProperty(package, "one", "mercury"); sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{abc}{{def}hi{j[one]k}}"); r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 5, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,"{abc}"), "wrong output (%s)\n",buffer); - } + ok( sz == 5, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,"{abc}"), "wrong output (%s)\n",buffer); MsiSetProperty(package, "one", "mercury"); + sz = sizeof buffer; MsiRecordSetString(hrec, 0, "{{def}hi{j[one]k}}"); r = MsiFormatRecord(package, hrec, buffer, &sz); ok( r == ERROR_SUCCESS, "format failed\n"); - todo_wine - { - ok( sz == 0, "size wrong(%i)\n",sz); - ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); - } + ok( sz == 0, "size wrong(%i)\n",sz); + ok( 0 == strcmp(buffer,""), "wrong output (%s)\n",buffer); sz = sizeof(buffer); MsiRecordSetString(hrec, 0, "[1] {[noprop] [twoprop]} {abcdef}"); @@ -2153,11 +2141,8 @@ static void test_formatrecord_package(void) r = MsiFormatRecord(package, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 13, "Expected 13, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one {abcdef}"), - "Expected \"one {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one {abcdef}"), + "Expected \"one {abcdef}\", got \"%s\"\n", buffer); sz = sizeof(buffer); MsiRecordSetString(hrec, 0, "[1] {[noprop] [one]} {abcdef}"); @@ -2165,11 +2150,8 @@ static void test_formatrecord_package(void) r = MsiFormatRecord(package, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 13, "Expected 13, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one {abcdef}"), - "Expected \"one {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one {abcdef}"), + "Expected \"one {abcdef}\", got \"%s\"\n", buffer); sz = sizeof(buffer); MsiRecordSetString(hrec, 0, "[1] {[one]} {abcdef}"); @@ -2177,11 +2159,8 @@ static void test_formatrecord_package(void) r = MsiFormatRecord(package, hrec, buffer, &sz); ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r); ok(sz == 20, "Expected 20, got %d\n",sz); - todo_wine - { - ok(!lstrcmpA(buffer, "one mercury {abcdef}"), - "Expected \"one mercury {abcdef}\", got \"%s\"\n", buffer); - } + ok(!lstrcmpA(buffer, "one mercury {abcdef}"), + "Expected \"one mercury {abcdef}\", got \"%s\"\n", buffer); MsiCloseHandle(hrec); -- 2.11.4.GIT