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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/debug.h"
37 #include "msiserver.h"
38 #include "wine/unicode.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
42 /* types arranged by precedence */
43 #define FORMAT_NULL 0x0001
44 #define FORMAT_LITERAL 0x0002
45 #define FORMAT_NUMBER 0x0004
46 #define FORMAT_LBRACK 0x0010
47 #define FORMAT_LBRACE 0x0020
48 #define FORMAT_RBRACK 0x0011
49 #define FORMAT_RBRACE 0x0021
50 #define FORMAT_ESCAPE 0x0040
51 #define FORMAT_PROPNULL 0x0080
52 #define FORMAT_ERROR 0x1000
53 #define FORMAT_FAIL 0x2000
55 #define left_type(x) (x & 0xF0)
57 typedef struct _tagFORMAT
69 typedef struct _tagFORMSTR
79 typedef struct _tagSTACK
84 static STACK
*create_stack(void)
86 STACK
*stack
= msi_alloc(sizeof(STACK
));
87 list_init(&stack
->items
);
91 static void free_stack(STACK
*stack
)
93 while (!list_empty(&stack
->items
))
95 FORMSTR
*str
= LIST_ENTRY(list_head(&stack
->items
), FORMSTR
, entry
);
96 list_remove(&str
->entry
);
103 static void stack_push(STACK
*stack
, FORMSTR
*str
)
105 list_add_head(&stack
->items
, &str
->entry
);
108 static FORMSTR
*stack_pop(STACK
*stack
)
112 if (list_empty(&stack
->items
))
115 ret
= LIST_ENTRY(list_head(&stack
->items
), FORMSTR
, entry
);
116 list_remove(&ret
->entry
);
120 static FORMSTR
*stack_find(STACK
*stack
, int type
)
124 LIST_FOR_EACH_ENTRY(str
, &stack
->items
, FORMSTR
, entry
)
126 if (str
->type
== type
)
133 static FORMSTR
*stack_peek(STACK
*stack
)
135 return LIST_ENTRY(list_head(&stack
->items
), FORMSTR
, entry
);
138 static LPCWSTR
get_formstr_data(FORMAT
*format
, FORMSTR
*str
)
140 return &format
->deformatted
[str
->n
];
143 static LPWSTR
dup_formstr(FORMAT
*format
, FORMSTR
*str
)
151 val
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
152 data
= get_formstr_data(format
, str
);
153 lstrcpynW(val
, data
, str
->len
+ 1);
158 static LPWSTR
deformat_index(FORMAT
*format
, FORMSTR
*str
)
162 val
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
163 lstrcpynW(val
, get_formstr_data(format
, str
), str
->len
+ 1);
165 ret
= msi_dup_record_field(format
->record
, atoiW(val
));
171 static LPWSTR
deformat_property(FORMAT
*format
, FORMSTR
*str
)
175 val
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
176 lstrcpynW(val
, get_formstr_data(format
, str
), str
->len
+ 1);
178 ret
= msi_dup_property(format
->package
, val
);
184 static LPWSTR
deformat_component(FORMAT
*format
, FORMSTR
*str
)
186 LPWSTR key
, ret
= NULL
;
190 key
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
191 lstrcpynW(key
, get_formstr_data(format
, str
), str
->len
+ 1);
193 comp
= get_loaded_component(format
->package
, key
);
197 source
= (comp
->Action
== INSTALLSTATE_SOURCE
) ? TRUE
: FALSE
;
198 ret
= resolve_folder(format
->package
, comp
->Directory
, source
, FALSE
, TRUE
, NULL
);
205 static LPWSTR
deformat_file(FORMAT
*format
, FORMSTR
*str
, BOOL shortname
)
207 LPWSTR key
, ret
= NULL
;
211 key
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
212 lstrcpynW(key
, get_formstr_data(format
, str
), str
->len
+ 1);
214 file
= get_loaded_file(format
->package
, key
);
220 ret
= strdupW(file
->TargetPath
);
224 size
= GetShortPathNameW(file
->TargetPath
, NULL
, 0);
227 ret
= strdupW(file
->TargetPath
);
232 ret
= msi_alloc(size
* sizeof(WCHAR
));
233 GetShortPathNameW(file
->TargetPath
, ret
, size
);
240 static LPWSTR
deformat_environment(FORMAT
*format
, FORMSTR
*str
)
242 LPWSTR key
, ret
= NULL
;
245 key
= msi_alloc((str
->len
+ 1) * sizeof(WCHAR
));
246 lstrcpynW(key
, get_formstr_data(format
, str
), str
->len
+ 1);
248 sz
= GetEnvironmentVariableW(key
, NULL
,0);
253 ret
= msi_alloc(sz
* sizeof(WCHAR
));
254 GetEnvironmentVariableW(key
, ret
, sz
);
261 static LPWSTR
deformat_literal(FORMAT
*format
, FORMSTR
*str
, BOOL
*propfound
,
262 BOOL
*nonprop
, int *type
)
264 LPCWSTR data
= get_formstr_data(format
, str
);
265 LPWSTR replaced
= NULL
;
279 replaced
= dup_formstr(format
, str
);
288 replaced
= msi_alloc(sizeof(WCHAR
));
292 else if (ch
== '%' || ch
== '#' || ch
== '!' || ch
== '$')
300 replaced
= deformat_environment(format
, str
); break;
302 replaced
= deformat_file(format
, str
, FALSE
); break;
304 replaced
= deformat_file(format
, str
, TRUE
); break;
306 replaced
= deformat_component(format
, str
); break;
309 *type
= FORMAT_LITERAL
;
313 replaced
= deformat_property(format
, str
);
314 *type
= FORMAT_LITERAL
;
319 format
->propfailed
= TRUE
;
325 static LPWSTR
build_default_format(const MSIRECORD
* record
)
330 static const WCHAR fmt
[] = {'%','i',':',' ','%','s',' ',0};
331 static const WCHAR fmt_null
[] = {'%','i',':',' ',' ',0};
332 static const WCHAR fmt_index
[] = {'%','i',0};
335 DWORD size
, max_len
, len
;
337 count
= MSI_RecordGetFieldCount(record
);
340 buf
= msi_alloc((max_len
+ 1) * sizeof(WCHAR
));
344 for (i
= 1; i
<= count
; i
++)
346 sprintfW(index
, fmt_index
, i
);
347 str
= MSI_RecordGetString(record
, i
);
348 len
= (str
) ? lstrlenW(str
) : 0;
349 len
+= (sizeof(fmt_null
) - 3) + lstrlenW(index
);
355 buf
= msi_realloc(buf
, (max_len
+ 1) * sizeof(WCHAR
));
356 if (!buf
) return NULL
;
360 sprintfW(buf
, fmt
, i
, str
);
362 sprintfW(buf
, fmt_null
, i
);
366 rc
= msi_alloc(size
* sizeof(WCHAR
));
371 rc
= msi_realloc(rc
, size
* sizeof(WCHAR
));
380 static BOOL
format_is_number(WCHAR x
)
382 return ((x
>= '0') && (x
<= '9'));
385 static BOOL
format_str_is_number(LPWSTR str
)
389 for (ptr
= str
; *ptr
; ptr
++)
390 if (!format_is_number(*ptr
))
396 static BOOL
format_is_alpha(WCHAR x
)
398 return (!format_is_number(x
) && x
!= '\0' &&
399 x
!= '[' && x
!= ']' && x
!= '{' && x
!= '}');
402 static BOOL
format_is_literal(WCHAR x
)
404 return (format_is_alpha(x
) || format_is_number(x
));
407 static int format_lex(FORMAT
*format
, FORMSTR
**out
)
416 if (!format
->deformatted
)
419 *out
= msi_alloc_zero(sizeof(FORMSTR
));
426 data
= get_formstr_data(format
, str
);
431 case '{': type
= FORMAT_LBRACE
; break;
432 case '}': type
= FORMAT_RBRACE
; break;
433 case '[': type
= FORMAT_LBRACK
; break;
434 case ']': type
= FORMAT_RBRACK
; break;
435 case '~': type
= FORMAT_PROPNULL
; break;
436 case '\0': type
= FORMAT_NULL
; break;
451 while (data
[len
] && data
[len
] != ']')
454 type
= FORMAT_ESCAPE
;
456 else if (format_is_alpha(ch
))
458 while (format_is_literal(data
[len
]))
461 type
= FORMAT_LITERAL
;
463 else if (format_is_number(ch
))
465 while (format_is_number(data
[len
]))
468 type
= FORMAT_NUMBER
;
470 if (data
[len
] != ']')
472 while (format_is_literal(data
[len
]))
475 type
= FORMAT_LITERAL
;
480 ERR("Got unknown character %c(%x)\n", ch
, ch
);
491 static FORMSTR
*format_replace(FORMAT
*format
, BOOL propfound
, BOOL nonprop
,
492 int oldsize
, int type
, LPWSTR replace
)
504 size
= lstrlenW(replace
);
508 size
= format
->len
+ size
+ 1;
512 msi_free(format
->deformatted
);
513 format
->deformatted
= NULL
;
518 str
= msi_alloc(size
* sizeof(WCHAR
));
523 memcpy(str
, format
->deformatted
, format
->n
* sizeof(WCHAR
));
535 lstrcpyW(&str
[n
], replace
);
536 n
+= lstrlenW(replace
);
540 ptr
= &format
->deformatted
[format
->n
+ oldsize
];
541 memcpy(&str
[n
], ptr
, (lstrlenW(ptr
) + 1) * sizeof(WCHAR
));
543 msi_free(format
->deformatted
);
544 format
->deformatted
= str
;
545 format
->len
= size
- 1;
550 ret
= msi_alloc_zero(sizeof(FORMSTR
));
554 ret
->len
= lstrlenW(replace
);
557 ret
->propfound
= propfound
;
558 ret
->nonprop
= nonprop
;
563 static LPWSTR
replace_stack_group(FORMAT
*format
, STACK
*values
,
564 BOOL
*propfound
, BOOL
*nonprop
,
565 int *oldsize
, int *type
)
567 LPWSTR replaced
= NULL
;
575 node
= stack_pop(values
);
577 *oldsize
= node
->len
;
580 while ((node
= stack_pop(values
)))
582 *oldsize
+= node
->len
;
593 content
= msi_alloc_zero(sizeof(FORMSTR
));
595 content
->len
= *oldsize
;
596 content
->type
= FORMAT_LITERAL
;
598 if (!format
->groupfailed
&& (*oldsize
== 2 ||
599 (format
->propfailed
&& !*nonprop
)))
604 else if (format
->deformatted
[content
->n
+ 1] == '{' &&
605 format
->deformatted
[content
->n
+ content
->len
- 2] == '}')
607 format
->groupfailed
= FALSE
;
610 else if (*propfound
&& !*nonprop
&&
611 !format
->groupfailed
&& format
->groups
== 0)
618 if (format
->groups
!= 0)
619 format
->groupfailed
= TRUE
;
624 replaced
= dup_formstr(format
, content
);
625 *type
= content
->type
;
628 if (format
->groups
== 0)
629 format
->propfailed
= FALSE
;
634 static LPWSTR
replace_stack_prop(FORMAT
*format
, STACK
*values
,
635 BOOL
*propfound
, BOOL
*nonprop
,
636 int *oldsize
, int *type
)
638 LPWSTR replaced
= NULL
;
646 node
= stack_pop(values
);
648 *oldsize
= node
->len
;
649 *type
= stack_peek(values
)->type
;
652 while ((node
= stack_pop(values
)))
654 *oldsize
+= node
->len
;
656 if (*type
!= FORMAT_ESCAPE
&&
657 stack_peek(values
) && node
->type
!= *type
)
658 *type
= FORMAT_LITERAL
;
663 content
= msi_alloc_zero(sizeof(FORMSTR
));
665 content
->len
= *oldsize
- 2;
666 content
->type
= *type
;
668 if (*type
== FORMAT_NUMBER
)
670 replaced
= deformat_index(format
, content
);
674 format
->propfailed
= TRUE
;
677 *type
= format_str_is_number(replaced
) ?
678 FORMAT_NUMBER
: FORMAT_LITERAL
;
680 else if (format
->package
)
682 replaced
= deformat_literal(format
, content
, propfound
, nonprop
, type
);
689 replaced
= dup_formstr(format
, content
);
696 static UINT
replace_stack(FORMAT
*format
, STACK
*stack
, STACK
*values
)
698 LPWSTR replaced
= NULL
;
702 BOOL propfound
= FALSE
;
703 BOOL nonprop
= FALSE
;
708 node
= stack_peek(values
);
712 if (type
== FORMAT_LBRACK
)
713 replaced
= replace_stack_prop(format
, values
, &propfound
,
714 &nonprop
, &oldsize
, &type
);
715 else if (type
== FORMAT_LBRACE
)
717 replaced
= replace_stack_group(format
, values
, &propfound
,
718 &nonprop
, &oldsize
, &type
);
723 beg
= format_replace(format
, propfound
, nonprop
, oldsize
, type
, replaced
);
725 return ERROR_SUCCESS
;
728 format
->n
= beg
->n
+ beg
->len
;
730 if (type
== FORMAT_PROPNULL
)
733 top
= stack_peek(stack
);
738 if ((type
== FORMAT_LITERAL
|| type
== FORMAT_NUMBER
) &&
741 top
->len
+= beg
->len
;
744 top
->nonprop
= FALSE
;
746 if (type
== FORMAT_LITERAL
)
747 top
->nonprop
= beg
->nonprop
;
750 top
->propfound
= TRUE
;
753 return ERROR_SUCCESS
;
757 stack_push(stack
, beg
);
758 return ERROR_SUCCESS
;
761 static BOOL
verify_format(LPWSTR data
)
767 if (*data
== '[' && *(data
- 1) != '\\')
769 else if (*data
== ']')
781 static DWORD
deformat_string_internal(MSIPACKAGE
*package
, LPCWSTR ptr
,
782 WCHAR
** data
, DWORD
*len
,
783 MSIRECORD
* record
, INT
* failcount
)
795 return ERROR_SUCCESS
;
798 *data
= strdupW(ptr
);
799 *len
= lstrlenW(ptr
);
801 ZeroMemory(&format
, sizeof(FORMAT
));
802 format
.package
= package
;
803 format
.record
= record
;
804 format
.deformatted
= *data
;
807 stack
= create_stack();
808 temp
= create_stack();
810 if (!verify_format(*data
))
811 return ERROR_SUCCESS
;
813 while ((type
= format_lex(&format
, &str
)) != FORMAT_NULL
)
815 if (type
== FORMAT_LBRACK
|| type
== FORMAT_LBRACE
||
816 type
== FORMAT_LITERAL
|| type
== FORMAT_NUMBER
||
817 type
== FORMAT_ESCAPE
|| type
== FORMAT_PROPNULL
)
819 if (type
== FORMAT_LBRACE
)
821 format
.propfailed
= FALSE
;
824 else if (type
== FORMAT_ESCAPE
&&
825 !stack_find(stack
, FORMAT_LBRACK
))
827 format
.n
-= str
->len
- 1;
831 stack_push(stack
, str
);
833 else if (type
== FORMAT_RBRACK
|| type
== FORMAT_RBRACE
)
835 if (type
== FORMAT_RBRACE
)
838 stack_push(stack
, str
);
840 if (stack_find(stack
, left_type(type
)))
844 node
= stack_pop(stack
);
845 stack_push(temp
, node
);
846 } while (node
->type
!= left_type(type
));
848 replace_stack(&format
, stack
, temp
);
853 *data
= format
.deformatted
;
860 return ERROR_SUCCESS
;
863 UINT
MSI_FormatRecordW( MSIPACKAGE
* package
, MSIRECORD
* record
, LPWSTR buffer
,
869 UINT rc
= ERROR_INVALID_PARAMETER
;
871 TRACE("%p %p %p %i\n", package
, record
,buffer
, *size
);
873 rec
= msi_dup_record_field(record
,0);
875 rec
= build_default_format(record
);
877 TRACE("(%s)\n",debugstr_w(rec
));
879 deformat_string_internal(package
, rec
, &deformated
, &len
, record
, NULL
);
884 memcpy(buffer
,deformated
,len
*sizeof(WCHAR
));
892 memcpy(buffer
,deformated
,(*size
)*sizeof(WCHAR
));
893 buffer
[(*size
)-1] = 0;
895 rc
= ERROR_MORE_DATA
;
904 msi_free(deformated
);
908 UINT WINAPI
MsiFormatRecordW( MSIHANDLE hInstall
, MSIHANDLE hRecord
,
909 LPWSTR szResult
, LPDWORD sz
)
911 UINT r
= ERROR_INVALID_HANDLE
;
915 TRACE("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
917 package
= msihandle2msiinfo( hInstall
, MSIHANDLETYPE_PACKAGE
);
921 IWineMsiRemotePackage
*remote_package
;
926 remote_package
= (IWineMsiRemotePackage
*)msi_get_remote( hInstall
);
930 hr
= IWineMsiRemotePackage_FormatRecord( remote_package
, hRecord
,
936 value
= SysAllocStringLen( NULL
, len
);
939 r
= ERROR_OUTOFMEMORY
;
943 hr
= IWineMsiRemotePackage_FormatRecord( remote_package
, hRecord
,
949 wstr
.str
.w
= szResult
;
950 r
= msi_strcpy_to_awstring( value
, &wstr
, sz
);
953 IWineMsiRemotePackage_Release( remote_package
);
954 SysFreeString( value
);
958 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
959 return HRESULT_CODE(hr
);
961 return ERROR_FUNCTION_FAILED
;
968 record
= msihandle2msiinfo( hRecord
, MSIHANDLETYPE_RECORD
);
971 return ERROR_INVALID_HANDLE
;
974 msiobj_release( &record
->hdr
);
976 return ERROR_INVALID_PARAMETER
;
978 return ERROR_SUCCESS
;
981 r
= MSI_FormatRecordW( package
, record
, szResult
, sz
);
982 msiobj_release( &record
->hdr
);
984 msiobj_release( &package
->hdr
);
988 UINT WINAPI
MsiFormatRecordA( MSIHANDLE hInstall
, MSIHANDLE hRecord
,
989 LPSTR szResult
, LPDWORD sz
)
995 TRACE("%ld %ld %p %p\n", hInstall
, hRecord
, szResult
, sz
);
998 return ERROR_INVALID_HANDLE
;
1003 return ERROR_INVALID_PARAMETER
;
1005 return ERROR_SUCCESS
;
1008 r
= MsiFormatRecordW( hInstall
, hRecord
, NULL
, &len
);
1009 if (r
!= ERROR_SUCCESS
)
1012 value
= msi_alloc(++len
* sizeof(WCHAR
));
1014 return ERROR_OUTOFMEMORY
;
1016 r
= MsiFormatRecordW( hInstall
, hRecord
, value
, &len
);
1017 if (r
!= ERROR_SUCCESS
)
1021 len
= WideCharToMultiByte(CP_ACP
, 0, value
, len
+ 1, NULL
, 0, NULL
, NULL
);
1022 WideCharToMultiByte(CP_ACP
, 0, value
, len
, szResult
, *sz
, NULL
, NULL
);
1024 if (szResult
&& len
> *sz
)
1026 if (*sz
) szResult
[*sz
- 1] = '\0';
1027 r
= ERROR_MORE_DATA
;