Implement adding new sections/lines/fields and writing the resulting file
[reactos.git] / reactos / 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 _T("\r\n")
15 #define SIZE_INC 1024
16
17 typedef struct _OUTPUTBUFFER
18 {
19 PCHAR Buffer;
20 PCHAR Current;
21 ULONG TotalSize;
22 ULONG FreeSize;
23 INFSTATUS Status;
24 } OUTPUTBUFFER, *POUTPUTBUFFER;
25
26 static void
27 Output(POUTPUTBUFFER OutBuf, PCTSTR Text)
28 {
29 ULONG Length;
30 PCHAR 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 = _tcslen(Text);
41 if (OutBuf->FreeSize < Length + 1 && INF_SUCCESS(OutBuf->Status))
42 {
43 DPRINT("Out of free space. TotalSize %lu FreeSize %lu Length %u\n",
44 OutBuf->TotalSize, OutBuf->FreeSize, 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 %lu\n", 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 %lu bytes from old content\n",
63 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 %lu FreeSize %lu\n",
76 OutBuf->TotalSize, 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++ = (char) *Text++;
84 OutBuf->FreeSize--;
85 }
86 OutBuf->Current[1] = '\0';
87 }
88
89 INFSTATUS
90 InfpBuildFileBuffer(PINFCACHE Cache,
91 PCHAR *Buffer,
92 PULONG BufferSize)
93 {
94 OUTPUTBUFFER OutBuf;
95 PINFCACHESECTION CacheSection;
96 PINFCACHELINE CacheLine;
97 PINFCACHEFIELD CacheField;
98 PTCHAR 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 " STRFMT "\n", CacheSection->Name);
112 if (CacheSection != Cache->FirstSection)
113 {
114 Output(&OutBuf, EOL);
115 }
116 Output(&OutBuf, _T("["));
117 Output(&OutBuf, CacheSection->Name);
118 Output(&OutBuf, _T("]"));
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 " STRFMT "\n", CacheLine->Key);
128 Output(&OutBuf, CacheLine->Key);
129 Output(&OutBuf, _T(" = "));
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, _T(","));
143 }
144 p = CacheField->Data;
145 NeedQuotes = FALSE;
146 while (_T('\0') != *p && ! NeedQuotes)
147 {
148 NeedQuotes = _T(',') == *p || _T(';') == *p ||
149 _T('\\') == *p;
150 p++;
151 }
152 if (NeedQuotes)
153 {
154 Output(&OutBuf, _T("\""));
155 Output(&OutBuf, CacheField->Data);
156 Output(&OutBuf, _T("\""));
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 PCTSTR Section,
192 PINFCONTEXT *Context)
193 {
194 DPRINT("InfpFindOrAddSection section " STRFMT "\n", Section);
195
196 *Context = MALLOC(sizeof(INFCONTEXT));
197 if (NULL == *Context)
198 {
199 DPRINT1("MALLOC() failed\n");
200 return INF_STATUS_NO_MEMORY;
201 }
202
203 (*Context)->Inf = Cache;
204 (*Context)->Section = InfpFindSection(Cache, Section);
205 (*Context)->Line = NULL;
206 if (NULL == (*Context)->Section)
207 {
208 DPRINT("Section not found, creating it\n");
209 (*Context)->Section = InfpAddSection(Cache, Section);
210 if (NULL == (*Context)->Section)
211 {
212 DPRINT("Failed to create section\n");
213 FREE(*Context);
214 return INF_STATUS_NO_MEMORY;
215 }
216 }
217
218 return INF_STATUS_SUCCESS;
219 }
220
221 INFSTATUS
222 InfpAddLineWithKey(PINFCONTEXT Context, PCTSTR Key)
223 {
224 if (NULL == Context)
225 {
226 DPRINT1("Invalid parameter\n");
227 return INF_STATUS_INVALID_PARAMETER;
228 }
229
230 Context->Line = InfpAddLine(Context->Section);
231 if (NULL == Context->Line)
232 {
233 DPRINT("Failed to create line\n");
234 return INF_STATUS_NO_MEMORY;
235 }
236
237 if (NULL != Key && NULL == InfpAddKeyToLine(Context->Line, Key))
238 {
239 DPRINT("Failed to add key\n");
240 return INF_STATUS_NO_MEMORY;
241 }
242
243 return INF_STATUS_SUCCESS;
244 }
245
246 INFSTATUS
247 InfpAddField(PINFCONTEXT Context, PCTSTR Data)
248 {
249 if (NULL == Context || NULL == Context->Line)
250 {
251 DPRINT1("Invalid parameter\n");
252 return INF_STATUS_INVALID_PARAMETER;
253 }
254
255 if (NULL == InfpAddFieldToLine(Context->Line, Data))
256 {
257 DPRINT("Failed to add field\n");
258 return INF_STATUS_NO_MEMORY;
259 }
260
261 return INF_STATUS_SUCCESS;
262 }
263
264 /* EOF */