ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

inffile.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.