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.
19 /* $Id: infcache.c,v 1.9 2003/11/14 17:13:33 weiden Exp $
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
)
510 if (!parser
->line
) /* need to start a new line */
512 if (parser
->cur_section
== NULL
) /* got a line before the first section */
514 parser
->error
= STATUS_WRONG_INF_STYLE
;
518 parser
->line
= InfpCacheAddLine (parser
->cur_section
);
519 if (parser
->line
== NULL
)
529 field
= InfpAddKeyToLine(parser
->line
, parser
->token
);
533 field
= InfpAddFieldToLine(parser
->line
, parser
->token
);
538 parser
->token_len
= 0;
543 parser
->error
= STATUS_NOT_ENOUGH_MEMORY
;
548 /* close the current line and prepare for parsing a new one */
549 static void close_current_line( struct parser
*parser
)
556 /* handler for parser LINE_START state */
557 static const CHAR
*line_start_state( struct parser
*parser
, const CHAR
*pos
)
561 for (p
= pos
; !is_eof( parser
, p
); p
++)
570 close_current_line( parser
);
574 push_state( parser
, LINE_START
);
575 set_state( parser
, COMMENT
);
579 parser
->start
= p
+ 1;
580 set_state( parser
, SECTION_NAME
);
587 set_state( parser
, KEY_NAME
);
593 close_current_line( parser
);
598 /* handler for parser SECTION_NAME state */
599 static const CHAR
*section_name_state( struct parser
*parser
, const CHAR
*pos
)
603 for (p
= pos
; !is_eol( parser
, p
); p
++)
607 push_token( parser
, p
);
608 if (add_section_from_token( parser
) == NULL
)
610 push_state( parser
, LINE_START
);
611 set_state( parser
, COMMENT
); /* ignore everything else on the line */
615 parser
->error
= STATUS_BAD_SECTION_NAME_LINE
; /* unfinished section name */
620 /* handler for parser KEY_NAME state */
621 static const CHAR
*key_name_state( struct parser
*parser
, const CHAR
*pos
)
623 const CHAR
*p
, *token_end
= parser
->start
;
625 for (p
= pos
; !is_eol( parser
, p
); p
++)
627 if (*p
== ',') break;
632 push_token( parser
, token_end
);
633 if (!add_field_from_token( parser
, 1 )) return NULL
;
634 parser
->start
= p
+ 1;
635 push_state( parser
, VALUE_NAME
);
636 set_state( parser
, LEADING_SPACES
);
639 push_token( parser
, token_end
);
640 if (!add_field_from_token( parser
, 0 )) return NULL
;
641 push_state( parser
, LINE_START
);
642 set_state( parser
, COMMENT
);
645 push_token( parser
, token_end
);
646 parser
->start
= p
+ 1;
647 push_state( parser
, KEY_NAME
);
648 set_state( parser
, QUOTES
);
651 push_token( parser
, token_end
);
653 push_state( parser
, KEY_NAME
);
654 set_state( parser
, EOL_BACKSLASH
);
657 if (!isspace(*p
)) token_end
= p
+ 1;
660 push_token( parser
, p
);
661 push_state( parser
, KEY_NAME
);
662 set_state( parser
, TRAILING_SPACES
);
668 push_token( parser
, token_end
);
669 set_state( parser
, VALUE_NAME
);
674 /* handler for parser VALUE_NAME state */
675 static const CHAR
*value_name_state( struct parser
*parser
, const CHAR
*pos
)
677 const CHAR
*p
, *token_end
= parser
->start
;
679 for (p
= pos
; !is_eol( parser
, p
); p
++)
684 push_token( parser
, token_end
);
685 if (!add_field_from_token( parser
, 0 )) return NULL
;
686 push_state( parser
, LINE_START
);
687 set_state( parser
, COMMENT
);
690 push_token( parser
, token_end
);
691 if (!add_field_from_token( parser
, 0 )) return NULL
;
692 parser
->start
= p
+ 1;
693 push_state( parser
, VALUE_NAME
);
694 set_state( parser
, LEADING_SPACES
);
697 push_token( parser
, token_end
);
698 parser
->start
= p
+ 1;
699 push_state( parser
, VALUE_NAME
);
700 set_state( parser
, QUOTES
);
703 push_token( parser
, token_end
);
705 push_state( parser
, VALUE_NAME
);
706 set_state( parser
, EOL_BACKSLASH
);
709 if (!isspace(*p
)) token_end
= p
+ 1;
712 push_token( parser
, p
);
713 push_state( parser
, VALUE_NAME
);
714 set_state( parser
, TRAILING_SPACES
);
720 push_token( parser
, token_end
);
721 if (!add_field_from_token( parser
, 0 )) return NULL
;
722 set_state( parser
, LINE_START
);
727 /* handler for parser EOL_BACKSLASH state */
728 static const CHAR
*eol_backslash_state( struct parser
*parser
, const CHAR
*pos
)
732 for (p
= pos
; !is_eof( parser
, p
); p
++)
741 parser
->start
= p
+ 1;
742 set_state( parser
, LEADING_SPACES
);
749 push_state( parser
, EOL_BACKSLASH
);
750 set_state( parser
, COMMENT
);
756 push_token( parser
, p
);
768 /* handler for parser QUOTES state */
769 static const CHAR
*quotes_state( struct parser
*parser
, const CHAR
*pos
)
771 const CHAR
*p
, *token_end
= parser
->start
;
773 for (p
= pos
; !is_eol( parser
, p
); p
++)
777 if (p
+1 < parser
->end
&& p
[1] == '"') /* double quotes */
779 push_token( parser
, p
+ 1 );
780 parser
->start
= token_end
= p
+ 2;
783 else /* end of quotes */
785 push_token( parser
, p
);
786 parser
->start
= p
+ 1;
792 push_token( parser
, p
);
798 /* handler for parser LEADING_SPACES state */
799 static const CHAR
*leading_spaces_state( struct parser
*parser
, const CHAR
*pos
)
803 for (p
= pos
; !is_eol( parser
, p
); p
++)
808 set_state( parser
, EOL_BACKSLASH
);
820 /* handler for parser TRAILING_SPACES state */
821 static const CHAR
*trailing_spaces_state( struct parser
*parser
, const CHAR
*pos
)
825 for (p
= pos
; !is_eol( parser
, p
); p
++)
829 set_state( parser
, EOL_BACKSLASH
);
840 /* handler for parser COMMENT state */
841 static const CHAR
*comment_state( struct parser
*parser
, const CHAR
*pos
)
845 while (!is_eol( parser
, p
))
852 /* parse a complete buffer */
854 InfpParseBuffer (PINFCACHE file
,
859 struct parser parser
;
860 const CHAR
*pos
= buffer
;
862 parser
.start
= buffer
;
866 parser
.state
= LINE_START
;
867 parser
.stack_pos
= 0;
868 parser
.cur_section
= NULL
;
871 parser
.token_len
= 0;
873 /* parser main loop */
875 pos
= (parser_funcs
[parser
.state
])(&parser
, pos
);
880 *error_line
= parser
.line_pos
;
884 /* find the [strings] section */
885 file
->StringsSection
= InfpCacheFindSection (file
,
888 return STATUS_SUCCESS
;
893 /* PUBLIC FUNCTIONS *********************************************************/
896 InfOpenBufferedFile(PHINF InfHandle
,
906 *ErrorLine
= (ULONG
)-1;
908 /* Allocate file buffer */
909 FileBuffer
= RtlAllocateHeap(ProcessHeap
,
912 if (FileBuffer
== NULL
)
914 DPRINT1("RtlAllocateHeap() failed\n");
915 return(STATUS_INSUFFICIENT_RESOURCES
);
918 RtlCopyMemory(FileBuffer
, Buffer
, BufferSize
);
920 /* Append string terminator */
921 FileBuffer
[BufferSize
] = 0;
923 /* Allocate infcache header */
924 Cache
= (PINFCACHE
)RtlAllocateHeap(ProcessHeap
,
929 DPRINT("RtlAllocateHeap() failed\n");
930 RtlFreeHeap(ProcessHeap
,
933 return(STATUS_INSUFFICIENT_RESOURCES
);
936 /* Initialize inicache header */
940 /* Parse the inf buffer */
941 Status
= InfpParseBuffer (Cache
,
943 FileBuffer
+ BufferSize
,
945 if (!NT_SUCCESS(Status
))
947 RtlFreeHeap(ProcessHeap
,
953 /* Free file buffer */
954 RtlFreeHeap(ProcessHeap
,
958 *InfHandle
= (HINF
)Cache
;
965 InfOpenFile(PHINF InfHandle
,
966 PUNICODE_STRING FileName
,
969 OBJECT_ATTRIBUTES ObjectAttributes
;
970 FILE_STANDARD_INFORMATION FileInfo
;
971 IO_STATUS_BLOCK IoStatusBlock
;
976 LARGE_INTEGER FileOffset
;
981 *ErrorLine
= (ULONG
)-1;
983 /* Open the inf file */
984 InitializeObjectAttributes(&ObjectAttributes
,
990 Status
= NtOpenFile(&FileHandle
,
991 GENERIC_READ
| SYNCHRONIZE
,
995 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
996 if (!NT_SUCCESS(Status
))
998 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
1002 DPRINT("NtOpenFile() successful\n");
1004 /* Query file size */
1005 Status
= NtQueryInformationFile(FileHandle
,
1008 sizeof(FILE_STANDARD_INFORMATION
),
1009 FileStandardInformation
);
1010 if (!NT_SUCCESS(Status
))
1012 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
1013 NtClose(FileHandle
);
1017 FileLength
= FileInfo
.EndOfFile
.u
.LowPart
;
1019 DPRINT("File size: %lu\n", FileLength
);
1021 /* Allocate file buffer */
1022 FileBuffer
= RtlAllocateHeap(ProcessHeap
,
1025 if (FileBuffer
== NULL
)
1027 DPRINT1("RtlAllocateHeap() failed\n");
1028 NtClose(FileHandle
);
1029 return(STATUS_INSUFFICIENT_RESOURCES
);
1033 FileOffset
.QuadPart
= 0ULL;
1034 Status
= NtReadFile(FileHandle
,
1044 /* Append string terminator */
1045 FileBuffer
[FileLength
] = 0;
1047 NtClose(FileHandle
);
1049 if (!NT_SUCCESS(Status
))
1051 DPRINT("NtReadFile() failed (Status %lx)\n", Status
);
1052 RtlFreeHeap(ProcessHeap
,
1058 /* Allocate infcache header */
1059 Cache
= (PINFCACHE
)RtlAllocateHeap(ProcessHeap
,
1064 DPRINT("RtlAllocateHeap() failed\n");
1065 RtlFreeHeap(ProcessHeap
,
1068 return(STATUS_INSUFFICIENT_RESOURCES
);
1071 /* Initialize inicache header */
1072 RtlZeroMemory(Cache
,
1075 /* Parse the inf buffer */
1076 Status
= InfpParseBuffer (Cache
,
1078 FileBuffer
+ FileLength
,
1080 if (!NT_SUCCESS(Status
))
1082 RtlFreeHeap(ProcessHeap
,
1088 /* Free file buffer */
1089 RtlFreeHeap(ProcessHeap
,
1093 *InfHandle
= (HINF
)Cache
;
1100 InfCloseFile(HINF InfHandle
)
1104 Cache
= (PINFCACHE
)InfHandle
;
1111 while (Cache
->FirstSection
!= NULL
)
1113 Cache
->FirstSection
= InfpCacheFreeSection(Cache
->FirstSection
);
1115 Cache
->LastSection
= NULL
;
1117 RtlFreeHeap(ProcessHeap
,
1124 InfFindFirstLine (HINF InfHandle
,
1127 PINFCONTEXT Context
)
1130 PINFCACHESECTION CacheSection
;
1131 PINFCACHELINE CacheLine
;
1133 if (InfHandle
== NULL
|| Section
== NULL
|| Context
== NULL
)
1135 DPRINT("Invalid parameter\n");
1139 Cache
= (PINFCACHE
)InfHandle
;
1141 /* Iterate through list of sections */
1142 CacheSection
= Cache
->FirstSection
;
1143 while (CacheSection
!= NULL
)
1145 DPRINT("Comparing '%S' and '%S'\n", CacheSection
->Name
, Section
);
1147 /* Are the section names the same? */
1148 if (_wcsicmp(CacheSection
->Name
, Section
) == 0)
1152 CacheLine
= InfpCacheFindKeyLine (CacheSection
, (PWCHAR
)Key
);
1156 CacheLine
= CacheSection
->FirstLine
;
1159 if (CacheLine
== NULL
)
1162 Context
->Inf
= (PVOID
)Cache
;
1163 Context
->Section
= (PVOID
)CacheSection
;
1164 Context
->Line
= (PVOID
)CacheLine
;
1169 /* Get the next section */
1170 CacheSection
= CacheSection
->Next
;
1173 DPRINT("Section not found\n");
1180 InfFindNextLine (PINFCONTEXT ContextIn
,
1181 PINFCONTEXT ContextOut
)
1183 PINFCACHELINE CacheLine
;
1185 if (ContextIn
== NULL
|| ContextOut
== NULL
)
1188 if (ContextIn
->Line
== NULL
)
1191 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
1192 if (CacheLine
->Next
== NULL
)
1195 if (ContextIn
!= ContextOut
)
1197 ContextOut
->Inf
= ContextIn
->Inf
;
1198 ContextOut
->Section
= ContextIn
->Section
;
1200 ContextOut
->Line
= (PVOID
)(CacheLine
->Next
);
1207 InfFindFirstMatchLine (PINFCONTEXT ContextIn
,
1209 PINFCONTEXT ContextOut
)
1211 PINFCACHELINE CacheLine
;
1213 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
1216 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
)
1219 CacheLine
= ((PINFCACHESECTION
)(ContextIn
->Section
))->FirstLine
;
1220 while (CacheLine
!= NULL
)
1222 if (CacheLine
->Key
!= NULL
&& _wcsicmp (CacheLine
->Key
, Key
) == 0)
1225 if (ContextIn
!= ContextOut
)
1227 ContextOut
->Inf
= ContextIn
->Inf
;
1228 ContextOut
->Section
= ContextIn
->Section
;
1230 ContextOut
->Line
= (PVOID
)CacheLine
;
1235 CacheLine
= CacheLine
->Next
;
1243 InfFindNextMatchLine (PINFCONTEXT ContextIn
,
1245 PINFCONTEXT ContextOut
)
1247 PINFCACHELINE CacheLine
;
1249 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
1252 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
|| ContextIn
->Line
== NULL
)
1255 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
1256 while (CacheLine
!= NULL
)
1258 if (CacheLine
->Key
!= NULL
&& _wcsicmp (CacheLine
->Key
, Key
) == 0)
1261 if (ContextIn
!= ContextOut
)
1263 ContextOut
->Inf
= ContextIn
->Inf
;
1264 ContextOut
->Section
= ContextIn
->Section
;
1266 ContextOut
->Line
= (PVOID
)CacheLine
;
1271 CacheLine
= CacheLine
->Next
;
1279 InfGetLineCount(HINF InfHandle
,
1283 PINFCACHESECTION CacheSection
;
1285 if (InfHandle
== NULL
|| Section
== NULL
)
1287 DPRINT("Invalid parameter\n");
1291 Cache
= (PINFCACHE
)InfHandle
;
1293 /* Iterate through list of sections */
1294 CacheSection
= Cache
->FirstSection
;
1295 while (Section
!= NULL
)
1297 DPRINT("Comparing '%S' and '%S'\n", CacheSection
->Name
, Section
);
1299 /* Are the section names the same? */
1300 if (_wcsicmp(CacheSection
->Name
, Section
) == 0)
1302 return CacheSection
->LineCount
;
1305 /* Get the next section */
1306 CacheSection
= CacheSection
->Next
;
1309 DPRINT("Section not found\n");
1315 /* InfGetLineText */
1319 InfGetFieldCount(PINFCONTEXT Context
)
1321 if (Context
== NULL
|| Context
->Line
== NULL
)
1324 return ((PINFCACHELINE
)Context
->Line
)->FieldCount
;
1329 InfGetBinaryField (PINFCONTEXT Context
,
1331 PUCHAR ReturnBuffer
,
1332 ULONG ReturnBufferSize
,
1333 PULONG RequiredSize
)
1335 PINFCACHELINE CacheLine
;
1336 PINFCACHEFIELD CacheField
;
1341 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
1343 DPRINT("Invalid parameter\n");
1347 if (RequiredSize
!= NULL
)
1350 CacheLine
= (PINFCACHELINE
)Context
->Line
;
1352 if (FieldIndex
> CacheLine
->FieldCount
)
1355 CacheField
= CacheLine
->FirstField
;
1356 for (Index
= 1; Index
< FieldIndex
; Index
++)
1357 CacheField
= CacheField
->Next
;
1359 Size
= CacheLine
->FieldCount
- FieldIndex
+ 1;
1361 if (RequiredSize
!= NULL
)
1362 *RequiredSize
= Size
;
1364 if (ReturnBuffer
!= NULL
)
1366 if (ReturnBufferSize
< Size
)
1369 /* Copy binary data */
1371 while (CacheField
!= NULL
)
1373 *Ptr
= (UCHAR
)wcstoul (CacheField
->Data
, NULL
, 16);
1376 CacheField
= CacheField
->Next
;
1385 InfGetIntField (PINFCONTEXT Context
,
1389 PINFCACHELINE CacheLine
;
1390 PINFCACHEFIELD CacheField
;
1394 if (Context
== NULL
|| Context
->Line
== NULL
|| IntegerValue
== NULL
)
1396 DPRINT("Invalid parameter\n");
1400 CacheLine
= (PINFCACHELINE
)Context
->Line
;
1402 if (FieldIndex
> CacheLine
->FieldCount
)
1404 DPRINT("Invalid parameter\n");
1408 if (FieldIndex
== 0)
1410 Ptr
= CacheLine
->Key
;
1414 CacheField
= CacheLine
->FirstField
;
1415 for (Index
= 1; Index
< FieldIndex
; Index
++)
1416 CacheField
= CacheField
->Next
;
1418 Ptr
= CacheField
->Data
;
1421 *IntegerValue
= wcstol (Ptr
, NULL
, 0);
1428 InfGetMultiSzField (PINFCONTEXT Context
,
1431 ULONG ReturnBufferSize
,
1432 PULONG RequiredSize
)
1434 PINFCACHELINE CacheLine
;
1435 PINFCACHEFIELD CacheField
;
1436 PINFCACHEFIELD FieldPtr
;
1441 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
1443 DPRINT("Invalid parameter\n");
1447 if (RequiredSize
!= NULL
)
1450 CacheLine
= (PINFCACHELINE
)Context
->Line
;
1452 if (FieldIndex
> CacheLine
->FieldCount
)
1455 CacheField
= CacheLine
->FirstField
;
1456 for (Index
= 1; Index
< FieldIndex
; Index
++)
1457 CacheField
= CacheField
->Next
;
1459 /* Calculate the required buffer size */
1460 FieldPtr
= CacheField
;
1462 while (FieldPtr
!= NULL
)
1464 Size
+= (wcslen (FieldPtr
->Data
) + 1);
1465 FieldPtr
= FieldPtr
->Next
;
1469 if (RequiredSize
!= NULL
)
1470 *RequiredSize
= Size
;
1472 if (ReturnBuffer
!= NULL
)
1474 if (ReturnBufferSize
< Size
)
1477 /* Copy multi-sz string */
1479 FieldPtr
= CacheField
;
1480 while (FieldPtr
!= NULL
)
1482 Size
= wcslen (FieldPtr
->Data
) + 1;
1484 wcscpy (Ptr
, FieldPtr
->Data
);
1487 FieldPtr
= FieldPtr
->Next
;
1497 InfGetStringField (PINFCONTEXT Context
,
1500 ULONG ReturnBufferSize
,
1501 PULONG RequiredSize
)
1503 PINFCACHELINE CacheLine
;
1504 PINFCACHEFIELD CacheField
;
1509 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
1511 DPRINT("Invalid parameter\n");
1515 if (RequiredSize
!= NULL
)
1518 CacheLine
= (PINFCACHELINE
)Context
->Line
;
1520 if (FieldIndex
> CacheLine
->FieldCount
)
1523 if (FieldIndex
== 0)
1525 Ptr
= CacheLine
->Key
;
1529 CacheField
= CacheLine
->FirstField
;
1530 for (Index
= 1; Index
< FieldIndex
; Index
++)
1531 CacheField
= CacheField
->Next
;
1533 Ptr
= CacheField
->Data
;
1536 Size
= wcslen (Ptr
) + 1;
1538 if (RequiredSize
!= NULL
)
1539 *RequiredSize
= Size
;
1541 if (ReturnBuffer
!= NULL
)
1543 if (ReturnBufferSize
< Size
)
1546 wcscpy (ReturnBuffer
, Ptr
);
1556 InfGetData (PINFCONTEXT Context
,
1560 PINFCACHELINE CacheKey
;
1562 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
1564 DPRINT("Invalid parameter\n");
1568 CacheKey
= (PINFCACHELINE
)Context
->Line
;
1570 *Key
= CacheKey
->Key
;
1574 if (CacheKey
->FirstField
== NULL
)
1580 *Data
= CacheKey
->FirstField
->Data
;
1589 InfGetDataField (PINFCONTEXT Context
,
1593 PINFCACHELINE CacheLine
;
1594 PINFCACHEFIELD CacheField
;
1597 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
1599 DPRINT("Invalid parameter\n");
1603 CacheLine
= (PINFCACHELINE
)Context
->Line
;
1605 if (FieldIndex
> CacheLine
->FieldCount
)
1608 if (FieldIndex
== 0)
1610 *Data
= CacheLine
->Key
;
1614 CacheField
= CacheLine
->FirstField
;
1615 for (Index
= 1; Index
< FieldIndex
; Index
++)
1616 CacheField
= CacheField
->Next
;
1618 *Data
= CacheField
->Data
;