Home | History | Annotate | Download | only in Common
      1 /*++
      2 
      3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   ParseInf.c
     15 
     16 Abstract:
     17 
     18   This contains some useful functions for parsing INF files.
     19 
     20 --*/
     21 
     22 #include "ParseInf.h"
     23 #include <assert.h>
     24 #include <string.h>
     25 #include <ctype.h>
     26 
     27 CHAR8 *
     28 ReadLine (
     29   IN MEMORY_FILE    *InputFile,
     30   IN OUT CHAR8      *InputBuffer,
     31   IN UINTN          MaxLength
     32   )
     33 /*++
     34 
     35 Routine Description:
     36 
     37   This function reads a line, stripping any comments.
     38   The function reads a string from the input stream argument and stores it in
     39   the input string. ReadLine reads characters from the current file position
     40   to and including the first newline character, to the end of the stream, or
     41   until the number of characters read is equal to MaxLength - 1, whichever
     42   comes first.  The newline character, if read, is replaced with a \0.
     43 
     44 Arguments:
     45 
     46   InputFile     Memory file image.
     47   InputBuffer   Buffer to read into, must be _MAX_PATH size.
     48   MaxLength     The maximum size of the input buffer.
     49 
     50 Returns:
     51 
     52   NULL if error or EOF
     53   InputBuffer otherwise
     54 
     55 --*/
     56 {
     57   CHAR8 *CharPtr;
     58   CHAR8 *EndOfLine;
     59   UINTN CharsToCopy;
     60 
     61   //
     62   // Verify input parameters are not null
     63   //
     64   assert (InputBuffer);
     65   assert (InputFile->FileImage);
     66   assert (InputFile->Eof);
     67   assert (InputFile->CurrentFilePointer);
     68 
     69   //
     70   // Check for end of file condition
     71   //
     72   if (InputFile->CurrentFilePointer >= InputFile->Eof) {
     73     return NULL;
     74   }
     75   //
     76   // Find the next newline char
     77   //
     78   EndOfLine = strchr (InputFile->CurrentFilePointer, '\n');
     79 
     80   //
     81   // Determine the number of characters to copy.
     82   //
     83   if (EndOfLine == 0) {
     84     //
     85     // If no newline found, copy to the end of the file.
     86     //
     87     CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
     88   } else if (EndOfLine >= InputFile->Eof) {
     89     //
     90     // If the newline found was beyond the end of file, copy to the eof.
     91     //
     92     CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
     93   } else {
     94     //
     95     // Newline found in the file.
     96     //
     97     CharsToCopy = EndOfLine - InputFile->CurrentFilePointer;
     98   }
     99   //
    100   // If the end of line is too big for the current buffer, set it to the max
    101   // size of the buffer (leaving room for the \0.
    102   //
    103   if (CharsToCopy > MaxLength - 1) {
    104     CharsToCopy = MaxLength - 1;
    105   }
    106   //
    107   // Copy the line.
    108   //
    109   memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy);
    110 
    111   //
    112   // Add the null termination over the 0x0D
    113   //
    114   InputBuffer[CharsToCopy - 1] = '\0';
    115 
    116   //
    117   // Increment the current file pointer (include the 0x0A)
    118   //
    119   InputFile->CurrentFilePointer += CharsToCopy + 1;
    120 
    121   //
    122   // Strip any comments
    123   //
    124   CharPtr = strstr (InputBuffer, "//");
    125   if (CharPtr != 0) {
    126     CharPtr[0] = 0;
    127   }
    128   //
    129   // Return the string
    130   //
    131   return InputBuffer;
    132 }
    133 
    134 BOOLEAN
    135 FindSection (
    136   IN MEMORY_FILE    *InputFile,
    137   IN CHAR8          *Section
    138   )
    139 /*++
    140 
    141 Routine Description:
    142 
    143   This function parses a file from the beginning to find a section.
    144   The section string may be anywhere within a line.
    145 
    146 Arguments:
    147 
    148   InputFile     Memory file image.
    149   Section       Section to search for
    150 
    151 Returns:
    152 
    153   FALSE if error or EOF
    154   TRUE if section found
    155 
    156 --*/
    157 {
    158   CHAR8 InputBuffer[_MAX_PATH];
    159   CHAR8 *CurrentToken;
    160 
    161   //
    162   // Verify input is not NULL
    163   //
    164   assert (InputFile->FileImage);
    165   assert (InputFile->Eof);
    166   assert (InputFile->CurrentFilePointer);
    167   assert (Section);
    168 
    169   //
    170   // Rewind to beginning of file
    171   //
    172   InputFile->CurrentFilePointer = InputFile->FileImage;
    173 
    174   //
    175   // Read lines until the section is found
    176   //
    177   while (InputFile->CurrentFilePointer < InputFile->Eof) {
    178     //
    179     // Read a line
    180     //
    181     ReadLine (InputFile, InputBuffer, _MAX_PATH);
    182 
    183     //
    184     // Check if the section is found
    185     //
    186     CurrentToken = strstr (InputBuffer, Section);
    187     if (CurrentToken != NULL) {
    188       return TRUE;
    189     }
    190   }
    191 
    192   return FALSE;
    193 }
    194 
    195 EFI_STATUS
    196 FindToken (
    197   IN MEMORY_FILE    *InputFile,
    198   IN CHAR8          *Section,
    199   IN CHAR8          *Token,
    200   IN UINTN          Instance,
    201   OUT CHAR8         *Value
    202   )
    203 /*++
    204 
    205 Routine Description:
    206 
    207   Finds a token value given the section and token to search for.
    208 
    209 Arguments:
    210 
    211   InputFile Memory file image.
    212   Section   The section to search for, a string within [].
    213   Token     The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file.
    214   Instance  The instance of the token to search for.  Zero is the first instance.
    215   Value     The string that holds the value following the =.  Must be _MAX_PATH in size.
    216 
    217 Returns:
    218 
    219   EFI_SUCCESS             Value found.
    220   EFI_ABORTED             Format error detected in INF file.
    221   EFI_INVALID_PARAMETER   Input argument was null.
    222   EFI_LOAD_ERROR          Error reading from the file.
    223   EFI_NOT_FOUND           Section/Token/Value not found.
    224 
    225 --*/
    226 {
    227   CHAR8   InputBuffer[_MAX_PATH];
    228   CHAR8   *CurrentToken;
    229   BOOLEAN ParseError;
    230   BOOLEAN ReadError;
    231   UINTN   Occurrance;
    232 
    233   //
    234   // Check input parameters
    235   //
    236   if (InputFile->FileImage == NULL ||
    237       InputFile->Eof == NULL ||
    238       InputFile->CurrentFilePointer == NULL ||
    239       Section == NULL ||
    240       strlen (Section) == 0 ||
    241       Token == NULL ||
    242       strlen (Token) == 0 ||
    243       Value == NULL
    244       ) {
    245     return EFI_INVALID_PARAMETER;
    246   }
    247   //
    248   // Initialize error codes
    249   //
    250   ParseError  = FALSE;
    251   ReadError   = FALSE;
    252 
    253   //
    254   // Initialize our instance counter for the search token
    255   //
    256   Occurrance = 0;
    257 
    258   if (FindSection (InputFile, Section)) {
    259     //
    260     // Found the desired section, find and read the desired token
    261     //
    262     do {
    263       //
    264       // Read a line from the file
    265       //
    266       if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) {
    267         //
    268         // Error reading from input file
    269         //
    270         ReadError = TRUE;
    271         break;
    272       }
    273       //
    274       // Get the first non-whitespace string
    275       //
    276       CurrentToken = strtok (InputBuffer, " \t\n");
    277       if (CurrentToken == NULL) {
    278         //
    279         // Whitespace line found (or comment) so continue
    280         //
    281         CurrentToken = InputBuffer;
    282         continue;
    283       }
    284       //
    285       // Make sure we have not reached the end of the current section
    286       //
    287       if (CurrentToken[0] == '[') {
    288         break;
    289       }
    290       //
    291       // Compare the current token with the desired token
    292       //
    293       if (strcmp (CurrentToken, Token) == 0) {
    294         //
    295         // Found it
    296         //
    297         //
    298         // Check if it is the correct instance
    299         //
    300         if (Instance == Occurrance) {
    301           //
    302           // Copy the contents following the =
    303           //
    304           CurrentToken = strtok (NULL, "= \t\n");
    305           if (CurrentToken == NULL) {
    306             //
    307             // Nothing found, parsing error
    308             //
    309             ParseError = TRUE;
    310           } else {
    311             //
    312             // Copy the current token to the output value
    313             //
    314             strcpy (Value, CurrentToken);
    315             return EFI_SUCCESS;
    316           }
    317         } else {
    318           //
    319           // Increment the occurrance found
    320           //
    321           Occurrance++;
    322         }
    323       }
    324     } while (
    325       !ParseError &&
    326       !ReadError &&
    327       InputFile->CurrentFilePointer < InputFile->Eof &&
    328       CurrentToken[0] != '[' &&
    329       Occurrance <= Instance
    330     );
    331   }
    332   //
    333   // Distinguish between read errors and INF file format errors.
    334   //
    335   if (ReadError) {
    336     return EFI_LOAD_ERROR;
    337   }
    338 
    339   if (ParseError) {
    340     return EFI_ABORTED;
    341   }
    342 
    343   return EFI_NOT_FOUND;
    344 }
    345 
    346 EFI_STATUS
    347 FindTokenInstanceInSection (
    348   IN MEMORY_FILE    *InputFile,
    349   IN CHAR8          *Section,
    350   IN UINTN          Instance,
    351   OUT CHAR8         *Token,
    352   OUT CHAR8         *Value
    353   )
    354 /*++
    355 
    356 Routine Description:
    357 
    358   Finds the Instance-th token in a section.
    359 
    360 Arguments:
    361 
    362   InputFile Memory file image.
    363   Section   The section to search for, a string within [].
    364   Instance  Specify the Instance-th token to search for, starting from zero
    365   Token     The token name to return. Caller should allocate the buffer.
    366             Must be _MAX_PATH in size.
    367   Value     The token value to return. Caller should allocate the buffer.
    368             Must be _MAX_PATH in size.
    369 
    370 Returns:
    371 
    372   EFI_SUCCESS             Token and Value found.
    373   EFI_ABORTED             Format error detected in INF file.
    374   EFI_INVALID_PARAMETER   Input argument was null.
    375   EFI_LOAD_ERROR          Error reading from the file.
    376   EFI_NOT_FOUND           Section/Token/Value not found.
    377 
    378 --*/
    379 {
    380   CHAR8   InputBuffer[_MAX_PATH];
    381   CHAR8   *CurrentToken;
    382   CHAR8   *CurrentValue;
    383   BOOLEAN ParseError;
    384   BOOLEAN ReadError;
    385   UINTN   InstanceIndex;
    386 
    387   //
    388   // Check input parameters
    389   //
    390   if (InputFile->FileImage == NULL ||
    391       InputFile->Eof == NULL ||
    392       InputFile->CurrentFilePointer == NULL ||
    393       Section == NULL ||
    394       strlen (Section) == 0 ||
    395       Value == NULL
    396       ) {
    397     return EFI_INVALID_PARAMETER;
    398   }
    399   //
    400   // Initialize error codes
    401   //
    402   ParseError  = FALSE;
    403   ReadError   = FALSE;
    404 
    405   //
    406   // Initialize our instance counter for the search token
    407   //
    408   InstanceIndex = 0;
    409 
    410   if (FindSection (InputFile, Section)) {
    411     //
    412     // Found the desired section, find and read the desired token
    413     //
    414     do {
    415       //
    416       // Read a line from the file
    417       //
    418       if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) {
    419         //
    420         // Error reading from input file
    421         //
    422         ReadError = TRUE;
    423         break;
    424       }
    425       //
    426       // Get the first non-whitespace string
    427       //
    428       CurrentToken = strtok (InputBuffer, " \t\n");
    429       if (CurrentToken == NULL) {
    430         //
    431         // Whitespace line found (or comment) so continue
    432         //
    433         CurrentToken = InputBuffer;
    434         continue;
    435       }
    436       //
    437       // Make sure we have not reached the end of the current section
    438       //
    439       if (CurrentToken[0] == '[') {
    440         break;
    441       }
    442       //
    443       // Check if it is the correct instance
    444       //
    445       if (Instance == InstanceIndex) {
    446         //
    447         // Copy the contents following the =
    448         //
    449         CurrentValue = strtok (NULL, "= \t\n");
    450         if (CurrentValue == NULL) {
    451           //
    452           // Nothing found, parsing error
    453           //
    454           ParseError = TRUE;
    455         } else {
    456           //
    457           // Copy the current token to the output value
    458           //
    459           strcpy (Token, CurrentToken);
    460           strcpy (Value, CurrentValue);
    461           return EFI_SUCCESS;
    462         }
    463       } else {
    464         //
    465         // Increment the occurrance found
    466         //
    467         InstanceIndex++;
    468       }
    469     } while (
    470       !ParseError &&
    471       !ReadError &&
    472       InputFile->CurrentFilePointer < InputFile->Eof &&
    473       CurrentToken[0] != '[' &&
    474       InstanceIndex <= Instance
    475     );
    476   }
    477   //
    478   // Distinguish between read errors and INF file format errors.
    479   //
    480   if (ReadError) {
    481     return EFI_LOAD_ERROR;
    482   }
    483 
    484   if (ParseError) {
    485     return EFI_ABORTED;
    486   }
    487 
    488   return EFI_NOT_FOUND;
    489 }
    490 
    491 
    492 EFI_STATUS
    493 StringToGuid (
    494   IN CHAR8      *AsciiGuidBuffer,
    495   OUT EFI_GUID  *GuidBuffer
    496   )
    497 /*++
    498 
    499 Routine Description:
    500 
    501   Converts a string to an EFI_GUID.  The string must be in the
    502   xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
    503 
    504 Arguments:
    505 
    506   AsciiGuidBuffer - pointer to ascii string
    507   GuidBuffer      - pointer to destination Guid
    508 
    509 Returns:
    510 
    511   EFI_ABORTED             Could not convert the string
    512   EFI_SUCCESS             The string was successfully converted
    513   EFI_INVALID_PARAMETER   Input parameter is invalid.
    514 
    515 --*/
    516 {
    517   INT32 Index;
    518   UINTN Data1;
    519   UINTN Data2;
    520   UINTN Data3;
    521   UINTN Data4[8];
    522 
    523   if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) {
    524     return EFI_INVALID_PARAMETER;
    525   }
    526   //
    527   // Scan the guid string into the buffer
    528   //
    529   Index = sscanf (
    530             AsciiGuidBuffer,
    531             "%08x-%04x-%04x-%02x%02x-%02hx%02hx%02hx%02hx%02hx%02hx",
    532             &Data1,
    533             &Data2,
    534             &Data3,
    535             &Data4[0],
    536             &Data4[1],
    537             &Data4[2],
    538             &Data4[3],
    539             &Data4[4],
    540             &Data4[5],
    541             &Data4[6],
    542             &Data4[7]
    543             );
    544 
    545   //
    546   // Verify the correct number of items were scanned.
    547   //
    548   if (Index != 11) {
    549     printf ("ERROR: Malformed GUID \"%s\".\n\n", AsciiGuidBuffer);
    550     return EFI_ABORTED;
    551   }
    552   //
    553   // Copy the data into our GUID.
    554   //
    555   GuidBuffer->Data1     = (UINT32) Data1;
    556   GuidBuffer->Data2     = (UINT16) Data2;
    557   GuidBuffer->Data3     = (UINT16) Data3;
    558   GuidBuffer->Data4[0]  = (UINT8) Data4[0];
    559   GuidBuffer->Data4[1]  = (UINT8) Data4[1];
    560   GuidBuffer->Data4[2]  = (UINT8) Data4[2];
    561   GuidBuffer->Data4[3]  = (UINT8) Data4[3];
    562   GuidBuffer->Data4[4]  = (UINT8) Data4[4];
    563   GuidBuffer->Data4[5]  = (UINT8) Data4[5];
    564   GuidBuffer->Data4[6]  = (UINT8) Data4[6];
    565   GuidBuffer->Data4[7]  = (UINT8) Data4[7];
    566 
    567   return EFI_SUCCESS;
    568 }
    569 
    570 EFI_STATUS
    571 AsciiStringToUint64 (
    572   IN CONST CHAR8  *AsciiString,
    573   IN BOOLEAN      IsHex,
    574   OUT UINT64      *ReturnValue
    575   )
    576 /*++
    577 
    578 Routine Description:
    579 
    580   Converts a null terminated ascii string that represents a number into a
    581   UINT64 value.  A hex number may be preceeded by a 0x, but may not be
    582   succeeded by an h.  A number without 0x or 0X is considered to be base 10
    583   unless the IsHex input is true.
    584 
    585 Arguments:
    586 
    587   AsciiString   The string to convert.
    588   IsHex         Force the string to be treated as a hex number.
    589   ReturnValue   The return value.
    590 
    591 Returns:
    592 
    593   EFI_SUCCESS   Number successfully converted.
    594   EFI_ABORTED   Invalid character encountered.
    595 
    596 --*/
    597 {
    598   UINT8   Index;
    599   UINT64  HexNumber;
    600   CHAR8   CurrentChar;
    601 
    602   //
    603   // Initialize the result
    604   //
    605   HexNumber = 0;
    606 
    607   //
    608   // Add each character to the result
    609   //
    610   if (IsHex || (AsciiString[0] == '0' && (AsciiString[1] == 'x' || AsciiString[1] == 'X'))) {
    611     //
    612     // Verify string is a hex number
    613     //
    614     for (Index = 2; Index < strlen (AsciiString); Index++) {
    615       if (isxdigit (AsciiString[Index]) == 0) {
    616         return EFI_ABORTED;
    617       }
    618     }
    619     //
    620     // Convert the hex string.
    621     //
    622     for (Index = 2; AsciiString[Index] != '\0'; Index++) {
    623       CurrentChar = AsciiString[Index];
    624       HexNumber *= 16;
    625       if (CurrentChar >= '0' && CurrentChar <= '9') {
    626         HexNumber += CurrentChar - '0';
    627       } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {
    628         HexNumber += CurrentChar - 'a' + 10;
    629       } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {
    630         HexNumber += CurrentChar - 'A' + 10;
    631       } else {
    632         //
    633         // Unrecognized character
    634         //
    635         return EFI_ABORTED;
    636       }
    637     }
    638 
    639     *ReturnValue = HexNumber;
    640   } else {
    641     //
    642     // Verify string is a number
    643     //
    644     for (Index = 0; Index < strlen (AsciiString); Index++) {
    645       if (isdigit (AsciiString[Index]) == 0) {
    646         return EFI_ABORTED;
    647       }
    648     }
    649 
    650     *ReturnValue = atol (AsciiString);
    651   }
    652 
    653   return EFI_SUCCESS;
    654 };
    655 
    656 CHAR8 *
    657 ReadLineInStream (
    658   IN FILE       *InputFile,
    659   IN OUT CHAR8  *InputBuffer
    660   )
    661 /*++
    662 
    663 Routine Description:
    664 
    665   This function reads a line, stripping any comments.
    666   // BUGBUG:  This is obsolete once genmake goes away...
    667 
    668 Arguments:
    669 
    670   InputFile     Stream pointer.
    671   InputBuffer   Buffer to read into, must be _MAX_PATH size.
    672 
    673 Returns:
    674 
    675   NULL if error or EOF
    676   InputBuffer otherwise
    677 
    678 --*/
    679 {
    680   CHAR8 *CharPtr;
    681 
    682   //
    683   // Verify input parameters are not null
    684   //
    685   assert (InputFile);
    686   assert (InputBuffer);
    687 
    688   //
    689   // Read a line
    690   //
    691   if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {
    692     return NULL;
    693   }
    694   //
    695   // Strip any comments
    696   //
    697   CharPtr = strstr (InputBuffer, "//");
    698   if (CharPtr != 0) {
    699     CharPtr[0] = 0;
    700   }
    701 
    702   CharPtr = strstr (InputBuffer, "#");
    703   if (CharPtr != 0) {
    704     CharPtr[0] = 0;
    705   }
    706   //
    707   // Return the string
    708   //
    709   return InputBuffer;
    710 }
    711 
    712 BOOLEAN
    713 FindSectionInStream (
    714   IN FILE       *InputFile,
    715   IN CHAR8      *Section
    716   )
    717 /*++
    718 
    719 Routine Description:
    720 
    721   This function parses a stream file from the beginning to find a section.
    722   The section string may be anywhere within a line.
    723   // BUGBUG:  This is obsolete once genmake goes away...
    724 
    725 Arguments:
    726 
    727   InputFile     Stream pointer.
    728   Section       Section to search for
    729 
    730 Returns:
    731 
    732   FALSE if error or EOF
    733   TRUE if section found
    734 
    735 --*/
    736 {
    737   CHAR8 InputBuffer[_MAX_PATH];
    738   CHAR8 *CurrentToken;
    739 
    740   //
    741   // Verify input is not NULL
    742   //
    743   assert (InputFile);
    744   assert (Section);
    745 
    746   //
    747   // Rewind to beginning of file
    748   //
    749   if (fseek (InputFile, 0, SEEK_SET) != 0) {
    750     return FALSE;
    751   }
    752   //
    753   // Read lines until the section is found
    754   //
    755   while (feof (InputFile) == 0) {
    756     //
    757     // Read a line
    758     //
    759     ReadLineInStream (InputFile, InputBuffer);
    760 
    761     //
    762     // Check if the section is found
    763     //
    764     CurrentToken = strstr (InputBuffer, Section);
    765     if (CurrentToken != NULL) {
    766       return TRUE;
    767     }
    768   }
    769 
    770   return FALSE;
    771 }
    772