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