Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeninffile.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS kernel 00003 * Copyright (C) 2002,2003 ReactOS Team 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 /* $Id: inffile.c 53526 2011-09-01 19:01:19Z tkreuzer $ 00020 * COPYRIGHT: See COPYING in the top level directory 00021 * PROJECT: ReactOS text-mode setup 00022 * FILE: subsys/system/usetup/infcache.c 00023 * PURPOSE: INF file parser that caches contents of INF file in memory 00024 * PROGRAMMER: Royce Mitchell III 00025 * Eric Kohl 00026 */ 00027 00028 /* INCLUDES *****************************************************************/ 00029 00030 #include <freeldr.h> 00031 00032 #define CONTROL_Z '\x1a' 00033 #define MAX_SECTION_NAME_LEN 255 00034 #define MAX_FIELD_LEN 511 /* larger fields get silently truncated */ 00035 /* actual string limit is MAX_INF_STRING_LENGTH+1 (plus terminating null) under Windows */ 00036 #define MAX_STRING_LEN (MAX_INF_STRING_LENGTH+1) 00037 00038 00039 typedef struct _INFCACHEFIELD 00040 { 00041 struct _INFCACHEFIELD *Next; 00042 struct _INFCACHEFIELD *Prev; 00043 00044 CHAR Data[1]; 00045 } INFCACHEFIELD, *PINFCACHEFIELD; 00046 00047 00048 typedef struct _INFCACHELINE 00049 { 00050 struct _INFCACHELINE *Next; 00051 struct _INFCACHELINE *Prev; 00052 00053 ULONG FieldCount; 00054 00055 PCHAR Key; 00056 00057 PINFCACHEFIELD FirstField; 00058 PINFCACHEFIELD LastField; 00059 00060 } INFCACHELINE, *PINFCACHELINE; 00061 00062 00063 typedef struct _INFCACHESECTION 00064 { 00065 struct _INFCACHESECTION *Next; 00066 struct _INFCACHESECTION *Prev; 00067 00068 PINFCACHELINE FirstLine; 00069 PINFCACHELINE LastLine; 00070 00071 LONG LineCount; 00072 00073 CHAR Name[1]; 00074 } INFCACHESECTION, *PINFCACHESECTION; 00075 00076 00077 typedef struct _INFCACHE 00078 { 00079 PINFCACHESECTION FirstSection; 00080 PINFCACHESECTION LastSection; 00081 00082 PINFCACHESECTION StringsSection; 00083 } INFCACHE, *PINFCACHE; 00084 00085 00086 /* parser definitions */ 00087 00088 enum parser_state 00089 { 00090 LINE_START, /* at beginning of a line */ 00091 SECTION_NAME, /* parsing a section name */ 00092 KEY_NAME, /* parsing a key name */ 00093 VALUE_NAME, /* parsing a value name */ 00094 EOL_BACKSLASH, /* backslash at end of line */ 00095 QUOTES, /* inside quotes */ 00096 LEADING_SPACES, /* leading spaces */ 00097 TRAILING_SPACES, /* trailing spaces */ 00098 COMMENT, /* inside a comment */ 00099 NB_PARSER_STATES 00100 }; 00101 00102 struct parser 00103 { 00104 const CHAR *start; /* start position of item being parsed */ 00105 const CHAR *end; /* end of buffer */ 00106 PINFCACHE file; /* file being built */ 00107 enum parser_state state; /* current parser state */ 00108 enum parser_state stack[4]; /* state stack */ 00109 int stack_pos; /* current pos in stack */ 00110 00111 PINFCACHESECTION cur_section; /* pointer to the section being parsed*/ 00112 PINFCACHELINE line; /* current line */ 00113 unsigned int line_pos; /* current line position in file */ 00114 unsigned int error; /* error code */ 00115 unsigned int token_len; /* current token len */ 00116 CHAR token[MAX_FIELD_LEN+1]; /* current token */ 00117 }; 00118 00119 typedef const CHAR * (*parser_state_func)( struct parser *parser, const CHAR *pos ); 00120 00121 /* parser state machine functions */ 00122 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos ); 00123 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos ); 00124 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos ); 00125 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos ); 00126 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos ); 00127 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos ); 00128 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos ); 00129 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos ); 00130 static const CHAR *comment_state( struct parser *parser, const CHAR *pos ); 00131 00132 static const parser_state_func parser_funcs[NB_PARSER_STATES] = 00133 { 00134 line_start_state, /* LINE_START */ 00135 section_name_state, /* SECTION_NAME */ 00136 key_name_state, /* KEY_NAME */ 00137 value_name_state, /* VALUE_NAME */ 00138 eol_backslash_state, /* EOL_BACKSLASH */ 00139 quotes_state, /* QUOTES */ 00140 leading_spaces_state, /* LEADING_SPACES */ 00141 trailing_spaces_state, /* TRAILING_SPACES */ 00142 comment_state /* COMMENT */ 00143 }; 00144 00145 00146 /* PRIVATE FUNCTIONS ********************************************************/ 00147 00148 static PINFCACHELINE 00149 InfpCacheFreeLine (PINFCACHELINE Line) 00150 { 00151 PINFCACHELINE Next; 00152 PINFCACHEFIELD Field; 00153 00154 if (Line == NULL) 00155 { 00156 return NULL; 00157 } 00158 00159 Next = Line->Next; 00160 if (Line->Key != NULL) 00161 { 00162 MmHeapFree (Line->Key); 00163 Line->Key = NULL; 00164 } 00165 00166 /* Remove data fields */ 00167 while (Line->FirstField != NULL) 00168 { 00169 Field = Line->FirstField->Next; 00170 MmHeapFree (Line->FirstField); 00171 Line->FirstField = Field; 00172 } 00173 Line->LastField = NULL; 00174 00175 MmHeapFree (Line); 00176 00177 return Next; 00178 } 00179 00180 00181 static PINFCACHESECTION 00182 InfpCacheFreeSection (PINFCACHESECTION Section) 00183 { 00184 PINFCACHESECTION Next; 00185 00186 if (Section == NULL) 00187 { 00188 return NULL; 00189 } 00190 00191 /* Release all keys */ 00192 Next = Section->Next; 00193 while (Section->FirstLine != NULL) 00194 { 00195 Section->FirstLine = InfpCacheFreeLine (Section->FirstLine); 00196 } 00197 Section->LastLine = NULL; 00198 00199 MmHeapFree (Section); 00200 00201 return Next; 00202 } 00203 00204 00205 static PINFCACHESECTION 00206 InfpCacheFindSection (PINFCACHE Cache, 00207 PCSTR Name) 00208 { 00209 PINFCACHESECTION Section = NULL; 00210 00211 if (Cache == NULL || Name == NULL) 00212 { 00213 return NULL; 00214 } 00215 00216 /* iterate through list of sections */ 00217 Section = Cache->FirstSection; 00218 while (Section != NULL) 00219 { 00220 if (_stricmp (Section->Name, Name) == 0) 00221 { 00222 return Section; 00223 } 00224 00225 /* get the next section*/ 00226 Section = Section->Next; 00227 } 00228 00229 return NULL; 00230 } 00231 00232 00233 static PINFCACHESECTION 00234 InfpCacheAddSection (PINFCACHE Cache, 00235 PCHAR Name) 00236 { 00237 PINFCACHESECTION Section = NULL; 00238 ULONG Size; 00239 00240 if (Cache == NULL || Name == NULL) 00241 { 00242 // DPRINT("Invalid parameter\n"); 00243 return NULL; 00244 } 00245 00246 /* Allocate and initialize the new section */ 00247 Size = sizeof(INFCACHESECTION) + strlen (Name); 00248 Section = (PINFCACHESECTION)MmHeapAlloc (Size); 00249 if (Section == NULL) 00250 { 00251 // DPRINT("RtlAllocateHeap() failed\n"); 00252 return NULL; 00253 } 00254 memset (Section, 0, Size); 00255 00256 /* Copy section name */ 00257 strcpy (Section->Name, Name); 00258 00259 /* Append section */ 00260 if (Cache->FirstSection == NULL) 00261 { 00262 Cache->FirstSection = Section; 00263 Cache->LastSection = Section; 00264 } 00265 else 00266 { 00267 Cache->LastSection->Next = Section; 00268 Section->Prev = Cache->LastSection; 00269 Cache->LastSection = Section; 00270 } 00271 00272 return Section; 00273 } 00274 00275 00276 static PINFCACHELINE 00277 InfpCacheAddLine (PINFCACHESECTION Section) 00278 { 00279 PINFCACHELINE Line; 00280 00281 if (Section == NULL) 00282 { 00283 // DPRINT("Invalid parameter\n"); 00284 return NULL; 00285 } 00286 00287 Line = (PINFCACHELINE)MmHeapAlloc (sizeof(INFCACHELINE)); 00288 if (Line == NULL) 00289 { 00290 // DPRINT("RtlAllocateHeap() failed\n"); 00291 return NULL; 00292 } 00293 memset (Line, 0, sizeof(INFCACHELINE)); 00294 00295 /* Append line */ 00296 if (Section->FirstLine == NULL) 00297 { 00298 Section->FirstLine = Line; 00299 Section->LastLine = Line; 00300 } 00301 else 00302 { 00303 Section->LastLine->Next = Line; 00304 Line->Prev = Section->LastLine; 00305 Section->LastLine = Line; 00306 } 00307 Section->LineCount++; 00308 00309 return Line; 00310 } 00311 00312 00313 static PVOID 00314 InfpAddKeyToLine (PINFCACHELINE Line, 00315 PCHAR Key) 00316 { 00317 if (Line == NULL) 00318 return NULL; 00319 00320 if (Line->Key != NULL) 00321 return NULL; 00322 00323 Line->Key = MmHeapAlloc(strlen(Key) + 1); 00324 if (Line->Key == NULL) 00325 return NULL; 00326 00327 strcpy (Line->Key, Key); 00328 00329 return (PVOID)Line->Key; 00330 } 00331 00332 00333 static PVOID 00334 InfpAddFieldToLine (PINFCACHELINE Line, 00335 PCHAR Data) 00336 { 00337 PINFCACHEFIELD Field; 00338 ULONG Size; 00339 00340 Size = sizeof(INFCACHEFIELD) + strlen(Data); 00341 Field = (PINFCACHEFIELD)MmHeapAlloc (Size); 00342 if (Field == NULL) 00343 { 00344 return NULL; 00345 } 00346 memset (Field, 0, Size); 00347 00348 strcpy (Field->Data, Data); 00349 00350 /* Append key */ 00351 if (Line->FirstField == NULL) 00352 { 00353 Line->FirstField = Field; 00354 Line->LastField = Field; 00355 } 00356 else 00357 { 00358 Line->LastField->Next = Field; 00359 Field->Prev = Line->LastField; 00360 Line->LastField = Field; 00361 } 00362 Line->FieldCount++; 00363 00364 return (PVOID)Field; 00365 } 00366 00367 00368 static PINFCACHELINE 00369 InfpCacheFindKeyLine (PINFCACHESECTION Section, 00370 PCSTR Key) 00371 { 00372 PINFCACHELINE Line; 00373 00374 Line = Section->FirstLine; 00375 while (Line != NULL) 00376 { 00377 if (Line->Key != NULL && _stricmp (Line->Key, Key) == 0) 00378 { 00379 return Line; 00380 } 00381 00382 Line = Line->Next; 00383 } 00384 00385 return NULL; 00386 } 00387 00388 00389 /* push the current state on the parser stack */ 00390 __inline static void push_state( struct parser *parser, enum parser_state state ) 00391 { 00392 // assert( parser->stack_pos < sizeof(parser->stack)/sizeof(parser->stack[0]) ); 00393 parser->stack[parser->stack_pos++] = state; 00394 } 00395 00396 00397 /* pop the current state */ 00398 __inline static void pop_state( struct parser *parser ) 00399 { 00400 // assert( parser->stack_pos ); 00401 parser->state = parser->stack[--parser->stack_pos]; 00402 } 00403 00404 00405 /* set the parser state and return the previous one */ 00406 __inline static enum parser_state set_state( struct parser *parser, enum parser_state state ) 00407 { 00408 enum parser_state ret = parser->state; 00409 parser->state = state; 00410 return ret; 00411 } 00412 00413 00414 /* check if the pointer points to an end of file */ 00415 __inline static int is_eof( struct parser *parser, const CHAR *ptr ) 00416 { 00417 return (ptr >= parser->end || *ptr == CONTROL_Z); 00418 } 00419 00420 00421 /* check if the pointer points to an end of line */ 00422 __inline static int is_eol( struct parser *parser, const CHAR *ptr ) 00423 { 00424 return (ptr >= parser->end || 00425 *ptr == CONTROL_Z || 00426 *ptr == '\n' || 00427 (*ptr == '\r' && *(ptr + 1) == '\n')); 00428 } 00429 00430 00431 /* push data from current token start up to pos into the current token */ 00432 static int push_token( struct parser *parser, const CHAR *pos ) 00433 { 00434 SIZE_T len = pos - parser->start; 00435 const CHAR *src = parser->start; 00436 CHAR *dst = parser->token + parser->token_len; 00437 00438 if (len > MAX_FIELD_LEN - parser->token_len) 00439 len = MAX_FIELD_LEN - parser->token_len; 00440 00441 parser->token_len += len; 00442 for ( ; len > 0; len--, dst++, src++) 00443 *dst = *src ? (CHAR)*src : L' '; 00444 *dst = 0; 00445 parser->start = pos; 00446 00447 return 0; 00448 } 00449 00450 00451 00452 /* add a section with the current token as name */ 00453 static PVOID add_section_from_token( struct parser *parser ) 00454 { 00455 PINFCACHESECTION Section; 00456 00457 if (parser->token_len > MAX_SECTION_NAME_LEN) 00458 { 00459 parser->error = FALSE; 00460 return NULL; 00461 } 00462 00463 Section = InfpCacheFindSection (parser->file, 00464 parser->token); 00465 if (Section == NULL) 00466 { 00467 /* need to create a new one */ 00468 Section= InfpCacheAddSection (parser->file, 00469 parser->token); 00470 if (Section == NULL) 00471 { 00472 parser->error = FALSE; 00473 return NULL; 00474 } 00475 } 00476 00477 parser->token_len = 0; 00478 parser->cur_section = Section; 00479 00480 return (PVOID)Section; 00481 } 00482 00483 00484 /* add a field containing the current token to the current line */ 00485 static struct field *add_field_from_token( struct parser *parser, int is_key ) 00486 { 00487 PVOID field; 00488 00489 if (!parser->line) /* need to start a new line */ 00490 { 00491 if (parser->cur_section == NULL) /* got a line before the first section */ 00492 { 00493 parser->error = STATUS_WRONG_INF_STYLE; 00494 return NULL; 00495 } 00496 00497 parser->line = InfpCacheAddLine (parser->cur_section); 00498 if (parser->line == NULL) 00499 goto error; 00500 } 00501 else 00502 { 00503 // assert(!is_key); 00504 } 00505 00506 if (is_key) 00507 { 00508 field = InfpAddKeyToLine(parser->line, parser->token); 00509 } 00510 else 00511 { 00512 field = InfpAddFieldToLine(parser->line, parser->token); 00513 } 00514 00515 if (field != NULL) 00516 { 00517 parser->token_len = 0; 00518 return field; 00519 } 00520 00521 error: 00522 parser->error = FALSE; 00523 return NULL; 00524 } 00525 00526 00527 /* close the current line and prepare for parsing a new one */ 00528 static void close_current_line( struct parser *parser ) 00529 { 00530 parser->line = NULL; 00531 } 00532 00533 00534 00535 /* handler for parser LINE_START state */ 00536 static const CHAR *line_start_state( struct parser *parser, const CHAR *pos ) 00537 { 00538 const CHAR *p; 00539 00540 for (p = pos; !is_eof( parser, p ); p++) 00541 { 00542 switch(*p) 00543 { 00544 case '\r': 00545 continue; 00546 00547 case '\n': 00548 parser->line_pos++; 00549 close_current_line( parser ); 00550 break; 00551 00552 case ';': 00553 push_state( parser, LINE_START ); 00554 set_state( parser, COMMENT ); 00555 return p + 1; 00556 00557 case '[': 00558 parser->start = p + 1; 00559 set_state( parser, SECTION_NAME ); 00560 return p + 1; 00561 00562 default: 00563 if (!isspace(*p)) 00564 { 00565 parser->start = p; 00566 set_state( parser, KEY_NAME ); 00567 return p; 00568 } 00569 break; 00570 } 00571 } 00572 close_current_line( parser ); 00573 return NULL; 00574 } 00575 00576 00577 /* handler for parser SECTION_NAME state */ 00578 static const CHAR *section_name_state( struct parser *parser, const CHAR *pos ) 00579 { 00580 const CHAR *p; 00581 00582 for (p = pos; !is_eol( parser, p ); p++) 00583 { 00584 if (*p == ']') 00585 { 00586 push_token( parser, p ); 00587 if (add_section_from_token( parser ) == NULL) 00588 return NULL; 00589 push_state( parser, LINE_START ); 00590 set_state( parser, COMMENT ); /* ignore everything else on the line */ 00591 return p + 1; 00592 } 00593 } 00594 parser->error = STATUS_BAD_SECTION_NAME_LINE; /* unfinished section name */ 00595 return NULL; 00596 } 00597 00598 00599 /* handler for parser KEY_NAME state */ 00600 static const CHAR *key_name_state( struct parser *parser, const CHAR *pos ) 00601 { 00602 const CHAR *p, *token_end = parser->start; 00603 00604 for (p = pos; !is_eol( parser, p ); p++) 00605 { 00606 if (*p == ',') break; 00607 switch(*p) 00608 { 00609 00610 case '=': 00611 push_token( parser, token_end ); 00612 if (!add_field_from_token( parser, 1 )) return NULL; 00613 parser->start = p + 1; 00614 push_state( parser, VALUE_NAME ); 00615 set_state( parser, LEADING_SPACES ); 00616 return p + 1; 00617 case ';': 00618 push_token( parser, token_end ); 00619 if (!add_field_from_token( parser, 0 )) return NULL; 00620 push_state( parser, LINE_START ); 00621 set_state( parser, COMMENT ); 00622 return p + 1; 00623 case '"': 00624 push_token( parser, token_end ); 00625 parser->start = p + 1; 00626 push_state( parser, KEY_NAME ); 00627 set_state( parser, QUOTES ); 00628 return p + 1; 00629 case '\\': 00630 push_token( parser, token_end ); 00631 parser->start = p; 00632 push_state( parser, KEY_NAME ); 00633 set_state( parser, EOL_BACKSLASH ); 00634 return p; 00635 default: 00636 if (!isspace(*p)) token_end = p + 1; 00637 else 00638 { 00639 push_token( parser, p ); 00640 push_state( parser, KEY_NAME ); 00641 set_state( parser, TRAILING_SPACES ); 00642 return p; 00643 } 00644 break; 00645 } 00646 } 00647 push_token( parser, token_end ); 00648 set_state( parser, VALUE_NAME ); 00649 return p; 00650 } 00651 00652 00653 /* handler for parser VALUE_NAME state */ 00654 static const CHAR *value_name_state( struct parser *parser, const CHAR *pos ) 00655 { 00656 const CHAR *p, *token_end = parser->start; 00657 00658 for (p = pos; !is_eol( parser, p ); p++) 00659 { 00660 switch(*p) 00661 { 00662 case ';': 00663 push_token( parser, token_end ); 00664 if (!add_field_from_token( parser, 0 )) return NULL; 00665 push_state( parser, LINE_START ); 00666 set_state( parser, COMMENT ); 00667 return p + 1; 00668 case ',': 00669 push_token( parser, token_end ); 00670 if (!add_field_from_token( parser, 0 )) return NULL; 00671 parser->start = p + 1; 00672 push_state( parser, VALUE_NAME ); 00673 set_state( parser, LEADING_SPACES ); 00674 return p + 1; 00675 case '"': 00676 push_token( parser, token_end ); 00677 parser->start = p + 1; 00678 push_state( parser, VALUE_NAME ); 00679 set_state( parser, QUOTES ); 00680 return p + 1; 00681 case '\\': 00682 push_token( parser, token_end ); 00683 parser->start = p; 00684 push_state( parser, VALUE_NAME ); 00685 set_state( parser, EOL_BACKSLASH ); 00686 return p; 00687 default: 00688 if (!isspace(*p)) token_end = p + 1; 00689 else 00690 { 00691 push_token( parser, p ); 00692 push_state( parser, VALUE_NAME ); 00693 set_state( parser, TRAILING_SPACES ); 00694 return p; 00695 } 00696 break; 00697 } 00698 } 00699 push_token( parser, token_end ); 00700 if (!add_field_from_token( parser, 0 )) return NULL; 00701 set_state( parser, LINE_START ); 00702 return p; 00703 } 00704 00705 00706 /* handler for parser EOL_BACKSLASH state */ 00707 static const CHAR *eol_backslash_state( struct parser *parser, const CHAR *pos ) 00708 { 00709 const CHAR *p; 00710 00711 for (p = pos; !is_eof( parser, p ); p++) 00712 { 00713 switch(*p) 00714 { 00715 case '\r': 00716 continue; 00717 00718 case '\n': 00719 parser->line_pos++; 00720 parser->start = p + 1; 00721 set_state( parser, LEADING_SPACES ); 00722 return p + 1; 00723 00724 case '\\': 00725 continue; 00726 00727 case ';': 00728 push_state( parser, EOL_BACKSLASH ); 00729 set_state( parser, COMMENT ); 00730 return p + 1; 00731 00732 default: 00733 if (isspace(*p)) 00734 continue; 00735 push_token( parser, p ); 00736 pop_state( parser ); 00737 return p; 00738 } 00739 } 00740 parser->start = p; 00741 pop_state( parser ); 00742 00743 return p; 00744 } 00745 00746 00747 /* handler for parser QUOTES state */ 00748 static const CHAR *quotes_state( struct parser *parser, const CHAR *pos ) 00749 { 00750 const CHAR *p, *token_end = parser->start; 00751 00752 for (p = pos; !is_eol( parser, p ); p++) 00753 { 00754 if (*p == '"') 00755 { 00756 if (p+1 < parser->end && p[1] == '"') /* double quotes */ 00757 { 00758 push_token( parser, p + 1 ); 00759 parser->start = token_end = p + 2; 00760 p++; 00761 } 00762 else /* end of quotes */ 00763 { 00764 push_token( parser, p ); 00765 parser->start = p + 1; 00766 pop_state( parser ); 00767 return p + 1; 00768 } 00769 } 00770 } 00771 push_token( parser, p ); 00772 pop_state( parser ); 00773 return p; 00774 } 00775 00776 00777 /* handler for parser LEADING_SPACES state */ 00778 static const CHAR *leading_spaces_state( struct parser *parser, const CHAR *pos ) 00779 { 00780 const CHAR *p; 00781 00782 for (p = pos; !is_eol( parser, p ); p++) 00783 { 00784 if (*p == '\\') 00785 { 00786 parser->start = p; 00787 set_state( parser, EOL_BACKSLASH ); 00788 return p; 00789 } 00790 if (!isspace(*p)) 00791 break; 00792 } 00793 parser->start = p; 00794 pop_state( parser ); 00795 return p; 00796 } 00797 00798 00799 /* handler for parser TRAILING_SPACES state */ 00800 static const CHAR *trailing_spaces_state( struct parser *parser, const CHAR *pos ) 00801 { 00802 const CHAR *p; 00803 00804 for (p = pos; !is_eol( parser, p ); p++) 00805 { 00806 if (*p == '\\') 00807 { 00808 set_state( parser, EOL_BACKSLASH ); 00809 return p; 00810 } 00811 if (!isspace(*p)) 00812 break; 00813 } 00814 pop_state( parser ); 00815 return p; 00816 } 00817 00818 00819 /* handler for parser COMMENT state */ 00820 static const CHAR *comment_state( struct parser *parser, const CHAR *pos ) 00821 { 00822 const CHAR *p = pos; 00823 00824 while (!is_eol( parser, p )) 00825 p++; 00826 pop_state( parser ); 00827 return p; 00828 } 00829 00830 00831 /* parse a complete buffer */ 00832 static BOOLEAN 00833 InfpParseBuffer (PINFCACHE file, 00834 const CHAR *buffer, 00835 const CHAR *end, 00836 PULONG error_line) 00837 { 00838 struct parser parser; 00839 const CHAR *pos = buffer; 00840 00841 parser.start = buffer; 00842 parser.end = end; 00843 parser.file = file; 00844 parser.line = NULL; 00845 parser.state = LINE_START; 00846 parser.stack_pos = 0; 00847 parser.cur_section = NULL; 00848 parser.line_pos = 1; 00849 parser.error = TRUE; 00850 parser.token_len = 0; 00851 00852 /* parser main loop */ 00853 while (pos) 00854 pos = (parser_funcs[parser.state])(&parser, pos); 00855 00856 if (parser.error) 00857 { 00858 if (error_line) 00859 *error_line = parser.line_pos; 00860 return parser.error; 00861 } 00862 00863 /* find the [strings] section */ 00864 file->StringsSection = InfpCacheFindSection (file, "Strings"); 00865 00866 return TRUE; 00867 } 00868 00869 /* PUBLIC FUNCTIONS *********************************************************/ 00870 00871 BOOLEAN 00872 InfOpenFile(PHINF InfHandle, 00873 PCSTR FileName, 00874 PULONG ErrorLine) 00875 { 00876 FILEINFORMATION Information; 00877 ULONG FileId; 00878 PCHAR FileBuffer; 00879 ULONG FileSize, Count; 00880 PINFCACHE Cache; 00881 BOOLEAN Success; 00882 LONG ret; 00883 00884 *InfHandle = NULL; 00885 *ErrorLine = (ULONG)-1; 00886 00887 // 00888 // Open the .inf file 00889 // 00890 FileId = FsOpenFile(FileName); 00891 if (!FileId) 00892 { 00893 return FALSE; 00894 } 00895 00896 // 00897 // Query file size 00898 // 00899 ret = ArcGetFileInformation(FileId, &Information); 00900 if (ret != ESUCCESS || Information.EndingAddress.HighPart != 0) 00901 { 00902 ArcClose(FileId); 00903 return FALSE; 00904 } 00905 FileSize = Information.EndingAddress.LowPart; 00906 00907 // 00908 // Allocate buffer to cache the file 00909 // 00910 FileBuffer = MmHeapAlloc(FileSize + 1); 00911 if (!FileBuffer) 00912 { 00913 ArcClose(FileId); 00914 return FALSE; 00915 } 00916 00917 // 00918 // Read file into memory 00919 // 00920 ret = ArcRead(FileId, FileBuffer, FileSize, &Count); 00921 if (ret != ESUCCESS || Count != FileSize) 00922 { 00923 ArcClose(FileId); 00924 MmHeapFree(FileBuffer); 00925 return FALSE; 00926 } 00927 00928 // 00929 // We don't need the file anymore. Close it 00930 // 00931 ArcClose(FileId); 00932 00933 // 00934 // Append string terminator 00935 // 00936 FileBuffer[FileSize] = 0; 00937 00938 // 00939 // Allocate infcache header 00940 // 00941 Cache = (PINFCACHE)MmHeapAlloc(sizeof(INFCACHE)); 00942 if (!Cache) 00943 { 00944 MmHeapFree (FileBuffer); 00945 return FALSE; 00946 } 00947 00948 // 00949 // Initialize inicache header 00950 // 00951 RtlZeroMemory(Cache, sizeof(INFCACHE)); 00952 00953 // 00954 // Parse the inf buffer 00955 // 00956 Success = InfpParseBuffer(Cache, 00957 FileBuffer, 00958 FileBuffer + FileSize, 00959 ErrorLine); 00960 if (!Success) 00961 { 00962 MmHeapFree(Cache); 00963 Cache = NULL; 00964 } 00965 00966 // 00967 // Free file buffer, as it has been parsed 00968 // 00969 MmHeapFree(FileBuffer); 00970 00971 // 00972 // Return .inf parsed contents 00973 // 00974 *InfHandle = (HINF)Cache; 00975 00976 return Success; 00977 } 00978 00979 00980 VOID 00981 InfCloseFile(HINF InfHandle) 00982 { 00983 PINFCACHE Cache; 00984 00985 Cache = (PINFCACHE)InfHandle; 00986 00987 if (Cache == NULL) 00988 { 00989 return; 00990 } 00991 00992 while (Cache->FirstSection != NULL) 00993 { 00994 Cache->FirstSection = InfpCacheFreeSection(Cache->FirstSection); 00995 } 00996 Cache->LastSection = NULL; 00997 00998 MmHeapFree(Cache); 00999 } 01000 01001 01002 BOOLEAN 01003 InfFindFirstLine (HINF InfHandle, 01004 PCSTR Section, 01005 PCSTR Key, 01006 PINFCONTEXT Context) 01007 { 01008 PINFCACHE Cache; 01009 PINFCACHESECTION CacheSection; 01010 PINFCACHELINE CacheLine; 01011 01012 if (InfHandle == NULL || Section == NULL || Context == NULL) 01013 { 01014 // DPRINT("Invalid parameter\n"); 01015 return FALSE; 01016 } 01017 01018 Cache = (PINFCACHE)InfHandle; 01019 01020 /* Iterate through list of sections */ 01021 CacheSection = Cache->FirstSection; 01022 while (Section != NULL) 01023 { 01024 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section); 01025 01026 /* Are the section names the same? */ 01027 if (_stricmp(CacheSection->Name, Section) == 0) 01028 { 01029 if (Key != NULL) 01030 { 01031 CacheLine = InfpCacheFindKeyLine (CacheSection, Key); 01032 } 01033 else 01034 { 01035 CacheLine = CacheSection->FirstLine; 01036 } 01037 01038 if (CacheLine == NULL) 01039 return FALSE; 01040 01041 Context->Inf = (PVOID)Cache; 01042 Context->Section = (PVOID)CacheSection; 01043 Context->Line = (PVOID)CacheLine; 01044 01045 return TRUE; 01046 } 01047 01048 /* Get the next section */ 01049 CacheSection = CacheSection->Next; 01050 } 01051 01052 // DPRINT("Section not found\n"); 01053 01054 return FALSE; 01055 } 01056 01057 01058 BOOLEAN 01059 InfFindNextLine (PINFCONTEXT ContextIn, 01060 PINFCONTEXT ContextOut) 01061 { 01062 PINFCACHELINE CacheLine; 01063 01064 if (ContextIn == NULL || ContextOut == NULL) 01065 return FALSE; 01066 01067 if (ContextIn->Line == NULL) 01068 return FALSE; 01069 01070 CacheLine = (PINFCACHELINE)ContextIn->Line; 01071 if (CacheLine->Next == NULL) 01072 return FALSE; 01073 01074 if (ContextIn != ContextOut) 01075 { 01076 ContextOut->Inf = ContextIn->Inf; 01077 ContextOut->Section = ContextIn->Section; 01078 } 01079 ContextOut->Line = (PVOID)(CacheLine->Next); 01080 01081 return TRUE; 01082 } 01083 01084 01085 BOOLEAN 01086 InfFindFirstMatchLine (PINFCONTEXT ContextIn, 01087 PCHAR Key, 01088 PINFCONTEXT ContextOut) 01089 { 01090 PINFCACHELINE CacheLine; 01091 01092 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) 01093 return FALSE; 01094 01095 if (ContextIn->Inf == NULL || ContextIn->Section == NULL) 01096 return FALSE; 01097 01098 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine; 01099 while (CacheLine != NULL) 01100 { 01101 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0) 01102 { 01103 01104 if (ContextIn != ContextOut) 01105 { 01106 ContextOut->Inf = ContextIn->Inf; 01107 ContextOut->Section = ContextIn->Section; 01108 } 01109 ContextOut->Line = (PVOID)CacheLine; 01110 01111 return TRUE; 01112 } 01113 01114 CacheLine = CacheLine->Next; 01115 } 01116 01117 return FALSE; 01118 } 01119 01120 01121 BOOLEAN 01122 InfFindNextMatchLine (PINFCONTEXT ContextIn, 01123 PCHAR Key, 01124 PINFCONTEXT ContextOut) 01125 { 01126 PINFCACHELINE CacheLine; 01127 01128 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0) 01129 return FALSE; 01130 01131 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL) 01132 return FALSE; 01133 01134 CacheLine = (PINFCACHELINE)ContextIn->Line; 01135 while (CacheLine != NULL) 01136 { 01137 if (CacheLine->Key != NULL && _stricmp (CacheLine->Key, Key) == 0) 01138 { 01139 01140 if (ContextIn != ContextOut) 01141 { 01142 ContextOut->Inf = ContextIn->Inf; 01143 ContextOut->Section = ContextIn->Section; 01144 } 01145 ContextOut->Line = (PVOID)CacheLine; 01146 01147 return TRUE; 01148 } 01149 01150 CacheLine = CacheLine->Next; 01151 } 01152 01153 return FALSE; 01154 } 01155 01156 01157 LONG 01158 InfGetLineCount(HINF InfHandle, 01159 PCHAR Section) 01160 { 01161 PINFCACHE Cache; 01162 PINFCACHESECTION CacheSection; 01163 01164 if (InfHandle == NULL || Section == NULL) 01165 { 01166 // DPRINT("Invalid parameter\n"); 01167 return -1; 01168 } 01169 01170 Cache = (PINFCACHE)InfHandle; 01171 01172 /* Iterate through list of sections */ 01173 CacheSection = Cache->FirstSection; 01174 while (Section != NULL) 01175 { 01176 // DPRINT("Comparing '%S' and '%S'\n", CacheSection->Name, Section); 01177 01178 /* Are the section names the same? */ 01179 if (_stricmp(CacheSection->Name, Section) == 0) 01180 { 01181 return CacheSection->LineCount; 01182 } 01183 01184 /* Get the next section */ 01185 CacheSection = CacheSection->Next; 01186 } 01187 01188 // DPRINT("Section not found\n"); 01189 01190 return -1; 01191 } 01192 01193 01194 /* InfGetLineText */ 01195 01196 01197 LONG 01198 InfGetFieldCount(PINFCONTEXT Context) 01199 { 01200 if (Context == NULL || Context->Line == NULL) 01201 return 0; 01202 01203 return ((PINFCACHELINE)Context->Line)->FieldCount; 01204 } 01205 01206 01207 BOOLEAN 01208 InfGetBinaryField (PINFCONTEXT Context, 01209 ULONG FieldIndex, 01210 PUCHAR ReturnBuffer, 01211 ULONG ReturnBufferSize, 01212 PULONG RequiredSize) 01213 { 01214 PINFCACHELINE CacheLine; 01215 PINFCACHEFIELD CacheField; 01216 ULONG Index; 01217 ULONG Size; 01218 PUCHAR Ptr; 01219 01220 if (Context == NULL || Context->Line == NULL || FieldIndex == 0) 01221 { 01222 // DPRINT("Invalid parameter\n"); 01223 return FALSE; 01224 } 01225 01226 if (RequiredSize != NULL) 01227 *RequiredSize = 0; 01228 01229 CacheLine = (PINFCACHELINE)Context->Line; 01230 01231 if (FieldIndex > CacheLine->FieldCount) 01232 return FALSE; 01233 01234 CacheField = CacheLine->FirstField; 01235 for (Index = 1; Index < FieldIndex; Index++) 01236 CacheField = CacheField->Next; 01237 01238 Size = CacheLine->FieldCount - FieldIndex + 1; 01239 01240 if (RequiredSize != NULL) 01241 *RequiredSize = Size; 01242 01243 if (ReturnBuffer != NULL) 01244 { 01245 if (ReturnBufferSize < Size) 01246 return FALSE; 01247 01248 /* Copy binary data */ 01249 Ptr = ReturnBuffer; 01250 while (CacheField != NULL) 01251 { 01252 *Ptr = (UCHAR)atoi(CacheField->Data); //strtoul (CacheField->Data, NULL, 16); 01253 01254 Ptr++; 01255 CacheField = CacheField->Next; 01256 } 01257 } 01258 01259 return TRUE; 01260 } 01261 01262 01263 BOOLEAN 01264 InfGetIntField (PINFCONTEXT Context, 01265 ULONG FieldIndex, 01266 LONG *IntegerValue) 01267 { 01268 PINFCACHELINE CacheLine; 01269 PINFCACHEFIELD CacheField; 01270 ULONG Index; 01271 PCHAR Ptr; 01272 01273 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL) 01274 { 01275 // DPRINT("Invalid parameter\n"); 01276 return FALSE; 01277 } 01278 01279 CacheLine = (PINFCACHELINE)Context->Line; 01280 01281 if (FieldIndex > CacheLine->FieldCount) 01282 { 01283 // DPRINT("Invalid parameter\n"); 01284 return FALSE; 01285 } 01286 01287 if (FieldIndex == 0) 01288 { 01289 Ptr = CacheLine->Key; 01290 } 01291 else 01292 { 01293 CacheField = CacheLine->FirstField; 01294 for (Index = 1; Index < FieldIndex; Index++) 01295 CacheField = CacheField->Next; 01296 01297 Ptr = CacheField->Data; 01298 } 01299 01300 *IntegerValue = atoi (Ptr); //strtol (Ptr, NULL, 0); 01301 01302 return TRUE; 01303 } 01304 01305 01306 BOOLEAN 01307 InfGetMultiSzField (PINFCONTEXT Context, 01308 ULONG FieldIndex, 01309 PCHAR ReturnBuffer, 01310 ULONG ReturnBufferSize, 01311 PULONG RequiredSize) 01312 { 01313 PINFCACHELINE CacheLine; 01314 PINFCACHEFIELD CacheField; 01315 PINFCACHEFIELD FieldPtr; 01316 ULONG Index; 01317 ULONG Size; 01318 PCHAR Ptr; 01319 01320 if (Context == NULL || Context->Line == NULL || FieldIndex == 0) 01321 { 01322 // DPRINT("Invalid parameter\n"); 01323 return FALSE; 01324 } 01325 01326 if (RequiredSize != NULL) 01327 *RequiredSize = 0; 01328 01329 CacheLine = (PINFCACHELINE)Context->Line; 01330 01331 if (FieldIndex > CacheLine->FieldCount) 01332 return FALSE; 01333 01334 CacheField = CacheLine->FirstField; 01335 for (Index = 1; Index < FieldIndex; Index++) 01336 CacheField = CacheField->Next; 01337 01338 /* Calculate the required buffer size */ 01339 FieldPtr = CacheField; 01340 Size = 0; 01341 while (FieldPtr != NULL) 01342 { 01343 Size += (strlen (FieldPtr->Data) + 1); 01344 FieldPtr = FieldPtr->Next; 01345 } 01346 Size++; 01347 01348 if (RequiredSize != NULL) 01349 *RequiredSize = Size; 01350 01351 if (ReturnBuffer != NULL) 01352 { 01353 if (ReturnBufferSize < Size) 01354 return FALSE; 01355 01356 /* Copy multi-sz string */ 01357 Ptr = ReturnBuffer; 01358 FieldPtr = CacheField; 01359 while (FieldPtr != NULL) 01360 { 01361 Size = strlen (FieldPtr->Data) + 1; 01362 01363 strcpy (Ptr, FieldPtr->Data); 01364 01365 Ptr = Ptr + Size; 01366 FieldPtr = FieldPtr->Next; 01367 } 01368 *Ptr = 0; 01369 } 01370 01371 return TRUE; 01372 } 01373 01374 01375 BOOLEAN 01376 InfGetStringField (PINFCONTEXT Context, 01377 ULONG FieldIndex, 01378 PCHAR ReturnBuffer, 01379 ULONG ReturnBufferSize, 01380 PULONG RequiredSize) 01381 { 01382 PINFCACHELINE CacheLine; 01383 PINFCACHEFIELD CacheField; 01384 ULONG Index; 01385 PCHAR Ptr; 01386 ULONG Size; 01387 01388 if (Context == NULL || Context->Line == NULL || FieldIndex == 0) 01389 { 01390 // DPRINT("Invalid parameter\n"); 01391 return FALSE; 01392 } 01393 01394 if (RequiredSize != NULL) 01395 *RequiredSize = 0; 01396 01397 CacheLine = (PINFCACHELINE)Context->Line; 01398 01399 if (FieldIndex > CacheLine->FieldCount) 01400 return FALSE; 01401 01402 if (FieldIndex == 0) 01403 { 01404 Ptr = CacheLine->Key; 01405 } 01406 else 01407 { 01408 CacheField = CacheLine->FirstField; 01409 for (Index = 1; Index < FieldIndex; Index++) 01410 CacheField = CacheField->Next; 01411 01412 Ptr = CacheField->Data; 01413 } 01414 01415 Size = strlen (Ptr) + 1; 01416 01417 if (RequiredSize != NULL) 01418 *RequiredSize = Size; 01419 01420 if (ReturnBuffer != NULL) 01421 { 01422 if (ReturnBufferSize < Size) 01423 return FALSE; 01424 01425 strcpy (ReturnBuffer, Ptr); 01426 } 01427 01428 return TRUE; 01429 } 01430 01431 01432 01433 01434 BOOLEAN 01435 InfGetData (PINFCONTEXT Context, 01436 PCHAR *Key, 01437 PCHAR *Data) 01438 { 01439 PINFCACHELINE CacheKey; 01440 01441 if (Context == NULL || Context->Line == NULL || Data == NULL) 01442 { 01443 // DPRINT("Invalid parameter\n"); 01444 return FALSE; 01445 } 01446 01447 CacheKey = (PINFCACHELINE)Context->Line; 01448 if (Key != NULL) 01449 *Key = CacheKey->Key; 01450 01451 if (Data != NULL) 01452 { 01453 if (CacheKey->FirstField == NULL) 01454 { 01455 *Data = NULL; 01456 } 01457 else 01458 { 01459 *Data = CacheKey->FirstField->Data; 01460 } 01461 } 01462 01463 return TRUE; 01464 } 01465 01466 01467 BOOLEAN 01468 InfGetDataField (PINFCONTEXT Context, 01469 ULONG FieldIndex, 01470 PCSTR *Data) 01471 { 01472 PINFCACHELINE CacheLine; 01473 PINFCACHEFIELD CacheField; 01474 ULONG Index; 01475 01476 if (Context == NULL || Context->Line == NULL || Data == NULL) 01477 { 01478 // DPRINT("Invalid parameter\n"); 01479 return FALSE; 01480 } 01481 01482 CacheLine = (PINFCACHELINE)Context->Line; 01483 01484 if (FieldIndex > CacheLine->FieldCount) 01485 return FALSE; 01486 01487 if (FieldIndex == 0) 01488 { 01489 *Data = CacheLine->Key; 01490 } 01491 else 01492 { 01493 CacheField = CacheLine->FirstField; 01494 for (Index = 1; Index < FieldIndex; Index++) 01495 CacheField = CacheField->Next; 01496 01497 *Data = CacheField->Data; 01498 } 01499 01500 return TRUE; 01501 } 01502 01503 01504 /* EOF */ Generated on Wed May 23 2012 04:16:09 for ReactOS by
1.7.6.1
|