1/** @file
2  Source file for the component update driver. It parse the update
3  configuration file and pass the information to the update driver
4  so that the driver can perform updates accordingly.
5
6  Copyright (c) 2002 - 2015, Intel Corporation. All rights reserved.<BR>
7
8  This program and the accompanying materials
9  are licensed and made available under the terms and conditions
10  of the BSD License which accompanies this distribution.  The
11  full text of the license may be found at
12  http://opensource.org/licenses/bsd-license.php
13
14  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17**/
18
19#include "UpdateDriver.h"
20
21/**
22  Copy one line data from buffer data to the line buffer.
23
24  @param Buffer          Buffer data.
25  @param BufferSize      Buffer Size.
26  @param LineBuffer      Line buffer to store the found line data.
27  @param LineSize        On input, size of the input line buffer.
28                         On output, size of the actual line buffer.
29
30  @retval EFI_BUFFER_TOO_SMALL  The size of input line buffer is not enough.
31  @retval EFI_SUCCESS           Copy line data into the line buffer.
32
33**/
34EFI_STATUS
35ProfileGetLine (
36  IN      UINT8                         *Buffer,
37  IN      UINTN                         BufferSize,
38  IN OUT  UINT8                         *LineBuffer,
39  IN OUT  UINTN                         *LineSize
40  )
41{
42  UINTN                                 Length;
43  UINT8                                 *PtrBuf;
44  UINTN                                 PtrEnd;
45
46  PtrBuf      = Buffer;
47  PtrEnd      = (UINTN)Buffer + BufferSize;
48
49  //
50  // 0x0D indicates a line break. Otherwise there is no line break
51  //
52  while ((UINTN)PtrBuf < PtrEnd) {
53    if (*PtrBuf == 0x0D) {
54      break;
55    }
56    PtrBuf++;
57  }
58
59  if ((UINTN)PtrBuf >= (PtrEnd - 1)) {
60    //
61    // The buffer ends without any line break
62    // or it is the last character of the buffer
63    //
64    Length    = BufferSize;
65  } else if (*(PtrBuf + 1) == 0x0A) {
66    //
67    // Further check if a 0x0A follows. If yes, count 0xA
68    //
69    Length    = (UINTN) PtrBuf - (UINTN) Buffer + 2;
70  } else {
71    Length    = (UINTN) PtrBuf - (UINTN) Buffer + 1;
72  }
73
74  if (Length > (*LineSize)) {
75    *LineSize = Length;
76    return EFI_BUFFER_TOO_SMALL;
77  }
78
79  SetMem (LineBuffer, *LineSize, 0x0);
80  *LineSize   = Length;
81  CopyMem (LineBuffer, Buffer, Length);
82
83  return EFI_SUCCESS;
84}
85
86/**
87  Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
88
89  @param Buffer          On input,  buffer data to be trimed.
90                         On output, the trimmed buffer.
91  @param BufferSize      On input,  size of original buffer data.
92                         On output, size of the trimmed buffer.
93
94**/
95VOID
96ProfileTrim (
97  IN OUT  UINT8                         *Buffer,
98  IN OUT  UINTN                         *BufferSize
99  )
100{
101  UINTN                                 Length;
102  UINT8                                 *PtrBuf;
103  UINT8                                 *PtrEnd;
104
105  if (*BufferSize == 0) {
106    return;
107  }
108
109  //
110  // Trim the tail first, include CR, LF, TAB, and SPACE.
111  //
112  Length          = *BufferSize;
113  PtrBuf          = (UINT8 *) ((UINTN) Buffer + Length - 1);
114  while (PtrBuf >= Buffer) {
115    if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
116      && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
117      break;
118    }
119    PtrBuf --;
120  }
121
122  //
123  // all spaces, a blank line, return directly;
124  //
125  if (PtrBuf < Buffer) {
126    *BufferSize   = 0;
127    return;
128  }
129
130  Length          = (UINTN)PtrBuf - (UINTN)Buffer + 1;
131  PtrEnd          = PtrBuf;
132  PtrBuf          = Buffer;
133
134  //
135  // Now skip the heading CR, LF, TAB and SPACE
136  //
137  while (PtrBuf <= PtrEnd) {
138    if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
139      && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
140      break;
141    }
142    PtrBuf++;
143  }
144
145  //
146  // If no heading CR, LF, TAB or SPACE, directly return
147  //
148  if (PtrBuf == Buffer) {
149    *BufferSize   = Length;
150    return;
151  }
152
153  *BufferSize     = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;
154
155  //
156  // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
157  // Now move out all these characters.
158  //
159  while (PtrBuf <= PtrEnd) {
160    *Buffer       = *PtrBuf;
161    Buffer++;
162    PtrBuf++;
163  }
164
165  return;
166}
167
168/**
169  Insert new comment item into comment head.
170
171  @param Buffer          Comment buffer to be added.
172  @param BufferSize      Size of comment buffer.
173  @param CommentHead     Comment Item head entry.
174
175  @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
176  @retval EFI_SUCCESS            New comment item is inserted.
177
178**/
179EFI_STATUS
180ProfileGetComments (
181  IN      UINT8                         *Buffer,
182  IN      UINTN                         BufferSize,
183  IN OUT  COMMENT_LINE                  **CommentHead
184  )
185{
186  COMMENT_LINE                          *CommentItem;
187
188  CommentItem = NULL;
189  CommentItem = AllocatePool (sizeof (COMMENT_LINE));
190  if (CommentItem == NULL) {
191    return EFI_OUT_OF_RESOURCES;
192  }
193
194  CommentItem->ptrNext  = *CommentHead;
195  *CommentHead          = CommentItem;
196
197  //
198  // Add a trailing '\0'
199  //
200  CommentItem->ptrComment = AllocatePool (BufferSize + 1);
201  if (CommentItem->ptrComment == NULL) {
202    FreePool (CommentItem);
203    return EFI_OUT_OF_RESOURCES;
204  }
205  CopyMem (CommentItem->ptrComment, Buffer, BufferSize);
206  *(CommentItem->ptrComment + BufferSize) = '\0';
207
208  return EFI_SUCCESS;
209}
210
211/**
212  Add new section item into Section head.
213
214  @param Buffer          Section item data buffer.
215  @param BufferSize      Size of section item.
216  @param SectionHead     Section item head entry.
217
218  @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
219  @retval EFI_SUCCESS            Section item is NULL or Section item is added.
220
221**/
222EFI_STATUS
223ProfileGetSection (
224  IN      UINT8                         *Buffer,
225  IN      UINTN                         BufferSize,
226  IN OUT  SECTION_ITEM                  **SectionHead
227  )
228{
229  EFI_STATUS                            Status;
230  SECTION_ITEM                          *SectionItem;
231  UINTN                                 Length;
232  UINT8                                 *PtrBuf;
233
234  Status      = EFI_SUCCESS;
235  //
236  // The first character of Buffer is '[', now we want for ']'
237  //
238  PtrBuf      = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
239  while (PtrBuf > Buffer) {
240    if (*PtrBuf == ']') {
241      break;
242    }
243    PtrBuf --;
244  }
245  if (PtrBuf <= Buffer) {
246    //
247    // Not found. Omit this line
248    //
249    return Status;
250  }
251
252  //
253  // excluding the heading '[' and tailing ']'
254  //
255  Length      = PtrBuf - Buffer - 1;
256  ProfileTrim (
257    Buffer + 1,
258    &Length
259  );
260
261  //
262  // omit this line if the section name is null
263  //
264  if (Length == 0) {
265    return Status;
266  }
267
268  SectionItem = AllocatePool (sizeof (SECTION_ITEM));
269  if (SectionItem == NULL) {
270    return EFI_OUT_OF_RESOURCES;
271  }
272
273  SectionItem->ptrSection = NULL;
274  SectionItem->SecNameLen = Length;
275  SectionItem->ptrEntry   = NULL;
276  SectionItem->ptrValue   = NULL;
277  SectionItem->ptrNext    = *SectionHead;
278  *SectionHead            = SectionItem;
279
280  //
281  // Add a trailing '\0'
282  //
283  SectionItem->ptrSection = AllocatePool (Length + 1);
284  if (SectionItem->ptrSection == NULL) {
285    return EFI_OUT_OF_RESOURCES;
286  }
287
288  //
289  // excluding the heading '['
290  //
291  CopyMem (SectionItem->ptrSection, Buffer + 1, Length);
292  *(SectionItem->ptrSection + Length) = '\0';
293
294  return EFI_SUCCESS;
295}
296
297/**
298  Add new section entry and entry value into Section head.
299
300  @param Buffer          Section entry data buffer.
301  @param BufferSize      Size of section entry.
302  @param SectionHead     Section item head entry.
303
304  @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
305  @retval EFI_SUCCESS            Section entry is NULL or Section entry is added.
306
307**/
308EFI_STATUS
309ProfileGetEntry (
310  IN      UINT8                         *Buffer,
311  IN      UINTN                         BufferSize,
312  IN OUT  SECTION_ITEM                  **SectionHead
313  )
314{
315  EFI_STATUS                            Status;
316  SECTION_ITEM                          *SectionItem;
317  SECTION_ITEM                          *PtrSection;
318  UINTN                                 Length;
319  UINT8                                 *PtrBuf;
320  UINT8                                 *PtrEnd;
321
322  Status      = EFI_SUCCESS;
323  PtrBuf      = Buffer;
324  PtrEnd      = (UINT8 *) ((UINTN)Buffer + BufferSize - 1);
325
326  //
327  // First search for '='
328  //
329  while (PtrBuf <= PtrEnd) {
330    if (*PtrBuf == '=') {
331      break;
332    }
333    PtrBuf++;
334  }
335  if (PtrBuf > PtrEnd) {
336    //
337    // Not found. Omit this line
338    //
339    return Status;
340  }
341
342  //
343  // excluding the tailing '='
344  //
345  Length      = PtrBuf - Buffer;
346  ProfileTrim (
347    Buffer,
348    &Length
349  );
350
351  //
352  // Omit this line if the entry name is null
353  //
354  if (Length == 0) {
355    return Status;
356  }
357
358  //
359  // Omit this line if no section header has been found before
360  //
361  if (*SectionHead == NULL) {
362    return Status;
363  }
364  PtrSection  = *SectionHead;
365
366  SectionItem = AllocatePool (sizeof (SECTION_ITEM));
367  if (SectionItem == NULL) {
368    return EFI_OUT_OF_RESOURCES;
369  }
370
371  SectionItem->ptrSection = NULL;
372  SectionItem->ptrEntry   = NULL;
373  SectionItem->ptrValue   = NULL;
374  SectionItem->SecNameLen = PtrSection->SecNameLen;
375  SectionItem->ptrNext    = *SectionHead;
376  *SectionHead            = SectionItem;
377
378  //
379  // SectionName, add a trailing '\0'
380  //
381  SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1);
382  if (SectionItem->ptrSection == NULL) {
383    return EFI_OUT_OF_RESOURCES;
384  }
385  CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1);
386
387  //
388  // EntryName, add a trailing '\0'
389  //
390  SectionItem->ptrEntry = AllocatePool (Length + 1);
391  if (SectionItem->ptrEntry == NULL) {
392    return EFI_OUT_OF_RESOURCES;
393  }
394  CopyMem (SectionItem->ptrEntry, Buffer, Length);
395  *(SectionItem->ptrEntry + Length) = '\0';
396
397  //
398  // Next search for '#'
399  //
400  PtrBuf      = PtrBuf + 1;
401  Buffer      = PtrBuf;
402  while (PtrBuf <= PtrEnd) {
403    if (*PtrBuf == '#') {
404      break;
405    }
406    PtrBuf++;
407  }
408  Length      = PtrBuf - Buffer;
409  ProfileTrim (
410    Buffer,
411    &Length
412  );
413
414  if (Length > 0) {
415    //
416    // EntryValue, add a trailing '\0'
417    //
418    SectionItem->ptrValue = AllocatePool (Length + 1);
419    if (SectionItem->ptrValue == NULL) {
420      return EFI_OUT_OF_RESOURCES;
421    }
422    CopyMem (SectionItem->ptrValue, Buffer, Length);
423    *(SectionItem->ptrValue + Length) = '\0';
424  }
425
426  return EFI_SUCCESS;
427}
428
429/**
430  Free all comment entry and section entry.
431
432  @param Section         Section entry list.
433  @param Comment         Comment entry list.
434
435**/
436VOID
437FreeAllList (
438  IN      SECTION_ITEM                  *Section,
439  IN      COMMENT_LINE                  *Comment
440  )
441{
442  SECTION_ITEM                          *PtrSection;
443  COMMENT_LINE                          *PtrComment;
444
445  while (Section != NULL) {
446    PtrSection    = Section;
447    Section       = Section->ptrNext;
448    if (PtrSection->ptrEntry != NULL) {
449      FreePool (PtrSection->ptrEntry);
450    }
451    if (PtrSection->ptrSection != NULL) {
452      FreePool (PtrSection->ptrSection);
453    }
454    if (PtrSection->ptrValue != NULL) {
455      FreePool (PtrSection->ptrValue);
456    }
457    FreePool (PtrSection);
458  }
459
460  while (Comment != NULL) {
461    PtrComment    = Comment;
462    Comment       = Comment->ptrNext;
463    if (PtrComment->ptrComment != NULL) {
464      FreePool (PtrComment->ptrComment);
465    }
466    FreePool (PtrComment);
467  }
468
469  return;
470}
471
472/**
473  Get section entry value.
474
475  @param Section         Section entry list.
476  @param SectionName     Section name.
477  @param EntryName       Section entry name.
478  @param EntryValue      Point to the got entry value.
479
480  @retval EFI_NOT_FOUND  Section is not found.
481  @retval EFI_SUCCESS    Section entry value is got.
482
483**/
484EFI_STATUS
485UpdateGetProfileString (
486  IN      SECTION_ITEM                  *Section,
487  IN      UINT8                         *SectionName,
488  IN      UINT8                         *EntryName,
489  OUT     UINT8                         **EntryValue
490  )
491{
492  *EntryValue   = NULL;
493
494  while (Section != NULL) {
495    if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) {
496      if (Section->ptrEntry != NULL) {
497        if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) {
498          break;
499        }
500      }
501    }
502    Section     = Section->ptrNext;
503  }
504
505  if (Section == NULL) {
506    return EFI_NOT_FOUND;
507  }
508
509  *EntryValue   = (UINT8 *) Section->ptrValue;
510
511  return EFI_SUCCESS;
512}
513
514/**
515  Convert the dec or hex ascii string to value.
516
517  @param Str             ascii string to be converted.
518
519  @return the converted value.
520
521**/
522UINTN
523UpdateAtoi (
524  IN      UINT8                         *Str
525  )
526{
527  UINTN Number;
528
529  Number = 0;
530
531  //
532  // Skip preceeding while spaces
533  //
534  while (*Str != '\0') {
535    if (*Str != 0x20) {
536      break;
537    }
538    Str++;
539  }
540
541  if (*Str == '\0') {
542    return Number;
543  }
544
545  //
546  // Find whether the string is prefixed by 0x.
547  // That is, it should be xtoi or atoi.
548  //
549  if (*Str == '0') {
550    if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) {
551      return AsciiStrHexToUintn ((CONST CHAR8 *) Str);
552    }
553  }
554
555  while (*Str != '\0') {
556    if ((*Str >= '0') && (*Str <= '9')) {
557      Number  = Number * 10 + *Str - '0';
558    } else {
559      break;
560    }
561    Str++;
562  }
563
564  return Number;
565}
566
567/**
568  Converts a decimal value to a Null-terminated ascii string.
569
570  @param  Buffer  Pointer to the output buffer for the produced Null-terminated
571                  ASCII string.
572  @param  Value   The 64-bit sgned value to convert to a string.
573
574  @return The number of ASCII characters in Buffer not including the Null-terminator.
575
576**/
577UINTN
578UpdateValueToString (
579  IN  OUT UINT8                         *Buffer,
580  IN      INT64                         Value
581  )
582{
583  UINT8                                 TempBuffer[30];
584  UINT8                                 *TempStr;
585  UINT8                                 *BufferPtr;
586  UINTN                                 Count;
587  UINT32                                Remainder;
588
589  TempStr           = TempBuffer;
590  BufferPtr         = Buffer;
591  Count             = 0;
592
593  if (Value < 0) {
594    *BufferPtr      = '-';
595    BufferPtr++;
596    Value           = -Value;
597    Count++;
598  }
599
600  do {
601    Value = (INT64) DivU64x32Remainder  ((UINT64)Value, 10, &Remainder);
602    //
603    // The first item of TempStr is not occupied. It's kind of flag
604    //
605    TempStr++;
606    Count++;
607    *TempStr        = (UINT8) ((UINT8)Remainder + '0');
608  } while (Value != 0);
609
610  //
611  // Reverse temp string into Buffer.
612  //
613  while (TempStr != TempBuffer) {
614    *BufferPtr      = *TempStr;
615    BufferPtr++;
616    TempStr --;
617  }
618
619  *BufferPtr = 0;
620
621  return Count;
622}
623
624/**
625  Convert the input value to a ascii string,
626  and concatenates this string to the input string.
627
628  @param Str             Pointer to a Null-terminated ASCII string.
629  @param Number          The unsgned value to convert to a string.
630
631**/
632VOID
633UpdateStrCatNumber (
634  IN OUT  UINT8                         *Str,
635  IN      UINTN                         Number
636  )
637{
638  UINTN                                 Count;
639
640  while (*Str != '\0') {
641    Str++;
642  }
643
644  Count = UpdateValueToString (Str, (INT64)Number);
645
646  *(Str + Count) = '\0';
647
648  return;
649}
650
651/**
652  Convert the input ascii string into GUID value.
653
654  @param Str             Ascii GUID string to be converted.
655  @param Guid            Pointer to the converted GUID value.
656
657  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
658  @retval EFI_NOT_FOUND         The input ascii string is not a valid GUID format string.
659  @retval EFI_SUCCESS           GUID value is got.
660
661**/
662EFI_STATUS
663UpdateStringToGuid (
664  IN      UINT8                         *Str,
665  IN OUT  EFI_GUID                      *Guid
666  )
667{
668  UINT8                                 *PtrBuffer;
669  UINT8                                 *PtrPosition;
670  UINT8                                 *Buffer;
671  UINTN                                 Data;
672  UINTN                                 StrLen;
673  UINTN                                 Index;
674  UINT8                                 Digits[3];
675
676  StrLen          = AsciiStrLen  ((CONST CHAR8 *) Str);
677  Buffer          = AllocateCopyPool (StrLen + 1, Str);
678  if (Buffer == NULL) {
679    return EFI_OUT_OF_RESOURCES;
680  }
681
682  //
683  // Data1
684  //
685  PtrBuffer       = Buffer;
686  PtrPosition     = PtrBuffer;
687  while (*PtrBuffer != '\0') {
688    if (*PtrBuffer == '-') {
689      break;
690    }
691    PtrBuffer++;
692  }
693  if (*PtrBuffer == '\0') {
694    FreePool (Buffer);
695    return EFI_NOT_FOUND;
696  }
697
698  *PtrBuffer      = '\0';
699  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
700  Guid->Data1     = (UINT32)Data;
701
702  //
703  // Data2
704  //
705  PtrBuffer++;
706  PtrPosition     = PtrBuffer;
707  while (*PtrBuffer != '\0') {
708    if (*PtrBuffer == '-') {
709      break;
710    }
711    PtrBuffer++;
712  }
713  if (*PtrBuffer == '\0') {
714    FreePool (Buffer);
715    return EFI_NOT_FOUND;
716  }
717  *PtrBuffer      = '\0';
718  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
719  Guid->Data2     = (UINT16)Data;
720
721  //
722  // Data3
723  //
724  PtrBuffer++;
725  PtrPosition     = PtrBuffer;
726  while (*PtrBuffer != '\0') {
727    if (*PtrBuffer == '-') {
728      break;
729    }
730    PtrBuffer++;
731  }
732  if (*PtrBuffer == '\0') {
733    FreePool (Buffer);
734    return EFI_NOT_FOUND;
735  }
736  *PtrBuffer      = '\0';
737  Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
738  Guid->Data3     = (UINT16)Data;
739
740  //
741  // Data4[0..1]
742  //
743  for ( Index = 0 ; Index < 2 ; Index++) {
744    PtrBuffer++;
745    if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
746      FreePool (Buffer);
747      return EFI_NOT_FOUND;
748    }
749    Digits[0]     = *PtrBuffer;
750    PtrBuffer++;
751    Digits[1]     = *PtrBuffer;
752    Digits[2]     = '\0';
753    Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
754    Guid->Data4[Index] = (UINT8)Data;
755  }
756
757  //
758  // skip the '-'
759  //
760  PtrBuffer++;
761  if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) {
762    return EFI_NOT_FOUND;
763  }
764
765  //
766  // Data4[2..7]
767  //
768  for ( ; Index < 8; Index++) {
769    PtrBuffer++;
770    if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
771      FreePool (Buffer);
772      return EFI_NOT_FOUND;
773    }
774    Digits[0]     = *PtrBuffer;
775    PtrBuffer++;
776    Digits[1]     = *PtrBuffer;
777    Digits[2]     = '\0';
778    Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
779    Guid->Data4[Index] = (UINT8)Data;
780  }
781
782  FreePool (Buffer);
783
784  return EFI_SUCCESS;
785}
786
787/**
788  Pre process config data buffer into Section entry list and Comment entry list.
789
790  @param DataBuffer      Config raw file buffer.
791  @param BufferSize      Size of raw buffer.
792  @param SectionHead     Pointer to the section entry list.
793  @param CommentHead     Pointer to the comment entry list.
794
795  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
796  @retval EFI_SUCCESS           Config data buffer is preprocessed.
797
798**/
799EFI_STATUS
800PreProcessDataFile (
801  IN      UINT8                         *DataBuffer,
802  IN      UINTN                         BufferSize,
803  IN OUT  SECTION_ITEM                  **SectionHead,
804  IN OUT  COMMENT_LINE                  **CommentHead
805  )
806{
807  EFI_STATUS                            Status;
808  CHAR8                                 *Source;
809  CHAR8                                 *CurrentPtr;
810  CHAR8                                 *BufferEnd;
811  CHAR8                                 *PtrLine;
812  UINTN                                 LineLength;
813  UINTN                                 SourceLength;
814  UINTN                                 MaxLineLength;
815
816  *SectionHead          = NULL;
817  *CommentHead          = NULL;
818  BufferEnd             = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize);
819  CurrentPtr            = (CHAR8 *) DataBuffer;
820  MaxLineLength         = MAX_LINE_LENGTH;
821  Status                = EFI_SUCCESS;
822
823  PtrLine = AllocatePool (MaxLineLength);
824  if (PtrLine == NULL) {
825    return EFI_OUT_OF_RESOURCES;
826  }
827
828  while (CurrentPtr < BufferEnd) {
829    Source              = CurrentPtr;
830    SourceLength        = (UINTN)BufferEnd - (UINTN)CurrentPtr;
831    LineLength          = MaxLineLength;
832    //
833    // With the assumption that line length is less than 512
834    // characters. Otherwise BUFFER_TOO_SMALL will be returned.
835    //
836    Status              = ProfileGetLine (
837                            (UINT8 *) Source,
838                            SourceLength,
839                            (UINT8 *) PtrLine,
840                            &LineLength
841                            );
842    if (EFI_ERROR (Status)) {
843      if (Status == EFI_BUFFER_TOO_SMALL) {
844        //
845        // If buffer too small, re-allocate the buffer according
846        // to the returned LineLength and try again.
847        //
848        FreePool (PtrLine);
849        PtrLine         = NULL;
850        PtrLine = AllocatePool (LineLength);
851        if (PtrLine == NULL) {
852          Status        = EFI_OUT_OF_RESOURCES;
853          break;
854        }
855        SourceLength    = LineLength;
856        Status          = ProfileGetLine (
857                            (UINT8 *) Source,
858                            SourceLength,
859                            (UINT8 *) PtrLine,
860                            &LineLength
861                            );
862        if (EFI_ERROR (Status)) {
863          break;
864        }
865        MaxLineLength   = LineLength;
866      } else {
867        break;
868      }
869    }
870    CurrentPtr          = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength);
871
872    //
873    // Line got. Trim the line before processing it.
874    //
875    ProfileTrim (
876      (UINT8 *) PtrLine,
877      &LineLength
878   );
879
880    //
881    // Blank line
882    //
883    if (LineLength == 0) {
884      continue;
885    }
886
887    if (PtrLine[0] == '#') {
888      Status            = ProfileGetComments (
889                            (UINT8 *) PtrLine,
890                            LineLength,
891                            CommentHead
892                            );
893    } else if (PtrLine[0] == '[') {
894      Status            = ProfileGetSection (
895                            (UINT8 *) PtrLine,
896                            LineLength,
897                            SectionHead
898                            );
899    } else {
900      Status            = ProfileGetEntry (
901                            (UINT8 *) PtrLine,
902                            LineLength,
903                            SectionHead
904                            );
905    }
906
907    if (EFI_ERROR (Status)) {
908      break;
909    }
910  }
911
912  //
913  // Free buffer
914  //
915  FreePool (PtrLine);
916
917  return Status;
918}
919
920/**
921  Parse Config data file to get the updated data array.
922
923  @param DataBuffer      Config raw file buffer.
924  @param BufferSize      Size of raw buffer.
925  @param NumOfUpdates    Pointer to the number of update data.
926  @param UpdateArray     Pointer to the config of update data.
927
928  @retval EFI_NOT_FOUND         No config data is found.
929  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
930  @retval EFI_SUCCESS           Parse the config file successfully.
931
932**/
933EFI_STATUS
934ParseUpdateDataFile (
935  IN      UINT8                         *DataBuffer,
936  IN      UINTN                         BufferSize,
937  IN OUT  UINTN                         *NumOfUpdates,
938  IN OUT  UPDATE_CONFIG_DATA            **UpdateArray
939  )
940{
941  EFI_STATUS                            Status;
942  CHAR8                                 *Value;
943  CHAR8                                 *SectionName;
944  CHAR8                                 Entry[MAX_LINE_LENGTH];
945  SECTION_ITEM                          *SectionHead;
946  COMMENT_LINE                          *CommentHead;
947  UINTN                                 Num;
948  UINTN                                 Index;
949  EFI_GUID                              FileGuid;
950
951  SectionHead           = NULL;
952  CommentHead           = NULL;
953
954  //
955  // First process the data buffer and get all sections and entries
956  //
957  Status                = PreProcessDataFile (
958                            DataBuffer,
959                            BufferSize,
960                            &SectionHead,
961                            &CommentHead
962                            );
963  if (EFI_ERROR (Status)) {
964    FreeAllList (SectionHead, CommentHead);
965    return Status;
966  }
967
968  //
969  // Now get NumOfUpdate
970  //
971  Value                 = NULL;
972  Status                = UpdateGetProfileString (
973                            SectionHead,
974                            (UINT8 *) "Head",
975                            (UINT8 *) "NumOfUpdate",
976                            (UINT8 **) &Value
977                            );
978  if (Value == NULL) {
979    FreeAllList (SectionHead, CommentHead);
980    return EFI_NOT_FOUND;
981  }
982  Num                   = UpdateAtoi((UINT8 *) Value);
983  if (Num <= 0) {
984    FreeAllList (SectionHead, CommentHead);
985    return EFI_NOT_FOUND;
986  }
987
988  *NumOfUpdates         = Num;
989  *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num));
990  if (*UpdateArray == NULL) {
991    FreeAllList (SectionHead, CommentHead);
992    return EFI_OUT_OF_RESOURCES;
993  }
994
995  for ( Index = 0 ; Index < *NumOfUpdates ; Index++) {
996    //
997    // Get the section name of each update
998    //
999    AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update");
1000    UpdateStrCatNumber ((UINT8 *) Entry, Index);
1001    Value               = NULL;
1002    Status              = UpdateGetProfileString (
1003                            SectionHead,
1004                            (UINT8 *) "Head",
1005                            (UINT8 *) Entry,
1006                            (UINT8 **) &Value
1007                            );
1008    if (Value == NULL) {
1009      FreeAllList (SectionHead, CommentHead);
1010      return EFI_NOT_FOUND;
1011    }
1012
1013    //
1014    // The section name of this update has been found.
1015    // Now looks for all the config data of this update
1016    //
1017    SectionName         = Value;
1018
1019    //
1020    // UpdateType
1021    //
1022    Value               = NULL;
1023    Status              = UpdateGetProfileString (
1024                            SectionHead,
1025                            (UINT8 *) SectionName,
1026                            (UINT8 *) "UpdateType",
1027                            (UINT8 **) &Value
1028                            );
1029    if (Value == NULL) {
1030      FreeAllList (SectionHead, CommentHead);
1031      return EFI_NOT_FOUND;
1032    }
1033
1034    Num                 = UpdateAtoi((UINT8 *) Value);
1035    if (( Num >= (UINTN) UpdateOperationMaximum)) {
1036      FreeAllList (SectionHead, CommentHead);
1037      return Status;
1038    }
1039    (*UpdateArray)[Index].Index       = Index;
1040    (*UpdateArray)[Index].UpdateType  = (UPDATE_OPERATION_TYPE) Num;
1041
1042    //
1043    // FvBaseAddress
1044    //
1045    Value               = NULL;
1046    Status              = UpdateGetProfileString (
1047                            SectionHead,
1048                            (UINT8 *) SectionName,
1049                            (UINT8 *) "FvBaseAddress",
1050                            (UINT8 **) &Value
1051                            );
1052    if (Value == NULL) {
1053      FreeAllList (SectionHead, CommentHead);
1054      return EFI_NOT_FOUND;
1055    }
1056
1057    Num                 = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
1058    (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num;
1059
1060    //
1061    // FileBuid
1062    //
1063    Value               = NULL;
1064    Status              = UpdateGetProfileString (
1065                            SectionHead,
1066                            (UINT8 *) SectionName,
1067                            (UINT8 *) "FileGuid",
1068                            (UINT8 **) &Value
1069                            );
1070    if (Value == NULL) {
1071      FreeAllList (SectionHead, CommentHead);
1072      return EFI_NOT_FOUND;
1073    }
1074
1075    Status              = UpdateStringToGuid ((UINT8 *) Value, &FileGuid);
1076    if (EFI_ERROR (Status)) {
1077      FreeAllList (SectionHead, CommentHead);
1078      return Status;
1079    }
1080    CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID));
1081
1082    //
1083    // FaultTolerant
1084    // Default value is FALSE
1085    //
1086    Value               = NULL;
1087    (*UpdateArray)[Index].FaultTolerant = FALSE;
1088    Status              = UpdateGetProfileString (
1089                            SectionHead,
1090                            (UINT8 *) SectionName,
1091                            (UINT8 *) "FaultTolerant",
1092                            (UINT8 **) &Value
1093                           );
1094    if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1095      FreeAllList (SectionHead, CommentHead);
1096      return Status;
1097    } else if (Value != NULL) {
1098      if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) {
1099        (*UpdateArray)[Index].FaultTolerant = TRUE;
1100      } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) {
1101        (*UpdateArray)[Index].FaultTolerant = FALSE;
1102      }
1103    }
1104
1105    if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) {
1106      //
1107      // Length
1108      //
1109      Value             = NULL;
1110      Status            = UpdateGetProfileString (
1111                            SectionHead,
1112                            (UINT8 *) SectionName,
1113                            (UINT8 *) "Length",
1114                            (UINT8 **) &Value
1115                            );
1116      if (Value == NULL) {
1117        FreeAllList (SectionHead, CommentHead);
1118        return EFI_NOT_FOUND;
1119      }
1120
1121      Num               = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
1122      (*UpdateArray)[Index].Length = (UINTN) Num;
1123    }
1124  }
1125
1126  //
1127  // Now all configuration data got. Free those temporary buffers
1128  //
1129  FreeAllList (SectionHead, CommentHead);
1130
1131  return EFI_SUCCESS;
1132}
1133
1134