xref: /reactos/sdk/lib/inflib/infput.c (revision 1734f297)
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 */
275