1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2005 Mike McCormack for CodeWeavers
5 * Copyright 2005 Aric Stewart for CodeWeavers
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #define COBJMACROS
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winerror.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "winnls.h"
33 #include "objbase.h"
34 #include "oleauto.h"
35
36 #include "msipriv.h"
37 #include "winemsi_s.h"
38 #include "wine/exception.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
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
54
55 #define left_type(x) (x & 0xF0)
56
57 struct format
58 {
59 MSIPACKAGE *package;
60 MSIRECORD *record;
61 LPWSTR deformatted;
62 int len;
63 int n;
64 BOOL propfailed;
65 BOOL groupfailed;
66 int groups;
67 };
68
69 struct form_str
70 {
71 struct list entry;
72 int n;
73 int len;
74 int type;
75 BOOL propfound;
76 BOOL nonprop;
77 };
78
79 struct stack
80 {
81 struct list items;
82 };
83
create_stack(void)84 static struct stack *create_stack(void)
85 {
86 struct stack *stack = malloc(sizeof(*stack));
87 list_init(&stack->items);
88 return stack;
89 }
90
free_stack(struct stack * stack)91 static void free_stack(struct stack *stack)
92 {
93 while (!list_empty(&stack->items))
94 {
95 struct form_str *str = LIST_ENTRY(list_head(&stack->items), struct form_str, entry);
96 list_remove(&str->entry);
97 free(str);
98 }
99
100 free(stack);
101 }
102
stack_push(struct stack * stack,struct form_str * str)103 static void stack_push(struct stack *stack, struct form_str *str)
104 {
105 list_add_head(&stack->items, &str->entry);
106 }
107
stack_pop(struct stack * stack)108 static struct form_str *stack_pop(struct stack *stack)
109 {
110 struct form_str *ret;
111
112 if (list_empty(&stack->items))
113 return NULL;
114
115 ret = LIST_ENTRY(list_head(&stack->items), struct form_str, entry);
116 list_remove(&ret->entry);
117 return ret;
118 }
119
stack_find(struct stack * stack,int type)120 static struct form_str *stack_find(struct stack *stack, int type)
121 {
122 struct form_str *str;
123
124 LIST_FOR_EACH_ENTRY(str, &stack->items, struct form_str, entry)
125 {
126 if (str->type == type)
127 return str;
128 }
129
130 return NULL;
131 }
132
stack_peek(struct stack * stack)133 static struct form_str *stack_peek(struct stack *stack)
134 {
135 return LIST_ENTRY(list_head(&stack->items), struct form_str, entry);
136 }
137
get_formstr_data(struct format * format,struct form_str * str)138 static const WCHAR *get_formstr_data(struct format *format, struct form_str *str)
139 {
140 return &format->deformatted[str->n];
141 }
142
dup_formstr(struct format * format,struct form_str * str,int * ret_len)143 static WCHAR *dup_formstr( struct format *format, struct form_str *str, int *ret_len )
144 {
145 WCHAR *val;
146
147 if (!str->len) return NULL;
148 if ((val = malloc( (str->len + 1) * sizeof(WCHAR) )))
149 {
150 memcpy( val, get_formstr_data(format, str), str->len * sizeof(WCHAR) );
151 val[str->len] = 0;
152 *ret_len = str->len;
153 }
154 return val;
155 }
156
deformat_index(struct format * format,struct form_str * str,int * ret_len)157 static WCHAR *deformat_index( struct format *format, struct form_str *str, int *ret_len )
158 {
159 WCHAR *val, *ret;
160 DWORD len;
161 int field;
162
163 if (!(val = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL;
164 lstrcpynW(val, get_formstr_data(format, str), str->len + 1);
165 field = wcstol( val, NULL, 10 );
166 free( val );
167
168 if (MSI_RecordIsNull( format->record, field ) ||
169 MSI_RecordGetStringW( format->record, field, NULL, &len )) return NULL;
170
171 len++;
172 if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL;
173 ret[0] = 0;
174 if (MSI_RecordGetStringW( format->record, field, ret, &len ))
175 {
176 free( ret );
177 return NULL;
178 }
179 *ret_len = len;
180 return ret;
181 }
182
deformat_property(struct format * format,struct form_str * str,int * ret_len)183 static WCHAR *deformat_property( struct format *format, struct form_str *str, int *ret_len )
184 {
185 WCHAR *prop, *ret;
186 DWORD len = 0;
187 UINT r;
188
189 if (!(prop = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL;
190 lstrcpynW( prop, get_formstr_data(format, str), str->len + 1 );
191
192 r = msi_get_property( format->package->db, prop, NULL, &len );
193 if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
194 {
195 free( prop );
196 return NULL;
197 }
198 len++;
199 if ((ret = malloc( len * sizeof(WCHAR) )))
200 msi_get_property( format->package->db, prop, ret, &len );
201 free( prop );
202 *ret_len = len;
203 return ret;
204 }
205
deformat_component(struct format * format,struct form_str * str,int * ret_len)206 static WCHAR *deformat_component( struct format *format, struct form_str *str, int *ret_len )
207 {
208 WCHAR *key, *ret;
209 MSICOMPONENT *comp;
210
211 if (!(key = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL;
212 lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
213
214 if (!(comp = msi_get_loaded_component( format->package, key )))
215 {
216 free( key );
217 return NULL;
218 }
219 if (comp->Action == INSTALLSTATE_SOURCE)
220 ret = msi_resolve_source_folder( format->package, comp->Directory, NULL );
221 else
222 ret = wcsdup( msi_get_target_folder( format->package, comp->Directory ) );
223
224 if (ret) *ret_len = lstrlenW( ret );
225 else *ret_len = 0;
226 free( key );
227 return ret;
228 }
229
deformat_file(struct format * format,struct form_str * str,BOOL shortname,int * ret_len)230 static WCHAR *deformat_file( struct format *format, struct form_str *str, BOOL shortname, int *ret_len )
231 {
232 WCHAR *key, *ret = NULL;
233 const MSIFILE *file;
234 DWORD len = 0;
235
236 if (!(key = malloc( (str->len + 1) * sizeof(WCHAR) ))) return NULL;
237 lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
238
239 if (!(file = msi_get_loaded_file( format->package, key ))) goto done;
240 if (!shortname)
241 {
242 if ((ret = wcsdup( file->TargetPath ))) len = lstrlenW( ret );
243 goto done;
244 }
245 if (!(len = GetShortPathNameW(file->TargetPath, NULL, 0)))
246 {
247 if ((ret = wcsdup( file->TargetPath ))) len = lstrlenW( ret );
248 goto done;
249 }
250 len++;
251 if ((ret = malloc( len * sizeof(WCHAR) )))
252 len = GetShortPathNameW( file->TargetPath, ret, len );
253
254 done:
255 free( key );
256 *ret_len = len;
257 return ret;
258 }
259
deformat_environment(struct format * format,struct form_str * str,int * ret_len)260 static WCHAR *deformat_environment( struct format *format, struct form_str *str, int *ret_len )
261 {
262 WCHAR *key, *ret = NULL;
263 DWORD len;
264
265 if (!(key = malloc((str->len + 1) * sizeof(WCHAR)))) return NULL;
266 lstrcpynW(key, get_formstr_data(format, str), str->len + 1);
267
268 if ((len = GetEnvironmentVariableW( key, NULL, 0 )))
269 {
270 len++;
271 if ((ret = malloc( len * sizeof(WCHAR) )))
272 *ret_len = GetEnvironmentVariableW( key, ret, len );
273 }
274 free( key );
275 return ret;
276 }
277
deformat_literal(struct format * format,struct form_str * str,BOOL * propfound,int * type,int * len)278 static WCHAR *deformat_literal( struct format *format, struct form_str *str, BOOL *propfound,
279 int *type, int *len )
280 {
281 LPCWSTR data = get_formstr_data(format, str);
282 WCHAR *replaced = NULL;
283 char ch = data[0];
284
285 if (ch == '\\')
286 {
287 str->n++;
288 if (str->len == 1)
289 {
290 str->len = 0;
291 replaced = NULL;
292 }
293 else
294 {
295 str->len = 1;
296 replaced = dup_formstr( format, str, len );
297 }
298 }
299 else if (ch == '~')
300 {
301 if (str->len != 1)
302 replaced = NULL;
303 else if ((replaced = malloc( sizeof(WCHAR) )))
304 {
305 *replaced = 0;
306 *len = 0;
307 }
308 }
309 else if (ch == '%' || ch == '#' || ch == '!' || ch == '$')
310 {
311 str->n++;
312 str->len--;
313
314 switch (ch)
315 {
316 case '%':
317 replaced = deformat_environment( format, str, len ); break;
318 case '#':
319 replaced = deformat_file( format, str, FALSE, len ); break;
320 case '!':
321 replaced = deformat_file( format, str, TRUE, len ); break;
322 case '$':
323 replaced = deformat_component( format, str, len ); break;
324 }
325
326 *type = FORMAT_LITERAL;
327 }
328 else
329 {
330 replaced = deformat_property( format, str, len );
331 *type = FORMAT_LITERAL;
332
333 if (replaced)
334 *propfound = TRUE;
335 else
336 format->propfailed = TRUE;
337 }
338
339 return replaced;
340 }
341
build_default_format(const MSIRECORD * record)342 static WCHAR *build_default_format( const MSIRECORD *record )
343 {
344 int i, count = MSI_RecordGetFieldCount( record );
345 WCHAR *ret, *tmp, buf[26];
346 DWORD size = 1;
347
348 if (!(ret = malloc( sizeof(*ret) ))) return NULL;
349 ret[0] = 0;
350
351 for (i = 1; i <= count; i++)
352 {
353 size += swprintf( buf, ARRAY_SIZE(buf), L"%d: [%d] ", i, i );
354 if (!(tmp = realloc( ret, size * sizeof(*ret) )))
355 {
356 free( ret );
357 return NULL;
358 }
359 ret = tmp;
360 lstrcatW( ret, buf );
361 }
362 return ret;
363 }
364
format_is_number(WCHAR x)365 static BOOL format_is_number(WCHAR x)
366 {
367 return ((x >= '0') && (x <= '9'));
368 }
369
format_str_is_number(LPWSTR str)370 static BOOL format_str_is_number(LPWSTR str)
371 {
372 LPWSTR ptr;
373
374 for (ptr = str; *ptr; ptr++)
375 if (!format_is_number(*ptr))
376 return FALSE;
377
378 return TRUE;
379 }
380
format_is_alpha(WCHAR x)381 static BOOL format_is_alpha(WCHAR x)
382 {
383 return (!format_is_number(x) && x != '\0' &&
384 x != '[' && x != ']' && x != '{' && x != '}');
385 }
386
format_is_literal(WCHAR x)387 static BOOL format_is_literal(WCHAR x)
388 {
389 return (format_is_alpha(x) || format_is_number(x));
390 }
391
format_lex(struct format * format,struct form_str ** out)392 static int format_lex(struct format *format, struct form_str **out)
393 {
394 int type, len = 1;
395 struct form_str *str;
396 LPCWSTR data;
397 WCHAR ch;
398
399 *out = NULL;
400
401 if (!format->deformatted)
402 return FORMAT_NULL;
403
404 *out = calloc(1, sizeof(**out));
405 if (!*out)
406 return FORMAT_FAIL;
407
408 str = *out;
409 str->n = format->n;
410 str->len = 1;
411 data = get_formstr_data(format, str);
412
413 ch = data[0];
414 switch (ch)
415 {
416 case '{': type = FORMAT_LBRACE; break;
417 case '}': type = FORMAT_RBRACE; break;
418 case '[': type = FORMAT_LBRACK; break;
419 case ']': type = FORMAT_RBRACK; break;
420 case '~': type = FORMAT_PROPNULL; break;
421 case '\0': type = FORMAT_NULL; break;
422
423 default:
424 type = 0;
425 }
426
427 if (type)
428 {
429 str->type = type;
430 format->n++;
431 return type;
432 }
433
434 if (ch == '\\')
435 {
436 while (data[len] && data[len] != ']')
437 len++;
438
439 type = FORMAT_ESCAPE;
440 }
441 else if (format_is_alpha(ch))
442 {
443 while (format_is_literal(data[len]))
444 len++;
445
446 type = FORMAT_LITERAL;
447 }
448 else if (format_is_number(ch))
449 {
450 while (format_is_number(data[len]))
451 len++;
452
453 type = FORMAT_NUMBER;
454
455 if (data[len] != ']')
456 {
457 while (format_is_literal(data[len]))
458 len++;
459
460 type = FORMAT_LITERAL;
461 }
462 }
463 else
464 {
465 ERR("Got unknown character %c(%x)\n", ch, ch);
466 return FORMAT_ERROR;
467 }
468
469 format->n += len;
470 str->len = len;
471 str->type = type;
472
473 return type;
474 }
475
format_replace(struct format * format,BOOL propfound,BOOL nonprop,int oldsize,int type,WCHAR * replace,int len)476 static struct form_str *format_replace( struct format *format, BOOL propfound, BOOL nonprop,
477 int oldsize, int type, WCHAR *replace, int len )
478 {
479 struct form_str *ret;
480 LPWSTR str, ptr;
481 DWORD size = 0;
482 int n;
483
484 if (replace)
485 {
486 if (!len)
487 size = 1;
488 else
489 size = len;
490 }
491
492 size -= oldsize;
493 size = format->len + size + 1;
494
495 if (size <= 1)
496 {
497 free(format->deformatted);
498 format->deformatted = NULL;
499 format->len = 0;
500 return NULL;
501 }
502
503 str = malloc(size * sizeof(WCHAR));
504 if (!str)
505 return NULL;
506
507 str[0] = '\0';
508 memcpy(str, format->deformatted, format->n * sizeof(WCHAR));
509 n = format->n;
510
511 if (replace)
512 {
513 if (!len) str[n++] = 0;
514 else
515 {
516 memcpy( str + n, replace, len * sizeof(WCHAR) );
517 n += len;
518 str[n] = 0;
519 }
520 }
521
522 ptr = &format->deformatted[format->n + oldsize];
523 memcpy(&str[n], ptr, (lstrlenW(ptr) + 1) * sizeof(WCHAR));
524
525 free(format->deformatted);
526 format->deformatted = str;
527 format->len = size - 1;
528
529 /* don't reformat the NULL */
530 if (replace && !len)
531 format->n++;
532
533 if (!replace)
534 return NULL;
535
536 ret = calloc(1, sizeof(*ret));
537 if (!ret)
538 return NULL;
539
540 ret->len = len;
541 ret->type = type;
542 ret->n = format->n;
543 ret->propfound = propfound;
544 ret->nonprop = nonprop;
545
546 return ret;
547 }
548
replace_stack_group(struct format * format,struct stack * values,BOOL * propfound,BOOL * nonprop,int * oldsize,int * type,int * len)549 static WCHAR *replace_stack_group( struct format *format, struct stack *values,
550 BOOL *propfound, BOOL *nonprop,
551 int *oldsize, int *type, int *len )
552 {
553 WCHAR *replaced;
554 struct form_str *content, *node;
555 int n;
556
557 *nonprop = FALSE;
558 *propfound = FALSE;
559
560 node = stack_pop(values);
561 n = node->n;
562 *oldsize = node->len;
563 free(node);
564
565 while ((node = stack_pop(values)))
566 {
567 *oldsize += node->len;
568
569 if (node->nonprop)
570 *nonprop = TRUE;
571
572 if (node->propfound)
573 *propfound = TRUE;
574
575 free(node);
576 }
577
578 content = calloc(1, sizeof(*content));
579 content->n = n;
580 content->len = *oldsize;
581 content->type = FORMAT_LITERAL;
582
583 if (!format->groupfailed && (*oldsize == 2 ||
584 (format->propfailed && !*nonprop)))
585 {
586 free(content);
587 return NULL;
588 }
589 else if (format->deformatted[content->n + 1] == '{' &&
590 format->deformatted[content->n + content->len - 2] == '}')
591 {
592 format->groupfailed = FALSE;
593 content->len = 0;
594 }
595 else if (*propfound && !*nonprop &&
596 !format->groupfailed && format->groups == 0)
597 {
598 content->n++;
599 content->len -= 2;
600 }
601 else
602 {
603 if (format->groups != 0)
604 format->groupfailed = TRUE;
605
606 *nonprop = TRUE;
607 }
608
609 replaced = dup_formstr( format, content, len );
610 *type = content->type;
611 free(content);
612
613 if (format->groups == 0)
614 format->propfailed = FALSE;
615
616 return replaced;
617 }
618
replace_stack_prop(struct format * format,struct stack * values,BOOL * propfound,BOOL * nonprop,int * oldsize,int * type,int * len)619 static WCHAR *replace_stack_prop( struct format *format, struct stack *values,
620 BOOL *propfound, BOOL *nonprop,
621 int *oldsize, int *type, int *len )
622 {
623 WCHAR *replaced;
624 struct form_str *content, *node;
625 int n;
626
627 *propfound = FALSE;
628 *nonprop = FALSE;
629
630 node = stack_pop(values);
631 n = node->n;
632 *oldsize = node->len;
633 *type = stack_peek(values)->type;
634 free(node);
635
636 while ((node = stack_pop(values)))
637 {
638 *oldsize += node->len;
639
640 if (*type != FORMAT_ESCAPE &&
641 stack_peek(values) && node->type != *type)
642 *type = FORMAT_LITERAL;
643
644 free(node);
645 }
646
647 content = calloc(1, sizeof(*content));
648 content->n = n + 1;
649 content->len = *oldsize - 2;
650 content->type = *type;
651
652 if (*type == FORMAT_NUMBER && format->record)
653 {
654 replaced = deformat_index( format, content, len );
655 if (replaced)
656 *propfound = TRUE;
657 else
658 format->propfailed = TRUE;
659
660 if (replaced)
661 *type = format_str_is_number(replaced) ?
662 FORMAT_NUMBER : FORMAT_LITERAL;
663 }
664 else if (format->package)
665 {
666 replaced = deformat_literal( format, content, propfound, type, len );
667 }
668 else
669 {
670 *nonprop = TRUE;
671 content->n--;
672 content->len += 2;
673 replaced = dup_formstr( format, content, len );
674 }
675 free(content);
676 return replaced;
677 }
678
replace_stack(struct format * format,struct stack * stack,struct stack * values)679 static UINT replace_stack(struct format *format, struct stack *stack, struct stack *values)
680 {
681 WCHAR *replaced = NULL;
682 struct form_str *beg, *top, *node;
683 BOOL propfound = FALSE, nonprop = FALSE, group = FALSE;
684 int type, n, len = 0, oldsize = 0;
685
686 node = stack_peek(values);
687 type = node->type;
688 n = node->n;
689
690 if (type == FORMAT_LBRACK)
691 replaced = replace_stack_prop( format, values, &propfound,
692 &nonprop, &oldsize, &type, &len );
693 else if (type == FORMAT_LBRACE)
694 {
695 replaced = replace_stack_group( format, values, &propfound,
696 &nonprop, &oldsize, &type, &len );
697 group = TRUE;
698 }
699
700 format->n = n;
701 beg = format_replace( format, propfound, nonprop, oldsize, type, replaced, len );
702 free(replaced);
703 if (!beg)
704 return ERROR_SUCCESS;
705
706 format->n = beg->n + beg->len;
707
708 top = stack_peek(stack);
709 if (top)
710 {
711 type = top->type;
712
713 if ((type == FORMAT_LITERAL || type == FORMAT_NUMBER) &&
714 type == beg->type)
715 {
716 top->len += beg->len;
717
718 if (group)
719 top->nonprop = FALSE;
720
721 if (type == FORMAT_LITERAL)
722 top->nonprop = beg->nonprop;
723
724 if (beg->propfound)
725 top->propfound = TRUE;
726
727 free(beg);
728 return ERROR_SUCCESS;
729 }
730 }
731
732 stack_push(stack, beg);
733 return ERROR_SUCCESS;
734 }
735
verify_format(LPWSTR data)736 static BOOL verify_format(LPWSTR data)
737 {
738 int count = 0;
739
740 while (*data)
741 {
742 if (*data == '[' && *(data - 1) != '\\')
743 count++;
744 else if (*data == ']')
745 count--;
746
747 data++;
748 }
749
750 if (count > 0)
751 return FALSE;
752
753 return TRUE;
754 }
755
deformat_string_internal(MSIPACKAGE * package,LPCWSTR ptr,WCHAR ** data,DWORD * len,MSIRECORD * record)756 static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
757 WCHAR** data, DWORD *len,
758 MSIRECORD* record)
759 {
760 struct format format;
761 struct form_str *str = NULL;
762 struct stack *stack, *temp;
763 struct form_str *node;
764 int type;
765
766 if (!ptr)
767 {
768 *data = NULL;
769 *len = 0;
770 return ERROR_SUCCESS;
771 }
772
773 *data = wcsdup(ptr);
774 *len = lstrlenW(ptr);
775
776 ZeroMemory(&format, sizeof(format));
777 format.package = package;
778 format.record = record;
779 format.deformatted = *data;
780 format.len = *len;
781
782 if (!verify_format(*data))
783 return ERROR_SUCCESS;
784
785 stack = create_stack();
786 temp = create_stack();
787
788 while ((type = format_lex(&format, &str)) != FORMAT_NULL)
789 {
790 if (type == FORMAT_LBRACK || type == FORMAT_LBRACE ||
791 type == FORMAT_LITERAL || type == FORMAT_NUMBER ||
792 type == FORMAT_ESCAPE || type == FORMAT_PROPNULL)
793 {
794 if (type == FORMAT_LBRACE)
795 {
796 format.propfailed = FALSE;
797 format.groups++;
798 }
799 else if (type == FORMAT_ESCAPE &&
800 !stack_find(stack, FORMAT_LBRACK))
801 {
802 format.n -= str->len - 1;
803 str->len = 1;
804 }
805
806 stack_push(stack, str);
807 }
808 else if (type == FORMAT_RBRACK || type == FORMAT_RBRACE)
809 {
810 if (type == FORMAT_RBRACE)
811 format.groups--;
812
813 stack_push(stack, str);
814
815 if (stack_find(stack, left_type(type)))
816 {
817 do
818 {
819 node = stack_pop(stack);
820 stack_push(temp, node);
821 } while (node->type != left_type(type));
822
823 replace_stack(&format, stack, temp);
824 }
825 }
826 }
827
828 *data = format.deformatted;
829 *len = format.len;
830
831 free(str);
832 free_stack(stack);
833 free_stack(temp);
834
835 return ERROR_SUCCESS;
836 }
837
MSI_FormatRecordW(MSIPACKAGE * package,MSIRECORD * record,LPWSTR buffer,LPDWORD size)838 UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
839 LPDWORD size )
840 {
841 WCHAR *format, *deformated = NULL;
842 UINT rc = ERROR_INVALID_PARAMETER;
843 DWORD len;
844 MSIRECORD *record_deformated;
845 int field_count, i;
846
847 TRACE("%p %p %p %p\n", package, record, buffer, size);
848 dump_record(record);
849
850 if (!(format = msi_dup_record_field( record, 0 )))
851 format = build_default_format( record );
852
853 field_count = MSI_RecordGetFieldCount(record);
854 record_deformated = MSI_CloneRecord(record);
855 if (!record_deformated)
856 {
857 rc = ERROR_OUTOFMEMORY;
858 goto end;
859 }
860 MSI_RecordSetStringW(record_deformated, 0, format);
861 for (i = 1; i <= field_count; i++)
862 {
863 if (MSI_RecordGetString(record, i))
864 {
865 deformat_string_internal(package, MSI_RecordGetString(record, i), &deformated, &len, NULL);
866 MSI_RecordSetStringW(record_deformated, i, deformated);
867 free(deformated);
868 }
869 }
870
871 deformat_string_internal(package, format, &deformated, &len, record_deformated);
872 if (buffer)
873 {
874 if (*size>len)
875 {
876 memcpy(buffer,deformated,len*sizeof(WCHAR));
877 rc = ERROR_SUCCESS;
878 buffer[len] = 0;
879 }
880 else
881 {
882 if (*size > 0)
883 {
884 memcpy(buffer,deformated,(*size)*sizeof(WCHAR));
885 buffer[(*size)-1] = 0;
886 }
887 rc = ERROR_MORE_DATA;
888 }
889 }
890 else rc = ERROR_SUCCESS;
891
892 *size = len;
893 msiobj_release(&record_deformated->hdr);
894 end:
895 free( format );
896 free( deformated );
897 return rc;
898 }
899
MsiFormatRecordW(MSIHANDLE hInstall,MSIHANDLE hRecord,WCHAR * szResult,DWORD * sz)900 UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, WCHAR *szResult, DWORD *sz )
901 {
902 UINT r = ERROR_INVALID_HANDLE;
903 MSIPACKAGE *package;
904 MSIRECORD *record;
905
906 TRACE( "%lu, %lu, %p, %p\n", hInstall, hRecord, szResult, sz );
907
908 record = msihandle2msiinfo(hRecord, MSIHANDLETYPE_RECORD);
909 if (!record)
910 return ERROR_INVALID_HANDLE;
911
912 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
913 if (!package)
914 {
915 LPWSTR value = NULL;
916 MSIHANDLE remote;
917
918 if ((remote = msi_get_remote(hInstall)))
919 {
920 __TRY
921 {
922 r = remote_FormatRecord(remote, (struct wire_record *)&record->count, &value);
923 }
924 __EXCEPT(rpc_filter)
925 {
926 r = GetExceptionCode();
927 }
928 __ENDTRY
929
930 if (!r)
931 r = msi_strncpyW(value, -1, szResult, sz);
932
933 midl_user_free(value);
934 msiobj_release(&record->hdr);
935 return r;
936 }
937 }
938
939 if (!sz)
940 {
941 msiobj_release( &record->hdr );
942 if (szResult)
943 return ERROR_INVALID_PARAMETER;
944 else
945 return ERROR_SUCCESS;
946 }
947
948 r = MSI_FormatRecordW( package, record, szResult, sz );
949 msiobj_release( &record->hdr );
950 if (package)
951 msiobj_release( &package->hdr );
952 return r;
953 }
954
MsiFormatRecordA(MSIHANDLE hinst,MSIHANDLE hrec,char * buf,DWORD * sz)955 UINT WINAPI MsiFormatRecordA(MSIHANDLE hinst, MSIHANDLE hrec, char *buf, DWORD *sz)
956 {
957 MSIPACKAGE *package;
958 MSIRECORD *rec;
959 LPWSTR value;
960 DWORD len;
961 UINT r;
962
963 TRACE( "%lu, %lu, %p, %p\n", hinst, hrec, buf, sz );
964
965 rec = msihandle2msiinfo(hrec, MSIHANDLETYPE_RECORD);
966 if (!rec)
967 return ERROR_INVALID_HANDLE;
968
969 package = msihandle2msiinfo(hinst, MSIHANDLETYPE_PACKAGE);
970 if (!package)
971 {
972 LPWSTR value = NULL;
973 MSIHANDLE remote;
974
975 if ((remote = msi_get_remote(hinst)))
976 {
977 __TRY
978 {
979 r = remote_FormatRecord(remote, (struct wire_record *)&rec->count, &value);
980 }
981 __EXCEPT(rpc_filter)
982 {
983 r = GetExceptionCode();
984 }
985 __ENDTRY
986
987 if (!r)
988 r = msi_strncpyWtoA(value, -1, buf, sz, TRUE);
989
990 midl_user_free(value);
991 msiobj_release(&rec->hdr);
992 return r;
993 }
994 }
995
996 r = MSI_FormatRecordW(package, rec, NULL, &len);
997 if (r != ERROR_SUCCESS)
998 return r;
999
1000 value = malloc(++len * sizeof(WCHAR));
1001 if (!value)
1002 goto done;
1003
1004 r = MSI_FormatRecordW(package, rec, value, &len);
1005 if (!r)
1006 r = msi_strncpyWtoA(value, len, buf, sz, FALSE);
1007
1008 free(value);
1009 done:
1010 msiobj_release(&rec->hdr);
1011 if (package) msiobj_release(&package->hdr);
1012 return r;
1013 }
1014
1015 /* wrapper to resist a need for a full rewrite right now */
deformat_string(MSIPACKAGE * package,const WCHAR * fmt,WCHAR ** data)1016 DWORD deformat_string( MSIPACKAGE *package, const WCHAR *fmt, WCHAR **data )
1017 {
1018 DWORD len;
1019 MSIRECORD *rec;
1020
1021 *data = NULL;
1022 if (!fmt) return 0;
1023 if (!(rec = MSI_CreateRecord( 1 ))) return 0;
1024
1025 MSI_RecordSetStringW( rec, 0, fmt );
1026 MSI_FormatRecordW( package, rec, NULL, &len );
1027 if (!(*data = malloc( ++len * sizeof(WCHAR) )))
1028 {
1029 msiobj_release( &rec->hdr );
1030 return 0;
1031 }
1032 MSI_FormatRecordW( package, rec, *data, &len );
1033 msiobj_release( &rec->hdr );
1034 return len;
1035 }
1036