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