xref: /reactos/dll/win32/inseng/icif.c (revision cc439606)
1 /*
2  * Copyright 2016 Michael Müller
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #define COBJMACROS
20 
21 #include "config.h"
22 
23 #include <stdarg.h>
24 #include <string.h>
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "rpcproxy.h"
31 #include "inseng.h"
32 
33 #include "inseng_private.h"
34 
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 
38 WINE_DEFAULT_DEBUG_CHANNEL(inseng);
39 
40 #define DEFAULT_INSTALLER_DESC "Active Setup Installation"
41 
42 struct cifgroup
43 {
44     ICifGroup ICifGroup_iface;
45 
46     struct list entry;
47 
48     ICifFile *parent;
49 
50     char *id;
51     char *description;
52     DWORD priority;
53 };
54 
55 struct ciffenum_components
56 {
57     IEnumCifComponents IEnumCifComponents_iface;
58     LONG ref;
59 
60     ICifFile *file;
61     struct list *start;
62     struct list *position;
63 
64     char *group_id;
65 };
66 
67 struct ciffenum_groups
68 {
69     IEnumCifGroups IEnumCifGroups_iface;
70     LONG ref;
71 
72     ICifFile *file;
73     struct list *start;
74     struct list *position;
75 };
76 
77 struct url_info
78 {
79     struct list entry;
80     INT index;
81     char *url;
82     DWORD flags;
83 };
84 
85 struct dependency_info
86 {
87     struct list entry;
88     char *id;
89     char *type;
90 };
91 
92 struct cifcomponent
93 {
94     ICifComponent ICifComponent_iface;
95 
96     struct list entry;
97 
98     ICifFile *parent;
99 
100     char *id;
101     char *guid;
102     char *description;
103     char *details;
104     char *group;
105 
106 
107     DWORD version;
108     DWORD build;
109     char *patchid;
110 
111     char *locale;
112     char *key_uninstall;
113 
114     DWORD size_win;
115     DWORD size_app;
116     DWORD size_download;
117     DWORD size_extracted;
118 
119     char *key_success;
120     char *key_progress;
121     char *key_cancel;
122 
123     DWORD as_aware;
124     DWORD reboot;
125     DWORD admin;
126     DWORD visibleui;
127 
128     DWORD priority;
129     DWORD platform;
130 
131     struct list dependencies;
132     struct list urls;
133 
134     /* mode */
135     /* det version */
136     /* one component */
137     /* custom data */
138 
139     /* in memory state */
140     DWORD queue_state;
141     DWORD current_priority;
142     DWORD size_actual_download;
143     BOOL downloaded;
144     BOOL installed;
145 };
146 
147 struct ciffile
148 {
149     ICifFile ICifFile_iface;
150     LONG ref;
151 
152     struct list components;
153     struct list groups;
154 
155     char *name;
156 };
157 
158 static inline struct ciffile *impl_from_ICiffile(ICifFile *iface)
159 {
160     return CONTAINING_RECORD(iface, struct ciffile, ICifFile_iface);
161 }
162 
163 static inline struct cifcomponent *impl_from_ICifComponent(ICifComponent *iface)
164 {
165     return CONTAINING_RECORD(iface, struct cifcomponent, ICifComponent_iface);
166 }
167 
168 static inline struct cifgroup *impl_from_ICifGroup(ICifGroup *iface)
169 {
170     return CONTAINING_RECORD(iface, struct cifgroup, ICifGroup_iface);
171 }
172 
173 static inline struct ciffenum_components *impl_from_IEnumCifComponents(IEnumCifComponents *iface)
174 {
175     return CONTAINING_RECORD(iface, struct ciffenum_components, IEnumCifComponents_iface);
176 }
177 
178 static inline struct ciffenum_groups *impl_from_IEnumCifGroups(IEnumCifGroups *iface)
179 {
180     return CONTAINING_RECORD(iface, struct ciffenum_groups, IEnumCifGroups_iface);
181 }
182 
183 static HRESULT enum_components_create(ICifFile *file, struct list *start, char *group_id, IEnumCifComponents **iface);
184 
185 static HRESULT copy_substring_null(char *dest, int max_len, char *src)
186 {
187     if (!src)
188         return E_FAIL;
189 
190     if (max_len <= 0)
191         return S_OK;
192 
193     if (!dest)
194         return E_FAIL;
195 
196     while (*src && max_len-- > 1)
197         *dest++ = *src++;
198     *dest = 0;
199 
200     return S_OK;
201 }
202 
203 static void url_entry_free(struct url_info *url)
204 {
205     heap_free(url->url);
206     heap_free(url);
207 }
208 
209 static void dependency_entry_free(struct dependency_info *dependency)
210 {
211     heap_free(dependency->id);
212     heap_free(dependency);
213 }
214 
215 static void component_free(struct cifcomponent *comp)
216 {
217     struct dependency_info *dependency, *dependency_next;
218     struct url_info *url, *url_next;
219 
220     heap_free(comp->id);
221     heap_free(comp->guid);
222     heap_free(comp->description);
223     heap_free(comp->details);
224     heap_free(comp->group);
225 
226     heap_free(comp->patchid);
227 
228     heap_free(comp->locale);
229     heap_free(comp->key_uninstall);
230 
231     heap_free(comp->key_success);
232     heap_free(comp->key_progress);
233     heap_free(comp->key_cancel);
234 
235     LIST_FOR_EACH_ENTRY_SAFE(dependency, dependency_next, &comp->dependencies, struct dependency_info, entry)
236     {
237         list_remove(&dependency->entry);
238         dependency_entry_free(dependency);
239     }
240 
241     LIST_FOR_EACH_ENTRY_SAFE(url, url_next, &comp->urls, struct url_info, entry)
242     {
243         list_remove(&url->entry);
244         url_entry_free(url);
245     }
246 
247     heap_free(comp);
248 }
249 
250 static void group_free(struct cifgroup *group)
251 {
252     heap_free(group->id);
253     heap_free(group->description);
254     heap_free(group);
255 }
256 
257 static HRESULT WINAPI group_GetID(ICifGroup *iface, char *id, DWORD size)
258 {
259     struct cifgroup *This = impl_from_ICifGroup(iface);
260 
261     TRACE("(%p)->(%p, %u)\n", This, id, size);
262 
263     return copy_substring_null(id, size, This->id);
264 }
265 
266 static HRESULT WINAPI group_GetDescription(ICifGroup *iface, char *desc, DWORD size)
267 {
268     struct cifgroup *This = impl_from_ICifGroup(iface);
269 
270     TRACE("(%p)->(%p, %u)\n", This, desc, size);
271 
272     return copy_substring_null(desc, size, This->description);
273 }
274 
275 static DWORD WINAPI group_GetPriority(ICifGroup *iface)
276 {
277     struct cifgroup *This = impl_from_ICifGroup(iface);
278 
279     TRACE("(%p)\n", This);
280 
281     return This->priority;
282 }
283 
284 static HRESULT WINAPI group_EnumComponents(ICifGroup *iface, IEnumCifComponents **enum_components, DWORD filter, LPVOID pv)
285 {
286     struct cifgroup *This = impl_from_ICifGroup(iface);
287     struct ciffile *file;
288 
289     TRACE("(%p)->(%p, %u, %p)\n", This, enum_components, filter, pv);
290 
291     if (filter)
292         FIXME("filter (%x) not supported\n", filter);
293     if (pv)
294         FIXME("how to handle pv (%p)?\n", pv);
295 
296     file = impl_from_ICiffile(This->parent);
297     return enum_components_create(This->parent, &file->components, This->id, enum_components);
298 }
299 
300 static DWORD WINAPI group_GetCurrentPriority(ICifGroup *iface)
301 {
302     struct cifgroup *This = impl_from_ICifGroup(iface);
303 
304     FIXME("(%p): stub\n", This);
305 
306     return 0;
307 }
308 
309 static const ICifGroupVtbl cifgroupVtbl =
310 {
311     group_GetID,
312     group_GetDescription,
313     group_GetPriority,
314     group_EnumComponents,
315     group_GetCurrentPriority,
316 };
317 
318 void component_set_actual_download_size(ICifComponent *iface, DWORD size)
319 {
320     struct cifcomponent *This = impl_from_ICifComponent(iface);
321 
322     This->size_actual_download = size;
323 }
324 
325 void component_set_downloaded(ICifComponent *iface, BOOL value)
326 {
327     struct cifcomponent *This = impl_from_ICifComponent(iface);
328 
329     This->downloaded = value;
330 }
331 
332 void component_set_installed(ICifComponent *iface, BOOL value)
333 {
334     struct cifcomponent *This = impl_from_ICifComponent(iface);
335 
336     This->installed = value;
337 }
338 
339 char *component_get_id(ICifComponent *iface)
340 {
341     struct cifcomponent *This = impl_from_ICifComponent(iface);
342 
343     return This->id;
344 }
345 
346 static HRESULT WINAPI component_GetID(ICifComponent *iface, char *id, DWORD size)
347 {
348     struct cifcomponent *This = impl_from_ICifComponent(iface);
349 
350     TRACE("(%p)->(%p, %u)\n", This, id, size);
351 
352     return copy_substring_null(id, size, This->id);
353 }
354 
355 static HRESULT WINAPI component_GetGUID(ICifComponent *iface, char *guid, DWORD size)
356 {
357     struct cifcomponent *This = impl_from_ICifComponent(iface);
358 
359     TRACE("(%p)->(%p, %u)\n", This, guid, size);
360 
361     return copy_substring_null(guid, size, This->guid);
362 }
363 
364 static HRESULT WINAPI component_GetDescription(ICifComponent *iface, char *desc, DWORD size)
365 {
366     struct cifcomponent *This = impl_from_ICifComponent(iface);
367 
368     TRACE("(%p)->(%p, %u)\n", This, desc, size);
369 
370     return copy_substring_null(desc, size, This->description);
371 }
372 
373 static HRESULT WINAPI component_GetDetails(ICifComponent *iface, char *details, DWORD size)
374 {
375     struct cifcomponent *This = impl_from_ICifComponent(iface);
376 
377     TRACE("(%p)->(%p, %u)\n", This, details, size);
378 
379     return copy_substring_null(details, size, This->details);
380 }
381 
382 static HRESULT WINAPI component_GetUrl(ICifComponent *iface, UINT index, char *url, DWORD size, DWORD *flags)
383 {
384     struct cifcomponent *This = impl_from_ICifComponent(iface);
385     struct url_info *entry;
386 
387     TRACE("(%p)->(%u, %p, %u, %p)\n", This, index, url, size, flags);
388 
389     /* FIXME: check how functions behaves for url == NULL */
390 
391     if (!flags)
392         return E_FAIL;
393 
394     LIST_FOR_EACH_ENTRY(entry, &This->urls, struct url_info, entry)
395     {
396         if (entry->index != index)
397             continue;
398 
399         *flags = entry->flags;
400         return copy_substring_null(url, size, entry->url);
401     }
402 
403     return E_FAIL;
404 }
405 
406 static HRESULT WINAPI component_GetFileExtractList(ICifComponent *iface, UINT index, char *list, DWORD size)
407 {
408     struct cifcomponent *This = impl_from_ICifComponent(iface);
409 
410     FIXME("(%p)->(%u, %p, %u): stub\n", This, index, list, size);
411 
412     return E_NOTIMPL;
413 }
414 
415 static HRESULT WINAPI component_GetUrlCheckRange(ICifComponent *iface, UINT index, DWORD *min, DWORD *max)
416 {
417     struct cifcomponent *This = impl_from_ICifComponent(iface);
418 
419     FIXME("(%p)->(%u, %p, %p): stub\n", This, index, min, max);
420 
421     return E_NOTIMPL;
422 }
423 
424 static HRESULT WINAPI component_GetCommand(ICifComponent *iface, UINT index, char *cmd, DWORD cmd_size, char *switches, DWORD switch_size, DWORD *type)
425 {
426     struct cifcomponent *This = impl_from_ICifComponent(iface);
427 
428     FIXME("(%p)->(%u, %p, %u, %p, %u, %p): stub\n", This, index, cmd, cmd_size, switches, switch_size, type);
429 
430     return E_NOTIMPL;
431 }
432 
433 static HRESULT WINAPI component_GetVersion(ICifComponent *iface, DWORD *version, DWORD *build)
434 {
435     struct cifcomponent *This = impl_from_ICifComponent(iface);
436 
437     TRACE("(%p)->(%p, %p)\n", This, version, build);
438 
439     if (!version || !build)
440         return E_FAIL;
441 
442     *version = This->version;
443     *build = This->build;
444 
445     return S_OK;
446 }
447 
448 static HRESULT WINAPI component_GetLocale(ICifComponent *iface, char *locale, DWORD size)
449 {
450     struct cifcomponent *This = impl_from_ICifComponent(iface);
451 
452     TRACE("(%p)->(%p, %u)\n", This, locale, size);
453 
454     return copy_substring_null(locale, size, This->locale);
455 }
456 
457 static HRESULT WINAPI component_GetUninstallKey(ICifComponent *iface, char *key, DWORD size)
458 {
459     struct cifcomponent *This = impl_from_ICifComponent(iface);
460 
461     TRACE("(%p)->(%p, %u)\n", This, key, size);
462 
463     return copy_substring_null(key, size, This->key_uninstall);
464 }
465 
466 static HRESULT WINAPI component_GetInstalledSize(ICifComponent *iface, DWORD *win, DWORD *app)
467 {
468     struct cifcomponent *This = impl_from_ICifComponent(iface);
469 
470     TRACE("(%p)->(%p, %p)\n", This, win, app);
471 
472     if (!win || !app)
473         return E_FAIL;
474 
475     *win = This->size_win;
476     *app = This->size_app;
477 
478     return S_OK;
479 }
480 
481 static DWORD WINAPI component_GetDownloadSize(ICifComponent *iface)
482 {
483     struct cifcomponent *This = impl_from_ICifComponent(iface);
484 
485     TRACE("(%p)\n", This);
486 
487     return This->size_download;
488 }
489 
490 static DWORD WINAPI component_GetExtractSize(ICifComponent *iface)
491 {
492     struct cifcomponent *This = impl_from_ICifComponent(iface);
493 
494     TRACE("(%p)\n", This);
495 
496     return This->size_extracted;
497 }
498 
499 static HRESULT WINAPI component_GetSuccessKey(ICifComponent *iface, char *key, DWORD size)
500 {
501     struct cifcomponent *This = impl_from_ICifComponent(iface);
502 
503     TRACE("(%p)->(%p, %u)\n", This, key, size);
504 
505     return copy_substring_null(key, size, This->key_success);
506 }
507 
508 static HRESULT WINAPI component_GetProgressKeys(ICifComponent *iface, char *progress, DWORD progress_size,
509                                                 char *cancel, DWORD cancel_size)
510 {
511     struct cifcomponent *This = impl_from_ICifComponent(iface);
512     HRESULT hr;
513 
514     TRACE("(%p)->(%p, %u, %p, %u): semi-stub\n", This, progress, progress_size, cancel, cancel_size);
515 
516     hr = copy_substring_null(progress, progress_size, This->key_progress);
517     if (hr != S_OK) return hr;
518 
519     if (cancel_size > 0 && cancel)
520         *cancel = 0;
521 
522     return S_OK;
523 }
524 
525 static HRESULT WINAPI component_IsActiveSetupAware(ICifComponent *iface)
526 {
527     struct cifcomponent *This = impl_from_ICifComponent(iface);
528 
529     TRACE("(%p)\n", This);
530 
531     return This->as_aware ? S_OK : S_FALSE;
532 }
533 
534 static HRESULT WINAPI component_IsRebootRequired(ICifComponent *iface)
535 {
536     struct cifcomponent *This = impl_from_ICifComponent(iface);
537 
538     TRACE("(%p)\n", This);
539 
540     return This->reboot ? S_OK : S_FALSE;
541 }
542 
543 static HRESULT WINAPI component_RequiresAdminRights(ICifComponent *iface)
544 {
545     struct cifcomponent *This = impl_from_ICifComponent(iface);
546 
547     TRACE("(%p)\n", This);
548 
549     return This->admin ? S_OK : S_FALSE;
550 }
551 
552 static DWORD WINAPI component_GetPriority(ICifComponent *iface)
553 {
554     struct cifcomponent *This = impl_from_ICifComponent(iface);
555 
556     TRACE("(%p)\n", This);
557 
558     return This->priority;
559 }
560 
561 static HRESULT WINAPI component_GetDependency(ICifComponent *iface, UINT index, char *id, DWORD id_size, char *type, DWORD *ver, DWORD *build)
562 {
563     struct cifcomponent *This = impl_from_ICifComponent(iface);
564     struct dependency_info *entry;
565     ICifComponent *dependency;
566     int pos = 0;
567 
568     TRACE("(%p)->(%u, %p, %u, %p, %p, %p)\n", This, index, id, id_size, type, ver, build);
569 
570     if (!id || !ver || !build)
571         return E_FAIL;
572 
573     LIST_FOR_EACH_ENTRY(entry, &This->dependencies, struct dependency_info, entry)
574     {
575         if (pos++ < index)
576             continue;
577 
578         if (ICifFile_FindComponent(This->parent, entry->id, &dependency) == S_OK)
579         {
580             ICifComponent_GetVersion(dependency, ver, build);
581         }
582         else
583         {
584             *ver = -1;
585             *build = -1;
586         }
587 
588         if (entry->type)
589             *type = *entry->type;
590         else
591             *type = 'I';
592 
593         return copy_substring_null(id, id_size, entry->id);
594     }
595 
596     return E_FAIL;
597 }
598 
599 static DWORD WINAPI component_GetPlatform(ICifComponent *iface)
600 {
601     struct cifcomponent *This = impl_from_ICifComponent(iface);
602 
603     TRACE("(%p)\n", This);
604 
605     return This->platform;
606 }
607 
608 static HRESULT WINAPI component_GetMode(ICifComponent *iface, UINT index, char *mode, DWORD size)
609 {
610     struct cifcomponent *This = impl_from_ICifComponent(iface);
611 
612     FIXME("(%p)->(%u, %p, %u): stub\n", This, index, mode, size);
613 
614     return E_NOTIMPL;
615 }
616 
617 static HRESULT WINAPI component_GetGroup(ICifComponent *iface, char *id, DWORD size)
618 {
619     struct cifcomponent *This = impl_from_ICifComponent(iface);
620 
621     TRACE("(%p)->(%p, %u)\n", This, id, size);
622 
623     return copy_substring_null(id, size, This->group);
624 }
625 
626 static HRESULT WINAPI component_IsUIVisible(ICifComponent *iface)
627 {
628     struct cifcomponent *This = impl_from_ICifComponent(iface);
629 
630     TRACE("(%p)\n", This);
631 
632     return This->visibleui ? S_OK : S_FALSE;
633 }
634 
635 static HRESULT WINAPI component_GetPatchID(ICifComponent *iface, char *id, DWORD size)
636 {
637     struct cifcomponent *This = impl_from_ICifComponent(iface);
638 
639     TRACE("(%p)->(%p, %u)\n", This, id, size);
640 
641     return copy_substring_null(id, size, This->patchid);
642 }
643 
644 static HRESULT WINAPI component_GetDetVersion(ICifComponent *iface, char *dll, DWORD dll_size, char *entry, DWORD entry_size)
645 {
646     struct cifcomponent *This = impl_from_ICifComponent(iface);
647 
648     FIXME("(%p)->(%p, %u, %p, %u): stub\n", This, dll, dll_size, entry, entry_size);
649 
650     return E_NOTIMPL;
651 }
652 
653 static HRESULT WINAPI component_GetTreatAsOneComponents(ICifComponent *iface, UINT index, char *id, DWORD size)
654 {
655     struct cifcomponent *This = impl_from_ICifComponent(iface);
656 
657     FIXME("(%p)->(%u, %p, %u): stub\n", This, index, id, size);
658 
659     return E_NOTIMPL;
660 }
661 
662 static HRESULT WINAPI component_GetCustomData(ICifComponent *iface, char *key, char *data, DWORD size)
663 {
664     struct cifcomponent *This = impl_from_ICifComponent(iface);
665 
666     FIXME("(%p)->(%s, %p, %u): stub\n", This, debugstr_a(key), data, size);
667 
668     return E_NOTIMPL;
669 }
670 
671 static DWORD WINAPI component_IsComponentInstalled(ICifComponent *iface)
672 {
673     struct cifcomponent *This = impl_from_ICifComponent(iface);
674 
675     TRACE("(%p)\n", This);
676 
677     return This->installed;
678 }
679 
680 static HRESULT WINAPI component_IsComponentDownloaded(ICifComponent *iface)
681 {
682     struct cifcomponent *This = impl_from_ICifComponent(iface);
683 
684     TRACE("(%p)\n", This);
685 
686     return This->downloaded ? S_OK : S_FALSE;
687 }
688 
689 static DWORD WINAPI component_IsThisVersionInstalled(ICifComponent *iface, DWORD version, DWORD build, DWORD *ret_version, DWORD *ret_build)
690 {
691     struct cifcomponent *This = impl_from_ICifComponent(iface);
692 
693     FIXME("(%p)->(%u, %u, %p, %p): stub\n", This, version, build, ret_version, ret_build);
694 
695     return 0;
696 }
697 
698 static DWORD WINAPI component_GetInstallQueueState(ICifComponent *iface)
699 {
700     struct cifcomponent *This = impl_from_ICifComponent(iface);
701 
702     TRACE("(%p)\n", This);
703 
704     return This->queue_state;
705 }
706 
707 static HRESULT WINAPI component_SetInstallQueueState(ICifComponent *iface, DWORD state)
708 {
709     struct cifcomponent *This = impl_from_ICifComponent(iface);
710 
711     TRACE("(%p)->(%u)\n", This, state);
712 
713     This->queue_state = state;
714     return S_OK;
715 }
716 
717 static DWORD WINAPI component_GetActualDownloadSize(ICifComponent *iface)
718 {
719     struct cifcomponent *This = impl_from_ICifComponent(iface);
720 
721     TRACE("(%p)\n", This);
722 
723     return This->size_download;
724 }
725 
726 static DWORD WINAPI component_GetCurrentPriority(ICifComponent *iface)
727 {
728     struct cifcomponent *This = impl_from_ICifComponent(iface);
729 
730     TRACE("(%p)\n", This);
731 
732     return This->current_priority;
733 }
734 
735 
736 static HRESULT WINAPI component_SetCurrentPriority(ICifComponent *iface, DWORD priority)
737 {
738     struct cifcomponent *This = impl_from_ICifComponent(iface);
739 
740     TRACE("(%p)->(%u)\n", This, priority);
741 
742     This->current_priority = priority;
743     return S_OK;
744 }
745 
746 static const ICifComponentVtbl cifcomponentVtbl =
747 {
748     component_GetID,
749     component_GetGUID,
750     component_GetDescription,
751     component_GetDetails,
752     component_GetUrl,
753     component_GetFileExtractList,
754     component_GetUrlCheckRange,
755     component_GetCommand,
756     component_GetVersion,
757     component_GetLocale,
758     component_GetUninstallKey,
759     component_GetInstalledSize,
760     component_GetDownloadSize,
761     component_GetExtractSize,
762     component_GetSuccessKey,
763     component_GetProgressKeys,
764     component_IsActiveSetupAware,
765     component_IsRebootRequired,
766     component_RequiresAdminRights,
767     component_GetPriority,
768     component_GetDependency,
769     component_GetPlatform,
770     component_GetMode,
771     component_GetGroup,
772     component_IsUIVisible,
773     component_GetPatchID,
774     component_GetDetVersion,
775     component_GetTreatAsOneComponents,
776     component_GetCustomData,
777     component_IsComponentInstalled,
778     component_IsComponentDownloaded,
779     component_IsThisVersionInstalled,
780     component_GetInstallQueueState,
781     component_SetInstallQueueState,
782     component_GetActualDownloadSize,
783     component_GetCurrentPriority,
784     component_SetCurrentPriority,
785 };
786 
787 static HRESULT WINAPI enum_components_QueryInterface(IEnumCifComponents *iface, REFIID riid, void **ppv)
788 {
789     struct ciffenum_components *This = impl_from_IEnumCifComponents(iface);
790 
791     if (IsEqualGUID(&IID_IUnknown, riid))
792     {
793         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
794         *ppv = &This->IEnumCifComponents_iface;
795     }
796     /*
797     else if (IsEqualGUID(&IID_IEnumCifComponents, riid))
798     {
799         TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv);
800         *ppv = &This->IEnumCifComponents_iface;
801     }
802     */
803     else
804     {
805         FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv);
806         *ppv = NULL;
807         return E_NOINTERFACE;
808     }
809 
810     IUnknown_AddRef((IUnknown *)*ppv);
811     return S_OK;
812 }
813 
814 static ULONG WINAPI enum_components_AddRef(IEnumCifComponents *iface)
815 {
816     struct ciffenum_components *This = impl_from_IEnumCifComponents(iface);
817     LONG ref = InterlockedIncrement(&This->ref);
818 
819     TRACE("(%p) ref=%d\n", This, ref);
820 
821     return ref;
822 }
823 
824 static ULONG WINAPI enum_components_Release(IEnumCifComponents *iface)
825 {
826     struct ciffenum_components *This = impl_from_IEnumCifComponents(iface);
827     LONG ref = InterlockedDecrement(&This->ref);
828 
829     TRACE("(%p) ref=%d\n", This, ref);
830 
831     if(!ref)
832     {
833         ICifFile_Release(This->file);
834         heap_free(This);
835     }
836 
837     return ref;
838 }
839 
840 static HRESULT WINAPI enum_components_Next(IEnumCifComponents *iface, ICifComponent **component)
841 {
842     struct ciffenum_components *This = impl_from_IEnumCifComponents(iface);
843     struct cifcomponent *comp;
844 
845     TRACE("(%p)->(%p)\n", This, component);
846 
847     if (!component)
848         return E_FAIL;
849 
850     if (!This->position)
851     {
852         *component = NULL;
853         return E_FAIL;
854     }
855 
856     do
857     {
858         This->position = list_next(This->start, This->position);
859         if (!This->position)
860         {
861             *component = NULL;
862             return E_FAIL;
863         }
864 
865         comp = CONTAINING_RECORD(This->position, struct cifcomponent, entry);
866     } while (This->group_id && (!comp->group || strcmp(This->group_id, comp->group)));
867 
868     *component = &comp->ICifComponent_iface;
869     return S_OK;
870 }
871 
872 static HRESULT WINAPI enum_components_Reset(IEnumCifComponents *iface)
873 {
874     struct ciffenum_components *This = impl_from_IEnumCifComponents(iface);
875 
876     TRACE("(%p)\n", This);
877 
878     This->position = This->start;
879     return S_OK;
880 }
881 
882 static const IEnumCifComponentsVtbl enum_componentsVtbl =
883 {
884     enum_components_QueryInterface,
885     enum_components_AddRef,
886     enum_components_Release,
887     enum_components_Next,
888     enum_components_Reset,
889 };
890 
891 static HRESULT enum_components_create(ICifFile *file, struct list *start, char *group_id, IEnumCifComponents **iface)
892 {
893     struct ciffenum_components *enumerator;
894 
895     enumerator = heap_alloc_zero(sizeof(*enumerator));
896     if (!enumerator) return E_OUTOFMEMORY;
897 
898     enumerator->IEnumCifComponents_iface.lpVtbl = &enum_componentsVtbl;
899     enumerator->ref      = 1;
900     enumerator->file     = file;
901     enumerator->start    = start;
902     enumerator->position = start;
903     enumerator->group_id = group_id;
904 
905     ICifFile_AddRef(file);
906 
907     *iface = &enumerator->IEnumCifComponents_iface;
908     return S_OK;
909 }
910 
911 static HRESULT WINAPI enum_groups_QueryInterface(IEnumCifGroups *iface, REFIID riid, void **ppv)
912 {
913     struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface);
914 
915     if (IsEqualGUID(&IID_IUnknown, riid))
916     {
917         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
918         *ppv = &This->IEnumCifGroups_iface;
919     }
920     /*
921     else if (IsEqualGUID(&IID_IEnumCifGroups, riid))
922     {
923         TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv);
924         *ppv = &This->IEnumCifGroups_iface;
925     }
926     */
927     else
928     {
929         FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv);
930         *ppv = NULL;
931         return E_NOINTERFACE;
932     }
933 
934     IUnknown_AddRef((IUnknown *)*ppv);
935     return S_OK;
936 }
937 
938 static ULONG WINAPI enum_groups_AddRef(IEnumCifGroups *iface)
939 {
940     struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface);
941     LONG ref = InterlockedIncrement(&This->ref);
942 
943     TRACE("(%p) ref=%d\n", This, ref);
944 
945     return ref;
946 }
947 
948 static ULONG WINAPI enum_groups_Release(IEnumCifGroups *iface)
949 {
950     struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface);
951     LONG ref = InterlockedDecrement(&This->ref);
952 
953     TRACE("(%p) ref=%d\n", This, ref);
954 
955     if(!ref)
956     {
957         ICifFile_Release(This->file);
958         heap_free(This);
959     }
960 
961     return ref;
962 }
963 
964 static HRESULT WINAPI enum_groups_Next(IEnumCifGroups *iface, ICifGroup **group)
965 {
966     struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface);
967     struct cifgroup *gp;
968 
969     TRACE("(%p)->(%p)\n", This, group);
970 
971     if (!This->position || !group)
972         return E_FAIL;
973 
974     This->position = list_next(This->start, This->position);
975 
976     if (!This->position)
977         return E_FAIL;
978 
979     gp = CONTAINING_RECORD(This->position, struct cifgroup, entry);
980     *group = &gp->ICifGroup_iface;
981     return S_OK;
982 }
983 
984 static HRESULT WINAPI enum_groups_Reset(IEnumCifGroups *iface)
985 {
986     struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface);
987 
988     TRACE("(%p)\n", This);
989 
990     This->position = This->start;
991     return S_OK;
992 }
993 
994 static const IEnumCifGroupsVtbl enum_groupsVtbl =
995 {
996     enum_groups_QueryInterface,
997     enum_groups_AddRef,
998     enum_groups_Release,
999     enum_groups_Next,
1000     enum_groups_Reset,
1001 };
1002 
1003 static HRESULT enum_groups_create(ICifFile *file, struct list *start, IEnumCifGroups **iface)
1004 {
1005     struct ciffenum_groups *enumerator;
1006 
1007     enumerator = heap_alloc_zero(sizeof(*enumerator));
1008     if (!enumerator) return E_OUTOFMEMORY;
1009 
1010     enumerator->IEnumCifGroups_iface.lpVtbl = &enum_groupsVtbl;
1011     enumerator->ref      = 1;
1012     enumerator->file     = file;
1013     enumerator->start    = start;
1014     enumerator->position = start;
1015 
1016     ICifFile_AddRef(file);
1017 
1018     *iface = &enumerator->IEnumCifGroups_iface;
1019     return S_OK;
1020 }
1021 
1022 static HRESULT WINAPI ciffile_QueryInterface(ICifFile *iface, REFIID riid, void **ppv)
1023 {
1024     struct ciffile *This = impl_from_ICiffile(iface);
1025 
1026     if (IsEqualGUID(&IID_IUnknown, riid))
1027     {
1028         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1029         *ppv = &This->ICifFile_iface;
1030     }
1031     else if (IsEqualGUID(&IID_ICifFile, riid))
1032     {
1033         TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv);
1034         *ppv = &This->ICifFile_iface;
1035     }
1036     else
1037     {
1038         FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv);
1039         *ppv = NULL;
1040         return E_NOINTERFACE;
1041     }
1042 
1043     IUnknown_AddRef((IUnknown *)*ppv);
1044     return S_OK;
1045 }
1046 
1047 static ULONG WINAPI ciffile_AddRef(ICifFile *iface)
1048 {
1049     struct ciffile *This = impl_from_ICiffile(iface);
1050     LONG ref = InterlockedIncrement(&This->ref);
1051 
1052     TRACE("(%p) ref=%d\n", This, ref);
1053 
1054     return ref;
1055 }
1056 
1057 static ULONG WINAPI ciffile_Release(ICifFile *iface)
1058 {
1059     struct ciffile *This = impl_from_ICiffile(iface);
1060     LONG ref = InterlockedDecrement(&This->ref);
1061 
1062     TRACE("(%p) ref=%d\n", This, ref);
1063 
1064     if(!ref)
1065     {
1066         struct cifcomponent *comp, *comp_next;
1067         struct cifgroup *group, *group_next;
1068 
1069         heap_free(This->name);
1070 
1071         LIST_FOR_EACH_ENTRY_SAFE(comp, comp_next, &This->components, struct cifcomponent, entry)
1072         {
1073             list_remove(&comp->entry);
1074             component_free(comp);
1075         }
1076 
1077         LIST_FOR_EACH_ENTRY_SAFE(group, group_next, &This->groups, struct cifgroup, entry)
1078         {
1079             list_remove(&group->entry);
1080             group_free(group);
1081         }
1082 
1083         heap_free(This);
1084     }
1085 
1086     return ref;
1087 }
1088 
1089 static HRESULT WINAPI ciffile_EnumComponents(ICifFile *iface, IEnumCifComponents **enum_components, DWORD filter, void *pv)
1090 {
1091     struct ciffile *This = impl_from_ICiffile(iface);
1092 
1093     TRACE("(%p)->(%p, %u, %p)\n", This, enum_components, filter, pv);
1094 
1095     if (filter)
1096         FIXME("filter (%x) not supported\n", filter);
1097     if (pv)
1098         FIXME("how to handle pv (%p)?\n", pv);
1099 
1100     return enum_components_create(iface, &This->components, NULL, enum_components);
1101 }
1102 
1103 static HRESULT WINAPI ciffile_FindComponent(ICifFile *iface, const char *id, ICifComponent **component)
1104 {
1105     struct ciffile *This = impl_from_ICiffile(iface);
1106     struct cifcomponent *comp;
1107 
1108     TRACE("(%p)->(%s, %p)\n", This, debugstr_a(id), component);
1109 
1110     LIST_FOR_EACH_ENTRY(comp, &This->components, struct cifcomponent, entry)
1111     {
1112         if (strcmp(comp->id, id) != 0)
1113             continue;
1114 
1115         *component = &comp->ICifComponent_iface;
1116         return S_OK;
1117     }
1118 
1119     return E_FAIL;
1120 }
1121 
1122 static HRESULT WINAPI ciffile_EnumGroups(ICifFile *iface, IEnumCifGroups **enum_groups, DWORD filter, void *pv)
1123 {
1124     struct ciffile *This = impl_from_ICiffile(iface);
1125 
1126     TRACE("(%p)->(%p, %u, %p)\n", This, enum_groups, filter, pv);
1127 
1128     if (filter)
1129         FIXME("filter (%x) not supported\n", filter);
1130     if (pv)
1131         FIXME("how to handle pv (%p)?\n", pv);
1132 
1133     return enum_groups_create(iface, &This->groups, enum_groups);
1134 }
1135 
1136 static HRESULT WINAPI ciffile_FindGroup(ICifFile *iface, const char *id, ICifGroup **group)
1137 {
1138     struct ciffile *This = impl_from_ICiffile(iface);
1139     struct cifgroup *gp;
1140 
1141     TRACE("(%p)->(%s, %p)\n", This, debugstr_a(id), group);
1142 
1143     LIST_FOR_EACH_ENTRY(gp, &This->groups, struct cifgroup, entry)
1144     {
1145         if (strcmp(gp->id, id) != 0)
1146             continue;
1147 
1148         *group = &gp->ICifGroup_iface;
1149         return S_OK;
1150     }
1151 
1152     return E_FAIL;
1153 }
1154 
1155 static HRESULT WINAPI ciffile_EnumModes(ICifFile *iface, IEnumCifModes **cuf_modes, DWORD filter, void *pv)
1156 {
1157     struct ciffile *This = impl_from_ICiffile(iface);
1158 
1159     FIXME("(%p)->(%p, %u, %p): stub\n", This, cuf_modes, filter, pv);
1160 
1161     return E_NOTIMPL;
1162 }
1163 
1164 static HRESULT WINAPI ciffile_FindMode(ICifFile *iface, const char *id, ICifMode **mode)
1165 {
1166     struct ciffile *This = impl_from_ICiffile(iface);
1167 
1168     FIXME("(%p)->(%s, %p): stub\n", This, debugstr_a(id), mode);
1169 
1170     return E_NOTIMPL;
1171 }
1172 
1173 static HRESULT WINAPI ciffile_GetDescription(ICifFile *iface, char *desc, DWORD size)
1174 {
1175     struct ciffile *This = impl_from_ICiffile(iface);
1176 
1177     TRACE("(%p)->(%p, %u)\n", This, desc, size);
1178 
1179     return copy_substring_null(desc, size, This->name);
1180 }
1181 
1182 static HRESULT WINAPI ciffile_GetDetDlls(ICifFile *iface, char *dlls, DWORD size)
1183 {
1184     struct ciffile *This = impl_from_ICiffile(iface);
1185 
1186     FIXME("(%p)->(%p, %u): stub\n", This, dlls, size);
1187 
1188     return E_NOTIMPL;
1189 }
1190 
1191 static const ICifFileVtbl ciffileVtbl =
1192 {
1193     ciffile_QueryInterface,
1194     ciffile_AddRef,
1195     ciffile_Release,
1196     ciffile_EnumComponents,
1197     ciffile_FindComponent,
1198     ciffile_EnumGroups,
1199     ciffile_FindGroup,
1200     ciffile_EnumModes,
1201     ciffile_FindMode,
1202     ciffile_GetDescription,
1203     ciffile_GetDetDlls,
1204 };
1205 
1206 static BOOL copy_string(char **dest, const char *source)
1207 {
1208     if (!source)
1209     {
1210         *dest = NULL;
1211         return TRUE;
1212     }
1213 
1214     *dest = strdupA(source);
1215     if (!dest) return FALSE;
1216     return TRUE;
1217 }
1218 
1219 static BOOL section_get_str(struct inf_section *inf_sec, const char *key, char **value, const char *def)
1220 {
1221     struct inf_value *inf_val;
1222 
1223     inf_val = inf_get_value(inf_sec, key);
1224     if (!inf_val) return copy_string(value, def);
1225 
1226     *value = inf_value_get_value(inf_val);
1227     if (!*value) return FALSE;
1228 
1229     return TRUE;
1230 }
1231 
1232 static char *next_part(char **str, BOOL strip_quotes)
1233 {
1234     char *start = *str;
1235     char *next = *str;
1236 
1237     while (*next && *next != ',')
1238         next++;
1239 
1240     if (!*next)
1241     {
1242         *str = trim(start, NULL, strip_quotes);
1243         return NULL;
1244     }
1245 
1246     *next = 0;
1247     *str = trim(start, NULL, strip_quotes);
1248     return ++next;
1249 }
1250 
1251 static BOOL value_get_str_field(struct inf_value *inf_val, int field, char **value, const char *def)
1252 {
1253     char *line, *str, *next;
1254     int i = 0;
1255 
1256     line = inf_value_get_value(inf_val);
1257     if (!line) return FALSE;
1258 
1259     str = line;
1260     do
1261     {
1262         i++;
1263         next = next_part(&str, TRUE);
1264 
1265         if (field == i)
1266         {
1267             BOOL ret = copy_string(value, str);
1268             heap_free(line);
1269             return ret;
1270         }
1271 
1272         str = next;
1273     } while (str);
1274 
1275     return copy_string(value, def);
1276 }
1277 
1278 /*
1279 static BOOL section_get_str_field(struct inf_section *inf_sec, const char *key, int field, char **value, const char *def)
1280 {
1281     struct inf_value *inf_val;
1282 
1283     inf_val = inf_get_value(inf_sec, key);
1284     if (!inf_val) return copy_string(value, def);
1285 
1286     return value_get_str_field(inf_val, field, value, def);
1287 }
1288 */
1289 
1290 static BOOL section_get_dword(struct inf_section *inf_sec, const char *key, DWORD *value, DWORD def)
1291 {
1292     struct inf_value *inf_val;
1293     char *str;
1294 
1295     inf_val = inf_get_value(inf_sec, key);
1296     if (!inf_val)
1297     {
1298         *value = def;
1299         return TRUE;
1300     }
1301 
1302     str = inf_value_get_value(inf_val);
1303     if (!str) return FALSE;
1304 
1305     *value = atoi(str);
1306     heap_free(str);
1307 
1308     return TRUE;
1309 }
1310 
1311 static BOOL value_get_dword_field(struct inf_value *inf_val, int field, DWORD *value, DWORD def)
1312 {
1313     char *value_str;
1314     BOOL ret;
1315 
1316     ret = value_get_str_field(inf_val, field, &value_str, NULL);
1317     if (!ret) return FALSE;
1318     if (!value_str)
1319     {
1320         *value = def;
1321         return TRUE;
1322     }
1323 
1324     *value = atoi(value_str);
1325     heap_free(value_str);
1326 
1327     return TRUE;
1328 }
1329 
1330 static BOOL section_get_dword_field(struct inf_section *inf_sec, const char *key, int field, DWORD *value, DWORD def)
1331 {
1332     struct inf_value *inf_val;
1333 
1334     inf_val = inf_get_value(inf_sec, key);
1335     if (!inf_val)
1336     {
1337         *value = def;
1338         return TRUE;
1339     }
1340 
1341     return value_get_dword_field(inf_val, field, value, def);
1342 }
1343 
1344 static HRESULT process_version(struct ciffile *file, struct inf_section *section)
1345 {
1346     if (!section_get_str(section, "DisplayName", &file->name, DEFAULT_INSTALLER_DESC))
1347         return E_OUTOFMEMORY;
1348 
1349     return S_OK;
1350 }
1351 
1352 static BOOL read_version_entry(struct inf_section *section, DWORD *ret_ver, DWORD *ret_build)
1353 {
1354     DWORD version = 0;
1355     DWORD build = 0;
1356     char *line, *str, *next;
1357 
1358     if (!section_get_str(section, "Version", &line, NULL))
1359         return FALSE;
1360     if (!line) goto done;
1361 
1362     str = line;
1363 
1364     next = next_part(&str, TRUE);
1365     version |= atoi(str) << 16;
1366     if (!next) goto done;
1367     str = next;
1368 
1369     next = next_part(&str, TRUE);
1370     version |= atoi(str) & 0xffff;
1371     if (!next) goto done;
1372     str = next;
1373 
1374     next = next_part(&str, TRUE);
1375     build |= atoi(str) << 16;
1376     if (!next) goto done;
1377     str = next;
1378 
1379     next_part(&str, TRUE);
1380     build |= atoi(str) & 0xffff;
1381 
1382 done:
1383     heap_free(line);
1384     *ret_ver = version;
1385     *ret_build = build;
1386     return TRUE;
1387 }
1388 
1389 static BOOL read_platform_entry(struct inf_section *section, DWORD *ret_platform)
1390 {
1391     DWORD platform = PLATFORM_ALL;
1392     char *line, *str, *next;
1393 
1394     if (!section_get_str(section, "Platform", &line, NULL))
1395         return FALSE;
1396     if (!line) goto done;
1397 
1398     platform = 0;
1399     str = line;
1400     do
1401     {
1402         next = next_part(&str, TRUE);
1403 
1404         if (strcasecmp(str, "Win95") == 0)
1405             platform |= PLATFORM_WIN98;
1406         else if (strcasecmp(str, "Win98") == 0)
1407             platform |= PLATFORM_WIN98;
1408         else if (strcasecmp(str, "NT4") == 0)
1409             platform |= PLATFORM_NT4;
1410         else if (strcasecmp(str, "NT5") == 0)
1411             platform |= PLATFORM_NT5;
1412         else if (strcasecmp(str, "NT4Alpha") == 0)
1413             platform |= PLATFORM_NT4;
1414         else if (strcasecmp(str, "NT5Alpha") == 0)
1415             platform |= PLATFORM_NT5;
1416         else if (strcasecmp(str, "Millen") == 0)
1417             platform |= PLATFORM_MILLEN;
1418         else
1419             FIXME("Unknown platform: %s\n", debugstr_a(str));
1420 
1421         str = next;
1422     } while (str);
1423 
1424 done:
1425     heap_free(line);
1426     *ret_platform = platform;
1427     return TRUE;
1428 }
1429 
1430 static BOOL read_dependencies(struct cifcomponent *component, struct inf_section *section)
1431 {
1432     struct dependency_info *dependency;
1433     char *line, *str, *next;
1434     BOOL ret = TRUE;
1435 
1436     if (!section_get_str(section, "Dependencies", &line, NULL))
1437         return E_OUTOFMEMORY;
1438     if (!line) goto done;
1439 
1440     ret = FALSE;
1441     str = line;
1442     do
1443     {
1444         next = next_part(&str, TRUE);
1445 
1446         dependency = heap_alloc_zero(sizeof(*dependency));
1447         if (!dependency) goto done;
1448 
1449         dependency->id = strdupA(str);
1450         if (!dependency->id)
1451         {
1452             heap_free(dependency);
1453             goto done;
1454         }
1455 
1456         dependency->type = strstr(dependency->id, ":");
1457         if (dependency->type) *dependency->type++ = 0;
1458 
1459         list_add_tail(&component->dependencies, &dependency->entry);
1460 
1461         str = next;
1462     } while (str);
1463 
1464     ret = TRUE;
1465 
1466 done:
1467     heap_free(line);
1468     return ret;
1469 }
1470 
1471 static BOOL read_urls(struct cifcomponent *component, struct inf_section *section)
1472 {
1473     struct inf_value *inf_value = NULL;
1474     struct url_info *url_entry;
1475     char *str, *next;
1476     int index;
1477 
1478     while (inf_section_next_value(section, &inf_value))
1479     {
1480         str = inf_value_get_key(inf_value);
1481         if (!str) return E_OUTOFMEMORY;
1482 
1483         if (strncasecmp(str, "URL", 3))
1484             goto next;
1485 
1486         if (!str[3])
1487             goto next;
1488 
1489         index = strtol(str+3, &next, 10);
1490         if (next == str+3 || *next != 0 || index < 1)
1491             goto next;
1492         index--;
1493 
1494         url_entry = heap_alloc_zero(sizeof(*url_entry));
1495         if (!url_entry) goto error;
1496 
1497         url_entry->index = index;
1498 
1499         if (!value_get_str_field(inf_value, 1, &url_entry->url, NULL))
1500             goto error;
1501         if (!url_entry->url || !*url_entry->url)
1502         {
1503             url_entry_free(url_entry);
1504             goto next;
1505         }
1506 
1507         if (!value_get_dword_field(inf_value, 2, &url_entry->flags, 0))
1508             goto error;
1509 
1510         list_add_tail(&component->urls, &url_entry->entry);
1511 
1512     next:
1513         heap_free(str);
1514     }
1515 
1516     return TRUE;
1517 
1518 error:
1519     heap_free(str);
1520     url_entry_free(url_entry);
1521     return FALSE;
1522 };
1523 
1524 void add_component_by_priority(struct ciffile *file, struct cifcomponent *component)
1525 {
1526     struct cifcomponent *entry;
1527 
1528     LIST_FOR_EACH_ENTRY(entry, &file->components, struct cifcomponent, entry)
1529     {
1530         if (entry->priority > component->priority)
1531             continue;
1532 
1533         list_add_before(&entry->entry, &component->entry);
1534         return;
1535     }
1536 
1537     list_add_tail(&file->components, &component->entry);
1538 }
1539 
1540 static HRESULT process_component(struct ciffile *file, struct inf_section *section, const char *section_name)
1541 {
1542     struct cifcomponent *component;
1543     HRESULT hr = E_OUTOFMEMORY;
1544 
1545     component = heap_alloc_zero(sizeof(*component));
1546     if (!component) return E_OUTOFMEMORY;
1547 
1548     component->ICifComponent_iface.lpVtbl = &cifcomponentVtbl;
1549     component->parent = &file->ICifFile_iface;
1550 
1551     list_init(&component->urls);
1552     list_init(&component->dependencies);
1553 
1554     component->queue_state = ActionNone;
1555 
1556     component->id = strdupA(section_name);
1557     if (!component->id) goto error;
1558 
1559     if (!section_get_str(section, "DisplayName", &component->description, NULL))
1560         goto error;
1561     if (!section_get_str(section, "GUID", &component->guid, NULL))
1562         goto error;
1563     if (!section_get_str(section, "Details", &component->details, NULL))
1564         goto error;
1565     if (!section_get_str(section, "Group", &component->group, NULL))
1566         goto error;
1567     if (!section_get_str(section, "Locale", &component->locale, "en"))
1568         goto error;
1569     if (!section_get_str(section, "PatchID", &component->patchid, NULL))
1570         goto error;
1571 
1572     if (!section_get_dword_field(section, "Size", 1, &component->size_download, 0))
1573         goto error;
1574     if (!section_get_dword_field(section, "Size", 2, &component->size_extracted, 0))
1575         goto error;
1576     if (!section_get_dword_field(section, "InstalledSize", 1, &component->size_app, 0))
1577         goto error;
1578     if (!section_get_dword_field(section, "InstalledSize", 2, &component->size_win, 0))
1579         goto error;
1580 
1581     if (!section_get_str(section, "SuccessKey", &component->key_success, NULL))
1582         goto error;
1583     if (!section_get_str(section, "CancelKey", &component->key_cancel, NULL))
1584         goto error;
1585     if (!section_get_str(section, "ProgressKey", &component->key_progress, NULL))
1586         goto error;
1587     if (!section_get_str(section, "UninstallKey", &component->key_uninstall, NULL))
1588         goto error;
1589     if (!section_get_dword(section, "Reboot", &component->reboot, 0))
1590         goto error;
1591     if (!section_get_dword(section, "AdminCheck", &component->admin, 0))
1592         goto error;
1593     if (!section_get_dword(section, "UIVisible", &component->visibleui, 1))
1594         goto error;
1595     if (!section_get_dword(section, "ActiveSetupAware", &component->as_aware, 0))
1596         goto error;
1597     if (!section_get_dword(section, "Priority", &component->priority, 0))
1598         goto error;
1599 
1600     if (!read_version_entry(section, &component->version, &component->build))
1601         goto error;
1602     if (!read_platform_entry(section, &component->platform))
1603         goto error;
1604     if (!read_urls(component, section))
1605         goto error;
1606     if (!read_dependencies(component, section))
1607         goto error;
1608 
1609     component->current_priority = component->priority;
1610 
1611     add_component_by_priority(file, component);
1612     return S_OK;
1613 
1614 error:
1615     component_free(component);
1616     return hr;
1617 }
1618 
1619 static HRESULT process_group(struct ciffile *file, struct inf_section *section, const char *section_name)
1620 {
1621     struct cifgroup *group;
1622     HRESULT hr = E_OUTOFMEMORY;
1623 
1624     group = heap_alloc_zero(sizeof(*group));
1625     if (!group) return E_OUTOFMEMORY;
1626 
1627     group->ICifGroup_iface.lpVtbl = &cifgroupVtbl;
1628     group->parent = &file->ICifFile_iface;
1629 
1630     group->id = strdupA(section_name);
1631     if (!group->id) goto error;
1632 
1633     if (!section_get_str(section, "DisplayName", &group->description, NULL))
1634         goto error;
1635     if (!section_get_dword(section, "Priority", &group->priority, 0))
1636         goto error;
1637 
1638     list_add_head(&file->groups, &group->entry);
1639     return S_OK;
1640 
1641 error:
1642     group_free(group);
1643     return hr;
1644 }
1645 
1646 static HRESULT process_section(struct ciffile *file, struct inf_section *section, const char *section_name)
1647 {
1648     HRESULT hr;
1649     char *type;
1650 
1651     if (!section_get_str(section, "SectionType", &type, "Component"))
1652         return E_OUTOFMEMORY;
1653 
1654     if (!strcasecmp(type, "Component"))
1655         hr = process_component(file, section, section_name);
1656     else if (strcasecmp(type, "Group") == 0)
1657         hr = process_group(file, section, section_name);
1658     else
1659         FIXME("Don't know how to process %s\n", debugstr_a(type));
1660 
1661     heap_free(type);
1662     return hr;
1663 }
1664 
1665 static HRESULT process_inf(struct ciffile *file, struct inf_file *inf)
1666 {
1667     struct inf_section *section = NULL;
1668     char *section_name;
1669     HRESULT hr = S_OK;
1670 
1671     while (SUCCEEDED(hr) && inf_next_section(inf, &section))
1672     {
1673         section_name = inf_section_get_name(section);
1674         if (!section_name) return E_OUTOFMEMORY;
1675 
1676         TRACE("start processing section %s\n", debugstr_a(section_name));
1677 
1678         if (!strcasecmp(section_name, "Strings") ||
1679             !strncasecmp(section_name, "Strings.", strlen("Strings.")))
1680         {
1681             /* Ignore string sections */
1682         }
1683         else if (strcasecmp(section_name, "Version") == 0)
1684             hr = process_version(file, section);
1685         else
1686             hr = process_section(file, section, section_name);
1687 
1688         TRACE("finished processing section %s (%x)\n", debugstr_a(section_name), hr);
1689         heap_free(section_name);
1690     }
1691 
1692     /* In case there was no version section, set the default installer description */
1693     if (SUCCEEDED(hr) && !file->name)
1694     {
1695         file->name = strdupA(DEFAULT_INSTALLER_DESC);
1696         if (!file->name) hr = E_OUTOFMEMORY;
1697     }
1698 
1699     return hr;
1700 }
1701 
1702 static HRESULT load_ciffile(const char *path, ICifFile **icif)
1703 {
1704     struct inf_file *inf = NULL;
1705     struct ciffile *file;
1706     HRESULT hr = E_FAIL;
1707 
1708     file = heap_alloc_zero(sizeof(*file));
1709     if(!file) return E_OUTOFMEMORY;
1710 
1711     file->ICifFile_iface.lpVtbl = &ciffileVtbl;
1712     file->ref = 1;
1713 
1714     list_init(&file->components);
1715     list_init(&file->groups);
1716 
1717     hr = inf_load(path, &inf);
1718     if (FAILED(hr)) goto error;
1719 
1720     hr = process_inf(file, inf);
1721     if (FAILED(hr)) goto error;
1722 
1723     *icif = &file->ICifFile_iface;
1724     return S_OK;
1725 
1726 error:
1727     if (inf) inf_free(inf);
1728     ICifFile_Release(&file->ICifFile_iface);
1729     return hr;
1730 }
1731 
1732 HRESULT WINAPI GetICifFileFromFile(ICifFile **icif, const char *path)
1733 {
1734     TRACE("(%p, %s)\n", icif, debugstr_a(path));
1735 
1736     return load_ciffile(path, icif);
1737 }
1738 
1739 
1740 HRESULT WINAPI GetICifRWFileFromFile(ICifRWFile **icif, const char *path)
1741 {
1742     FIXME("(%p, %s): stub\n", icif, debugstr_a(path));
1743 
1744     return E_NOTIMPL;
1745 }
1746