msvc6 and gcc4 support
[reactos.git] / reactos / tools / mkhive / infcache.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 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: infcache.c,v 1.9 2004/12/30 16:02:12 royce Exp $
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS hive maker
22 * FILE: tools/mkhive/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 <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34
35 #include "mkhive.h"
36 #include "infcache.h"
37
38
39 #define CONTROL_Z '\x1a'
40 #define MAX_SECTION_NAME_LEN 255
41 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
42 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
43 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
44
45
46 typedef struct _INFCACHEFIELD
47 {
48 struct _INFCACHEFIELD *Next;
49 struct _INFCACHEFIELD *Prev;
50
51 CHAR Data[1];
52 } INFCACHEFIELD, *PINFCACHEFIELD;
53
54
55 typedef struct _INFCACHELINE
56 {
57 struct _INFCACHELINE *Next;
58 struct _INFCACHELINE *Prev;
59
60 ULONG FieldCount;
61
62 PCHAR Key;
63
64 PINFCACHEFIELD FirstField;
65 PINFCACHEFIELD LastField;
66
67 } INFCACHELINE, *PINFCACHELINE;
68
69
70 typedef struct _INFCACHESECTION
71 {
72 struct _INFCACHESECTION *Next;
73 struct _INFCACHESECTION *Prev;
74
75 PINFCACHELINE FirstLine;
76 PINFCACHELINE LastLine;
77
78 LONG LineCount;
79
80 CHAR Name[1];
81 } INFCACHESECTION, *PINFCACHESECTION;
82
83
84 typedef struct _INFCACHE
85 {
86 PINFCACHESECTION FirstSection;
87 PINFCACHESECTION LastSection;
88
89 PINFCACHESECTION StringsSection;
90 } INFCACHE, *PINFCACHE;
91
92
93 /* parser definitions */
94
95 enum parser_state
96 {
97 LINE_START, /* at beginning of a line */
98 SECTION_NAME, /* parsing a section name */
99 KEY_NAME, /* parsing a key name */
100 VALUE_NAME, /* parsing a value name */
101 EOL_BACKSLASH, /* backslash at end of line */
102 QUOTES, /* inside quotes */
103 LEADING_SPACES, /* leading spaces */
104 TRAILING_SPACES, /* trailing spaces */
105 COMMENT, /* inside a comment */
106 NB_PARSER_STATES
107 };
108
109 struct parser
110 {
111 const CHAR *start; /* start position of item being parsed */
112 const CHAR *end; /* end of buffer */
113 PINFCACHE file; /* file being built */
114 enum parser_state state; /* current parser state */
115 enum parser_state stack[4]; /* state stack */
116 int stack_pos; /* current pos in stack */
117
118 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/
119 PINFCACHELINE line; /* current line */
120 unsigned int line_pos; /* current line position in file */
121 unsigned int error; /* error code */
122 unsigned int token_len; /* current token len */
123 CHAR token[MAX_FIELD_LEN+1]; /* current token */
124 };
125
126 typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos );
127
128 /* parser state machine functions */
129 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos );
130 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos );
131 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos );
132 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos );
133 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos );
134 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos );
135 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos );
136 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos );
137 static const CHAR *comment_state( struct parser *parser, const CHAR *pos );
138
139 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
140 {
141 line_start_state, /* LINE_START */
142 section_name_state, /* SECTION_NAME */
143 key_name_state, /* KEY_NAME */
144 value_name_state, /* VALUE_NAME */
145 eol_backslash_state, /* EOL_BACKSLASH */
146 quotes_state, /* QUOTES */
147 leading_spaces_state, /* LEADING_SPACES */
148 trailing_spaces_state, /* TRAILING_SPACES */
149 comment_state /* COMMENT */
150 };
151
152
153 /* PRIVATE FUNCTIONS ********************************************************/
154
155 static PINFCACHELINE
156 InfpCacheFreeLine (PINFCACHELINE Line)
157 {
158 PINFCACHELINE Next;
159 PINFCACHEFIELD Field;
160
161 if (Line == NULL)
162 {
163 return NULL;
164 }
165
166 Next = Line->Next;
167 if (Line->Key != NULL)
168 {
169 free (Line->Key);
170 Line->Key = NULL;
171 }
172
173 /* Remove data fields */
174 while (Line->FirstField != NULL)
175 {
176 Field = Line->FirstField->Next;
177 free (Line->FirstField);
178 Line->FirstField = Field;
179 }
180 Line->LastField = NULL;
181
182 free (Line);
183
184 return Next;
185 }
186
187
188 static PINFCACHESECTION
189 InfpCacheFreeSection (PINFCACHESECTION Section)
190 {
191 PINFCACHESECTION Next;
192
193 if (Section == NULL)
194 {
195 return NULL;
196 }
197
198 /* Release all keys */
199 Next = Section->Next;
200 while (Section->FirstLine != NULL)
201 {
202 Section->FirstLine = InfpCacheFreeLine (Section->FirstLine);
203 }
204 Section->LastLine = NULL;
205
206 free (Section);
207
208 return Next;
209 }
210
211
212 static PINFCACHESECTION
213 InfpCacheFindSection (PINFCACHE Cache,
214 PCHAR Name)
215 {
216 PINFCACHESECTION Section = NULL;
217
218 if (Cache == NULL || Name == NULL)
219 {
220 return NULL;
221 }
222
223 /* iterate through list of sections */
224 Section = Cache->FirstSection;
225 while (Section != NULL)
226 {
227 if (strcasecmp (Section->Name, Name) == 0)
228 {
229 return Section;
230 }
231
232 /* get the next section*/
233 Section = Section->Next;
234 }
235
236 return NULL;
237 }
238
239
240 static PINFCACHESECTION
241 InfpCacheAddSection (PINFCACHE Cache,
242 PCHAR Name)
243 {
244 PINFCACHESECTION Section = NULL;
245 ULONG Size;
246
247 if (Cache == NULL || Name == NULL)
248 {
249 DPRINT ("Invalid parameter\n");
250 return NULL;
251 }
252
253 /* Allocate and initialize the new section */
254 Size = sizeof(INFCACHESECTION) + strlen (Name);
255 Section = (PINFCACHESECTION)malloc (Size);
256 if (Section == NULL)
257 {
258 DPRINT ("RtlAllocateHeap() failed\n");
259 return NULL;
260 }
261 memset (Section, 0, Size);
262
263 /* Copy section name */
264 strcpy (Section->Name, Name);
265
266 /* Append section */
267 if (Cache->FirstSection == NULL)
268 {
269 Cache->FirstSection = Section;
270 Cache->LastSection = Section;
271 }
272 else
273 {
274 Cache->LastSection->Next = Section;
275 Section->Prev = Cache->LastSection;
276 Cache->LastSection = Section;
277 }
278
279 return Section;
280 }
281
282
283 static PINFCACHELINE
284 InfpCacheAddLine (PINFCACHESECTION Section)
285 {
286 PINFCACHELINE Line;
287
288 if (Section == NULL)
289 {
290 DPRINT("Invalid parameter\n");
291 return NULL;
292 }
293
294 Line = (PINFCACHELINE)malloc (sizeof(INFCACHELINE));
295 if (Line == NULL)
296 {
297 DPRINT("RtlAllocateHeap() failed\n");
298 return NULL;
299 }
300 memset (Line, 0, sizeof(INFCACHELINE));
301
302 /* Append line */
303 if (Section->FirstLine == NULL)
304 {
305 Section->FirstLine = Line;
306 Section->LastLine = Line;
307 }
308 else
309 {
310 Section->LastLine->Next = Line;
311 Line->Prev = Section->LastLine;
312 Section->LastLine = Line;
313 }
314 Section->LineCount++;
315
316 return Line;
317 }
318
319
320 static PVOID
321 InfpAddKeyToLine (PINFCACHELINE Line,
322 PCHAR Key)
323 {
324 if (Line == NULL)
325 return NULL;
326
327 if (Line->Key != NULL)
328 return NULL;
329
330 Line->Key = (PCHAR)malloc (strlen (Key) + 1);
331 if (Line->Key == NULL)
332 return NULL;
333
334 strcpy (Line->Key, Key);
335
336 return (PVOID)Line->Key;
337 }
338
339
340 static PVOID
341 InfpAddFieldToLine (PINFCACHELINE Line,
342 PCHAR Data)
343 {
344 PINFCACHEFIELD Field;
345 ULONG Size;
346
347 Size = sizeof(INFCACHEFIELD) + strlen(Data);
348 Field = (PINFCACHEFIELD)malloc (Size);
349 if (Field == NULL)
350 {
351 return NULL;
352 }
353 memset (Field, 0, Size);
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 && strcasecmp (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 ULONG 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 ? *src : ' ';
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 = STATUS_SECTION_NAME_TOO_LONG;
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 = STATUS_NOT_ENOUGH_MEMORY;
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 = STATUS_NOT_ENOUGH_MEMORY;
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 BOOL
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 = 0;
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,
871 "Strings");
872
873 return TRUE;
874 }
875
876
877
878 /* PUBLIC FUNCTIONS *********************************************************/
879
880 BOOL
881 InfOpenFile(PHINF InfHandle,
882 PCHAR FileName,
883 PULONG ErrorLine)
884 {
885 FILE *File;
886 PCHAR FileBuffer;
887 ULONG FileLength;
888 PINFCACHE Cache;
889
890 *InfHandle = NULL;
891 *ErrorLine = (ULONG)-1;
892
893 /* Open the inf file */
894 File = fopen (FileName, "rb");
895 if (File == NULL)
896 {
897 DPRINT("fopen() failed\n");
898 return FALSE;
899 }
900
901 DPRINT("fopen() successful\n");
902
903 /* Query file size */
904 fseek (File, 0, SEEK_END);
905 FileLength = ftell (File);
906 fseek (File, 0, SEEK_SET);
907
908 DPRINT("File size: %lu\n", FileLength);
909
910 /* Allocate file buffer */
911 FileBuffer = malloc (FileLength + 1);
912 if (FileBuffer == NULL)
913 {
914 DPRINT1("malloc() failed\n");
915 fclose (File);
916 return FALSE;
917 }
918
919 /* Read file */
920 if (fread (FileBuffer, FileLength, 1, File) < 0)
921 {
922 DPRINT ("fread() failed\n");
923 fclose (File);
924 free (FileBuffer);
925 return FALSE;
926 }
927
928 fclose (File);
929
930 /* Append string terminator */
931 FileBuffer[FileLength] = 0;
932
933 /* Allocate infcache header */
934 Cache = (PINFCACHE)malloc (sizeof(INFCACHE));
935 if (Cache == NULL)
936 {
937 DPRINT("malloc() failed\n");
938 free (FileBuffer);
939 return FALSE;
940 }
941
942 /* Initialize inicache header */
943 memset (Cache, 0, sizeof(INFCACHE));
944
945 /* Parse the inf buffer */
946 if (!InfpParseBuffer (Cache,
947 FileBuffer,
948 FileBuffer + FileLength,
949 ErrorLine))
950 {
951 free (Cache);
952 free (FileBuffer);
953 return FALSE;
954 }
955
956 /* Free file buffer */
957 free (FileBuffer);
958
959 *InfHandle = (HINF)Cache;
960
961 return TRUE;
962 }
963
964
965 VOID
966 InfCloseFile(HINF InfHandle)
967 {
968 PINFCACHE Cache;
969
970 Cache = (PINFCACHE)InfHandle;
971
972 if (Cache == NULL)
973 {
974 return;
975 }
976
977 while (Cache->FirstSection != NULL)
978 {
979 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection);
980 }
981 Cache->LastSection = NULL;
982
983 free (Cache);
984 }
985
986
987 BOOL
988 InfFindFirstLine (HINF InfHandle,
989 PCHAR Section,
990 PCHAR Key,
991 PINFCONTEXT Context)
992 {
993 PINFCACHE Cache;
994 PINFCACHESECTION CacheSection;
995 PINFCACHELINE CacheLine;
996
997 if (InfHandle == NULL || Section == NULL || Context == NULL)
998 {
999 DPRINT("Invalid parameter\n");
1000 return FALSE;
1001 }
1002
1003 Cache = (PINFCACHE)InfHandle;
1004
1005 /* Iterate through list of sections */
1006 CacheSection = Cache->FirstSection;
1007 while (CacheSection != NULL)
1008 {
1009 DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section);
1010
1011 /* Are the section names the same? */
1012 if (strcasecmp(CacheSection->Name, Section) == 0)
1013 {
1014 if (Key != NULL)
1015 {
1016 CacheLine = InfpCacheFindKeyLine (CacheSection, (PCHAR)Key);
1017 }
1018 else
1019 {
1020 CacheLine = CacheSection->FirstLine;
1021 }
1022
1023 if (CacheLine == NULL)
1024 return FALSE;
1025
1026 Context->Inf = (PVOID)Cache;
1027 Context->Section = (PVOID)CacheSection;
1028 Context->Line = (PVOID)CacheLine;
1029
1030 return TRUE;
1031 }
1032
1033 /* Get the next section */
1034 CacheSection = CacheSection->Next;
1035 }
1036
1037 DPRINT("Section not found\n");
1038
1039 return FALSE;
1040 }
1041
1042
1043 BOOL
1044 InfFindNextLine (PINFCONTEXT ContextIn,
1045 PINFCONTEXT ContextOut)
1046 {
1047 PINFCACHELINE CacheLine;
1048
1049 if (ContextIn == NULL || ContextOut == NULL)
1050 return FALSE;
1051
1052 if (ContextIn->Line == NULL)
1053 return FALSE;
1054
1055 CacheLine = (PINFCACHELINE)ContextIn->Line;
1056 if (CacheLine->Next == NULL)
1057 return FALSE;
1058
1059 if (ContextIn != ContextOut)
1060 {
1061 ContextOut->Inf = ContextIn->Inf;
1062 ContextOut->Section = ContextIn->Section;
1063 }
1064 ContextOut->Line = (PVOID)(CacheLine->Next);
1065
1066 return TRUE;
1067 }
1068
1069
1070 BOOL
1071 InfFindFirstMatchLine (PINFCONTEXT ContextIn,
1072 PCHAR Key,
1073 PINFCONTEXT ContextOut)
1074 {
1075 PINFCACHELINE CacheLine;
1076
1077 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1078 return FALSE;
1079
1080 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
1081 return FALSE;
1082
1083 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
1084 while (CacheLine != NULL)
1085 {
1086 if (CacheLine->Key != NULL && strcasecmp (CacheLine->Key, Key) == 0)
1087 {
1088
1089 if (ContextIn != ContextOut)
1090 {
1091 ContextOut->Inf = ContextIn->Inf;
1092 ContextOut->Section = ContextIn->Section;
1093 }
1094 ContextOut->Line = (PVOID)CacheLine;
1095
1096 return TRUE;
1097 }
1098
1099 CacheLine = CacheLine->Next;
1100 }
1101
1102 return FALSE;
1103 }
1104
1105
1106 BOOL
1107 InfFindNextMatchLine (PINFCONTEXT ContextIn,
1108 PCHAR Key,
1109 PINFCONTEXT ContextOut)
1110 {
1111 PINFCACHELINE CacheLine;
1112
1113 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1114 return FALSE;
1115
1116 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
1117 return FALSE;
1118
1119 CacheLine = (PINFCACHELINE)ContextIn->Line;
1120 while (CacheLine != NULL)
1121 {
1122 if (CacheLine->Key != NULL && strcasecmp (CacheLine->Key, Key) == 0)
1123 {
1124
1125 if (ContextIn != ContextOut)
1126 {
1127 ContextOut->Inf = ContextIn->Inf;
1128 ContextOut->Section = ContextIn->Section;
1129 }
1130 ContextOut->Line = (PVOID)CacheLine;
1131
1132 return TRUE;
1133 }
1134
1135 CacheLine = CacheLine->Next;
1136 }
1137
1138 return FALSE;
1139 }
1140
1141
1142 LONG
1143 InfGetLineCount(HINF InfHandle,
1144 PCHAR Section)
1145 {
1146 PINFCACHE Cache;
1147 PINFCACHESECTION CacheSection;
1148
1149 if (InfHandle == NULL || Section == NULL)
1150 {
1151 DPRINT("Invalid parameter\n");
1152 return -1;
1153 }
1154
1155 Cache = (PINFCACHE)InfHandle;
1156
1157 /* Iterate through list of sections */
1158 CacheSection = Cache->FirstSection;
1159 while (Section != NULL)
1160 {
1161 DPRINT("Comparing '%s' and '%s'\n", CacheSection->Name, Section);
1162
1163 /* Are the section names the same? */
1164 if (strcasecmp(CacheSection->Name, Section) == 0)
1165 {
1166 return CacheSection->LineCount;
1167 }
1168
1169 /* Get the next section */
1170 CacheSection = CacheSection->Next;
1171 }
1172
1173 DPRINT("Section not found\n");
1174
1175 return -1;
1176 }
1177
1178
1179 /* InfGetLineText */
1180
1181
1182 LONG
1183 InfGetFieldCount(PINFCONTEXT Context)
1184 {
1185 if (Context == NULL || Context->Line == NULL)
1186 return 0;
1187
1188 return ((PINFCACHELINE)Context->Line)->FieldCount;
1189 }
1190
1191
1192 BOOL
1193 InfGetBinaryField (PINFCONTEXT Context,
1194 ULONG FieldIndex,
1195 PUCHAR ReturnBuffer,
1196 ULONG ReturnBufferSize,
1197 PULONG RequiredSize)
1198 {
1199 PINFCACHELINE CacheLine;
1200 PINFCACHEFIELD CacheField;
1201 ULONG Index;
1202 ULONG Size;
1203 PUCHAR Ptr;
1204
1205 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1206 {
1207 DPRINT("Invalid parameter\n");
1208 return FALSE;
1209 }
1210
1211 if (RequiredSize != NULL)
1212 *RequiredSize = 0;
1213
1214 CacheLine = (PINFCACHELINE)Context->Line;
1215
1216 if (FieldIndex > CacheLine->FieldCount)
1217 return FALSE;
1218
1219 CacheField = CacheLine->FirstField;
1220 for (Index = 1; Index < FieldIndex; Index++)
1221 CacheField = CacheField->Next;
1222
1223 Size = CacheLine->FieldCount - FieldIndex + 1;
1224
1225 if (RequiredSize != NULL)
1226 *RequiredSize = Size;
1227
1228 if (ReturnBuffer != NULL)
1229 {
1230 if (ReturnBufferSize < Size)
1231 return FALSE;
1232
1233 /* Copy binary data */
1234 Ptr = ReturnBuffer;
1235 while (CacheField != NULL)
1236 {
1237 *Ptr = (UCHAR)strtoul (CacheField->Data, NULL, 16);
1238
1239 Ptr++;
1240 CacheField = CacheField->Next;
1241 }
1242 }
1243
1244 return TRUE;
1245 }
1246
1247
1248 BOOL
1249 InfGetIntField (PINFCONTEXT Context,
1250 ULONG FieldIndex,
1251 PLONG IntegerValue)
1252 {
1253 PINFCACHELINE CacheLine;
1254 PINFCACHEFIELD CacheField;
1255 ULONG Index;
1256 PCHAR Ptr;
1257
1258 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
1259 {
1260 DPRINT("Invalid parameter\n");
1261 return FALSE;
1262 }
1263
1264 CacheLine = (PINFCACHELINE)Context->Line;
1265
1266 if (FieldIndex > CacheLine->FieldCount)
1267 {
1268 DPRINT("Invalid parameter\n");
1269 return FALSE;
1270 }
1271
1272 if (FieldIndex == 0)
1273 {
1274 Ptr = CacheLine->Key;
1275 }
1276 else
1277 {
1278 CacheField = CacheLine->FirstField;
1279 for (Index = 1; Index < FieldIndex; Index++)
1280 CacheField = CacheField->Next;
1281
1282 Ptr = CacheField->Data;
1283 }
1284
1285 *IntegerValue = strtol (Ptr, NULL, 0);
1286
1287 return TRUE;
1288 }
1289
1290
1291 BOOL
1292 InfGetMultiSzField (PINFCONTEXT Context,
1293 ULONG FieldIndex,
1294 PCHAR ReturnBuffer,
1295 ULONG ReturnBufferSize,
1296 PULONG RequiredSize)
1297 {
1298 PINFCACHELINE CacheLine;
1299 PINFCACHEFIELD CacheField;
1300 PINFCACHEFIELD FieldPtr;
1301 ULONG Index;
1302 ULONG Size;
1303 PCHAR Ptr;
1304
1305 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1306 {
1307 DPRINT("Invalid parameter\n");
1308 return FALSE;
1309 }
1310
1311 if (RequiredSize != NULL)
1312 *RequiredSize = 0;
1313
1314 CacheLine = (PINFCACHELINE)Context->Line;
1315
1316 if (FieldIndex > CacheLine->FieldCount)
1317 return FALSE;
1318
1319 CacheField = CacheLine->FirstField;
1320 for (Index = 1; Index < FieldIndex; Index++)
1321 CacheField = CacheField->Next;
1322
1323 /* Calculate the required buffer size */
1324 FieldPtr = CacheField;
1325 Size = 0;
1326 while (FieldPtr != NULL)
1327 {
1328 Size += (strlen (FieldPtr->Data) + 1);
1329 FieldPtr = FieldPtr->Next;
1330 }
1331 Size++;
1332
1333 if (RequiredSize != NULL)
1334 *RequiredSize = Size;
1335
1336 if (ReturnBuffer != NULL)
1337 {
1338 if (ReturnBufferSize < Size)
1339 return FALSE;
1340
1341 /* Copy multi-sz string */
1342 Ptr = ReturnBuffer;
1343 FieldPtr = CacheField;
1344 while (FieldPtr != NULL)
1345 {
1346 Size = strlen (FieldPtr->Data) + 1;
1347
1348 strcpy (Ptr, FieldPtr->Data);
1349
1350 Ptr = Ptr + Size;
1351 FieldPtr = FieldPtr->Next;
1352 }
1353 *Ptr = 0;
1354 }
1355
1356 return TRUE;
1357 }
1358
1359
1360 BOOL
1361 InfGetStringField (PINFCONTEXT Context,
1362 ULONG FieldIndex,
1363 PCHAR ReturnBuffer,
1364 ULONG ReturnBufferSize,
1365 PULONG RequiredSize)
1366 {
1367 PINFCACHELINE CacheLine;
1368 PINFCACHEFIELD CacheField;
1369 ULONG Index;
1370 PCHAR Ptr;
1371 ULONG Size;
1372
1373 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1374 {
1375 DPRINT("Invalid parameter\n");
1376 return FALSE;
1377 }
1378
1379 if (RequiredSize != NULL)
1380 *RequiredSize = 0;
1381
1382 CacheLine = (PINFCACHELINE)Context->Line;
1383
1384 if (FieldIndex > CacheLine->FieldCount)
1385 return FALSE;
1386
1387 if (FieldIndex == 0)
1388 {
1389 Ptr = CacheLine->Key;
1390 }
1391 else
1392 {
1393 CacheField = CacheLine->FirstField;
1394 for (Index = 1; Index < FieldIndex; Index++)
1395 CacheField = CacheField->Next;
1396
1397 Ptr = CacheField->Data;
1398 }
1399
1400 Size = strlen (Ptr) + 1;
1401
1402 if (RequiredSize != NULL)
1403 *RequiredSize = Size;
1404
1405 if (ReturnBuffer != NULL)
1406 {
1407 if (ReturnBufferSize < Size)
1408 return FALSE;
1409
1410 strcpy (ReturnBuffer, Ptr);
1411 }
1412
1413 return TRUE;
1414 }
1415
1416
1417
1418
1419 BOOL
1420 InfGetData (PINFCONTEXT Context,
1421 PCHAR *Key,
1422 PCHAR *Data)
1423 {
1424 PINFCACHELINE CacheKey;
1425
1426 if (Context == NULL || Context->Line == NULL || Data == NULL)
1427 {
1428 DPRINT("Invalid parameter\n");
1429 return FALSE;
1430 }
1431
1432 CacheKey = (PINFCACHELINE)Context->Line;
1433 if (Key != NULL)
1434 *Key = CacheKey->Key;
1435
1436 if (Data != NULL)
1437 {
1438 if (CacheKey->FirstField == NULL)
1439 {
1440 *Data = NULL;
1441 }
1442 else
1443 {
1444 *Data = CacheKey->FirstField->Data;
1445 }
1446 }
1447
1448 return TRUE;
1449 }
1450
1451
1452 BOOL
1453 InfGetDataField (PINFCONTEXT Context,
1454 ULONG FieldIndex,
1455 PCHAR *Data)
1456 {
1457 PINFCACHELINE CacheLine;
1458 PINFCACHEFIELD CacheField;
1459 ULONG Index;
1460
1461 if (Context == NULL || Context->Line == NULL || Data == NULL)
1462 {
1463 DPRINT("Invalid parameter\n");
1464 return FALSE;
1465 }
1466
1467 CacheLine = (PINFCACHELINE)Context->Line;
1468
1469 if (FieldIndex > CacheLine->FieldCount)
1470 return FALSE;
1471
1472 if (FieldIndex == 0)
1473 {
1474 *Data = CacheLine->Key;
1475 }
1476 else
1477 {
1478 CacheField = CacheLine->FirstField;
1479 for (Index = 1; Index < FieldIndex; Index++)
1480 CacheField = CacheField->Next;
1481
1482 *Data = CacheField->Data;
1483 }
1484
1485 return TRUE;
1486 }
1487
1488
1489 /* EOF */