3 * Copyright (C) 2002,2003 ReactOS Team
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.
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.
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.
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
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
35 #define CONTROL_Z '\x1a'
36 #define MAX_SECTION_NAME_LEN 255
37 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */
38 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */
39 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1)
42 typedef struct _INFCACHEFIELD
44 struct _INFCACHEFIELD *Next;
45 struct _INFCACHEFIELD *Prev;
48 } INFCACHEFIELD, *PINFCACHEFIELD;
51 typedef struct _INFCACHELINE
53 struct _INFCACHELINE *Next;
54 struct _INFCACHELINE *Prev;
60 PINFCACHEFIELD FirstField;
61 PINFCACHEFIELD LastField;
63 } INFCACHELINE, *PINFCACHELINE;
66 typedef struct _INFCACHESECTION
68 struct _INFCACHESECTION *Next;
69 struct _INFCACHESECTION *Prev;
71 PINFCACHELINE FirstLine;
72 PINFCACHELINE LastLine;
77 } INFCACHESECTION, *PINFCACHESECTION;
80 typedef struct _INFCACHE
82 PINFCACHESECTION FirstSection;
83 PINFCACHESECTION LastSection;
85 PINFCACHESECTION StringsSection;
86 } INFCACHE, *PINFCACHE;
89 /* parser definitions */
93 LINE_START, /* at beginning of a line */
94 SECTION_NAME, /* parsing a section name */
95 KEY_NAME, /* parsing a key name */
96 VALUE_NAME, /* parsing a value name */
97 EOL_BACKSLASH, /* backslash at end of line */
98 QUOTES, /* inside quotes */
99 LEADING_SPACES, /* leading spaces */
100 TRAILING_SPACES, /* trailing spaces */
101 COMMENT, /* inside a comment */
107 const CHAR *start; /* start position of item being parsed */
108 const CHAR *end; /* end of buffer */
109 PINFCACHE file; /* file being built */
110 enum parser_state state; /* current parser state */
111 enum parser_state stack[4]; /* state stack */
112 int stack_pos; /* current pos in stack */
114 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/
115 PINFCACHELINE line; /* current line */
116 unsigned int line_pos; /* current line position in file */
117 unsigned int error; /* error code */
118 unsigned int token_len; /* current token len */
119 WCHAR token[MAX_FIELD_LEN+1]; /* current token */
122 typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos );
124 /* parser state machine functions */
125 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos );
126 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos );
127 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos );
128 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos );
129 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos );
130 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos );
131 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos );
132 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos );
133 static const CHAR *comment_state( struct parser *parser, const CHAR *pos );
135 static const parser_state_func parser_funcs[NB_PARSER_STATES] =
137 line_start_state, /* LINE_START */
138 section_name_state, /* SECTION_NAME */
139 key_name_state, /* KEY_NAME */
140 value_name_state, /* VALUE_NAME */
141 eol_backslash_state, /* EOL_BACKSLASH */
142 quotes_state, /* QUOTES */
143 leading_spaces_state, /* LEADING_SPACES */
144 trailing_spaces_state, /* TRAILING_SPACES */
145 comment_state /* COMMENT */
149 /* PRIVATE FUNCTIONS ********************************************************/
152 InfpCacheFreeLine (PINFCACHELINE Line)
155 PINFCACHEFIELD Field;
163 if (Line->Key != NULL)
165 RtlFreeHeap (ProcessHeap,
171 /* Remove data fields */
172 while (Line->FirstField != NULL)
174 Field = Line->FirstField->Next;
175 RtlFreeHeap (ProcessHeap,
178 Line->FirstField = Field;
180 Line->LastField = NULL;
182 RtlFreeHeap (ProcessHeap,
190 static PINFCACHESECTION
191 InfpCacheFreeSection (PINFCACHESECTION Section)
193 PINFCACHESECTION Next;
200 /* Release all keys */
201 Next = Section->Next;
202 while (Section->FirstLine != NULL)
204 Section->FirstLine = InfpCacheFreeLine (Section->FirstLine);
206 Section->LastLine = NULL;
208 RtlFreeHeap (ProcessHeap,
216 static PINFCACHESECTION
217 InfpCacheFindSection (PINFCACHE Cache,
220 PINFCACHESECTION Section = NULL;
222 if (Cache == NULL || Name == NULL)
227 /* iterate through list of sections */
228 Section = Cache->FirstSection;
229 while (Section != NULL)
231 if (_wcsicmp (Section->Name, Name) == 0)
236 /* get the next section*/
237 Section = Section->Next;
244 static PINFCACHESECTION
245 InfpCacheAddSection (PINFCACHE Cache,
248 PINFCACHESECTION Section = NULL;
251 if (Cache == NULL || Name == NULL)
253 DPRINT("Invalid parameter\n");
257 /* Allocate and initialize the new section */
258 Size = sizeof(INFCACHESECTION) + (wcslen (Name) * sizeof(WCHAR));
259 Section = (PINFCACHESECTION)RtlAllocateHeap (ProcessHeap,
264 DPRINT("RtlAllocateHeap() failed\n");
267 RtlZeroMemory (Section,
270 /* Copy section name */
271 wcscpy (Section->Name, Name);
274 if (Cache->FirstSection == NULL)
276 Cache->FirstSection = Section;
277 Cache->LastSection = Section;
281 Cache->LastSection->Next = Section;
282 Section->Prev = Cache->LastSection;
283 Cache->LastSection = Section;
291 InfpCacheAddLine (PINFCACHESECTION Section)
297 DPRINT("Invalid parameter\n");
301 Line = (PINFCACHELINE)RtlAllocateHeap (ProcessHeap,
303 sizeof(INFCACHELINE));
306 DPRINT("RtlAllocateHeap() failed\n");
310 sizeof(INFCACHELINE));
313 if (Section->FirstLine == NULL)
315 Section->FirstLine = Line;
316 Section->LastLine = Line;
320 Section->LastLine->Next = Line;
321 Line->Prev = Section->LastLine;
322 Section->LastLine = Line;
324 Section->LineCount++;
331 InfpAddKeyToLine (PINFCACHELINE Line,
337 if (Line->Key != NULL)
340 Line->Key = (PWCHAR)RtlAllocateHeap (ProcessHeap,
342 (wcslen (Key) + 1) * sizeof(WCHAR));
343 if (Line->Key == NULL)
346 wcscpy (Line->Key, Key);
348 return (PVOID)Line->Key;
353 InfpAddFieldToLine (PINFCACHELINE Line,
356 PINFCACHEFIELD Field;
359 Size = sizeof(INFCACHEFIELD) + (wcslen(Data) * sizeof(WCHAR));
360 Field = (PINFCACHEFIELD)RtlAllocateHeap (ProcessHeap,
367 RtlZeroMemory (Field,
369 wcscpy (Field->Data, Data);
372 if (Line->FirstField == NULL)
374 Line->FirstField = Field;
375 Line->LastField = Field;
379 Line->LastField->Next = Field;
380 Field->Prev = Line->LastField;
381 Line->LastField = Field;
390 InfpCacheFindKeyLine (PINFCACHESECTION Section,
395 Line = Section->FirstLine;
398 if (Line->Key != NULL && _wcsicmp (Line->Key, Key) == 0)
410 /* push the current state on the parser stack */
411 inline static void push_state( struct parser *parser, enum parser_state state )
413 // assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) );
414 parser->stack[parser->stack_pos++] = state;
418 /* pop the current state */
419 inline static void pop_state( struct parser *parser )
421 // assert( parser->stack_pos );
422 parser->state = parser->stack[--parser->stack_pos];
426 /* set the parser state and return the previous one */
427 inline static enum parser_state set_state( struct parser *parser, enum parser_state state )
429 enum parser_state ret = parser->state;
430 parser->state = state;
435 /* check if the pointer points to an end of file */
436 inline static int is_eof( struct parser *parser, const CHAR *ptr )
438 return (ptr >= parser->end || *ptr == CONTROL_Z);
442 /* check if the pointer points to an end of line */
443 inline static int is_eol( struct parser *parser, const CHAR *ptr )
445 return (ptr >= parser->end || *ptr == CONTROL_Z || *ptr == '\r' /*'\n'*/);
449 /* push data from current token start up to pos into the current token */
450 static int push_token( struct parser *parser, const CHAR *pos )
452 int len = pos - parser->start;
453 const CHAR *src = parser->start;
454 WCHAR *dst = parser->token + parser->token_len;
456 if (len > MAX_FIELD_LEN - parser->token_len)
457 len = MAX_FIELD_LEN - parser->token_len;
459 parser->token_len += len;
460 for ( ; len > 0; len--, dst++, src++)
461 *dst = *src ? (WCHAR)*src : L' ';
470 /* add a section with the current token as name */
471 static PVOID add_section_from_token( struct parser *parser )
473 PINFCACHESECTION Section;
475 if (parser->token_len > MAX_SECTION_NAME_LEN)
477 parser->error = STATUS_SECTION_NAME_TOO_LONG;
481 Section = InfpCacheFindSection (parser->file,
485 /* need to create a new one */
486 Section= InfpCacheAddSection (parser->file,
490 parser->error = STATUS_NOT_ENOUGH_MEMORY;
495 parser->token_len = 0;
496 parser->cur_section = Section;
498 return (PVOID)Section;
502 /* add a field containing the current token to the current line */
503 static struct field *add_field_from_token( struct parser *parser, int is_key )
508 if (!parser->line) /* need to start a new line */
510 if (parser->cur_section == NULL) /* got a line before the first section */
512 parser->error = STATUS_WRONG_INF_STYLE;
516 parser->line = InfpCacheAddLine (parser->cur_section);
517 if (parser->line == NULL)
527 field = InfpAddKeyToLine(parser->line, parser->token);
531 field = InfpAddFieldToLine(parser->line, parser->token);
536 parser->token_len = 0;
541 parser->error = STATUS_NOT_ENOUGH_MEMORY;
546 /* close the current line and prepare for parsing a new one */
547 static void close_current_line( struct parser *parser )
554 /* handler for parser LINE_START state */
555 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos )
559 for (p = pos; !is_eof( parser, p ); p++)
567 close_current_line( parser );
570 push_state( parser, LINE_START );
571 set_state( parser, COMMENT );
574 parser->start = p + 1;
575 set_state( parser, SECTION_NAME );
581 set_state( parser, KEY_NAME );
587 close_current_line( parser );
592 /* handler for parser SECTION_NAME state */
593 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos )
597 for (p = pos; !is_eol( parser, p ); p++)
601 push_token( parser, p );
602 if (add_section_from_token( parser ) == NULL)
604 push_state( parser, LINE_START );
605 set_state( parser, COMMENT ); /* ignore everything else on the line */
609 parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
614 /* handler for parser KEY_NAME state */
615 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos )
617 const CHAR *p, *token_end = parser->start;
619 for (p = pos; !is_eol( parser, p ); p++)
621 if (*p == ',') break;
626 push_token( parser, token_end );
627 if (!add_field_from_token( parser, 1 )) return NULL;
628 parser->start = p + 1;
629 push_state( parser, VALUE_NAME );
630 set_state( parser, LEADING_SPACES );
633 push_token( parser, token_end );
634 if (!add_field_from_token( parser, 0 )) return NULL;
635 push_state( parser, LINE_START );
636 set_state( parser, COMMENT );
639 push_token( parser, token_end );
640 parser->start = p + 1;
641 push_state( parser, KEY_NAME );
642 set_state( parser, QUOTES );
645 push_token( parser, token_end );
647 push_state( parser, KEY_NAME );
648 set_state( parser, EOL_BACKSLASH );
651 if (!isspace(*p)) token_end = p + 1;
654 push_token( parser, p );
655 push_state( parser, KEY_NAME );
656 set_state( parser, TRAILING_SPACES );
662 push_token( parser, token_end );
663 set_state( parser, VALUE_NAME );
668 /* handler for parser VALUE_NAME state */
669 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos )
671 const CHAR *p, *token_end = parser->start;
673 for (p = pos; !is_eol( parser, p ); p++)
678 push_token( parser, token_end );
679 if (!add_field_from_token( parser, 0 )) return NULL;
680 push_state( parser, LINE_START );
681 set_state( parser, COMMENT );
684 push_token( parser, token_end );
685 if (!add_field_from_token( parser, 0 )) return NULL;
686 parser->start = p + 1;
687 push_state( parser, VALUE_NAME );
688 set_state( parser, LEADING_SPACES );
691 push_token( parser, token_end );
692 parser->start = p + 1;
693 push_state( parser, VALUE_NAME );
694 set_state( parser, QUOTES );
697 push_token( parser, token_end );
699 push_state( parser, VALUE_NAME );
700 set_state( parser, EOL_BACKSLASH );
703 if (!isspace(*p)) token_end = p + 1;
706 push_token( parser, p );
707 push_state( parser, VALUE_NAME );
708 set_state( parser, TRAILING_SPACES );
714 push_token( parser, token_end );
715 if (!add_field_from_token( parser, 0 )) return NULL;
716 set_state( parser, LINE_START );
721 /* handler for parser EOL_BACKSLASH state */
722 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos )
726 for (p = pos; !is_eof( parser, p ); p++)
733 // parser->start = p + 1;
734 parser->start = p + 2;
735 set_state( parser, LEADING_SPACES );
741 push_state( parser, EOL_BACKSLASH );
742 set_state( parser, COMMENT );
747 push_token( parser, p );
759 /* handler for parser QUOTES state */
760 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos )
762 const CHAR *p, *token_end = parser->start;
764 for (p = pos; !is_eol( parser, p ); p++)
768 if (p+1 < parser->end && p[1] == '"') /* double quotes */
770 push_token( parser, p + 1 );
771 parser->start = token_end = p + 2;
774 else /* end of quotes */
776 push_token( parser, p );
777 parser->start = p + 1;
783 push_token( parser, p );
789 /* handler for parser LEADING_SPACES state */
790 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos )
794 for (p = pos; !is_eol( parser, p ); p++)
799 set_state( parser, EOL_BACKSLASH );
811 /* handler for parser TRAILING_SPACES state */
812 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos )
816 for (p = pos; !is_eol( parser, p ); p++)
820 set_state( parser, EOL_BACKSLASH );
831 /* handler for parser COMMENT state */
832 static const CHAR *comment_state( struct parser *parser, const CHAR *pos )
836 while (!is_eol( parser, p ))
843 /* parse a complete buffer */
845 InfpParseBuffer (PINFCACHE file,
850 struct parser parser;
851 const CHAR *pos = buffer;
853 parser.start = buffer;
857 parser.state = LINE_START;
858 parser.stack_pos = 0;
859 parser.cur_section = NULL;
862 parser.token_len = 0;
864 /* parser main loop */
866 pos = (parser_funcs[parser.state])(&parser, pos);
871 *error_line = parser.line_pos;
875 /* find the [strings] section */
876 file->StringsSection = InfpCacheFindSection (file,
879 return STATUS_SUCCESS;
884 /* PUBLIC FUNCTIONS *********************************************************/
887 InfOpenFile(PHINF InfHandle,
888 PUNICODE_STRING FileName,
891 OBJECT_ATTRIBUTES ObjectAttributes;
892 FILE_STANDARD_INFORMATION FileInfo;
893 IO_STATUS_BLOCK IoStatusBlock;
898 LARGE_INTEGER FileOffset;
903 *ErrorLine = (ULONG)-1;
905 /* Open the inf file */
906 InitializeObjectAttributes(&ObjectAttributes,
912 Status = NtOpenFile(&FileHandle,
913 GENERIC_READ | SYNCHRONIZE,
917 FILE_NON_DIRECTORY_FILE);
918 if (!NT_SUCCESS(Status))
920 DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
924 DPRINT("NtOpenFile() successful\n");
926 /* Query file size */
927 Status = NtQueryInformationFile(FileHandle,
930 sizeof(FILE_STANDARD_INFORMATION),
931 FileStandardInformation);
932 if (Status == STATUS_PENDING)
934 DPRINT("NtQueryInformationFile() returns STATUS_PENDING\n");
937 else if (!NT_SUCCESS(Status))
939 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
944 FileLength = FileInfo.EndOfFile.u.LowPart;
946 DPRINT("File size: %lu\n", FileLength);
948 /* Allocate file buffer */
949 FileBuffer = RtlAllocateHeap(ProcessHeap,
952 if (FileBuffer == NULL)
954 DPRINT1("RtlAllocateHeap() failed\n");
956 return(STATUS_INSUFFICIENT_RESOURCES);
960 FileOffset.QuadPart = 0ULL;
961 Status = NtReadFile(FileHandle,
971 if (Status == STATUS_PENDING)
973 DPRINT("NtReadFile() returns STATUS_PENDING\n");
975 Status = IoStatusBlock.Status;
978 /* Append string terminator */
979 FileBuffer[FileLength] = 0;
983 if (!NT_SUCCESS(Status))
985 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
986 RtlFreeHeap(ProcessHeap,
992 /* Allocate infcache header */
993 Cache = (PINFCACHE)RtlAllocateHeap(ProcessHeap,
998 DPRINT("RtlAllocateHeap() failed\n");
999 RtlFreeHeap(ProcessHeap,
1002 return(STATUS_INSUFFICIENT_RESOURCES);
1005 /* Initialize inicache header */
1006 RtlZeroMemory(Cache,
1009 /* Parse the inf buffer */
1010 Status = InfpParseBuffer (Cache,
1012 FileBuffer + FileLength,
1014 if (!NT_SUCCESS(Status))
1016 RtlFreeHeap(ProcessHeap,
1022 /* Free file buffer */
1023 RtlFreeHeap(ProcessHeap,
1027 *InfHandle = (HINF)Cache;
1034 InfCloseFile(HINF InfHandle)
1038 Cache = (PINFCACHE)InfHandle;
1045 while (Cache->FirstSection != NULL)
1047 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection);
1049 Cache->LastSection = NULL;
1051 RtlFreeHeap(ProcessHeap,
1058 InfFindFirstLine (HINF InfHandle,
1061 PINFCONTEXT Context)
1064 PINFCACHESECTION CacheSection;
1065 PINFCACHELINE CacheLine;
1067 if (InfHandle == NULL || Section == NULL || Context == NULL)
1069 DPRINT("Invalid parameter\n");
1073 Cache = (PINFCACHE)InfHandle;
1075 /* Iterate through list of sections */
1076 CacheSection = Cache->FirstSection;
1077 while (Section != NULL)
1079 DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1081 /* Are the section names the same? */
1082 if (_wcsicmp(CacheSection->Name, Section) == 0)
1086 CacheLine = InfpCacheFindKeyLine (CacheSection, (PWCHAR)Key);
1090 CacheLine = CacheSection->FirstLine;
1093 if (CacheLine == NULL)
1096 Context->Inf = (PVOID)Cache;
1097 Context->Section = (PVOID)CacheSection;
1098 Context->Line = (PVOID)CacheLine;
1103 /* Get the next section */
1104 CacheSection = CacheSection->Next;
1107 DPRINT("Section not found\n");
1114 InfFindNextLine (PINFCONTEXT ContextIn,
1115 PINFCONTEXT ContextOut)
1117 PINFCACHELINE CacheLine;
1119 if (ContextIn == NULL || ContextOut == NULL)
1122 if (ContextIn->Line == NULL)
1125 CacheLine = (PINFCACHELINE)ContextIn->Line;
1126 if (CacheLine->Next == NULL)
1129 if (ContextIn != ContextOut)
1131 ContextOut->Inf = ContextIn->Inf;
1132 ContextOut->Section = ContextIn->Section;
1134 ContextOut->Line = (PVOID)(CacheLine->Next);
1141 InfFindFirstMatchLine (PINFCONTEXT ContextIn,
1143 PINFCONTEXT ContextOut)
1145 PINFCACHELINE CacheLine;
1147 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1150 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
1153 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
1154 while (CacheLine != NULL)
1156 if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
1159 if (ContextIn != ContextOut)
1161 ContextOut->Inf = ContextIn->Inf;
1162 ContextOut->Section = ContextIn->Section;
1164 ContextOut->Line = (PVOID)CacheLine;
1169 CacheLine = CacheLine->Next;
1177 InfFindNextMatchLine (PINFCONTEXT ContextIn,
1179 PINFCONTEXT ContextOut)
1181 PINFCACHELINE CacheLine;
1183 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1186 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
1189 CacheLine = (PINFCACHELINE)ContextIn->Line;
1190 while (CacheLine != NULL)
1192 if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
1195 if (ContextIn != ContextOut)
1197 ContextOut->Inf = ContextIn->Inf;
1198 ContextOut->Section = ContextIn->Section;
1200 ContextOut->Line = (PVOID)CacheLine;
1205 CacheLine = CacheLine->Next;
1213 InfGetLineCount(HINF InfHandle,
1217 PINFCACHESECTION CacheSection;
1219 if (InfHandle == NULL || Section == NULL)
1221 DPRINT("Invalid parameter\n");
1225 Cache = (PINFCACHE)InfHandle;
1227 /* Iterate through list of sections */
1228 CacheSection = Cache->FirstSection;
1229 while (Section != NULL)
1231 DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1233 /* Are the section names the same? */
1234 if (_wcsicmp(CacheSection->Name, Section) == 0)
1236 return CacheSection->LineCount;
1239 /* Get the next section */
1240 CacheSection = CacheSection->Next;
1243 DPRINT("Section not found\n");
1249 /* InfGetLineText */
1253 InfGetFieldCount(PINFCONTEXT Context)
1255 if (Context == NULL || Context->Line == NULL)
1258 return ((PINFCACHELINE)Context->Line)->FieldCount;
1263 InfGetBinaryField (PINFCONTEXT Context,
1265 PUCHAR ReturnBuffer,
1266 ULONG ReturnBufferSize,
1267 PULONG RequiredSize)
1269 PINFCACHELINE CacheLine;
1270 PINFCACHEFIELD CacheField;
1275 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1277 DPRINT("Invalid parameter\n");
1281 if (RequiredSize != NULL)
1284 CacheLine = (PINFCACHELINE)Context->Line;
1286 if (FieldIndex > CacheLine->FieldCount)
1289 CacheField = CacheLine->FirstField;
1290 for (Index = 1; Index < FieldIndex; Index++)
1291 CacheField = CacheField->Next;
1293 Size = CacheLine->FieldCount - FieldIndex + 1;
1295 if (RequiredSize != NULL)
1296 *RequiredSize = Size;
1298 if (ReturnBuffer != NULL)
1300 if (ReturnBufferSize < Size)
1303 /* Copy binary data */
1305 while (CacheField != NULL)
1307 *Ptr = (UCHAR)wcstoul (CacheField->Data, NULL, 16);
1310 CacheField = CacheField->Next;
1319 InfGetIntField (PINFCONTEXT Context,
1323 PINFCACHELINE CacheLine;
1324 PINFCACHEFIELD CacheField;
1328 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
1330 DPRINT("Invalid parameter\n");
1334 CacheLine = (PINFCACHELINE)Context->Line;
1336 if (FieldIndex > CacheLine->FieldCount)
1338 DPRINT("Invalid parameter\n");
1342 if (FieldIndex == 0)
1344 Ptr = CacheLine->Key;
1348 CacheField = CacheLine->FirstField;
1349 for (Index = 1; Index < FieldIndex; Index++)
1350 CacheField = CacheField->Next;
1352 Ptr = CacheField->Data;
1355 *IntegerValue = wcstol (Ptr, NULL, 0);
1362 InfGetMultiSzField (PINFCONTEXT Context,
1365 ULONG ReturnBufferSize,
1366 PULONG RequiredSize)
1368 PINFCACHELINE CacheLine;
1369 PINFCACHEFIELD CacheField;
1370 PINFCACHEFIELD FieldPtr;
1375 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1377 DPRINT("Invalid parameter\n");
1381 if (RequiredSize != NULL)
1384 CacheLine = (PINFCACHELINE)Context->Line;
1386 if (FieldIndex > CacheLine->FieldCount)
1389 CacheField = CacheLine->FirstField;
1390 for (Index = 1; Index < FieldIndex; Index++)
1391 CacheField = CacheField->Next;
1393 /* Calculate the required buffer size */
1394 FieldPtr = CacheField;
1396 while (FieldPtr != NULL)
1398 Size += (wcslen (FieldPtr->Data) + 1);
1399 FieldPtr = FieldPtr->Next;
1403 if (RequiredSize != NULL)
1404 *RequiredSize = Size;
1406 if (ReturnBuffer != NULL)
1408 if (ReturnBufferSize < Size)
1411 /* Copy multi-sz string */
1413 FieldPtr = CacheField;
1414 while (FieldPtr != NULL)
1416 Size = wcslen (FieldPtr->Data) + 1;
1418 wcscpy (Ptr, FieldPtr->Data);
1421 FieldPtr = FieldPtr->Next;
1431 InfGetStringField (PINFCONTEXT Context,
1434 ULONG ReturnBufferSize,
1435 PULONG RequiredSize)
1437 PINFCACHELINE CacheLine;
1438 PINFCACHEFIELD CacheField;
1443 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1445 DPRINT("Invalid parameter\n");
1449 if (RequiredSize != NULL)
1452 CacheLine = (PINFCACHELINE)Context->Line;
1454 if (FieldIndex > CacheLine->FieldCount)
1457 if (FieldIndex == 0)
1459 Ptr = CacheLine->Key;
1463 CacheField = CacheLine->FirstField;
1464 for (Index = 1; Index < FieldIndex; Index++)
1465 CacheField = CacheField->Next;
1467 Ptr = CacheField->Data;
1470 Size = wcslen (Ptr) + 1;
1472 if (RequiredSize != NULL)
1473 *RequiredSize = Size;
1475 if (ReturnBuffer != NULL)
1477 if (ReturnBufferSize < Size)
1480 wcscpy (ReturnBuffer, Ptr);
1490 InfGetData (PINFCONTEXT Context,
1494 PINFCACHELINE CacheKey;
1496 if (Context == NULL || Context->Line == NULL || Data == NULL)
1498 DPRINT("Invalid parameter\n");
1502 CacheKey = (PINFCACHELINE)Context->Line;
1504 *Key = CacheKey->Key;
1508 if (CacheKey->FirstField == NULL)
1514 *Data = CacheKey->FirstField->Data;
1523 InfGetDataField (PINFCONTEXT Context,
1527 PINFCACHELINE CacheLine;
1528 PINFCACHEFIELD CacheField;
1531 if (Context == NULL || Context->Line == NULL || Data == NULL)
1533 DPRINT("Invalid parameter\n");
1537 CacheLine = (PINFCACHELINE)Context->Line;
1539 if (FieldIndex > CacheLine->FieldCount)
1542 if (FieldIndex == 0)
1544 *Data = CacheLine->Key;
1548 CacheField = CacheLine->FirstField;
1549 for (Index = 1; Index < FieldIndex; Index++)
1550 CacheField = CacheField->Next;
1552 *Data = CacheField->Data;