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