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
);
53 LPWSTR
build_default_format(MSIRECORD
* record
)
58 static const WCHAR fmt
[] = {'%','i',':',' ','[','%','i',']',' ',0};
61 count
= MSI_RecordGetFieldCount(record
);
63 rc
= HeapAlloc(GetProcessHeap(),0,(11*count
)*sizeof(WCHAR
));
65 for (i
= 1; i
<= count
; i
++)
67 sprintfW(buf
,fmt
,i
,i
);
73 static const WCHAR
* scanW(LPCWSTR buf
, WCHAR token
, DWORD len
)
76 for (i
= 0; i
< len
; i
++)
82 /* break out helper functions for deformating */
83 static LPWSTR
deformat_component(MSIPACKAGE
* package
, LPCWSTR key
, DWORD
* sz
)
92 ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
93 index
= get_loaded_component(package
,key
);
96 value
= resolve_folder(package
, package
->components
[index
].Directory
,
98 *sz
= (strlenW(value
)) * sizeof(WCHAR
);
104 static LPWSTR
deformat_file(MSIPACKAGE
* package
, LPCWSTR key
, DWORD
* sz
)
114 index
= get_loaded_file(package
,key
);
117 value
= strdupW(package
->files
[index
].TargetPath
);
118 *sz
= (strlenW(value
)) * sizeof(WCHAR
);
124 static LPWSTR
deformat_environment(MSIPACKAGE
* package
, LPCWSTR key
,
130 sz
= GetEnvironmentVariableW(key
,NULL
,0);
134 value
= HeapAlloc(GetProcessHeap(),0,sz
* sizeof(WCHAR
));
135 GetEnvironmentVariableW(&key
[1],value
,sz
);
136 *chunk
= (strlenW(value
)) * sizeof(WCHAR
);
140 ERR("Unknown environment variable %s\n", debugstr_w(key
));
148 static LPWSTR
deformat_NULL(DWORD
* chunk
)
152 value
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
)*2);
154 *chunk
= sizeof(WCHAR
);
158 static LPWSTR
deformat_escape(LPCWSTR key
, DWORD
* chunk
)
162 value
= HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR
)*2);
164 *chunk
= sizeof(WCHAR
);
170 static BOOL
is_key_number(LPCWSTR key
)
176 while (isdigitW(key
[index
])) index
++;
183 static LPWSTR
deformat_index(MSIRECORD
* record
, LPCWSTR key
, DWORD
* chunk
)
189 TRACE("record index %i\n",index
);
190 value
= load_dynamic_stringW(record
,index
);
192 *chunk
= strlenW(value
) * sizeof(WCHAR
);
201 static LPWSTR
deformat_property(MSIPACKAGE
* package
, LPCWSTR key
, DWORD
* chunk
)
209 value
= load_dynamic_property(package
,key
, &rc
);
211 if (rc
== ERROR_SUCCESS
)
212 *chunk
= (strlenW(value
)) * sizeof(WCHAR
);
217 static BOOL
find_next_outermost_key(LPCWSTR source
, DWORD len_remaining
,
218 LPWSTR
*key
, LPCWSTR
*mark
, LPCWSTR
* mark2
,
225 *mark
= scanW(source
,'[',len_remaining
);
232 for (i
= 1; (*mark
- source
) + i
< len_remaining
&& count
> 0; i
++)
234 if ((*mark
)[i
] == '[' && (*mark
)[i
-1] != '\\')
240 else if ((*mark
)[i
] == ']' && (*mark
)[i
-1] != '\\')
249 *mark2
= &(*mark
)[i
-1];
252 *key
= HeapAlloc(GetProcessHeap(),0,i
*sizeof(WCHAR
));
253 /* do not have the [] in the key */
255 memcpy(*key
,&(*mark
)[1],i
*sizeof(WCHAR
));
258 TRACE("Found Key %s\n",debugstr_w(*key
));
265 * return is also in WCHARs
267 static DWORD
deformat_string_internal(MSIPACKAGE
*package
, LPCWSTR ptr
,
268 WCHAR
** data
, DWORD len
, MSIRECORD
* record
)
271 LPCWSTR mark2
= NULL
;
277 LPBYTE newdata
= NULL
;
278 const WCHAR
* progress
= NULL
;
283 TRACE("Deformatting NULL string\n");
288 TRACE("Starting with %s\n",debugstr_w(ptr
));
290 /* scan for special characters... fast exit */
291 if (!scanW(ptr
,'[',len
) || (scanW(ptr
,'[',len
) && !scanW(ptr
,']',len
)))
294 *data
= HeapAlloc(GetProcessHeap(),0,(len
*sizeof(WCHAR
)));
295 memcpy(*data
,ptr
,len
*sizeof(WCHAR
));
296 TRACE("Returning %s\n",debugstr_w(*data
));
302 while (progress
- ptr
< len
)
304 /* formatted string located */
305 if (!find_next_outermost_key(progress
, len
- (progress
- ptr
), &key
,
306 &mark
, &mark2
, &nested
))
310 TRACE("after value %s .. %s\n",debugstr_w((LPWSTR
)newdata
),
312 chunk
= (len
- (progress
- ptr
)) * sizeof(WCHAR
);
313 TRACE("after chunk is %li + %li\n",size
,chunk
);
315 nd2
= HeapReAlloc(GetProcessHeap(),0,newdata
,(size
+chunk
));
317 nd2
= HeapAlloc(GetProcessHeap(),0,chunk
);
320 memcpy(&newdata
[size
],progress
,chunk
);
325 if (mark
!= progress
)
328 DWORD old_size
= size
;
329 INT cnt
= (mark
- progress
);
330 TRACE("%i (%i) characters before marker\n",cnt
,(mark
-progress
));
331 size
+= cnt
* sizeof(WCHAR
);
333 tgt
= HeapAlloc(GetProcessHeap(),0,size
);
335 tgt
= HeapReAlloc(GetProcessHeap(),0,newdata
,size
);
337 memcpy(&newdata
[old_size
],progress
,(cnt
* sizeof(WCHAR
)));
344 TRACE("Nested key... %s\n",debugstr_w(key
));
345 deformat_string_internal(package
, key
, &value
, strlenW(key
)+1,
348 HeapFree(GetProcessHeap(),0,key
);
352 TRACE("Current %s .. %s\n",debugstr_w((LPWSTR
)newdata
),debugstr_w(key
));
356 /* only deformat number indexs */
357 if (is_key_number(key
))
358 value
= deformat_index(record
,key
,&chunk
);
361 DWORD keylen
= strlenW(key
);
362 chunk
= (keylen
+ 2)*sizeof(WCHAR
);
363 value
= HeapAlloc(GetProcessHeap(),0,chunk
);
365 memcpy(&value
[1],key
,keylen
*sizeof(WCHAR
));
366 value
[1+keylen
] = ']';
375 value
= deformat_NULL(&chunk
);
378 value
= deformat_component(package
,&key
[1],&chunk
);
381 case '!': /* should be short path */
382 value
= deformat_file(package
,&key
[1], &chunk
);
385 value
= deformat_escape(&key
[1],&chunk
);
388 value
= deformat_environment(package
,&key
[1],&chunk
);
391 if (is_key_number(key
))
392 value
= deformat_index(record
,key
,&chunk
);
394 value
= deformat_property(package
,key
,&chunk
);
399 HeapFree(GetProcessHeap(),0,key
);
404 TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR
)value
),
407 nd2
= HeapReAlloc(GetProcessHeap(),0,newdata
,(size
+ chunk
));
409 nd2
= HeapAlloc(GetProcessHeap(),0,chunk
);
411 memcpy(&newdata
[size
],value
,chunk
);
413 HeapFree(GetProcessHeap(),0,value
);
419 TRACE("after everything %s\n",debugstr_w((LPWSTR
)newdata
));
421 *data
= (LPWSTR
)newdata
;
422 return size
/ sizeof(WCHAR
);
426 UINT
MSI_FormatRecordW( MSIPACKAGE
* package
, MSIRECORD
* record
, LPWSTR buffer
,
432 UINT rc
= ERROR_INVALID_PARAMETER
;
434 TRACE("%p %p %p %li\n",package
, record
,buffer
, *size
);
436 rec
= load_dynamic_stringW(record
,0);
438 rec
= build_default_format(record
);
440 TRACE("(%s)\n",debugstr_w(rec
));
442 len
= deformat_string_internal(package
,rec
,&deformated
,strlenW(rec
),
449 memcpy(buffer
,deformated
,len
*sizeof(WCHAR
));
457 memcpy(buffer
,deformated
,(*size
)*sizeof(WCHAR
));
458 buffer
[(*size
)-1] = 0;
460 rc
= ERROR_MORE_DATA
;
468 HeapFree(GetProcessHeap(),0,rec
);
469 HeapFree(GetProcessHeap(),0,deformated
);
473 UINT
MSI_FormatRecordA( MSIPACKAGE
* package
, MSIRECORD
* record
, LPSTR buffer
,
479 UINT rc
= ERROR_INVALID_PARAMETER
;
481 TRACE("%p %p %p %li\n",package
, record
,buffer
, *size
);
483 rec
= load_dynamic_stringW(record
,0);
485 rec
= build_default_format(record
);
487 TRACE("(%s)\n",debugstr_w(rec
));
489 len
= deformat_string_internal(package
,rec
,&deformated
,strlenW(rec
),
491 lenA
= WideCharToMultiByte(CP_ACP
,0,deformated
,len
,NULL
,0,NULL
,NULL
);
495 WideCharToMultiByte(CP_ACP
,0,deformated
,len
,buffer
,*size
,NULL
, NULL
);
503 rc
= ERROR_MORE_DATA
;
504 buffer
[(*size
)-1] = 0;
512 HeapFree(GetProcessHeap(),0,rec
);
513 HeapFree(GetProcessHeap(),0,deformated
);
518 UINT WINAPI
MsiFormatRecordW( MSIHANDLE hInstall
, MSIHANDLE hRecord
,
519 LPWSTR szResult
, DWORD
*sz
)
521 UINT r
= ERROR_INVALID_HANDLE
;
525 TRACE("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
527 record
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
530 return ERROR_INVALID_HANDLE
;
533 msiobj_release( &record
->hdr
);
535 return ERROR_INVALID_PARAMETER
;
537 return ERROR_SUCCESS
;
540 package
= msihandle2msiinfo( hInstall
, MSIHANDLETYPE_PACKAGE
);
542 r
= MSI_FormatRecordW( package
, record
, szResult
, sz
);
543 msiobj_release( &record
->hdr
);
545 msiobj_release( &package
->hdr
);
549 UINT WINAPI
MsiFormatRecordA( MSIHANDLE hInstall
, MSIHANDLE hRecord
,
550 LPSTR szResult
, DWORD
*sz
)
552 UINT r
= ERROR_INVALID_HANDLE
;
553 MSIPACKAGE
*package
= NULL
;
554 MSIRECORD
*record
= NULL
;
556 TRACE("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
558 record
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
561 return ERROR_INVALID_HANDLE
;
564 msiobj_release( &record
->hdr
);
566 return ERROR_INVALID_PARAMETER
;
568 return ERROR_SUCCESS
;
571 package
= msihandle2msiinfo( hInstall
, MSIHANDLETYPE_PACKAGE
);
573 r
= MSI_FormatRecordA( package
, record
, szResult
, sz
);
574 msiobj_release( &record
->hdr
);
576 msiobj_release( &package
->hdr
);