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