1 /*
2 * PROJECT: .inf file parser
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PROGRAMMER: Royce Mitchell III
5 * Eric Kohl
6 * Ge van Geldorp <gvg@reactos.org>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "inflib.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #define CONTROL_Z '\x1a'
17 #define MAX_SECTION_NAME_LEN 255
18 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
19 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
20 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
21
22
23 /* parser definitions */
24
25 enum parser_state
26 {
27 LINE_START, /* at beginning of a line */
28 SECTION_NAME, /* parsing a section name */
29 KEY_NAME, /* parsing a key name */
30 VALUE_NAME, /* parsing a value name */
31 EOL_BACKSLASH, /* backslash at end of line */
32 QUOTES, /* inside quotes */
33 LEADING_SPACES, /* leading spaces */
34 TRAILING_SPACES, /* trailing spaces */
35 COMMENT, /* inside a comment */
36 NB_PARSER_STATES
37 };
38
39 struct parser
40 {
41 const WCHAR *start; /* start position of item being parsed */
42 const WCHAR *end; /* end of buffer */
43 PINFCACHE file; /* file being built */
44 enum parser_state state; /* current parser state */
45 enum parser_state stack[4]; /* state stack */
46 int stack_pos; /* current pos in stack */
47
48 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/
49 PINFCACHELINE line; /* current line */
50 unsigned int line_pos; /* current line position in file */
51 INFSTATUS error; /* error code */
52 unsigned int token_len; /* current token len */
53 WCHAR token[MAX_FIELD_LEN+1]; /* current token */
54 };
55
56 typedef const WCHAR * (*parser_state_func)( struct parser *parser, const WCHAR *pos );
57
58 /* parser state machine functions */
59 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos );
60 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos );
61 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos );
62 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos );
63 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos );
64 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos );
65 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos );
66 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos );
67 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos );
68
69 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
70 {
71 line_start_state, /* LINE_START */
72 section_name_state, /* SECTION_NAME */
73 key_name_state, /* KEY_NAME */
74 value_name_state, /* VALUE_NAME */
75 eol_backslash_state, /* EOL_BACKSLASH */
76 quotes_state, /* QUOTES */
77 leading_spaces_state, /* LEADING_SPACES */
78 trailing_spaces_state, /* TRAILING_SPACES */
79 comment_state /* COMMENT */
80 };
81
82
83 /* PRIVATE FUNCTIONS ********************************************************/
84
85 static PINFCACHELINE
InfpFreeLine(PINFCACHELINE Line)86 InfpFreeLine (PINFCACHELINE Line)
87 {
88 PINFCACHELINE Next;
89 PINFCACHEFIELD Field;
90
91 if (Line == NULL)
92 {
93 return NULL;
94 }
95
96 Next = Line->Next;
97 if (Line->Key != NULL)
98 {
99 FREE (Line->Key);
100 Line->Key = NULL;
101 }
102
103 /* Remove data fields */
104 while (Line->FirstField != NULL)
105 {
106 Field = Line->FirstField->Next;
107 FREE (Line->FirstField);
108 Line->FirstField = Field;
109 }
110 Line->LastField = NULL;
111
112 FREE (Line);
113
114 return Next;
115 }
116
117
118 PINFCACHESECTION
InfpFreeSection(PINFCACHESECTION Section)119 InfpFreeSection (PINFCACHESECTION Section)
120 {
121 PINFCACHESECTION Next;
122
123 if (Section == NULL)
124 {
125 return NULL;
126 }
127
128 /* Release all keys */
129 Next = Section->Next;
130 while (Section->FirstLine != NULL)
131 {
132 Section->FirstLine = InfpFreeLine (Section->FirstLine);
133 }
134 Section->LastLine = NULL;
135
136 FREE (Section);
137
138 return Next;
139 }
140
141
142 PINFCACHESECTION
InfpFindSection(PINFCACHE Cache,PCWSTR Name)143 InfpFindSection(PINFCACHE Cache,
144 PCWSTR Name)
145 {
146 PINFCACHESECTION Section = NULL;
147
148 if (Cache == NULL || Name == NULL)
149 {
150 return NULL;
151 }
152
153 /* iterate through list of sections */
154 Section = Cache->FirstSection;
155 while (Section != NULL)
156 {
157 if (strcmpiW(Section->Name, Name) == 0)
158 {
159 return Section;
160 }
161
162 /* get the next section*/
163 Section = Section->Next;
164 }
165
166 return NULL;
167 }
168
169
170 PINFCACHESECTION
InfpAddSection(PINFCACHE Cache,PCWSTR Name)171 InfpAddSection(PINFCACHE Cache,
172 PCWSTR Name)
173 {
174 PINFCACHESECTION Section = NULL;
175 ULONG Size;
176
177 if (Cache == NULL || Name == NULL)
178 {
179 DPRINT("Invalid parameter\n");
180 return NULL;
181 }
182
183 /* Allocate and initialize the new section */
184 Size = (ULONG)FIELD_OFFSET(INFCACHESECTION,
185 Name[strlenW(Name) + 1]);
186 Section = (PINFCACHESECTION)MALLOC(Size);
187 if (Section == NULL)
188 {
189 DPRINT("MALLOC() failed\n");
190 return NULL;
191 }
192 ZEROMEMORY (Section,
193 Size);
194 Section->Id = ++Cache->NextSectionId;
195
196 /* Copy section name */
197 strcpyW(Section->Name, Name);
198
199 /* Append section */
200 if (Cache->FirstSection == NULL)
201 {
202 Cache->FirstSection = Section;
203 Cache->LastSection = Section;
204 }
205 else
206 {
207 Cache->LastSection->Next = Section;
208 Section->Prev = Cache->LastSection;
209 Cache->LastSection = Section;
210 }
211
212 return Section;
213 }
214
215
216 PINFCACHELINE
InfpAddLine(PINFCACHESECTION Section)217 InfpAddLine(PINFCACHESECTION Section)
218 {
219 PINFCACHELINE Line;
220
221 if (Section == NULL)
222 {
223 DPRINT("Invalid parameter\n");
224 return NULL;
225 }
226
227 Line = (PINFCACHELINE)MALLOC(sizeof(INFCACHELINE));
228 if (Line == NULL)
229 {
230 DPRINT("MALLOC() failed\n");
231 return NULL;
232 }
233 ZEROMEMORY(Line,
234 sizeof(INFCACHELINE));
235 Line->Id = ++Section->NextLineId;
236
237 /* Append line */
238 if (Section->FirstLine == NULL)
239 {
240 Section->FirstLine = Line;
241 Section->LastLine = Line;
242 }
243 else
244 {
245 Section->LastLine->Next = Line;
246 Line->Prev = Section->LastLine;
247 Section->LastLine = Line;
248 }
249 Section->LineCount++;
250
251 return Line;
252 }
253
254 PINFCACHESECTION
InfpFindSectionById(PINFCACHE Cache,UINT Id)255 InfpFindSectionById(PINFCACHE Cache, UINT Id)
256 {
257 PINFCACHESECTION Section;
258
259 for (Section = Cache->FirstSection;
260 Section != NULL;
261 Section = Section->Next)
262 {
263 if (Section->Id == Id)
264 {
265 return Section;
266 }
267 }
268
269 return NULL;
270 }
271
272 PINFCACHESECTION
InfpGetSectionForContext(PINFCONTEXT Context)273 InfpGetSectionForContext(PINFCONTEXT Context)
274 {
275 PINFCACHE Cache;
276
277 if (Context == NULL)
278 {
279 return NULL;
280 }
281
282 Cache = (PINFCACHE)Context->Inf;
283 if (Cache == NULL)
284 {
285 return NULL;
286 }
287
288 return InfpFindSectionById(Cache, Context->Section);
289 }
290
291 PINFCACHELINE
InfpFindLineById(PINFCACHESECTION Section,UINT Id)292 InfpFindLineById(PINFCACHESECTION Section, UINT Id)
293 {
294 PINFCACHELINE Line;
295
296 for (Line = Section->FirstLine;
297 Line != NULL;
298 Line = Line->Next)
299 {
300 if (Line->Id == Id)
301 {
302 return Line;
303 }
304 }
305
306 return NULL;
307 }
308
309 PINFCACHELINE
InfpGetLineForContext(PINFCONTEXT Context)310 InfpGetLineForContext(PINFCONTEXT Context)
311 {
312 PINFCACHESECTION Section;
313
314 Section = InfpGetSectionForContext(Context);
315 if (Section == NULL)
316 {
317 return NULL;
318 }
319
320 return InfpFindLineById(Section, Context->Line);
321 }
322
323 PVOID
InfpAddKeyToLine(PINFCACHELINE Line,PCWSTR Key)324 InfpAddKeyToLine(PINFCACHELINE Line,
325 PCWSTR Key)
326 {
327 if (Line == NULL)
328 {
329 DPRINT1("Invalid Line\n");
330 return NULL;
331 }
332
333 if (Line->Key != NULL)
334 {
335 DPRINT1("Line already has a key\n");
336 return NULL;
337 }
338
339 Line->Key = (PWCHAR)MALLOC((strlenW(Key) + 1) * sizeof(WCHAR));
340 if (Line->Key == NULL)
341 {
342 DPRINT1("MALLOC() failed\n");
343 return NULL;
344 }
345
346 strcpyW(Line->Key, Key);
347
348 return (PVOID)Line->Key;
349 }
350
351
352 PVOID
InfpAddFieldToLine(PINFCACHELINE Line,PCWSTR Data)353 InfpAddFieldToLine(PINFCACHELINE Line,
354 PCWSTR Data)
355 {
356 PINFCACHEFIELD Field;
357 ULONG Size;
358
359 Size = (ULONG)FIELD_OFFSET(INFCACHEFIELD,
360 Data[strlenW(Data) + 1]);
361 Field = (PINFCACHEFIELD)MALLOC(Size);
362 if (Field == NULL)
363 {
364 DPRINT1("MALLOC() failed\n");
365 return NULL;
366 }
367 ZEROMEMORY (Field,
368 Size);
369 strcpyW(Field->Data, Data);
370
371 /* Append key */
372 if (Line->FirstField == NULL)
373 {
374 Line->FirstField = Field;
375 Line->LastField = Field;
376 }
377 else
378 {
379 Line->LastField->Next = Field;
380 Field->Prev = Line->LastField;
381 Line->LastField = Field;
382 }
383 Line->FieldCount++;
384
385 return (PVOID)Field;
386 }
387
388
389 PINFCACHELINE
InfpFindKeyLine(PINFCACHESECTION Section,PCWSTR Key)390 InfpFindKeyLine(PINFCACHESECTION Section,
391 PCWSTR Key)
392 {
393 PINFCACHELINE Line;
394
395 Line = Section->FirstLine;
396 while (Line != NULL)
397 {
398 if (Line->Key != NULL && strcmpiW(Line->Key, Key) == 0)
399 {
400 return Line;
401 }
402
403 Line = Line->Next;
404 }
405
406 return NULL;
407 }
408
409
410 /* push the current state on the parser stack */
push_state(struct parser * parser,enum parser_state state)411 __inline static void push_state( struct parser *parser, enum parser_state state )
412 {
413 // assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
414 parser->stack[parser->stack_pos++] = state;
415 }
416
417
418 /* pop the current state */
pop_state(struct parser * parser)419 __inline static void pop_state( struct parser *parser )
420 {
421 // assert( parser->stack_pos );
422 parser->state = parser->stack[--parser->stack_pos];
423 }
424
425
426 /* set the parser state and return the previous one */
set_state(struct parser * parser,enum parser_state state)427 __inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
428 {
429 enum parser_state ret = parser->state;
430 parser->state = state;
431 return ret;
432 }
433
434
435 /* check if the pointer points to an end of file */
is_eof(struct parser * parser,const WCHAR * ptr)436 __inline static int is_eof( struct parser *parser, const WCHAR *ptr )
437 {
438 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == 0);
439 }
440
441
442 /* check if the pointer points to an end of line */
is_eol(struct parser * parser,const WCHAR * ptr)443 __inline static int is_eol( struct parser *parser, const WCHAR *ptr )
444 {
445 return (ptr >= parser->end ||
446 *ptr == CONTROL_Z ||
447 *ptr == '\n' ||
448 (*ptr == '\r' && *(ptr + 1) == '\n') ||
449 *ptr == 0);
450 }
451
452
453 /* push data from current token start up to pos into the current token */
push_token(struct parser * parser,const WCHAR * pos)454 static int push_token( struct parser *parser, const WCHAR *pos )
455 {
456 UINT len = (UINT)(pos - parser->start);
457 const WCHAR *src = parser->start;
458 WCHAR *dst = parser->token + parser->token_len;
459
460 if (len > MAX_FIELD_LEN - parser->token_len)
461 len = MAX_FIELD_LEN - parser->token_len;
462
463 parser->token_len += len;
464 for ( ; len > 0; len--, dst++, src++)
465 {
466 if (*src)
467 {
468 *dst = *src;
469 }
470 else
471 {
472 *dst = ' ';
473 }
474 }
475
476 *dst = 0;
477 parser->start = pos;
478
479 return 0;
480 }
481
482
483
484 /* add a section with the current token as name */
add_section_from_token(struct parser * parser)485 static PVOID add_section_from_token( struct parser *parser )
486 {
487 PINFCACHESECTION Section;
488
489 if (parser->token_len > MAX_SECTION_NAME_LEN)
490 {
491 parser->error = INF_STATUS_SECTION_NAME_TOO_LONG;
492 return NULL;
493 }
494
495 Section = InfpFindSection(parser->file,
496 parser->token);
497 if (Section == NULL)
498 {
499 /* need to create a new one */
500 Section= InfpAddSection(parser->file,
501 parser->token);
502 if (Section == NULL)
503 {
504 parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
505 return NULL;
506 }
507 }
508
509 parser->token_len = 0;
510 parser->cur_section = Section;
511
512 return (PVOID)Section;
513 }
514
515
516 /* add a field containing the current token to the current line */
add_field_from_token(struct parser * parser,int is_key)517 static struct field *add_field_from_token( struct parser *parser, int is_key )
518 {
519 PVOID field;
520
521 if (!parser->line) /* need to start a new line */
522 {
523 if (parser->cur_section == NULL) /* got a line before the first section */
524 {
525 parser->error = INF_STATUS_WRONG_INF_STYLE;
526 return NULL;
527 }
528
529 parser->line = InfpAddLine(parser->cur_section);
530 if (parser->line == NULL)
531 goto error;
532 }
533 else
534 {
535 // assert(!is_key);
536 }
537
538 if (is_key)
539 {
540 field = InfpAddKeyToLine(parser->line, parser->token);
541 }
542 else
543 {
544 field = InfpAddFieldToLine(parser->line, parser->token);
545 }
546
547 if (field != NULL)
548 {
549 parser->token_len = 0;
550 return field;
551 }
552
553 error:
554 parser->error = INF_STATUS_NOT_ENOUGH_MEMORY;
555 return NULL;
556 }
557
558
559 /* close the current line and prepare for parsing a new one */
close_current_line(struct parser * parser)560 static void close_current_line( struct parser *parser )
561 {
562 parser->line = NULL;
563 }
564
565
566
567 /* handler for parser LINE_START state */
line_start_state(struct parser * parser,const WCHAR * pos)568 static const WCHAR *line_start_state( struct parser *parser, const WCHAR *pos )
569 {
570 const WCHAR *p;
571
572 for (p = pos; !is_eof( parser, p ); p++)
573 {
574 switch(*p)
575 {
576 case '\r':
577 continue;
578
579 case '\n':
580 parser->line_pos++;
581 close_current_line( parser );
582 break;
583
584 case ';':
585 push_state( parser, LINE_START );
586 set_state( parser, COMMENT );
587 return p + 1;
588
589 case '[':
590 parser->start = p + 1;
591 set_state( parser, SECTION_NAME );
592 return p + 1;
593
594 default:
595 if (!isspaceW(*p))
596 {
597 parser->start = p;
598 set_state( parser, KEY_NAME );
599 return p;
600 }
601 break;
602 }
603 }
604 close_current_line( parser );
605 return NULL;
606 }
607
608
609 /* handler for parser SECTION_NAME state */
section_name_state(struct parser * parser,const WCHAR * pos)610 static const WCHAR *section_name_state( struct parser *parser, const WCHAR *pos )
611 {
612 const WCHAR *p;
613
614 for (p = pos; !is_eol( parser, p ); p++)
615 {
616 if (*p == ']')
617 {
618 push_token( parser, p );
619 if (add_section_from_token( parser ) == NULL)
620 return NULL;
621 push_state( parser, LINE_START );
622 set_state( parser, COMMENT ); /* ignore everything else on the line */
623 return p + 1;
624 }
625 }
626 parser->error = INF_STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
627 return NULL;
628 }
629
630
631 /* handler for parser KEY_NAME state */
key_name_state(struct parser * parser,const WCHAR * pos)632 static const WCHAR *key_name_state( struct parser *parser, const WCHAR *pos )
633 {
634 const WCHAR *p, *token_end = parser->start;
635
636 for (p = pos; !is_eol( parser, p ); p++)
637 {
638 if (*p == ',') break;
639 switch(*p)
640 {
641
642 case '=':
643 push_token( parser, token_end );
644 if (!add_field_from_token( parser, 1 )) return NULL;
645 parser->start = p + 1;
646 push_state( parser, VALUE_NAME );
647 set_state( parser, LEADING_SPACES );
648 return p + 1;
649 case ';':
650 push_token( parser, token_end );
651 if (!add_field_from_token( parser, 0 )) return NULL;
652 push_state( parser, LINE_START );
653 set_state( parser, COMMENT );
654 return p + 1;
655 case '"':
656 push_token( parser, token_end );
657 parser->start = p + 1;
658 push_state( parser, KEY_NAME );
659 set_state( parser, QUOTES );
660 return p + 1;
661 case '\\':
662 push_token( parser, token_end );
663 parser->start = p;
664 push_state( parser, KEY_NAME );
665 set_state( parser, EOL_BACKSLASH );
666 return p;
667 default:
668 if (!isspaceW(*p)) token_end = p + 1;
669 else
670 {
671 push_token( parser, p );
672 push_state( parser, KEY_NAME );
673 set_state( parser, TRAILING_SPACES );
674 return p;
675 }
676 break;
677 }
678 }
679 push_token( parser, token_end );
680 set_state( parser, VALUE_NAME );
681 return p;
682 }
683
684
685 /* handler for parser VALUE_NAME state */
value_name_state(struct parser * parser,const WCHAR * pos)686 static const WCHAR *value_name_state( struct parser *parser, const WCHAR *pos )
687 {
688 const WCHAR *p, *token_end = parser->start;
689
690 for (p = pos; !is_eol( parser, p ); p++)
691 {
692 switch(*p)
693 {
694 case ';':
695 push_token( parser, token_end );
696 if (!add_field_from_token( parser, 0 )) return NULL;
697 push_state( parser, LINE_START );
698 set_state( parser, COMMENT );
699 return p + 1;
700 case ',':
701 push_token( parser, token_end );
702 if (!add_field_from_token( parser, 0 )) return NULL;
703 parser->start = p + 1;
704 push_state( parser, VALUE_NAME );
705 set_state( parser, LEADING_SPACES );
706 return p + 1;
707 case '"':
708 push_token( parser, token_end );
709 parser->start = p + 1;
710 push_state( parser, VALUE_NAME );
711 set_state( parser, QUOTES );
712 return p + 1;
713 case '\\':
714 push_token( parser, token_end );
715 parser->start = p;
716 push_state( parser, VALUE_NAME );
717 set_state( parser, EOL_BACKSLASH );
718 return p;
719 default:
720 if (!isspaceW(*p)) token_end = p + 1;
721 else
722 {
723 push_token( parser, p );
724 push_state( parser, VALUE_NAME );
725 set_state( parser, TRAILING_SPACES );
726 return p;
727 }
728 break;
729 }
730 }
731 push_token( parser, token_end );
732 if (!add_field_from_token( parser, 0 )) return NULL;
733 set_state( parser, LINE_START );
734 return p;
735 }
736
737
738 /* handler for parser EOL_BACKSLASH state */
eol_backslash_state(struct parser * parser,const WCHAR * pos)739 static const WCHAR *eol_backslash_state( struct parser *parser, const WCHAR *pos )
740 {
741 const WCHAR *p;
742
743 for (p = pos; !is_eof( parser, p ); p++)
744 {
745 switch(*p)
746 {
747 case '\r':
748 continue;
749
750 case '\n':
751 parser->line_pos++;
752 parser->start = p + 1;
753 set_state( parser, LEADING_SPACES );
754 return p + 1;
755
756 case '\\':
757 continue;
758
759 case ';':
760 push_state( parser, EOL_BACKSLASH );
761 set_state( parser, COMMENT );
762 return p + 1;
763
764 default:
765 if (isspaceW(*p))
766 continue;
767 push_token( parser, p );
768 pop_state( parser );
769 return p;
770 }
771 }
772 parser->start = p;
773 pop_state( parser );
774
775 return p;
776 }
777
778
779 /* handler for parser QUOTES state */
quotes_state(struct parser * parser,const WCHAR * pos)780 static const WCHAR *quotes_state( struct parser *parser, const WCHAR *pos )
781 {
782 const WCHAR *p, *token_end = parser->start;
783
784 for (p = pos; !is_eol( parser, p ); p++)
785 {
786 if (*p == '"')
787 {
788 if (p+1 < parser->end && p[1] == '"') /* double quotes */
789 {
790 push_token( parser, p + 1 );
791 parser->start = token_end = p + 2;
792 p++;
793 }
794 else /* end of quotes */
795 {
796 push_token( parser, p );
797 parser->start = p + 1;
798 pop_state( parser );
799 return p + 1;
800 }
801 }
802 }
803 push_token( parser, p );
804 pop_state( parser );
805 return p;
806 }
807
808
809 /* handler for parser LEADING_SPACES state */
leading_spaces_state(struct parser * parser,const WCHAR * pos)810 static const WCHAR *leading_spaces_state( struct parser *parser, const WCHAR *pos )
811 {
812 const WCHAR *p;
813
814 for (p = pos; !is_eol( parser, p ); p++)
815 {
816 if (*p == '\\')
817 {
818 parser->start = p;
819 set_state( parser, EOL_BACKSLASH );
820 return p;
821 }
822 if (!isspaceW(*p))
823 break;
824 }
825 parser->start = p;
826 pop_state( parser );
827 return p;
828 }
829
830
831 /* handler for parser TRAILING_SPACES state */
trailing_spaces_state(struct parser * parser,const WCHAR * pos)832 static const WCHAR *trailing_spaces_state( struct parser *parser, const WCHAR *pos )
833 {
834 const WCHAR *p;
835
836 for (p = pos; !is_eol( parser, p ); p++)
837 {
838 if (*p == '\\')
839 {
840 set_state( parser, EOL_BACKSLASH );
841 return p;
842 }
843 if (!isspaceW(*p))
844 break;
845 }
846 pop_state( parser );
847 return p;
848 }
849
850
851 /* handler for parser COMMENT state */
comment_state(struct parser * parser,const WCHAR * pos)852 static const WCHAR *comment_state( struct parser *parser, const WCHAR *pos )
853 {
854 const WCHAR *p = pos;
855
856 while (!is_eol( parser, p ))
857 p++;
858 pop_state( parser );
859 return p;
860 }
861
862
863 /* parse a complete buffer */
864 INFSTATUS
InfpParseBuffer(PINFCACHE file,const WCHAR * buffer,const WCHAR * end,PULONG error_line)865 InfpParseBuffer (PINFCACHE file,
866 const WCHAR *buffer,
867 const WCHAR *end,
868 PULONG error_line)
869 {
870 struct parser parser;
871 const WCHAR *pos = buffer;
872
873 parser.start = buffer;
874 parser.end = end;
875 parser.file = file;
876 parser.line = NULL;
877 parser.state = LINE_START;
878 parser.stack_pos = 0;
879 parser.cur_section = NULL;
880 parser.line_pos = 1;
881 parser.error = 0;
882 parser.token_len = 0;
883
884 /* parser main loop */
885 while (pos)
886 pos = (parser_funcs[parser.state])(&parser, pos);
887
888 if (parser.error)
889 {
890 if (error_line)
891 *error_line = parser.line_pos;
892 return parser.error;
893 }
894
895 /* find the [strings] section */
896 file->StringsSection = InfpFindSection(file,
897 L"Strings");
898
899 return INF_STATUS_SUCCESS;
900 }
901
902 /* EOF */
903