2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Aric Stewart for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiformatrecord.asp
35 #include "wine/debug.h"
39 #include "msvcrt/fcntl.h"
46 #include "wine/unicode.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(msi);
52 static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len)
55 for (i = 0; i < len; i++)
62 * This helper function should probably go a lot of places
64 * Thinking about this, maybe this should become yet another Bison file
67 * return is also in WCHARs
69 static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
70 WCHAR** data, DWORD len, MSIRECORD* record)
72 const WCHAR* mark=NULL;
81 LPWSTR newdata = NULL;
85 TRACE("Deformatting NULL string\n");
90 TRACE("Starting with %s\n",debugstr_w(ptr));
92 /* scan for special characters */
93 if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
96 *data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR)));
97 memcpy(*data,ptr,len*sizeof(WCHAR));
98 TRACE("Returning %s\n",debugstr_w(*data));
102 /* formatted string located */
103 mark = scanW(ptr,'[',len);
106 INT cnt = (mark - ptr);
107 TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
108 size = cnt * sizeof(WCHAR);
109 newdata = HeapAlloc(GetProcessHeap(),0,size);
110 memcpy(newdata,ptr,(cnt * sizeof(WCHAR)));
115 newdata = HeapAlloc(GetProcessHeap(),0,size);
119 /* there should be no null characters in a key so strchrW is ok */
120 mark2 = strchrW(mark,']');
121 strncpyW(key,mark,mark2-mark);
123 mark = strchrW(mark,']');
125 TRACE("Current %s .. %s\n",debugstr_w(newdata),debugstr_w(key));
127 /* expand what we can deformat... Again, this should become a bison file */
131 value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
133 chunk = sizeof(WCHAR);
137 ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
138 index = get_loaded_component(package,&key[1]);
141 value = resolve_folder(package,
142 package->components[index].Directory,
144 chunk = (strlenW(value)) * sizeof(WCHAR);
148 rc = ERROR_FUNCTION_FAILED;
151 case '!': /* should be short path */
152 index = get_loaded_file(package,&key[1]);
155 sz = strlenW(package->files[index].TargetPath);
156 value = dupstrW(package->files[index].TargetPath);
157 chunk = (strlenW(value)) * sizeof(WCHAR);
161 rc = ERROR_FUNCTION_FAILED;
164 value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
166 chunk = sizeof(WCHAR);
170 sz = GetEnvironmentVariableW(&key[1],NULL,0);
174 value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
175 GetEnvironmentVariableW(&key[1],value,sz);
176 chunk = (strlenW(value)) * sizeof(WCHAR);
181 ERR("Unknown environment variable\n");
184 rc = ERROR_FUNCTION_FAILED;
188 /* check for numeric values */
190 while (isdigitW(key[index])) index++;
194 TRACE("record index %i\n",index);
195 value = load_dynamic_stringW(record,index);
198 chunk = strlenW(value) * sizeof(WCHAR);
204 rc = ERROR_FUNCTION_FAILED;
209 value = load_dynamic_property(package,key, &rc);
210 if (rc == ERROR_SUCCESS)
211 chunk = (strlenW(value)) * sizeof(WCHAR);
215 if (((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA)) && value!=NULL)
218 TRACE("value %s, chunk %li size %li\n",debugstr_w(value),chunk,size);
220 nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
222 memcpy(&newdata[(size/sizeof(WCHAR))],value,chunk);
224 HeapFree(GetProcessHeap(),0,value);
226 TRACE("after value %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
227 if (mark - ptr < len)
230 chunk = (len - (mark - ptr)) * sizeof(WCHAR);
231 TRACE("after chunk is %li\n",chunk);
232 nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
234 memcpy(&newdata[(size/sizeof(WCHAR))],mark,chunk);
237 TRACE("after trailing %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
239 /* recursively do this to clean up */
240 size = deformat_string_internal(package,newdata,data,(size/sizeof(WCHAR)),
242 HeapFree(GetProcessHeap(),0,newdata);
247 UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
253 UINT rc = ERROR_INVALID_PARAMETER;
255 TRACE("%p %p %p %li\n",package, record ,buffer, *size);
257 rec = load_dynamic_stringW(record,0);
261 TRACE("(%s)\n",debugstr_w(rec));
263 len = deformat_string_internal(package,rec,&deformated,(strlenW(rec)+1),
268 memcpy(buffer,deformated,len*sizeof(WCHAR));
274 rc = ERROR_MORE_DATA;
277 HeapFree(GetProcessHeap(),0,rec);
278 HeapFree(GetProcessHeap(),0,deformated);
282 UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR
291 TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
293 package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
294 record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
296 if (!package || !record)
297 return ERROR_INVALID_HANDLE;
300 /* +1 just to make sure we have a buffer in case the len is 0 */
301 szwResult = HeapAlloc(GetProcessHeap(),0,(original_len+1) * sizeof(WCHAR));
303 rc = MSI_FormatRecordW(package, record, szwResult, sz);
305 WideCharToMultiByte(CP_ACP,0,szwResult,original_len, szResult, original_len,
308 HeapFree(GetProcessHeap(),0,szwResult);
314 UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord,
315 LPWSTR szResult, DWORD *sz)
321 TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
323 package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
324 record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
326 if (!package || !record)
327 return ERROR_INVALID_HANDLE;
329 rc = MSI_FormatRecordW(package, record, szResult, sz);