inline -> __inline
[reactos.git] / reactos / boot / freeldr / freeldr / inffile / inffile.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002,2003 ReactOS Team
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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/infcache.c
23 * PURPOSE: INF file parser that caches contents of INF file in memory
24 * PROGRAMMER: Royce Mitchell III
25 * Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <freeldr.h>
31
32 #define CONTROL_Z '\x1a'
33 #define MAX_SECTION_NAME_LEN 255
34 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
35 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
36 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
37
38
39 typedef struct _INFCACHEFIELD
40 {
41 struct _INFCACHEFIELD *Next;
42 struct _INFCACHEFIELD *Prev;
43
44 CHAR Data[1];
45 } INFCACHEFIELD, *PINFCACHEFIELD;
46
47
48 typedef struct _INFCACHELINE
49 {
50 struct _INFCACHELINE *Next;
51 struct _INFCACHELINE *Prev;
52
53 ULONG FieldCount;
54
55 PCHAR Key;
56
57 PINFCACHEFIELD FirstField;
58 PINFCACHEFIELD LastField;
59
60 } INFCACHELINE, *PINFCACHELINE;
61
62
63 typedef struct _INFCACHESECTION
64 {
65 struct _INFCACHESECTION *Next;
66 struct _INFCACHESECTION *Prev;
67
68 PINFCACHELINE FirstLine;
69 PINFCACHELINE LastLine;
70
71 LONG LineCount;
72
73 CHAR Name[1];
74 } INFCACHESECTION, *PINFCACHESECTION;
75
76
77 typedef struct _INFCACHE
78 {
79 PINFCACHESECTION FirstSection;
80 PINFCACHESECTION LastSection;
81
82 PINFCACHESECTION StringsSection;
83 } INFCACHE, *PINFCACHE;
84
85
86 /* parser definitions */
87
88 enum parser_state
89 {
90 LINE_START, /* at beginning of a line */
91 SECTION_NAME, /* parsing a section name */
92 KEY_NAME, /* parsing a key name */
93 VALUE_NAME, /* parsing a value name */
94 EOL_BACKSLASH, /* backslash at end of line */
95 QUOTES, /* inside quotes */
96 LEADING_SPACES, /* leading spaces */
97 TRAILING_SPACES, /* trailing spaces */
98 COMMENT, /* inside a comment */
99 NB_PARSER_STATES
100 };
101
102 struct parser
103 {
104 const CHAR *start; /* start position of item being parsed */
105 const CHAR *end; /* end of buffer */
106 PINFCACHE file; /* file being built */
107 enum parser_state state; /* current parser state */
108 enum parser_state stack[4]; /* state stack */
109 int stack_pos; /* current pos in stack */
110
111 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/
112 PINFCACHELINE line; /* current line */
113 unsigned int line_pos; /* current line position in file */
114 unsigned int error; /* error code */
115 unsigned int token_len; /* current token len */
116 CHAR token[MAX_FIELD_LEN+1]; /* current token */
117 };
118
119 typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos );
120
121 /* parser state machine functions */
122 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos );
123 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos );
124 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos );
125 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos );
126 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos );
127 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos );
128 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos );
129 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos );
130 static const CHAR *comment_state( struct parser *parser, const CHAR *pos );
131
132 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
133 {
134 line_start_state, /* LINE_START */
135 section_name_state, /* SECTION_NAME */
136 key_name_state, /* KEY_NAME */
137 value_name_state, /* VALUE_NAME */
138 eol_backslash_state, /* EOL_BACKSLASH */
139 quotes_state, /* QUOTES */
140 leading_spaces_state, /* LEADING_SPACES */
141 trailing_spaces_state, /* TRAILING_SPACES */
142 comment_state /* COMMENT */
143 };
144
145
146 /* PRIVATE FUNCTIONS ********************************************************/
147
148 static PINFCACHELINE
149 InfpCacheFreeLine (PINFCACHELINE Line)
150 {
151 PINFCACHELINE Next;
152 PINFCACHEFIELD Field;
153
154 if (Line == NULL)
155 {
156 return NULL;
157 }
158
159 Next = Line->Next;
160 if (Line->Key != NULL)
161 {
162 MmFreeMemory (Line->Key);
163 Line->Key = NULL;
164 }
165
166 /* Remove data fields */
167 while (Line->FirstField != NULL)
168 {
169 Field = Line->FirstField->Next;
170 MmFreeMemory (Line->FirstField);
171 Line->FirstField = Field;
172 }
173 Line->LastField = NULL;
174
175 MmFreeMemory (Line);
176
177 return Next;
178 }
179
180
181 static PINFCACHESECTION
182 InfpCacheFreeSection (PINFCACHESECTION Section)
183 {
184 PINFCACHESECTION Next;
185
186 if (Section == NULL)
187 {
188 return NULL;
189 }
190
191 /* Release all keys */
192 Next = Section->Next;
193 while (Section->FirstLine != NULL)
194 {
195 Section->FirstLine = InfpCacheFreeLine (Section->FirstLine);
196 }
197 Section->LastLine = NULL;
198
199 MmFreeMemory (Section);
200
201 return Next;
202 }
203
204
205 static PINFCACHESECTION
206 InfpCacheFindSection (PINFCACHE Cache,
207 PCSTR Name)
208 {
209 PINFCACHESECTION Section = NULL;
210
211 if (Cache == NULL || Name == NULL)
212 {
213 return NULL;
214 }
215
216 /* iterate through list of sections */
217 Section = Cache->FirstSection;
218 while (Section != NULL)
219 {
220 if (_stricmp (Section->Name, Name) == 0)
221 {
222 return Section;
223 }
224
225 /* get the next section*/
226 Section = Section->Next;
227 }
228
229 return NULL;
230 }
231
232
233 static PINFCACHESECTION
234 InfpCacheAddSection (PINFCACHE Cache,
235 PCHAR Name)
236 {
237 PINFCACHESECTION Section = NULL;
238 ULONG Size;
239
240 if (Cache == NULL || Name == NULL)
241 {
242 // DPRINT("Invalid parameter\n");
243 return NULL;
244 }
245
246 /* Allocate and initialize the new section */
247 Size = sizeof(INFCACHESECTION) + strlen (Name);
248 Section = (PINFCACHESECTION)MmAllocateMemory (Size);
249 if (Section == NULL)
250 {
251 // DPRINT("RtlAllocateHeap() failed\n");
252 return NULL;
253 }
254 memset (Section, 0, Size);
255
256 /* Copy section name */
257 strcpy (Section->Name, Name);
258
259 /* Append section */
260 if (Cache->FirstSection == NULL)
261 {
262 Cache->FirstSection = Section;
263 Cache->LastSection = Section;
264 }
265 else
266 {
267 Cache->LastSection->Next = Section;
268 Section->Prev = Cache->LastSection;
269 Cache->LastSection = Section;
270 }
271
272 return Section;
273 }
274
275
276 static PINFCACHELINE
277 InfpCacheAddLine (PINFCACHESECTION Section)
278 {
279 PINFCACHELINE Line;
280
281 if (Section == NULL)
282 {
283 // DPRINT("Invalid parameter\n");
284 return NULL;
285 }
286
287 Line = (PINFCACHELINE)MmAllocateMemory (sizeof(INFCACHELINE));
288 if (Line == NULL)
289 {
290 // DPRINT("RtlAllocateHeap() failed\n");
291 return NULL;
292 }
293 memset (Line, 0, sizeof(INFCACHELINE));
294
295 /* Append line */
296 if (Section->FirstLine == NULL)
297 {
298 Section->FirstLine = Line;
299 Section->LastLine = Line;
300 }
301 else
302 {
303 Section->LastLine->Next = Line;
304 Line->Prev = Section->LastLine;
305 Section->LastLine = Line;
306 }
307 Section->LineCount++;
308
309 return Line;
310 }
311
312
313 static PVOID
314 InfpAddKeyToLine (PINFCACHELINE Line,
315 PCHAR Key)
316 {
317 if (Line == NULL)
318 return NULL;
319
320 if (Line->Key != NULL)
321 return NULL;
322
323 Line->Key = (PCHAR)MmAllocateMemory (strlen (Key) + 1);
324 if (Line->Key == NULL)
325 return NULL;
326
327 strcpy (Line->Key, Key);
328
329 return (PVOID)Line->Key;
330 }
331
332
333 static PVOID
334 InfpAddFieldToLine (PINFCACHELINE Line,
335 PCHAR Data)
336 {
337 PINFCACHEFIELD Field;
338 ULONG Size;
339
340 Size = sizeof(INFCACHEFIELD) + strlen(Data);
341 Field = (PINFCACHEFIELD)MmAllocateMemory (Size);
342 if (Field == NULL)
343 {
344 return NULL;
345 }
346 memset (Field, 0, Size);
347
348 strcpy (Field->Data, Data);
349
350 /* Append key */
351 if (Line->FirstField == NULL)
352 {
353 Line->FirstField = Field;
354 Line->LastField = Field;
355 }
356 else
357 {
358 Line->LastField->Next = Field;
359 Field->Prev = Line->LastField;
360 Line->LastField = Field;
361 }
362 Line->FieldCount++;
363
364 return (PVOID)Field;
365 }
366
367
368 static PINFCACHELINE
369 InfpCacheFindKeyLine (PINFCACHESECTION Section,
370 PCSTR Key)
371 {
372 PINFCACHELINE Line;
373
374 Line = Section->FirstLine;
375 while (Line != NULL)
376 {
377 if (Line->Key != NULL && _stricmp (Line->Key, Key) == 0)
378 {
379 return Line;
380 }
381
382 Line = Line->Next;
383 }
384
385 return NULL;
386 }
387
388
389 /* push the current state on the parser stack */
390 __inline static void push_state( struct parser *parser, enum parser_state state )
391 {
392 // assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
393 parser->stack[parser->stack_pos++] = state;
394 }
395
396
397 /* pop the current state */
398 __inline static void pop_state( struct parser *parser )
399 {
400 // assert( parser->stack_pos );
401 parser->state = parser->stack[--parser->stack_pos];
402 }
403
404
405 /* set the parser state and return the previous one */
406 __inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
407 {
408 enum parser_state ret = parser->state;
409 parser->state = state;
410 return ret;
411 }
412
413
414 /* check if the pointer points to an end of file */
415 __inline static int is_eof( struct parser *parser, const CHAR *ptr )
416 {
417 return (ptr >= parser->end || *ptr == CONTROL_Z);
418 }
419
420
421 /* check if the pointer points to an end of line */
422 __inline static int is_eol( struct parser *parser, const CHAR *ptr )
423 {
424 return (ptr >= parser->end ||
425 *ptr == CONTROL_Z ||
426 *ptr == '\n' ||
427 (*ptr == '\r' && *(ptr + 1) == '\n'));
428 }
429
430
431 /* push data from current token start up to pos into the current token */
432 static int push_token( struct parser *parser, const CHAR *pos )
433 {
434 unsigned int len = pos - parser->start;
435 const CHAR *src = parser->start;
436 CHAR *dst = parser->token + parser->token_len;
437
438 if (len > MAX_FIELD_LEN - parser->token_len)
439 len = MAX_FIELD_LEN - parser->token_len;
440
441 parser->token_len += len;
442 for ( ; len > 0; len--, dst++, src++)
443 *dst = *src ? (CHAR)*src : L' ';
444 *dst = 0;
445 parser->start = pos;
446
447 return 0;
448 }
449
450
451
452 /* add a section with the current token as name */
453 static PVOID add_section_from_token( struct parser *parser )
454 {
455 PINFCACHESECTION Section;
456
457 if (parser->token_len > MAX_SECTION_NAME_LEN)
458 {
459 parser->error = FALSE;
460 return NULL;
461 }
462
463 Section = InfpCacheFindSection (parser->file,
464 parser->token);
465 if (Section == NULL)
466 {
467 /* need to create a new one */
468 Section= InfpCacheAddSection (parser->file,
469 parser->token);
470 if (Section == NULL)
471 {
472 parser->error = FALSE;
473 return NULL;
474 }
475 }
476
477 parser->token_len = 0;
478 parser->cur_section = Section;
479
480 return (PVOID)Section;
481 }
482
483
484 /* add a field containing the current token to the current line */
485 static struct field *add_field_from_token( struct parser *parser, int is_key )
486 {
487 PVOID field;
488
489 if (!parser->line) /* need to start a new line */
490 {
491 if (parser->cur_section == NULL) /* got a line before the first section */
492 {
493 parser->error = STATUS_WRONG_INF_STYLE;
494 return NULL;
495 }
496
497 parser->line = InfpCacheAddLine (parser->cur_section);
498 if (parser->line == NULL)
499 goto error;
500 }
501 else
502 {
503 // assert(!is_key);
504 }
505
506 if (is_key)
507 {
508 field = InfpAddKeyToLine(parser->line, parser->token);
509 }
510 else
511 {
512 field = InfpAddFieldToLine(parser->line, parser->token);
513 }
514
515 if (field != NULL)
516 {
517 parser->token_len = 0;
518 return field;
519 }
520
521 error:
522 parser->error = FALSE;
523 return NULL;
524 }
525
526
527 /* close the current line and prepare for parsing a new one */
528 static void close_current_line( struct parser *parser )
529 {
530 parser->line = NULL;
531 }
532
533
534
535 /* handler for parser LINE_START state */
536 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos )
537 {
538 const CHAR *p;
539
540 for (p = pos; !is_eof( parser, p ); p++)
541 {
542 switch(*p)
543 {
544 case '\r':
545 continue;
546
547 case '\n':
548 parser->line_pos++;
549 close_current_line( parser );
550 break;
551
552 case ';':
553 push_state( parser, LINE_START );
554 set_state( parser, COMMENT );
555 return p + 1;
556
557 case '[':
558 parser->start = p + 1;
559 set_state( parser, SECTION_NAME );
560 return p + 1;
561
562 default:
563 if (!isspace(*p))
564 {
565 parser->start = p;
566 set_state( parser, KEY_NAME );
567 return p;
568 }
569 break;
570 }
571 }
572 close_current_line( parser );
573 return NULL;
574 }
575
576
577 /* handler for parser SECTION_NAME state */
578 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos )
579 {
580 const CHAR *p;
581
582 for (p = pos; !is_eol( parser, p ); p++)
583 {
584 if (*p == ']')
585 {
586 push_token( parser, p );
587 if (add_section_from_token( parser ) == NULL)
588 return NULL;
589 push_state( parser, LINE_START );
590 set_state( parser, COMMENT ); /* ignore everything else on the line */
591 return p + 1;
592 }
593 }
594 parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
595 return NULL;
596 }
597
598
599 /* handler for parser KEY_NAME state */
600 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos )
601 {
602 const CHAR *p, *token_end = parser->start;
603
604 for (p = pos; !is_eol( parser, p ); p++)
605 {
606 if (*p == ',') break;
607 switch(*p)
608 {
609
610 case '=':
611 push_token( parser, token_end );
612 if (!add_field_from_token( parser, 1 )) return NULL;
613 parser->start = p + 1;
614 push_state( parser, VALUE_NAME );
615 set_state( parser, LEADING_SPACES );
616 return p + 1;
617 case ';':
618 push_token( parser, token_end );
619 if (!add_field_from_token( parser, 0 )) return NULL;
620 push_state( parser, LINE_START );
621 set_state( parser, COMMENT );
622 return p + 1;
623 case '"':
624 push_token( parser, token_end );
625 parser->start = p + 1;
626 push_state( parser, KEY_NAME );
627 set_state( parser, QUOTES );
628 return p + 1;
629 case '\\':
630 push_token( parser, token_end );
631 parser->start = p;
632 push_state( parser, KEY_NAME );
633 set_state( parser, EOL_BACKSLASH );
634 return p;
635 default:
636 if (!isspace(*p)) token_end = p + 1;
637 else
638 {
639 push_token( parser, p );
640 push_state( parser, KEY_NAME );
641 set_state( parser, TRAILING_SPACES );
642 return p;
643 }
644 break;
645 }
646 }
647 push_token( parser, token_end );
648 set_state( parser, VALUE_NAME );
649 return p;
650 }
651
652
653 /* handler for parser VALUE_NAME state */
654 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos )
655 {
656 const CHAR *p, *token_end = parser->start;
657
658 for (p = pos; !is_eol( parser, p ); p++)
659 {
660 switch(*p)
661 {
662 case ';':
663 push_token( parser, token_end );
664 if (!add_field_from_token( parser, 0 )) return NULL;
665 push_state( parser, LINE_START );
666 set_state( parser, COMMENT );
667 return p + 1;
668 case ',':
669 push_token( parser, token_end );
670 if (!add_field_from_token( parser, 0 )) return NULL;
671 parser->start = p + 1;
672 push_state( parser, VALUE_NAME );
673 set_state( parser, LEADING_SPACES );
674 return p + 1;
675 case '"':
676 push_token( parser, token_end );
677 parser->start = p + 1;
678 push_state( parser, VALUE_NAME );
679 set_state( parser, QUOTES );
680 return p + 1;
681 case '\\':
682 push_token( parser, token_end );
683 parser->start = p;
684 push_state( parser, VALUE_NAME );
685 set_state( parser, EOL_BACKSLASH );
686 return p;
687 default:
688 if (!isspace(*p)) token_end = p + 1;
689 else
690 {
691 push_token( parser, p );
692 push_state( parser, VALUE_NAME );
693 set_state( parser, TRAILING_SPACES );
694 return p;
695 }
696 break;
697 }
698 }
699 push_token( parser, token_end );
700 if (!add_field_from_token( parser, 0 )) return NULL;
701 set_state( parser, LINE_START );
702 return p;
703 }
704
705
706 /* handler for parser EOL_BACKSLASH state */
707 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos )
708 {
709 const CHAR *p;
710
711 for (p = pos; !is_eof( parser, p ); p++)
712 {
713 switch(*p)
714 {
715 case '\r':
716 continue;
717
718 case '\n':
719 parser->line_pos++;
720 parser->start = p + 1;
721 set_state( parser, LEADING_SPACES );
722 return p + 1;
723
724 case '\\':
725 continue;
726
727 case ';':
728 push_state( parser, EOL_BACKSLASH );
729 set_state( parser, COMMENT );
730 return p + 1;
731
732 default:
733 if (isspace(*p))
734 continue;
735 push_token( parser, p );
736 pop_state( parser );
737 return p;
738 }
739 }
740 parser->start = p;
741 pop_state( parser );
742
743 return p;
744 }
745
746
747 /* handler for parser QUOTES state */
748 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos )
749 {
750 const CHAR *p, *token_end = parser->start;
751
752 for (p = pos; !is_eol( parser, p ); p++)
753 {
754 if (*p == '"')
755 {
756 if (p+1 < parser->end && p[1] == '"') /* double quotes */
757 {
758 push_token( parser, p + 1 );
759 parser->start = token_end = p + 2;
760 p++;
761 }
762 else /* end of quotes */
763 {
764 push_token( parser, p );
765 parser->start = p + 1;
766 pop_state( parser );
767 return p + 1;
768 }
769 }
770 }
771 push_token( parser, p );
772 pop_state( parser );
773 return p;
774 }
775
776
777 /* handler for parser LEADING_SPACES state */
778 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos )
779 {
780 const CHAR *p;
781
782 for (p = pos; !is_eol( parser, p ); p++)
783 {
784 if (*p == '\\')
785 {
786 parser->start = p;
787 set_state( parser, EOL_BACKSLASH );
788 return p;
789 }
790 if (!isspace(*p))
791 break;
792 }
793 parser->start = p;
794 pop_state( parser );
795 return p;
796 }
797
798
799 /* handler for parser TRAILING_SPACES state */
800 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos )
801 {
802 const CHAR *p;
803
804 for (p = pos; !is_eol( parser, p ); p++)
805 {
806 if (*p == '\\')
807 {
808 set_state( parser, EOL_BACKSLASH );
809 return p;
810 }
811 if (!isspace(*p))
812 break;
813 }
814 pop_state( parser );
815 return p;
816 }
817
818
819 /* handler for parser COMMENT state */
820 static const CHAR *comment_state( struct parser *parser, const CHAR *pos )
821 {
822 const CHAR *p = pos;
823
824 while (!is_eol( parser, p ))
825 p++;
826 pop_state( parser );
827 return p;
828 }
829
830
831 /* parse a complete buffer */
832 static BOOLEAN
833 InfpParseBuffer (PINFCACHE file,
834 const CHAR *buffer,
835 const CHAR *end,
836 PULONG error_line)
837 {
838 struct parser parser;
839 const CHAR *pos = buffer;
840
841 parser.start = buffer;
842 parser.end = end;
843 parser.file = file;
844 parser.line = NULL;
845 parser.state = LINE_START;
846 parser.stack_pos = 0;
847 parser.cur_section = NULL;
848 parser.line_pos = 1;
849 parser.error = TRUE;
850 parser.token_len = 0;
851
852 /* parser main loop */
853 while (pos)
854 pos = (parser_funcs[parser.state])(&parser, pos);
855
856 if (parser.error)
857 {
858 if (error_line)
859 *error_line = parser.line_pos;
860 return parser.error;
861 }
862
863 /* find the [strings] section */
864 file->StringsSection = InfpCacheFindSection (file, "Strings");
865
866 return TRUE;
867 }
868
869 /* PUBLIC FUNCTIONS *********************************************************/
870
871 BOOLEAN
872 InfOpenFile(PHINF InfHandle,
873 PCSTR FileName,
874 PULONG ErrorLine)
875 {
876 PFILE FileHandle;
877 PCHAR FileBuffer;
878 ULONG FileSize;
879 PINFCACHE Cache;
880 BOOLEAN Success;
881
882
883 *InfHandle = NULL;
884 *ErrorLine = (ULONG)-1;
885
886
887 /* Open the inf file */
888 FileHandle = FsOpenFile (FileName);
889 if (FileHandle == NULL)
890 {
891 // DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
892 return FALSE;
893 }
894
895 // DPRINT("NtOpenFile() successful\n");
896
897 /* Query file size */
898 FileSize = FsGetFileSize (FileHandle);
899 if (FileSize == 0)
900 {
901 // DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
902 FsCloseFile (FileHandle);
903 return FALSE;
904 }
905
906 // DPRINT("File size: %lu\n", FileLength);
907
908 /* Allocate file buffer */
909 FileBuffer = MmAllocateMemory (FileSize + 1);
910 if (FileBuffer == NULL)
911 {
912 // DPRINT1("RtlAllocateHeap() failed\n");
913 FsCloseFile (FileHandle);
914 return FALSE;
915 }
916
917 /* Read file */
918 Success = FsReadFile(FileHandle, FileSize, NULL, FileBuffer);
919
920 FsCloseFile (FileHandle);
921 if (!Success)
922 {
923 // DPRINT("FsReadFile() failed\n");
924 MmFreeMemory (FileBuffer);
925 return FALSE;
926 }
927
928 /* Append string terminator */
929 FileBuffer[FileSize] = 0;
930
931 /* Allocate infcache header */
932 Cache = (PINFCACHE)MmAllocateMemory (sizeof(INFCACHE));
933 if (Cache == NULL)
934 {
935 // DPRINT("RtlAllocateHeap() failed\n");
936 MmFreeMemory (FileBuffer);
937 return FALSE;
938 }
939
940 /* Initialize inicache header */
941 RtlZeroMemory(Cache,
942 sizeof(INFCACHE));
943
944 /* Parse the inf buffer */
945 Success = InfpParseBuffer (Cache,
946 FileBuffer,
947 FileBuffer + FileSize,
948 ErrorLine);
949 if (!Success)
950 {
951 MmFreeMemory (Cache);
952 Cache = NULL;
953 }
954
955 /* Free file buffer */
956 MmFreeMemory (FileBuffer);
957
958 *InfHandle = (HINF)Cache;
959
960 return Success;
961 }
962
963
964 VOID
965 InfCloseFile(HINF InfHandle)
966 {
967 PINFCACHE Cache;
968
969 Cache = (PINFCACHE)InfHandle;
970
971 if (Cache == NULL)
972 {
973 return;
974 }
975
976 while (Cache->FirstSection != NULL)
977 {
978 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection);
979 }
980 Cache->LastSection = NULL;
981
982 MmFreeMemory(Cache);
983 }
984
985
986 BOOLEAN
987 InfFindFirstLine (HINF InfHandle,
988 PCSTR Section,
989 PCSTR Key,
990 PINFCONTEXT Context)
991 {
992 PINFCACHE Cache;
993 PINFCACHESECTION CacheSection;
994 PINFCACHELINE CacheLine;
995
996 if (InfHandle == NULL || Section == NULL || Context == NULL)
997 {
998 // DPRINT("Invalid parameter\n");
999 return FALSE;
1000 }
1001
1002 Cache = (PINFCACHE)InfHandle;
1003
1004 /* Iterate through list of sections */
1005 CacheSection = Cache->FirstSection;
1006 while (Section != NULL)
1007 {
1008 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1009
1010 /* Are the section names the same? */
1011 if (_stricmp(CacheSection->Name, Section) == 0)
1012 {
1013 if (Key != NULL)
1014 {
1015 CacheLine = InfpCacheFindKeyLine (CacheSection, Key);
1016 }
1017 else
1018 {
1019 CacheLine = CacheSection->FirstLine;
1020 }
1021
1022 if (CacheLine == NULL)
1023 return FALSE;
1024
1025 Context->Inf = (PVOID)Cache;
1026 Context->Section = (PVOID)CacheSection;
1027 Context->Line = (PVOID)CacheLine;
1028
1029 return TRUE;
1030 }
1031
1032 /* Get the next section */
1033 CacheSection = CacheSection->Next;
1034 }
1035
1036 // DPRINT("Section not found\n");
1037
1038 return FALSE;
1039 }
1040
1041
1042 BOOLEAN
1043 InfFindNextLine (PINFCONTEXT ContextIn,
1044 PINFCONTEXT ContextOut)
1045 {
1046 PINFCACHELINE CacheLine;
1047
1048 if (ContextIn == NULL || ContextOut == NULL)
1049 return FALSE;
1050
1051 if (ContextIn->Line == NULL)
1052 return FALSE;
1053
1054 CacheLine = (PINFCACHELINE)ContextIn->Line;
1055 if (CacheLine->Next == NULL)
1056 return FALSE;
1057
1058 if (ContextIn != ContextOut)
1059 {
1060 ContextOut->Inf = ContextIn->Inf;
1061 ContextOut->Section = ContextIn->Section;
1062 }
1063 ContextOut->Line = (PVOID)(CacheLine->Next);
1064
1065 return TRUE;
1066 }
1067
1068
1069 BOOLEAN
1070 InfFindFirstMatchLine (PINFCONTEXT ContextIn,
1071 PCHAR Key,
1072 PINFCONTEXT ContextOut)
1073 {
1074 PINFCACHELINE CacheLine;
1075
1076 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1077 return FALSE;
1078
1079 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
1080 return FALSE;
1081
1082 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
1083 while (CacheLine != NULL)
1084 {
1085 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0)
1086 {
1087
1088 if (ContextIn != ContextOut)
1089 {
1090 ContextOut->Inf = ContextIn->Inf;
1091 ContextOut->Section = ContextIn->Section;
1092 }
1093 ContextOut->Line = (PVOID)CacheLine;
1094
1095 return TRUE;
1096 }
1097
1098 CacheLine = CacheLine->Next;
1099 }
1100
1101 return FALSE;
1102 }
1103
1104
1105 BOOLEAN
1106 InfFindNextMatchLine (PINFCONTEXT ContextIn,
1107 PCHAR Key,
1108 PINFCONTEXT ContextOut)
1109 {
1110 PINFCACHELINE CacheLine;
1111
1112 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1113 return FALSE;
1114
1115 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
1116 return FALSE;
1117
1118 CacheLine = (PINFCACHELINE)ContextIn->Line;
1119 while (CacheLine != NULL)
1120 {
1121 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0)
1122 {
1123
1124 if (ContextIn != ContextOut)
1125 {
1126 ContextOut->Inf = ContextIn->Inf;
1127 ContextOut->Section = ContextIn->Section;
1128 }
1129 ContextOut->Line = (PVOID)CacheLine;
1130
1131 return TRUE;
1132 }
1133
1134 CacheLine = CacheLine->Next;
1135 }
1136
1137 return FALSE;
1138 }
1139
1140
1141 LONG
1142 InfGetLineCount(HINF InfHandle,
1143 PCHAR Section)
1144 {
1145 PINFCACHE Cache;
1146 PINFCACHESECTION CacheSection;
1147
1148 if (InfHandle == NULL || Section == NULL)
1149 {
1150 // DPRINT("Invalid parameter\n");
1151 return -1;
1152 }
1153
1154 Cache = (PINFCACHE)InfHandle;
1155
1156 /* Iterate through list of sections */
1157 CacheSection = Cache->FirstSection;
1158 while (Section != NULL)
1159 {
1160 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1161
1162 /* Are the section names the same? */
1163 if (_stricmp(CacheSection->Name, Section) == 0)
1164 {
1165 return CacheSection->LineCount;
1166 }
1167
1168 /* Get the next section */
1169 CacheSection = CacheSection->Next;
1170 }
1171
1172 // DPRINT("Section not found\n");
1173
1174 return -1;
1175 }
1176
1177
1178 /* InfGetLineText */
1179
1180
1181 LONG
1182 InfGetFieldCount(PINFCONTEXT Context)
1183 {
1184 if (Context == NULL || Context->Line == NULL)
1185 return 0;
1186
1187 return ((PINFCACHELINE)Context->Line)->FieldCount;
1188 }
1189
1190
1191 BOOLEAN
1192 InfGetBinaryField (PINFCONTEXT Context,
1193 ULONG FieldIndex,
1194 PUCHAR ReturnBuffer,
1195 ULONG ReturnBufferSize,
1196 PULONG RequiredSize)
1197 {
1198 PINFCACHELINE CacheLine;
1199 PINFCACHEFIELD CacheField;
1200 ULONG Index;
1201 ULONG Size;
1202 PUCHAR Ptr;
1203
1204 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1205 {
1206 // DPRINT("Invalid parameter\n");
1207 return FALSE;
1208 }
1209
1210 if (RequiredSize != NULL)
1211 *RequiredSize = 0;
1212
1213 CacheLine = (PINFCACHELINE)Context->Line;
1214
1215 if (FieldIndex > CacheLine->FieldCount)
1216 return FALSE;
1217
1218 CacheField = CacheLine->FirstField;
1219 for (Index = 1; Index < FieldIndex; Index++)
1220 CacheField = CacheField->Next;
1221
1222 Size = CacheLine->FieldCount - FieldIndex + 1;
1223
1224 if (RequiredSize != NULL)
1225 *RequiredSize = Size;
1226
1227 if (ReturnBuffer != NULL)
1228 {
1229 if (ReturnBufferSize < Size)
1230 return FALSE;
1231
1232 /* Copy binary data */
1233 Ptr = ReturnBuffer;
1234 while (CacheField != NULL)
1235 {
1236 *Ptr = (UCHAR)atoi(CacheField->Data); //strtoul (CacheField->Data, NULL, 16);
1237
1238 Ptr++;
1239 CacheField = CacheField->Next;
1240 }
1241 }
1242
1243 return TRUE;
1244 }
1245
1246
1247 BOOLEAN
1248 InfGetIntField (PINFCONTEXT Context,
1249 ULONG FieldIndex,
1250 LONG *IntegerValue)
1251 {
1252 PINFCACHELINE CacheLine;
1253 PINFCACHEFIELD CacheField;
1254 ULONG Index;
1255 PCHAR Ptr;
1256
1257 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
1258 {
1259 // DPRINT("Invalid parameter\n");
1260 return FALSE;
1261 }
1262
1263 CacheLine = (PINFCACHELINE)Context->Line;
1264
1265 if (FieldIndex > CacheLine->FieldCount)
1266 {
1267 // DPRINT("Invalid parameter\n");
1268 return FALSE;
1269 }
1270
1271 if (FieldIndex == 0)
1272 {
1273 Ptr = CacheLine->Key;
1274 }
1275 else
1276 {
1277 CacheField = CacheLine->FirstField;
1278 for (Index = 1; Index < FieldIndex; Index++)
1279 CacheField = CacheField->Next;
1280
1281 Ptr = CacheField->Data;
1282 }
1283
1284 *IntegerValue = atoi (Ptr); //strtol (Ptr, NULL, 0);
1285
1286 return TRUE;
1287 }
1288
1289
1290 BOOLEAN
1291 InfGetMultiSzField (PINFCONTEXT Context,
1292 ULONG FieldIndex,
1293 PCHAR ReturnBuffer,
1294 ULONG ReturnBufferSize,
1295 PULONG RequiredSize)
1296 {
1297 PINFCACHELINE CacheLine;
1298 PINFCACHEFIELD CacheField;
1299 PINFCACHEFIELD FieldPtr;
1300 ULONG Index;
1301 ULONG Size;
1302 PCHAR Ptr;
1303
1304 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1305 {
1306 // DPRINT("Invalid parameter\n");
1307 return FALSE;
1308 }
1309
1310 if (RequiredSize != NULL)
1311 *RequiredSize = 0;
1312
1313 CacheLine = (PINFCACHELINE)Context->Line;
1314
1315 if (FieldIndex > CacheLine->FieldCount)
1316 return FALSE;
1317
1318 CacheField = CacheLine->FirstField;
1319 for (Index = 1; Index < FieldIndex; Index++)
1320 CacheField = CacheField->Next;
1321
1322 /* Calculate the required buffer size */
1323 FieldPtr = CacheField;
1324 Size = 0;
1325 while (FieldPtr != NULL)
1326 {
1327 Size += (strlen (FieldPtr->Data) + 1);
1328 FieldPtr = FieldPtr->Next;
1329 }
1330 Size++;
1331
1332 if (RequiredSize != NULL)
1333 *RequiredSize = Size;
1334
1335 if (ReturnBuffer != NULL)
1336 {
1337 if (ReturnBufferSize < Size)
1338 return FALSE;
1339
1340 /* Copy multi-sz string */
1341 Ptr = ReturnBuffer;
1342 FieldPtr = CacheField;
1343 while (FieldPtr != NULL)
1344 {
1345 Size = strlen (FieldPtr->Data) + 1;
1346
1347 strcpy (Ptr, FieldPtr->Data);
1348
1349 Ptr = Ptr + Size;
1350 FieldPtr = FieldPtr->Next;
1351 }
1352 *Ptr = 0;
1353 }
1354
1355 return TRUE;
1356 }
1357
1358
1359 BOOLEAN
1360 InfGetStringField (PINFCONTEXT Context,
1361 ULONG FieldIndex,
1362 PCHAR ReturnBuffer,
1363 ULONG ReturnBufferSize,
1364 PULONG RequiredSize)
1365 {
1366 PINFCACHELINE CacheLine;
1367 PINFCACHEFIELD CacheField;
1368 ULONG Index;
1369 PCHAR Ptr;
1370 ULONG Size;
1371
1372 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1373 {
1374 // DPRINT("Invalid parameter\n");
1375 return FALSE;
1376 }
1377
1378 if (RequiredSize != NULL)
1379 *RequiredSize = 0;
1380
1381 CacheLine = (PINFCACHELINE)Context->Line;
1382
1383 if (FieldIndex > CacheLine->FieldCount)
1384 return FALSE;
1385
1386 if (FieldIndex == 0)
1387 {
1388 Ptr = CacheLine->Key;
1389 }
1390 else
1391 {
1392 CacheField = CacheLine->FirstField;
1393 for (Index = 1; Index < FieldIndex; Index++)
1394 CacheField = CacheField->Next;
1395
1396 Ptr = CacheField->Data;
1397 }
1398
1399 Size = strlen (Ptr) + 1;
1400
1401 if (RequiredSize != NULL)
1402 *RequiredSize = Size;
1403
1404 if (ReturnBuffer != NULL)
1405 {
1406 if (ReturnBufferSize < Size)
1407 return FALSE;
1408
1409 strcpy (ReturnBuffer, Ptr);
1410 }
1411
1412 return TRUE;
1413 }
1414
1415
1416
1417
1418 BOOLEAN
1419 InfGetData (PINFCONTEXT Context,
1420 PCHAR *Key,
1421 PCHAR *Data)
1422 {
1423 PINFCACHELINE CacheKey;
1424
1425 if (Context == NULL || Context->Line == NULL || Data == NULL)
1426 {
1427 // DPRINT("Invalid parameter\n");
1428 return FALSE;
1429 }
1430
1431 CacheKey = (PINFCACHELINE)Context->Line;
1432 if (Key != NULL)
1433 *Key = CacheKey->Key;
1434
1435 if (Data != NULL)
1436 {
1437 if (CacheKey->FirstField == NULL)
1438 {
1439 *Data = NULL;
1440 }
1441 else
1442 {
1443 *Data = CacheKey->FirstField->Data;
1444 }
1445 }
1446
1447 return TRUE;
1448 }
1449
1450
1451 BOOLEAN
1452 InfGetDataField (PINFCONTEXT Context,
1453 ULONG FieldIndex,
1454 PCSTR *Data)
1455 {
1456 PINFCACHELINE CacheLine;
1457 PINFCACHEFIELD CacheField;
1458 ULONG Index;
1459
1460 if (Context == NULL || Context->Line == NULL || Data == NULL)
1461 {
1462 // DPRINT("Invalid parameter\n");
1463 return FALSE;
1464 }
1465
1466 CacheLine = (PINFCACHELINE)Context->Line;
1467
1468 if (FieldIndex > CacheLine->FieldCount)
1469 return FALSE;
1470
1471 if (FieldIndex == 0)
1472 {
1473 *Data = CacheLine->Key;
1474 }
1475 else
1476 {
1477 CacheField = CacheLine->FirstField;
1478 for (Index = 1; Index < FieldIndex; Index++)
1479 CacheField = CacheField->Next;
1480
1481 *Data = CacheField->Data;
1482 }
1483
1484 return TRUE;
1485 }
1486
1487
1488 /* EOF */