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 alot 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 enviroment variable\n");
184 rc
= ERROR_FUNCTION_FAILED
;
188 /* check for numaric 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 incase 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
);