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