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 ||
448 (*ptr == '\r' && *(ptr + 1) == '\n'));
452 /* push data from current token start up to pos into the current token */
453 static int push_token( struct parser *parser, const CHAR *pos )
455 int len = pos - parser->start;
456 const CHAR *src = parser->start;
457 WCHAR *dst = parser->token + parser->token_len;
459 if (len > MAX_FIELD_LEN - parser->token_len)
460 len = MAX_FIELD_LEN - parser->token_len;
462 parser->token_len += len;
463 for ( ; len > 0; len--, dst++, src++)
464 *dst = *src ? (WCHAR)*src : L' ';
473 /* add a section with the current token as name */
474 static PVOID add_section_from_token( struct parser *parser )
476 PINFCACHESECTION Section;
478 if (parser->token_len > MAX_SECTION_NAME_LEN)
480 parser->error = STATUS_SECTION_NAME_TOO_LONG;
484 Section = InfpCacheFindSection (parser->file,
488 /* need to create a new one */
489 Section= InfpCacheAddSection (parser->file,
493 parser->error = STATUS_NOT_ENOUGH_MEMORY;
498 parser->token_len = 0;
499 parser->cur_section = Section;
501 return (PVOID)Section;
505 /* add a field containing the current token to the current line */
506 static struct field *add_field_from_token( struct parser *parser, int is_key )
511 if (!parser->line) /* need to start a new line */
513 if (parser->cur_section == NULL) /* got a line before the first section */
515 parser->error = STATUS_WRONG_INF_STYLE;
519 parser->line = InfpCacheAddLine (parser->cur_section);
520 if (parser->line == NULL)
530 field = InfpAddKeyToLine(parser->line, parser->token);
534 field = InfpAddFieldToLine(parser->line, parser->token);
539 parser->token_len = 0;
544 parser->error = STATUS_NOT_ENOUGH_MEMORY;
549 /* close the current line and prepare for parsing a new one */
550 static void close_current_line( struct parser *parser )
557 /* handler for parser LINE_START state */
558 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos )
562 for (p = pos; !is_eof( parser, p ); p++)
571 close_current_line( parser );
575 push_state( parser, LINE_START );
576 set_state( parser, COMMENT );
580 parser->start = p + 1;
581 set_state( parser, SECTION_NAME );
588 set_state( parser, KEY_NAME );
594 close_current_line( parser );
599 /* handler for parser SECTION_NAME state */
600 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos )
604 for (p = pos; !is_eol( parser, p ); p++)
608 push_token( parser, p );
609 if (add_section_from_token( parser ) == NULL)
611 push_state( parser, LINE_START );
612 set_state( parser, COMMENT ); /* ignore everything else on the line */
616 parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */
621 /* handler for parser KEY_NAME state */
622 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos )
624 const CHAR *p, *token_end = parser->start;
626 for (p = pos; !is_eol( parser, p ); p++)
628 if (*p == ',') break;
633 push_token( parser, token_end );
634 if (!add_field_from_token( parser, 1 )) return NULL;
635 parser->start = p + 1;
636 push_state( parser, VALUE_NAME );
637 set_state( parser, LEADING_SPACES );
640 push_token( parser, token_end );
641 if (!add_field_from_token( parser, 0 )) return NULL;
642 push_state( parser, LINE_START );
643 set_state( parser, COMMENT );
646 push_token( parser, token_end );
647 parser->start = p + 1;
648 push_state( parser, KEY_NAME );
649 set_state( parser, QUOTES );
652 push_token( parser, token_end );
654 push_state( parser, KEY_NAME );
655 set_state( parser, EOL_BACKSLASH );
658 if (!isspace(*p)) token_end = p + 1;
661 push_token( parser, p );
662 push_state( parser, KEY_NAME );
663 set_state( parser, TRAILING_SPACES );
669 push_token( parser, token_end );
670 set_state( parser, VALUE_NAME );
675 /* handler for parser VALUE_NAME state */
676 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos )
678 const CHAR *p, *token_end = parser->start;
680 for (p = pos; !is_eol( parser, p ); p++)
685 push_token( parser, token_end );
686 if (!add_field_from_token( parser, 0 )) return NULL;
687 push_state( parser, LINE_START );
688 set_state( parser, COMMENT );
691 push_token( parser, token_end );
692 if (!add_field_from_token( parser, 0 )) return NULL;
693 parser->start = p + 1;
694 push_state( parser, VALUE_NAME );
695 set_state( parser, LEADING_SPACES );
698 push_token( parser, token_end );
699 parser->start = p + 1;
700 push_state( parser, VALUE_NAME );
701 set_state( parser, QUOTES );
704 push_token( parser, token_end );
706 push_state( parser, VALUE_NAME );
707 set_state( parser, EOL_BACKSLASH );
710 if (!isspace(*p)) token_end = p + 1;
713 push_token( parser, p );
714 push_state( parser, VALUE_NAME );
715 set_state( parser, TRAILING_SPACES );
721 push_token( parser, token_end );
722 if (!add_field_from_token( parser, 0 )) return NULL;
723 set_state( parser, LINE_START );
728 /* handler for parser EOL_BACKSLASH state */
729 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos )
733 for (p = pos; !is_eof( parser, p ); p++)
742 parser->start = p + 1;
743 set_state( parser, LEADING_SPACES );
750 push_state( parser, EOL_BACKSLASH );
751 set_state( parser, COMMENT );
757 push_token( parser, p );
769 /* handler for parser QUOTES state */
770 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos )
772 const CHAR *p, *token_end = parser->start;
774 for (p = pos; !is_eol( parser, p ); p++)
778 if (p+1 < parser->end && p[1] == '"') /* double quotes */
780 push_token( parser, p + 1 );
781 parser->start = token_end = p + 2;
784 else /* end of quotes */
786 push_token( parser, p );
787 parser->start = p + 1;
793 push_token( parser, p );
799 /* handler for parser LEADING_SPACES state */
800 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos )
804 for (p = pos; !is_eol( parser, p ); p++)
809 set_state( parser, EOL_BACKSLASH );
821 /* handler for parser TRAILING_SPACES state */
822 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos )
826 for (p = pos; !is_eol( parser, p ); p++)
830 set_state( parser, EOL_BACKSLASH );
841 /* handler for parser COMMENT state */
842 static const CHAR *comment_state( struct parser *parser, const CHAR *pos )
846 while (!is_eol( parser, p ))
853 /* parse a complete buffer */
855 InfpParseBuffer (PINFCACHE file,
860 struct parser parser;
861 const CHAR *pos = buffer;
863 parser.start = buffer;
867 parser.state = LINE_START;
868 parser.stack_pos = 0;
869 parser.cur_section = NULL;
872 parser.token_len = 0;
874 /* parser main loop */
876 pos = (parser_funcs[parser.state])(&parser, pos);
881 *error_line = parser.line_pos;
885 /* find the [strings] section */
886 file->StringsSection = InfpCacheFindSection (file,
889 return STATUS_SUCCESS;
894 /* PUBLIC FUNCTIONS *********************************************************/
897 InfOpenBufferedFile(PHINF InfHandle,
907 *ErrorLine = (ULONG)-1;
909 /* Allocate file buffer */
910 FileBuffer = RtlAllocateHeap(ProcessHeap,
913 if (FileBuffer == NULL)
915 DPRINT1("RtlAllocateHeap() failed\n");
916 return(STATUS_INSUFFICIENT_RESOURCES);
919 RtlCopyMemory(FileBuffer, Buffer, BufferSize);
921 /* Append string terminator */
922 FileBuffer[BufferSize] = 0;
924 /* Allocate infcache header */
925 Cache = (PINFCACHE)RtlAllocateHeap(ProcessHeap,
930 DPRINT("RtlAllocateHeap() failed\n");
931 RtlFreeHeap(ProcessHeap,
934 return(STATUS_INSUFFICIENT_RESOURCES);
937 /* Initialize inicache header */
941 /* Parse the inf buffer */
942 Status = InfpParseBuffer (Cache,
944 FileBuffer + BufferSize,
946 if (!NT_SUCCESS(Status))
948 RtlFreeHeap(ProcessHeap,
954 /* Free file buffer */
955 RtlFreeHeap(ProcessHeap,
959 *InfHandle = (HINF)Cache;
966 InfOpenFile(PHINF InfHandle,
967 PUNICODE_STRING FileName,
970 OBJECT_ATTRIBUTES ObjectAttributes;
971 FILE_STANDARD_INFORMATION FileInfo;
972 IO_STATUS_BLOCK IoStatusBlock;
977 LARGE_INTEGER FileOffset;
982 *ErrorLine = (ULONG)-1;
984 /* Open the inf file */
985 InitializeObjectAttributes(&ObjectAttributes,
991 Status = NtOpenFile(&FileHandle,
992 GENERIC_READ | SYNCHRONIZE,
996 FILE_NON_DIRECTORY_FILE);
997 if (!NT_SUCCESS(Status))
999 DPRINT("NtOpenFile() failed (Status %lx)\n", Status);
1003 DPRINT("NtOpenFile() successful\n");
1005 /* Query file size */
1006 Status = NtQueryInformationFile(FileHandle,
1009 sizeof(FILE_STANDARD_INFORMATION),
1010 FileStandardInformation);
1011 if (Status == STATUS_PENDING)
1013 DPRINT("NtQueryInformationFile() returns STATUS_PENDING\n");
1016 else if (!NT_SUCCESS(Status))
1018 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
1019 NtClose(FileHandle);
1023 FileLength = FileInfo.EndOfFile.u.LowPart;
1025 DPRINT("File size: %lu\n", FileLength);
1027 /* Allocate file buffer */
1028 FileBuffer = RtlAllocateHeap(ProcessHeap,
1031 if (FileBuffer == NULL)
1033 DPRINT1("RtlAllocateHeap() failed\n");
1034 NtClose(FileHandle);
1035 return(STATUS_INSUFFICIENT_RESOURCES);
1039 FileOffset.QuadPart = 0ULL;
1040 Status = NtReadFile(FileHandle,
1050 if (Status == STATUS_PENDING)
1052 DPRINT("NtReadFile() returns STATUS_PENDING\n");
1054 Status = IoStatusBlock.Status;
1057 /* Append string terminator */
1058 FileBuffer[FileLength] = 0;
1060 NtClose(FileHandle);
1062 if (!NT_SUCCESS(Status))
1064 DPRINT("NtReadFile() failed (Status %lx)\n", Status);
1065 RtlFreeHeap(ProcessHeap,
1071 /* Allocate infcache header */
1072 Cache = (PINFCACHE)RtlAllocateHeap(ProcessHeap,
1077 DPRINT("RtlAllocateHeap() failed\n");
1078 RtlFreeHeap(ProcessHeap,
1081 return(STATUS_INSUFFICIENT_RESOURCES);
1084 /* Initialize inicache header */
1085 RtlZeroMemory(Cache,
1088 /* Parse the inf buffer */
1089 Status = InfpParseBuffer (Cache,
1091 FileBuffer + FileLength,
1093 if (!NT_SUCCESS(Status))
1095 RtlFreeHeap(ProcessHeap,
1101 /* Free file buffer */
1102 RtlFreeHeap(ProcessHeap,
1106 *InfHandle = (HINF)Cache;
1113 InfCloseFile(HINF InfHandle)
1117 Cache = (PINFCACHE)InfHandle;
1124 while (Cache->FirstSection != NULL)
1126 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection);
1128 Cache->LastSection = NULL;
1130 RtlFreeHeap(ProcessHeap,
1137 InfFindFirstLine (HINF InfHandle,
1140 PINFCONTEXT Context)
1143 PINFCACHESECTION CacheSection;
1144 PINFCACHELINE CacheLine;
1146 if (InfHandle == NULL || Section == NULL || Context == NULL)
1148 DPRINT("Invalid parameter\n");
1152 Cache = (PINFCACHE)InfHandle;
1154 /* Iterate through list of sections */
1155 CacheSection = Cache->FirstSection;
1156 while (Section != NULL)
1158 DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1160 /* Are the section names the same? */
1161 if (_wcsicmp(CacheSection->Name, Section) == 0)
1165 CacheLine = InfpCacheFindKeyLine (CacheSection, (PWCHAR)Key);
1169 CacheLine = CacheSection->FirstLine;
1172 if (CacheLine == NULL)
1175 Context->Inf = (PVOID)Cache;
1176 Context->Section = (PVOID)CacheSection;
1177 Context->Line = (PVOID)CacheLine;
1182 /* Get the next section */
1183 CacheSection = CacheSection->Next;
1186 DPRINT("Section not found\n");
1193 InfFindNextLine (PINFCONTEXT ContextIn,
1194 PINFCONTEXT ContextOut)
1196 PINFCACHELINE CacheLine;
1198 if (ContextIn == NULL || ContextOut == NULL)
1201 if (ContextIn->Line == NULL)
1204 CacheLine = (PINFCACHELINE)ContextIn->Line;
1205 if (CacheLine->Next == NULL)
1208 if (ContextIn != ContextOut)
1210 ContextOut->Inf = ContextIn->Inf;
1211 ContextOut->Section = ContextIn->Section;
1213 ContextOut->Line = (PVOID)(CacheLine->Next);
1220 InfFindFirstMatchLine (PINFCONTEXT ContextIn,
1222 PINFCONTEXT ContextOut)
1224 PINFCACHELINE CacheLine;
1226 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1229 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
1232 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
1233 while (CacheLine != NULL)
1235 if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
1238 if (ContextIn != ContextOut)
1240 ContextOut->Inf = ContextIn->Inf;
1241 ContextOut->Section = ContextIn->Section;
1243 ContextOut->Line = (PVOID)CacheLine;
1248 CacheLine = CacheLine->Next;
1256 InfFindNextMatchLine (PINFCONTEXT ContextIn,
1258 PINFCONTEXT ContextOut)
1260 PINFCACHELINE CacheLine;
1262 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
1265 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
1268 CacheLine = (PINFCACHELINE)ContextIn->Line;
1269 while (CacheLine != NULL)
1271 if (CacheLine->Key != NULL && _wcsicmp (CacheLine->Key, Key) == 0)
1274 if (ContextIn != ContextOut)
1276 ContextOut->Inf = ContextIn->Inf;
1277 ContextOut->Section = ContextIn->Section;
1279 ContextOut->Line = (PVOID)CacheLine;
1284 CacheLine = CacheLine->Next;
1292 InfGetLineCount(HINF InfHandle,
1296 PINFCACHESECTION CacheSection;
1298 if (InfHandle == NULL || Section == NULL)
1300 DPRINT("Invalid parameter\n");
1304 Cache = (PINFCACHE)InfHandle;
1306 /* Iterate through list of sections */
1307 CacheSection = Cache->FirstSection;
1308 while (Section != NULL)
1310 DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section);
1312 /* Are the section names the same? */
1313 if (_wcsicmp(CacheSection->Name, Section) == 0)
1315 return CacheSection->LineCount;
1318 /* Get the next section */
1319 CacheSection = CacheSection->Next;
1322 DPRINT("Section not found\n");
1328 /* InfGetLineText */
1332 InfGetFieldCount(PINFCONTEXT Context)
1334 if (Context == NULL || Context->Line == NULL)
1337 return ((PINFCACHELINE)Context->Line)->FieldCount;
1342 InfGetBinaryField (PINFCONTEXT Context,
1344 PUCHAR ReturnBuffer,
1345 ULONG ReturnBufferSize,
1346 PULONG RequiredSize)
1348 PINFCACHELINE CacheLine;
1349 PINFCACHEFIELD CacheField;
1354 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1356 DPRINT("Invalid parameter\n");
1360 if (RequiredSize != NULL)
1363 CacheLine = (PINFCACHELINE)Context->Line;
1365 if (FieldIndex > CacheLine->FieldCount)
1368 CacheField = CacheLine->FirstField;
1369 for (Index = 1; Index < FieldIndex; Index++)
1370 CacheField = CacheField->Next;
1372 Size = CacheLine->FieldCount - FieldIndex + 1;
1374 if (RequiredSize != NULL)
1375 *RequiredSize = Size;
1377 if (ReturnBuffer != NULL)
1379 if (ReturnBufferSize < Size)
1382 /* Copy binary data */
1384 while (CacheField != NULL)
1386 *Ptr = (UCHAR)wcstoul (CacheField->Data, NULL, 16);
1389 CacheField = CacheField->Next;
1398 InfGetIntField (PINFCONTEXT Context,
1402 PINFCACHELINE CacheLine;
1403 PINFCACHEFIELD CacheField;
1407 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
1409 DPRINT("Invalid parameter\n");
1413 CacheLine = (PINFCACHELINE)Context->Line;
1415 if (FieldIndex > CacheLine->FieldCount)
1417 DPRINT("Invalid parameter\n");
1421 if (FieldIndex == 0)
1423 Ptr = CacheLine->Key;
1427 CacheField = CacheLine->FirstField;
1428 for (Index = 1; Index < FieldIndex; Index++)
1429 CacheField = CacheField->Next;
1431 Ptr = CacheField->Data;
1434 *IntegerValue = wcstol (Ptr, NULL, 0);
1441 InfGetMultiSzField (PINFCONTEXT Context,
1444 ULONG ReturnBufferSize,
1445 PULONG RequiredSize)
1447 PINFCACHELINE CacheLine;
1448 PINFCACHEFIELD CacheField;
1449 PINFCACHEFIELD FieldPtr;
1454 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1456 DPRINT("Invalid parameter\n");
1460 if (RequiredSize != NULL)
1463 CacheLine = (PINFCACHELINE)Context->Line;
1465 if (FieldIndex > CacheLine->FieldCount)
1468 CacheField = CacheLine->FirstField;
1469 for (Index = 1; Index < FieldIndex; Index++)
1470 CacheField = CacheField->Next;
1472 /* Calculate the required buffer size */
1473 FieldPtr = CacheField;
1475 while (FieldPtr != NULL)
1477 Size += (wcslen (FieldPtr->Data) + 1);
1478 FieldPtr = FieldPtr->Next;
1482 if (RequiredSize != NULL)
1483 *RequiredSize = Size;
1485 if (ReturnBuffer != NULL)
1487 if (ReturnBufferSize < Size)
1490 /* Copy multi-sz string */
1492 FieldPtr = CacheField;
1493 while (FieldPtr != NULL)
1495 Size = wcslen (FieldPtr->Data) + 1;
1497 wcscpy (Ptr, FieldPtr->Data);
1500 FieldPtr = FieldPtr->Next;
1510 InfGetStringField (PINFCONTEXT Context,
1513 ULONG ReturnBufferSize,
1514 PULONG RequiredSize)
1516 PINFCACHELINE CacheLine;
1517 PINFCACHEFIELD CacheField;
1522 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
1524 DPRINT("Invalid parameter\n");
1528 if (RequiredSize != NULL)
1531 CacheLine = (PINFCACHELINE)Context->Line;
1533 if (FieldIndex > CacheLine->FieldCount)
1536 if (FieldIndex == 0)
1538 Ptr = CacheLine->Key;
1542 CacheField = CacheLine->FirstField;
1543 for (Index = 1; Index < FieldIndex; Index++)
1544 CacheField = CacheField->Next;
1546 Ptr = CacheField->Data;
1549 Size = wcslen (Ptr) + 1;
1551 if (RequiredSize != NULL)
1552 *RequiredSize = Size;
1554 if (ReturnBuffer != NULL)
1556 if (ReturnBufferSize < Size)
1559 wcscpy (ReturnBuffer, Ptr);
1569 InfGetData (PINFCONTEXT Context,
1573 PINFCACHELINE CacheKey;
1575 if (Context == NULL || Context->Line == NULL || Data == NULL)
1577 DPRINT("Invalid parameter\n");
1581 CacheKey = (PINFCACHELINE)Context->Line;
1583 *Key = CacheKey->Key;
1587 if (CacheKey->FirstField == NULL)
1593 *Data = CacheKey->FirstField->Data;
1602 InfGetDataField (PINFCONTEXT Context,
1606 PINFCACHELINE CacheLine;
1607 PINFCACHEFIELD CacheField;
1610 if (Context == NULL || Context->Line == NULL || Data == NULL)
1612 DPRINT("Invalid parameter\n");
1616 CacheLine = (PINFCACHELINE)Context->Line;
1618 if (FieldIndex > CacheLine->FieldCount)
1621 if (FieldIndex == 0)
1623 *Data = CacheLine->Key;
1627 CacheField = CacheLine->FirstField;
1628 for (Index = 1; Index < FieldIndex; Index++)
1629 CacheField = CacheField->Next;
1631 *Data = CacheField->Data;