ReactOS 0.4.16-dev-2491-g3dc6630
parse.c
Go to the documentation of this file.
1/*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <freeldr.h>
21
22#include <debug.h>
24
29
30
31BOOLEAN IniParseFile(PCSTR IniFileData, ULONG IniFileSize)
32{
33 ULONG CurrentOffset;
34 ULONG CurrentLineNumber;
35 PCHAR IniFileLine;
36 ULONG IniFileLineSize;
37 ULONG LineLength;
38 PINI_SECTION CurrentSection = NULL;
39 PINI_SECTION_ITEM CurrentItem = NULL;
40
41 TRACE("IniParseFile() IniFileSize: %d\n", IniFileSize);
42
44 {
47 }
48
49 // Start with an 80-byte buffer
50 IniFileLineSize = 80;
51 IniFileLine = FrLdrTempAlloc(IniFileLineSize, TAG_INI_FILE);
52 if (!IniFileLine)
53 return FALSE;
54
55 // Loop through each line and parse it
56 CurrentLineNumber = 0;
57 CurrentOffset = 0;
58 while (CurrentOffset < IniFileSize)
59 {
60 // First check the line size and increase our buffer if necessary
61 if (IniFileLineSize < IniGetNextLineSize(IniFileData, IniFileSize, CurrentOffset))
62 {
63 IniFileLineSize = IniGetNextLineSize(IniFileData, IniFileSize, CurrentOffset);
64 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
65 IniFileLine = FrLdrTempAlloc(IniFileLineSize, TAG_INI_FILE);
66 if (!IniFileLine)
67 return FALSE;
68 }
69
70 // Get the line of data
71 CurrentOffset = IniGetNextLine(IniFileData, IniFileSize, IniFileLine, IniFileLineSize, CurrentOffset);
72 LineLength = (ULONG)strlen(IniFileLine);
73
74 // If it is a blank line or a comment then skip it
75 if (IniIsLineEmpty(IniFileLine, LineLength) || IniIsCommentLine(IniFileLine, LineLength))
76 {
77 CurrentLineNumber++;
78 continue;
79 }
80
81 // Check if it is a new section
82 if (IniIsSectionName(IniFileLine, LineLength))
83 {
84 // Allocate a new section structure
85 CurrentSection = FrLdrTempAlloc(sizeof(INI_SECTION), TAG_INI_SECTION);
86 if (!CurrentSection)
87 {
88 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
89 return FALSE;
90 }
91
92 RtlZeroMemory(CurrentSection, sizeof(INI_SECTION));
93
94 // Allocate the section name buffer
95 CurrentSection->SectionName = FrLdrTempAlloc(IniGetSectionNameSize(IniFileLine, LineLength), TAG_INI_NAME);
96 if (!CurrentSection->SectionName)
97 {
98 FrLdrTempFree(CurrentSection, TAG_INI_FILE);
99 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
100 return FALSE;
101 }
102
103 // Get the section name
104 IniExtractSectionName(CurrentSection->SectionName, IniFileLine, LineLength);
105 InitializeListHead(&CurrentSection->SectionItemList);
106
107 // Add it to the section list head
110
111 CurrentLineNumber++;
112 continue;
113 }
114
115 // Check if it is a setting
116 if (IniIsSetting(IniFileLine, LineLength))
117 {
118 // First check to make sure we're inside a [section]
119 if (CurrentSection == NULL)
120 {
121 ERR("Error: freeldr.ini:%lu: Setting '%s' found outside of a [section].\n", CurrentLineNumber, IniFileLine);
122
123 // Skip it
124 CurrentLineNumber++;
125 continue;
126 }
127
128 // Allocate a new item structure
130 if (!CurrentItem)
131 {
132 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
133 return FALSE;
134 }
135
136 RtlZeroMemory(CurrentItem, sizeof(INI_SECTION_ITEM));
137
138 // Allocate the setting name buffer
139 CurrentItem->ItemName = FrLdrTempAlloc(IniGetSettingNameSize(IniFileLine, LineLength), TAG_INI_NAME);
140 if (!CurrentItem->ItemName)
141 {
143 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
144 return FALSE;
145 }
146
147 // Allocate the setting value buffer
148 CurrentItem->ItemValue = FrLdrTempAlloc(IniGetSettingValueSize(IniFileLine, LineLength), TAG_INI_VALUE);
149 if (!CurrentItem->ItemValue)
150 {
151 FrLdrTempFree(CurrentItem->ItemName, TAG_INI_NAME);
153 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
154 return FALSE;
155 }
156
157 // Get the section name
158 IniExtractSettingName(CurrentItem->ItemName, IniFileLine, LineLength);
159 IniExtractSettingValue(CurrentItem->ItemValue, IniFileLine, LineLength);
160
161 // Add it to the current section
163 CurrentSection->SectionItemCount++;
164 InsertTailList(&CurrentSection->SectionItemList, &CurrentItem->ListEntry);
165
166 CurrentLineNumber++;
167 continue;
168 }
169
170 CurrentLineNumber++;
171 }
172
173 FrLdrTempFree(IniFileLine, TAG_INI_FILE);
174
175 TRACE("Parsed %d sections and %d settings.\n", IniFileSectionCount, IniFileSettingCount);
176 TRACE("IniParseFile() done.\n");
177
178 return TRUE;
179}
180
181ULONG IniGetNextLineSize(PCSTR IniFileData, ULONG IniFileSize, ULONG CurrentOffset)
182{
183 ULONG LineCharCount = 0;
184
185 // Loop through counting chars until we hit the end
186 // of the file or we encounter a newline character
187 for (; (CurrentOffset < IniFileSize); ++CurrentOffset)
188 {
189 // Increment the line character count
190 ++LineCharCount;
191
192 // Check for newline character
193 if (IniFileData[CurrentOffset] == '\n')
194 break;
195 }
196 // Count the NUL-terminator
197 ++LineCharCount;
198
199 return LineCharCount;
200}
201
202ULONG IniGetNextLine(PCSTR IniFileData, ULONG IniFileSize, PCHAR Buffer, ULONG BufferSize, ULONG CurrentOffset)
203{
204 ULONG Idx;
205
206 // Loop through grabbing chars until we hit the end
207 // of the file or we encounter a newline character
208 for (Idx = 0; (CurrentOffset < IniFileSize); ++CurrentOffset)
209 {
210 // If we haven't exceeded our buffer size yet
211 // then store another character
212 if (Idx < (BufferSize - 1))
213 Buffer[Idx++] = IniFileData[CurrentOffset];
214
215 // Check for newline character
216 if (IniFileData[CurrentOffset] == '\n')
217 {
218 ++CurrentOffset;
219 break;
220 }
221 }
222
223 // Terminate the string
224 Buffer[Idx] = '\0';
225
226 // Get rid of newline & linefeed characters (if any)
227 while (Idx && (Buffer[--Idx] == '\n' || Buffer[Idx] == '\r'))
228 Buffer[Idx] = '\0';
229
230 return CurrentOffset;
231}
232
233BOOLEAN IniIsLineEmpty(PCSTR TextLine, ULONG TextLength)
234{
235 ULONG Idx;
236
237 // Check for text (skipping whitespace)
238 for (Idx = 0; Idx < TextLength; ++Idx)
239 {
240 if ((TextLine[Idx] == ' ') || (TextLine[Idx] == '\t') ||
241 (TextLine[Idx] == '\n') || (TextLine[Idx] == '\r'))
242 {
243 continue;
244 }
245 return FALSE;
246 }
247 return TRUE;
248}
249
250BOOLEAN IniIsCommentLine(PCSTR TextLine, ULONG TextLength)
251{
252 ULONG Idx;
253
254 // Check the first character (skipping whitespace)
255 // and make sure that it is a comment character
256 for (Idx = 0; Idx < TextLength; ++Idx)
257 {
258 if ((TextLine[Idx] == ' ') || (TextLine[Idx] == '\t'))
259 continue;
260
261 if (TextLine[Idx] == INI_FILE_COMMENT_CHAR)
262 return TRUE;
263 break;
264 }
265 return FALSE;
266}
267
268BOOLEAN IniIsSectionName(PCSTR TextLine, ULONG TextLength)
269{
270 ULONG Idx;
271
272 // Check the first character (skipping whitespace)
273 // and make sure that it is an opening bracket
274 for (Idx = 0; Idx < TextLength; ++Idx)
275 {
276 if ((TextLine[Idx] == ' ') || (TextLine[Idx] == '\t'))
277 continue;
278
279 if (TextLine[Idx] == '[')
280 return TRUE;
281 break;
282 }
283 return FALSE;
284}
285
286ULONG IniGetSectionNameSize(PCSTR SectionNameLine, ULONG LineLength)
287{
288 ULONG Idx, NameSize;
289
290 // Find the opening bracket (skipping whitespace)
291 for (Idx = 0; Idx < LineLength; ++Idx)
292 {
293 if ((SectionNameLine[Idx] == ' ') || (SectionNameLine[Idx] == '\t'))
294 continue;
295
296 //if (SectionNameLine[Idx] == '[')
297 break;
298 }
299 // Skip past the opening bracket
300 ++Idx;
301
302 // Count the characters up until the closing bracket or EOL
303 for (NameSize = 0; Idx < LineLength; ++Idx)
304 {
305 if ((SectionNameLine[Idx] == ']') || (SectionNameLine[Idx] == '\0'))
306 break;
307 ++NameSize;
308 }
309 // Count the NUL-terminator
310 ++NameSize;
311
312 return NameSize;
313}
314
315VOID IniExtractSectionName(PSTR SectionName, PCSTR SectionNameLine, ULONG LineLength)
316{
317 ULONG Idx, DestIdx;
318
319 // Find the opening bracket (skipping whitespace)
320 for (Idx = 0; Idx < LineLength; ++Idx)
321 {
322 if ((SectionNameLine[Idx] == ' ') || (SectionNameLine[Idx] == '\t'))
323 continue;
324
325 //if (SectionNameLine[Idx] == '[')
326 break;
327 }
328 // Skip past the opening bracket
329 ++Idx;
330
331 // Count the characters up until the closing bracket or EOL
332 for (DestIdx = 0; Idx < LineLength; ++Idx)
333 {
334 if ((SectionNameLine[Idx] == ']') || (SectionNameLine[Idx] == '\0'))
335 break;
336
337 // Copy the character
338 SectionName[DestIdx] = SectionNameLine[Idx];
339 ++DestIdx;
340 }
341
342 // Terminate the string
343 SectionName[DestIdx] = '\0';
344}
345
346BOOLEAN IniIsSetting(PCSTR TextLine, ULONG TextLength)
347{
348 ULONG Idx;
349
350 // Just check for an '=' equals sign
351 for (Idx = 0; Idx < TextLength; ++Idx)
352 {
353 if (TextLine[Idx] == '=')
354 return TRUE;
355 }
356 return FALSE;
357}
358
359ULONG IniGetSettingNameSize(PCSTR SettingNameLine, ULONG LineLength)
360{
361 ULONG Idx, NameSize;
362
363 // Skip whitespace
364 for (Idx = 0; Idx < LineLength; ++Idx)
365 {
366 if ((SettingNameLine[Idx] == ' ') || (SettingNameLine[Idx] == '\t'))
367 continue;
368 break;
369 }
370
371 // Count the characters up until the '=' equals sign or EOL
372 for (NameSize = 0; Idx < LineLength; ++Idx)
373 {
374 if ((SettingNameLine[Idx] == '=') || (SettingNameLine[Idx] == '\0'))
375 break;
376 ++NameSize;
377 }
378 // Count the NUL-terminator
379 ++NameSize;
380
381 return NameSize;
382}
383
384ULONG IniGetSettingValueSize(PCSTR SettingValueLine, ULONG LineLength)
385{
386 ULONG Idx, ValueSize;
387
388 // Skip whitespace
389 for (Idx = 0; Idx < LineLength; ++Idx)
390 {
391 if ((SettingValueLine[Idx] == ' ') || (SettingValueLine[Idx] == '\t'))
392 continue;
393 break;
394 }
395
396 // Skip the characters up until the '=' equals sign or EOL
397 for (; Idx < LineLength; ++Idx)
398 {
399 if (SettingValueLine[Idx] == '=')
400 {
401 ++Idx;
402 break;
403 }
404
405 // If we hit EOL then obviously the value size is zero
406 if (SettingValueLine[Idx] == '\0')
407 return 0;
408 }
409
410 // Count the characters up until the EOL
411 for (ValueSize = 0; Idx < LineLength; ++Idx)
412 {
413 if (SettingValueLine[Idx] == '\0')
414 break;
415 ++ValueSize;
416 }
417 // Count the NUL-terminator
418 ++ValueSize;
419
420 return ValueSize;
421}
422
423VOID IniExtractSettingName(PSTR SettingName, PCSTR SettingNameLine, ULONG LineLength)
424{
425 ULONG Idx, DestIdx;
426
427 // Skip whitespace
428 for (Idx = 0; Idx < LineLength; ++Idx)
429 {
430 if ((SettingNameLine[Idx] == ' ') || (SettingNameLine[Idx] == '\t'))
431 continue;
432 break;
433 }
434
435 // Get the characters up until the '=' equals sign or EOL
436 for (DestIdx = 0; Idx < LineLength; ++Idx)
437 {
438 if ((SettingNameLine[Idx] == '=') || (SettingNameLine[Idx] == '\0'))
439 {
440 // Before ending, trim any trailing whitespace
441 for (; DestIdx > 0; --DestIdx)
442 {
443 if ((SettingName[DestIdx-1] == ' ') || (SettingName[DestIdx-1] == '\t'))
444 continue;
445 break;
446 }
447 break;
448 }
449
450 // Copy the character
451 SettingName[DestIdx] = SettingNameLine[Idx];
452 ++DestIdx;
453 }
454
455 // Terminate the string
456 SettingName[DestIdx] = '\0';
457}
458
459VOID IniExtractSettingValue(PSTR SettingValue, PCSTR SettingValueLine, ULONG LineLength)
460{
461 ULONG Idx, DestIdx;
462
463 // Skip whitespace
464 for (Idx = 0; Idx < LineLength; ++Idx)
465 {
466 if ((SettingValueLine[Idx] == ' ') || (SettingValueLine[Idx] == '\t'))
467 continue;
468 break;
469 }
470
471 // Skip the characters up until the '=' equals sign or EOL
472 for (; Idx < LineLength; ++Idx)
473 {
474 if (SettingValueLine[Idx] == '=')
475 {
476 ++Idx;
477 break;
478 }
479
480 // If we hit EOL then obviously the value size is zero
481 if (SettingValueLine[Idx] == '\0')
482 {
483 SettingValue[0] = '\0';
484 return;
485 }
486 }
487
488 // Get the characters up until the EOL
489 for (DestIdx = 0; Idx < LineLength; ++Idx)
490 {
491 if (SettingValueLine[Idx] == '\0')
492 break;
493
494 // Copy the character
495 SettingValue[DestIdx] = SettingValueLine[Idx];
496 ++DestIdx;
497 }
498
499 // Terminate the string
500 SettingValue[DestIdx] = '\0';
501}
unsigned char BOOLEAN
Definition: actypes.h:127
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: heap.c:553
PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: heap.c:545
ULONG IniFileSectionCount
Definition: parse.c:27
VOID IniExtractSettingValue(PSTR SettingValue, PCSTR SettingValueLine, ULONG LineLength)
Definition: parse.c:459
ULONG IniGetSectionNameSize(PCSTR SectionNameLine, ULONG LineLength)
Definition: parse.c:286
VOID IniExtractSectionName(PSTR SectionName, PCSTR SectionNameLine, ULONG LineLength)
Definition: parse.c:315
ULONG IniGetSettingValueSize(PCSTR SettingValueLine, ULONG LineLength)
Definition: parse.c:384
BOOLEAN IniIsLineEmpty(PCSTR TextLine, ULONG TextLength)
Definition: parse.c:233
ULONG IniGetSettingNameSize(PCSTR SettingNameLine, ULONG LineLength)
Definition: parse.c:359
ULONG IniFileSettingCount
Definition: parse.c:28
LIST_ENTRY IniFileSectionListHead
Definition: parse.c:25
BOOLEAN IniIsSectionName(PCSTR TextLine, ULONG TextLength)
Definition: parse.c:268
ULONG IniGetNextLine(PCSTR IniFileData, ULONG IniFileSize, PCHAR Buffer, ULONG BufferSize, ULONG CurrentOffset)
Definition: parse.c:202
VOID IniExtractSettingName(PSTR SettingName, PCSTR SettingNameLine, ULONG LineLength)
Definition: parse.c:423
BOOLEAN IniIsCommentLine(PCSTR TextLine, ULONG TextLength)
Definition: parse.c:250
BOOLEAN IniParseFile(PCSTR IniFileData, ULONG IniFileSize)
Definition: parse.c:31
ULONG IniGetNextLineSize(PCSTR IniFileData, ULONG IniFileSize, ULONG CurrentOffset)
Definition: parse.c:181
BOOLEAN IniIsSetting(PCSTR TextLine, ULONG TextLength)
Definition: parse.c:346
BOOLEAN IniFileSectionInitialized
Definition: parse.c:26
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1592
#define InsertTailList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define TAG_INI_VALUE
Definition: inifile.h:28
#define TAG_INI_SECTION_ITEM
Definition: inifile.h:26
#define TAG_INI_SECTION
Definition: inifile.h:25
#define TAG_INI_FILE
Definition: inifile.h:24
#define TAG_INI_NAME
Definition: inifile.h:27
#define INI_FILE_COMMENT_CHAR
Definition: inifile.h:22
#define TRACE(s)
Definition: solgame.cpp:4
LIST_ENTRY ListEntry
Definition: inifile.h:35
PSTR ItemValue
Definition: inifile.h:37
LIST_ENTRY ListEntry
Definition: inicache.h:21
Definition: typedefs.h:120
@ INIFILE
Definition: tnconfig.cpp:129
char * PSTR
Definition: typedefs.h:51
const char * PCSTR
Definition: typedefs.h:52
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG
Definition: typedefs.h:59
char * PCHAR
Definition: typedefs.h:51
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254