[FREELDR]
[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 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 /* $Id: inffile.c 53526 2011-09-01 19:01:19Z tkreuzer $
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 MmHeapFree (Line->Key);
163 Line->Key = NULL;
164 }
165
166 /* Remove data fields */
167 while (Line->FirstField != NULL)
168 {
169 Field = Line->FirstField->Next;
170 MmHeapFree (Line->FirstField);
171 Line->FirstField = Field;
172 }
173 Line->LastField = NULL;
174
175 MmHeapFree (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 MmHeapFree (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)MmHeapAlloc (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)MmHeapAlloc (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 = MmHeapAlloc(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)MmHeapAlloc (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 SIZE_T 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 FILEINFORMATION Information;
877 ULONG FileId;
878 PCHAR FileBuffer;
879 ULONG FileSize, Count;
880 PINFCACHE Cache;
881 BOOLEAN Success;
882 LONG ret;
883
884 *InfHandle = NULL;
885 *ErrorLine = (ULONG)-1;
886
887 //
888 // Open the .inf file
889 //
890 FileId = FsOpenFile(FileName);
891 if (!FileId)
892 {
893 return FALSE;
894 }
895
896 //
897 // Query file size
898 //
899 ret = ArcGetFileInformation(FileId, &Information);
900 if (ret != ESUCCESS || Information.EndingAddress.HighPart != 0)
901 {
902 ArcClose(FileId);
903 return FALSE;
904 }
905 FileSize = Information.EndingAddress.LowPart;
906
907 //
908 // Allocate buffer to cache the file
909 //
910 FileBuffer = MmHeapAlloc(FileSize + 1);
911 if (!FileBuffer)
912 {
913 ArcClose(FileId);
914 return FALSE;
915 }
916
917 //
918 // Read file into memory
919 //
920 ret = ArcRead(FileId, FileBuffer, FileSize, &Count);
921 if (ret != ESUCCESS || Count != FileSize)
922 {
923 ArcClose(FileId);
924 MmHeapFree(FileBuffer);
925 return FALSE;
926 }
927
928 //
929 // We don't need the file anymore. Close it
930 //
931 ArcClose(FileId);
932
933 //
934 // Append string terminator
935 //
936 FileBuffer[FileSize] = 0;
937
938 //
939 // Allocate infcache header
940 //
941 Cache = (PINFCACHE)MmHeapAlloc(sizeof(INFCACHE));
942 if (!Cache)
943 {
944 MmHeapFree (FileBuffer);
945 return FALSE;
946 }
947
948 //
949 // Initialize inicache header
950 //
951 RtlZeroMemory(Cache, sizeof(INFCACHE));
952
953 //
954 // Parse the inf buffer
955 //
956 Success = InfpParseBuffer(Cache,
957 FileBuffer,
958 FileBuffer + FileSize,
959 ErrorLine);
960 if (!Success)
961 {
962 MmHeapFree(Cache);
963 Cache = NULL;
964 }
965
966 //
967 // Free file buffer, as it has been parsed
968 //
969 MmHeapFree(FileBuffer);
970
971 //
972 // Return .inf parsed contents
973 //
974 *InfHandle = (HINF)Cache;
975
976 return Success;
977 }
978
979
980 VOID
981 InfCloseFile(HINF InfHandle)
982 {
983 PINFCACHE Cache;
984
985 Cache = (PINFCACHE)InfHandle;
986
987 if (Cache == NULL)
988 {
989 return;
990 }
991
992 while (Cache->FirstSection != NULL)
993 {
994 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection);
995 }
996 Cache->LastSection = NULL;
997
998 MmHeapFree(Cache);
999 }
1000
1001
1002 BOOLEAN
1003 InfFindFirstLine (HINF InfHandle,
1004 PCSTR Section,
1005 PCSTR Key,
1006 PINFCONTEXT Context)
1007 {
1008 PINFCACHE Cache;
1009 PINFCACHESECTION CacheSection;
1010 PINFCACHELINE CacheLine;
1011
1012 if (InfHandle == NULL || Section == NULL || Context == NULL)
1013 {
1014 // DPRINT("Invalid parameter\n");
1015 return FALSE;
1016 }
1017
1018 Cache = (PINFCACHE)InfHandle;
1019
1020 /* Iterate through list of sections */
1021 CacheSection = Cache->FirstSection;
1022 while (Section != NULL)
1023 {
1024 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1025
1026 /* Are the section names the same? */
1027 if (_stricmp(CacheSection->Name, Section) == 0)
1028 {
1029 if (Key != NULL)
1030 {
1031 CacheLine = InfpCacheFindKeyLine (CacheSection, Key);
1032 }
1033 else
1034 {
1035 CacheLine = CacheSection->FirstLine;
1036 }
1037
1038 if (CacheLine == NULL)
1039 return FALSE;
1040
1041 Context->Inf = (PVOID)Cache;
1042 Context->Section = (PVOID)CacheSection;
1043 Context->Line = (PVOID)CacheLine;
1044
1045 return TRUE;
1046 }
1047
1048 /* Get the next section */
1049 CacheSection = CacheSection->Next;
1050 }
1051
1052 // DPRINT("Section not found\n");
1053
1054 return FALSE;
1055 }
1056
1057
1058 BOOLEAN
1059 InfFindNextLine (PINFCONTEXT ContextIn,
1060 PINFCONTEXT ContextOut)
1061 {
1062 PINFCACHELINE CacheLine;
1063
1064 if (ContextIn == NULL || ContextOut == NULL)
1065 return FALSE;
1066
1067 if (ContextIn->Line == NULL)
1068 return FALSE;
1069
1070 CacheLine = (PINFCACHELINE)ContextIn->Line;
1071 if (CacheLine->Next == NULL)
1072 return FALSE;
1073
1074 if (ContextIn != ContextOut)
1075 {
1076 ContextOut->Inf = ContextIn->Inf;
1077 ContextOut->Section = ContextIn->Section;
1078 }
1079 ContextOut->Line = (PVOID)(CacheLine->Next);
1080
1081 return TRUE;
1082 }
1083
1084
1085 BOOLEAN
1086 InfFindFirstMatchLine (PINFCONTEXT ContextIn,
1087 PCHAR Key,
1088 PINFCONTEXT ContextOut)
1089 {
1090 PINFCACHELINE CacheLine;
1091
1092 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1093 return FALSE;
1094
1095 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
1096 return FALSE;
1097
1098 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
1099 while (CacheLine != NULL)
1100 {
1101 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0)
1102 {
1103
1104 if (ContextIn != ContextOut)
1105 {
1106 ContextOut->Inf = ContextIn->Inf;
1107 ContextOut->Section = ContextIn->Section;
1108 }
1109 ContextOut->Line = (PVOID)CacheLine;
1110
1111 return TRUE;
1112 }
1113
1114 CacheLine = CacheLine->Next;
1115 }
1116
1117 return FALSE;
1118 }
1119
1120
1121 BOOLEAN
1122 InfFindNextMatchLine (PINFCONTEXT ContextIn,
1123 PCHAR Key,
1124 PINFCONTEXT ContextOut)
1125 {
1126 PINFCACHELINE CacheLine;
1127
1128 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1129 return FALSE;
1130
1131 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
1132 return FALSE;
1133
1134 CacheLine = (PINFCACHELINE)ContextIn->Line;
1135 while (CacheLine != NULL)
1136 {
1137 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0)
1138 {
1139
1140 if (ContextIn != ContextOut)
1141 {
1142 ContextOut->Inf = ContextIn->Inf;
1143 ContextOut->Section = ContextIn->Section;
1144 }
1145 ContextOut->Line = (PVOID)CacheLine;
1146
1147 return TRUE;
1148 }
1149
1150 CacheLine = CacheLine->Next;
1151 }
1152
1153 return FALSE;
1154 }
1155
1156
1157 LONG
1158 InfGetLineCount(HINF InfHandle,
1159 PCHAR Section)
1160 {
1161 PINFCACHE Cache;
1162 PINFCACHESECTION CacheSection;
1163
1164 if (InfHandle == NULL || Section == NULL)
1165 {
1166 // DPRINT("Invalid parameter\n");
1167 return -1;
1168 }
1169
1170 Cache = (PINFCACHE)InfHandle;
1171
1172 /* Iterate through list of sections */
1173 CacheSection = Cache->FirstSection;
1174 while (Section != NULL)
1175 {
1176 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1177
1178 /* Are the section names the same? */
1179 if (_stricmp(CacheSection->Name, Section) == 0)
1180 {
1181 return CacheSection->LineCount;
1182 }
1183
1184 /* Get the next section */
1185 CacheSection = CacheSection->Next;
1186 }
1187
1188 // DPRINT("Section not found\n");
1189
1190 return -1;
1191 }
1192
1193
1194 /* InfGetLineText */
1195
1196
1197 LONG
1198 InfGetFieldCount(PINFCONTEXT Context)
1199 {
1200 if (Context == NULL || Context->Line == NULL)
1201 return 0;
1202
1203 return ((PINFCACHELINE)Context->Line)->FieldCount;
1204 }
1205
1206
1207 BOOLEAN
1208 InfGetBinaryField (PINFCONTEXT Context,
1209 ULONG FieldIndex,
1210 PUCHAR ReturnBuffer,
1211 ULONG ReturnBufferSize,
1212 PULONG RequiredSize)
1213 {
1214 PINFCACHELINE CacheLine;
1215 PINFCACHEFIELD CacheField;
1216 ULONG Index;
1217 ULONG Size;
1218 PUCHAR Ptr;
1219
1220 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1221 {
1222 // DPRINT("Invalid parameter\n");
1223 return FALSE;
1224 }
1225
1226 if (RequiredSize != NULL)
1227 *RequiredSize = 0;
1228
1229 CacheLine = (PINFCACHELINE)Context->Line;
1230
1231 if (FieldIndex > CacheLine->FieldCount)
1232 return FALSE;
1233
1234 CacheField = CacheLine->FirstField;
1235 for (Index = 1; Index < FieldIndex; Index++)
1236 CacheField = CacheField->Next;
1237
1238 Size = CacheLine->FieldCount - FieldIndex + 1;
1239
1240 if (RequiredSize != NULL)
1241 *RequiredSize = Size;
1242
1243 if (ReturnBuffer != NULL)
1244 {
1245 if (ReturnBufferSize < Size)
1246 return FALSE;
1247
1248 /* Copy binary data */
1249 Ptr = ReturnBuffer;
1250 while (CacheField != NULL)
1251 {
1252 *Ptr = (UCHAR)atoi(CacheField->Data); //strtoul (CacheField->Data, NULL, 16);
1253
1254 Ptr++;
1255 CacheField = CacheField->Next;
1256 }
1257 }
1258
1259 return TRUE;
1260 }
1261
1262
1263 BOOLEAN
1264 InfGetIntField (PINFCONTEXT Context,
1265 ULONG FieldIndex,
1266 LONG *IntegerValue)
1267 {
1268 PINFCACHELINE CacheLine;
1269 PINFCACHEFIELD CacheField;
1270 ULONG Index;
1271 PCHAR Ptr;
1272
1273 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
1274 {
1275 // DPRINT("Invalid parameter\n");
1276 return FALSE;
1277 }
1278
1279 CacheLine = (PINFCACHELINE)Context->Line;
1280
1281 if (FieldIndex > CacheLine->FieldCount)
1282 {
1283 // DPRINT("Invalid parameter\n");
1284 return FALSE;
1285 }
1286
1287 if (FieldIndex == 0)
1288 {
1289 Ptr = CacheLine->Key;
1290 }
1291 else
1292 {
1293 CacheField = CacheLine->FirstField;
1294 for (Index = 1; Index < FieldIndex; Index++)
1295 CacheField = CacheField->Next;
1296
1297 Ptr = CacheField->Data;
1298 }
1299
1300 *IntegerValue = atoi (Ptr); //strtol (Ptr, NULL, 0);
1301
1302 return TRUE;
1303 }
1304
1305
1306 BOOLEAN
1307 InfGetMultiSzField (PINFCONTEXT Context,
1308 ULONG FieldIndex,
1309 PCHAR ReturnBuffer,
1310 ULONG ReturnBufferSize,
1311 PULONG RequiredSize)
1312 {
1313 PINFCACHELINE CacheLine;
1314 PINFCACHEFIELD CacheField;
1315 PINFCACHEFIELD FieldPtr;
1316 ULONG Index;
1317 ULONG Size;
1318 PCHAR Ptr;
1319
1320 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1321 {
1322 // DPRINT("Invalid parameter\n");
1323 return FALSE;
1324 }
1325
1326 if (RequiredSize != NULL)
1327 *RequiredSize = 0;
1328
1329 CacheLine = (PINFCACHELINE)Context->Line;
1330
1331 if (FieldIndex > CacheLine->FieldCount)
1332 return FALSE;
1333
1334 CacheField = CacheLine->FirstField;
1335 for (Index = 1; Index < FieldIndex; Index++)
1336 CacheField = CacheField->Next;
1337
1338 /* Calculate the required buffer size */
1339 FieldPtr = CacheField;
1340 Size = 0;
1341 while (FieldPtr != NULL)
1342 {
1343 Size += (strlen (FieldPtr->Data) + 1);
1344 FieldPtr = FieldPtr->Next;
1345 }
1346 Size++;
1347
1348 if (RequiredSize != NULL)
1349 *RequiredSize = Size;
1350
1351 if (ReturnBuffer != NULL)
1352 {
1353 if (ReturnBufferSize < Size)
1354 return FALSE;
1355
1356 /* Copy multi-sz string */
1357 Ptr = ReturnBuffer;
1358 FieldPtr = CacheField;
1359 while (FieldPtr != NULL)
1360 {
1361 Size = strlen (FieldPtr->Data) + 1;
1362
1363 strcpy (Ptr, FieldPtr->Data);
1364
1365 Ptr = Ptr + Size;
1366 FieldPtr = FieldPtr->Next;
1367 }
1368 *Ptr = 0;
1369 }
1370
1371 return TRUE;
1372 }
1373
1374
1375 BOOLEAN
1376 InfGetStringField (PINFCONTEXT Context,
1377 ULONG FieldIndex,
1378 PCHAR ReturnBuffer,
1379 ULONG ReturnBufferSize,
1380 PULONG RequiredSize)
1381 {
1382 PINFCACHELINE CacheLine;
1383 PINFCACHEFIELD CacheField;
1384 ULONG Index;
1385 PCHAR Ptr;
1386 ULONG Size;
1387
1388 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1389 {
1390 // DPRINT("Invalid parameter\n");
1391 return FALSE;
1392 }
1393
1394 if (RequiredSize != NULL)
1395 *RequiredSize = 0;
1396
1397 CacheLine = (PINFCACHELINE)Context->Line;
1398
1399 if (FieldIndex > CacheLine->FieldCount)
1400 return FALSE;
1401
1402 if (FieldIndex == 0)
1403 {
1404 Ptr = CacheLine->Key;
1405 }
1406 else
1407 {
1408 CacheField = CacheLine->FirstField;
1409 for (Index = 1; Index < FieldIndex; Index++)
1410 CacheField = CacheField->Next;
1411
1412 Ptr = CacheField->Data;
1413 }
1414
1415 Size = strlen (Ptr) + 1;
1416
1417 if (RequiredSize != NULL)
1418 *RequiredSize = Size;
1419
1420 if (ReturnBuffer != NULL)
1421 {
1422 if (ReturnBufferSize < Size)
1423 return FALSE;
1424
1425 strcpy (ReturnBuffer, Ptr);
1426 }
1427
1428 return TRUE;
1429 }
1430
1431
1432
1433
1434 BOOLEAN
1435 InfGetData (PINFCONTEXT Context,
1436 PCHAR *Key,
1437 PCHAR *Data)
1438 {
1439 PINFCACHELINE CacheKey;
1440
1441 if (Context == NULL || Context->Line == NULL || Data == NULL)
1442 {
1443 // DPRINT("Invalid parameter\n");
1444 return FALSE;
1445 }
1446
1447 CacheKey = (PINFCACHELINE)Context->Line;
1448 if (Key != NULL)
1449 *Key = CacheKey->Key;
1450
1451 if (Data != NULL)
1452 {
1453 if (CacheKey->FirstField == NULL)
1454 {
1455 *Data = NULL;
1456 }
1457 else
1458 {
1459 *Data = CacheKey->FirstField->Data;
1460 }
1461 }
1462
1463 return TRUE;
1464 }
1465
1466
1467 BOOLEAN
1468 InfGetDataField (PINFCONTEXT Context,
1469 ULONG FieldIndex,
1470 PCSTR *Data)
1471 {
1472 PINFCACHELINE CacheLine;
1473 PINFCACHEFIELD CacheField;
1474 ULONG Index;
1475
1476 if (Context == NULL || Context->Line == NULL || Data == NULL)
1477 {
1478 // DPRINT("Invalid parameter\n");
1479 return FALSE;
1480 }
1481
1482 CacheLine = (PINFCACHELINE)Context->Line;
1483
1484 if (FieldIndex > CacheLine->FieldCount)
1485 return FALSE;
1486
1487 if (FieldIndex == 0)
1488 {
1489 *Data = CacheLine->Key;
1490 }
1491 else
1492 {
1493 CacheField = CacheLine->FirstField;
1494 for (Index = 1; Index < FieldIndex; Index++)
1495 CacheField = CacheField->Next;
1496
1497 *Data = CacheField->Data;
1498 }
1499
1500 return TRUE;
1501 }
1502
1503
1504 /* EOF */