[SHELL32] Fix Control_RunDLLW (#5400)
[reactos.git] / sdk / lib / inflib / infput.c
1 /*
2 * PROJECT: .inf file parser
3 * LICENSE: GPL - See COPYING in the top level directory
4 * COPYRIGHT: Copyright 2005 Ge van Geldorp <gvg@reactos.org>
5 */
6
7 /* INCLUDES *****************************************************************/
8
9 #include "inflib.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define EOL L"\r\n"
15 #define SIZE_INC 1024
16
17 typedef struct _OUTPUTBUFFER
18 {
19 PWCHAR Buffer;
20 PWCHAR Current;
21 ULONG TotalSize;
22 ULONG FreeSize;
23 INFSTATUS Status;
24 } OUTPUTBUFFER, *POUTPUTBUFFER;
25
26 static void
27 Output(POUTPUTBUFFER OutBuf, PCWSTR Text)
28 {
29 ULONG Length;
30 PWCHAR NewBuf;
31 ULONG NewSize;
32
33 /* Skip mode? */
34 if (! INF_SUCCESS(OutBuf->Status))
35 {
36 return;
37 }
38
39 /* Doesn't fit? */
40 Length = (ULONG)strlenW(Text) * sizeof(WCHAR);
41 if (OutBuf->FreeSize < Length + 1 && INF_SUCCESS(OutBuf->Status))
42 {
43 DPRINT("Out of free space. TotalSize %u FreeSize %u Length %u\n",
44 (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize, (UINT)Length);
45 /* Round up to next SIZE_INC */
46 NewSize = OutBuf->TotalSize +
47 (((Length + 1) - OutBuf->FreeSize + (SIZE_INC - 1)) /
48 SIZE_INC) * SIZE_INC;
49 DPRINT("NewSize %u\n", (UINT)NewSize);
50 NewBuf = MALLOC(NewSize);
51 /* Abort if failed */
52 if (NULL == NewBuf)
53 {
54 DPRINT1("MALLOC() failed\n");
55 OutBuf->Status = INF_STATUS_NO_MEMORY;
56 return;
57 }
58
59 /* Need to copy old contents? */
60 if (NULL != OutBuf->Buffer)
61 {
62 DPRINT("Copying %u bytes from old content\n",
63 (UINT)(OutBuf->TotalSize - OutBuf->FreeSize));
64 MEMCPY(NewBuf, OutBuf->Buffer, OutBuf->TotalSize - OutBuf->FreeSize);
65 OutBuf->Current = NewBuf + (OutBuf->Current - OutBuf->Buffer);
66 FREE(OutBuf->Buffer);
67 }
68 else
69 {
70 OutBuf->Current = NewBuf;
71 }
72 OutBuf->Buffer = NewBuf;
73 OutBuf->FreeSize += NewSize - OutBuf->TotalSize;
74 OutBuf->TotalSize = NewSize;
75 DPRINT("After reallocation TotalSize %u FreeSize %u\n",
76 (UINT)OutBuf->TotalSize, (UINT)OutBuf->FreeSize);
77 }
78
79 /* We're guaranteed to have enough room now. Copy char by char because of
80 possible "conversion" from Unicode to Ansi */
81 while (Length--)
82 {
83 *OutBuf->Current++ = *Text++;
84 OutBuf->FreeSize--;
85 }
86 *OutBuf->Current = '\0';
87 }
88
89 INFSTATUS
90 InfpBuildFileBuffer(PINFCACHE Cache,
91 PWCHAR *Buffer,
92 PULONG BufferSize)
93 {
94 OUTPUTBUFFER OutBuf;
95 PINFCACHESECTION CacheSection;
96 PINFCACHELINE CacheLine;
97 PINFCACHEFIELD CacheField;
98 PWCHAR p;
99 BOOLEAN NeedQuotes;
100
101 OutBuf.Buffer = NULL;
102 OutBuf.Current = NULL;
103 OutBuf.FreeSize = 0;
104 OutBuf.TotalSize = 0;
105 OutBuf.Status = INF_STATUS_SUCCESS;
106
107 /* Iterate through list of sections */
108 CacheSection = Cache->FirstSection;
109 while (CacheSection != NULL)
110 {
111 DPRINT("Processing section %S\n", CacheSection->Name);
112 if (CacheSection != Cache->FirstSection)
113 {
114 Output(&OutBuf, EOL);
115 }
116 Output(&OutBuf, L"[");
117 Output(&OutBuf, CacheSection->Name);
118 Output(&OutBuf, L"]");
119 Output(&OutBuf, EOL);
120
121 /* Iterate through list of lines */
122 CacheLine = CacheSection->FirstLine;
123 while (CacheLine != NULL)
124 {
125 if (NULL != CacheLine->Key)
126 {
127 DPRINT("Line with key %S\n", CacheLine->Key);
128 Output(&OutBuf, CacheLine->Key);
129 Output(&OutBuf, L" = ");
130 }
131 else
132 {
133 DPRINT("Line without key\n");
134 }
135
136 /* Iterate through list of lines */
137 CacheField = CacheLine->FirstField;
138 while (CacheField != NULL)
139 {
140 if (CacheField != CacheLine->FirstField)
141 {
142 Output(&OutBuf, L",");
143 }
144 p = CacheField->Data;
145 NeedQuotes = FALSE;
146 while (L'\0' != *p && ! NeedQuotes)
147 {
148 NeedQuotes = (BOOLEAN)(L',' == *p || L';' == *p ||
149 L'\\' == *p);
150 p++;
151 }
152 if (NeedQuotes)
153 {
154 Output(&OutBuf, L"\"");
155 Output(&OutBuf, CacheField->Data);
156 Output(&OutBuf, L"\"");
157 }
158 else
159 {
160 Output(&OutBuf, CacheField->Data);
161 }
162
163 /* Get the next field */
164 CacheField = CacheField->Next;
165 }
166
167 Output(&OutBuf, EOL);
168 /* Get the next line */
169 CacheLine = CacheLine->Next;
170 }
171
172 /* Get the next section */
173 CacheSection = CacheSection->Next;
174 }
175
176 if (INF_SUCCESS(OutBuf.Status))
177 {
178 *Buffer = OutBuf.Buffer;
179 *BufferSize = OutBuf.TotalSize - OutBuf.FreeSize;
180 }
181 else if (NULL != OutBuf.Buffer)
182 {
183 FREE(OutBuf.Buffer);
184 }
185
186 return INF_STATUS_SUCCESS;
187 }
188
189 INFSTATUS
190 InfpFindOrAddSection(PINFCACHE Cache,
191 PCWSTR Section,
192 PINFCONTEXT *Context)
193 {
194 PINFCACHESECTION CacheSection;
195 DPRINT("InfpFindOrAddSection section %S\n", Section);
196
197 *Context = MALLOC(sizeof(INFCONTEXT));
198 if (NULL == *Context)
199 {
200 DPRINT1("MALLOC() failed\n");
201 return INF_STATUS_NO_MEMORY;
202 }
203
204 (*Context)->Inf = Cache;
205 (*Context)->Line = 0;
206 CacheSection = InfpFindSection(Cache, Section);
207 if (NULL == CacheSection)
208 {
209 DPRINT("Section not found, creating it\n");
210 CacheSection = InfpAddSection(Cache, Section);
211 if (NULL == CacheSection)
212 {
213 DPRINT("Failed to create section\n");
214 FREE(*Context);
215 return INF_STATUS_NO_MEMORY;
216 }
217 }
218
219 (*Context)->Section = CacheSection->Id;
220 return INF_STATUS_SUCCESS;
221 }
222
223 INFSTATUS
224 InfpAddLineWithKey(PINFCONTEXT Context, PCWSTR Key)
225 {
226 PINFCACHESECTION Section;
227 PINFCACHELINE Line;
228
229 if (NULL == Context)
230 {
231 DPRINT1("Invalid parameter\n");
232 return INF_STATUS_INVALID_PARAMETER;
233 }
234
235 Section = InfpGetSectionForContext(Context);
236 Line = InfpAddLine(Section);
237 if (NULL == Line)
238 {
239 DPRINT("Failed to create line\n");
240 return INF_STATUS_NO_MEMORY;
241 }
242 Context->Line = Line->Id;
243
244 if (NULL != Key && NULL == InfpAddKeyToLine(Line, Key))
245 {
246 DPRINT("Failed to add key\n");
247 return INF_STATUS_NO_MEMORY;
248 }
249
250 return INF_STATUS_SUCCESS;
251 }
252
253 INFSTATUS
254 InfpAddField(PINFCONTEXT Context, PCWSTR Data)
255 {
256 PINFCACHELINE Line;
257
258 if (NULL == Context)
259 {
260 DPRINT1("Invalid parameter\n");
261 return INF_STATUS_INVALID_PARAMETER;
262 }
263
264 Line = InfpGetLineForContext(Context);
265 if (NULL == InfpAddFieldToLine(Line, Data))
266 {
267 DPRINT("Failed to add field\n");
268 return INF_STATUS_NO_MEMORY;
269 }
270
271 return INF_STATUS_SUCCESS;
272 }
273
274 /* EOF */