]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Tools/Source/Common/ParseInf.c
Sync all bug fixes between EDK1.04 and EDK1.06 into EdkCompatibilityPkg.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / Common / ParseInf.c
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 }