Signed-off-by: jljusten Reviewed-by: rsun3 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12257 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1135 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1135 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Source file for the component update driver. It parse the update
 | |
|   configuration file and pass the information to the update driver
 | |
|   so that the driver can perform updates accordingly.
 | |
| 
 | |
|   Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions
 | |
|   of the BSD License which accompanies this distribution.  The
 | |
|   full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "UpdateDriver.h"
 | |
| 
 | |
| /**
 | |
|   Copy one line data from buffer data to the line buffer.
 | |
| 
 | |
|   @param Buffer          Buffer data.
 | |
|   @param BufferSize      Buffer Size.
 | |
|   @param LineBuffer      Line buffer to store the found line data.
 | |
|   @param LineSize        On input, size of the input line buffer.
 | |
|                          On output, size of the actual line buffer.
 | |
| 
 | |
|   @retval EFI_BUFFER_TOO_SMALL  The size of input line buffer is not enough.
 | |
|   @retval EFI_SUCCESS           Copy line data into the line buffer.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ProfileGetLine (
 | |
|   IN      UINT8                         *Buffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  UINT8                         *LineBuffer,
 | |
|   IN OUT  UINTN                         *LineSize
 | |
|   )
 | |
| {
 | |
|   UINTN                                 Length;
 | |
|   UINT8                                 *PtrBuf;
 | |
|   UINTN                                 PtrEnd;
 | |
| 
 | |
|   PtrBuf      = Buffer;
 | |
|   PtrEnd      = (UINTN)Buffer + BufferSize;
 | |
| 
 | |
|   //
 | |
|   // 0x0D indicates a line break. Otherwise there is no line break
 | |
|   //
 | |
|   while ((UINTN)PtrBuf < PtrEnd) {
 | |
|     if (*PtrBuf == 0x0D) {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf++;
 | |
|   }
 | |
| 
 | |
|   if ((UINTN)PtrBuf >= (PtrEnd - 1)) {
 | |
|     //
 | |
|     // The buffer ends without any line break
 | |
|     // or it is the last character of the buffer
 | |
|     //
 | |
|     Length    = BufferSize;
 | |
|   } else if (*(PtrBuf + 1) == 0x0A) {
 | |
|     //
 | |
|     // Further check if a 0x0A follows. If yes, count 0xA
 | |
|     //
 | |
|     Length    = (UINTN) PtrBuf - (UINTN) Buffer + 2;
 | |
|   } else {
 | |
|     Length    = (UINTN) PtrBuf - (UINTN) Buffer + 1;
 | |
|   }
 | |
| 
 | |
|   if (Length > (*LineSize)) {
 | |
|     *LineSize = Length;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| 
 | |
|   SetMem (LineBuffer, *LineSize, 0x0);
 | |
|   *LineSize   = Length;
 | |
|   CopyMem (LineBuffer, Buffer, Length);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
 | |
| 
 | |
|   @param Buffer          On input,  buffer data to be trimed.
 | |
|                          On output, the trimmed buffer.
 | |
|   @param BufferSize      On input,  size of original buffer data.
 | |
|                          On output, size of the trimmed buffer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ProfileTrim (
 | |
|   IN OUT  UINT8                         *Buffer,
 | |
|   IN OUT  UINTN                         *BufferSize
 | |
|   )
 | |
| {
 | |
|   UINTN                                 Length;
 | |
|   UINT8                                 *PtrBuf;
 | |
|   UINT8                                 *PtrEnd;
 | |
| 
 | |
|   if (*BufferSize == 0) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Trim the tail first, include CR, LF, TAB, and SPACE.
 | |
|   //
 | |
|   Length          = *BufferSize;
 | |
|   PtrBuf          = (UINT8 *) ((UINTN) Buffer + Length - 1);
 | |
|   while (PtrBuf >= Buffer) {
 | |
|     if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
 | |
|       && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf --;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // all spaces, a blank line, return directly;
 | |
|   //
 | |
|   if (PtrBuf < Buffer) {
 | |
|     *BufferSize   = 0;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Length          = (UINTN)PtrBuf - (UINTN)Buffer + 1;
 | |
|   PtrEnd          = PtrBuf;
 | |
|   PtrBuf          = Buffer;
 | |
| 
 | |
|   //
 | |
|   // Now skip the heading CR, LF, TAB and SPACE
 | |
|   //
 | |
|   while (PtrBuf <= PtrEnd) {
 | |
|     if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
 | |
|       && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf++;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If no heading CR, LF, TAB or SPACE, directly return
 | |
|   //
 | |
|   if (PtrBuf == Buffer) {
 | |
|     *BufferSize   = Length;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   *BufferSize     = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;
 | |
| 
 | |
|   //
 | |
|   // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
 | |
|   // Now move out all these characters.
 | |
|   //
 | |
|   while (PtrBuf <= PtrEnd) {
 | |
|     *Buffer       = *PtrBuf;
 | |
|     Buffer++;
 | |
|     PtrBuf++;
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert new comment item into comment head.
 | |
| 
 | |
|   @param Buffer          Comment buffer to be added.
 | |
|   @param BufferSize      Size of comment buffer.
 | |
|   @param CommentHead     Comment Item head entry.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
 | |
|   @retval EFI_SUCCESS            New comment item is inserted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ProfileGetComments (
 | |
|   IN      UINT8                         *Buffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  COMMENT_LINE                  **CommentHead
 | |
|   )
 | |
| {
 | |
|   COMMENT_LINE                          *CommentItem;
 | |
| 
 | |
|   CommentItem = NULL;
 | |
|   CommentItem = AllocatePool (sizeof (COMMENT_LINE));
 | |
|   if (CommentItem == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CommentItem->ptrNext  = *CommentHead;
 | |
|   *CommentHead          = CommentItem;
 | |
| 
 | |
|   //
 | |
|   // Add a trailing '\0'
 | |
|   //
 | |
|   CommentItem->ptrComment = AllocatePool (BufferSize + 1);
 | |
|   if (CommentItem->ptrComment == NULL) {
 | |
|     FreePool (CommentItem);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   CopyMem (CommentItem->ptrComment, Buffer, BufferSize);
 | |
|   *(CommentItem->ptrComment + BufferSize) = '\0';
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add new section item into Section head.
 | |
| 
 | |
|   @param Buffer          Section item data buffer.
 | |
|   @param BufferSize      Size of section item.
 | |
|   @param SectionHead     Section item head entry.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
 | |
|   @retval EFI_SUCCESS            Section item is NULL or Section item is added.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ProfileGetSection (
 | |
|   IN      UINT8                         *Buffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  SECTION_ITEM                  **SectionHead
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   SECTION_ITEM                          *SectionItem;
 | |
|   UINTN                                 Length;
 | |
|   UINT8                                 *PtrBuf;
 | |
| 
 | |
|   Status      = EFI_SUCCESS;
 | |
|   //
 | |
|   // The first character of Buffer is '[', now we want for ']'
 | |
|   //
 | |
|   PtrBuf      = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
 | |
|   while (PtrBuf > Buffer) {
 | |
|     if (*PtrBuf == ']') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf --;
 | |
|   }
 | |
|   if (PtrBuf <= Buffer) {
 | |
|     //
 | |
|     // Not found. Omit this line
 | |
|     //
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // excluding the heading '[' and tailing ']'
 | |
|   //
 | |
|   Length      = PtrBuf - Buffer - 1;
 | |
|   ProfileTrim (
 | |
|     Buffer + 1,
 | |
|     &Length
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // omit this line if the section name is null
 | |
|   //
 | |
|   if (Length == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   SectionItem = AllocatePool (sizeof (SECTION_ITEM));
 | |
|   if (SectionItem == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   SectionItem->ptrSection = NULL;
 | |
|   SectionItem->SecNameLen = Length;
 | |
|   SectionItem->ptrEntry   = NULL;
 | |
|   SectionItem->ptrValue   = NULL;
 | |
|   SectionItem->ptrNext    = *SectionHead;
 | |
|   *SectionHead            = SectionItem;
 | |
| 
 | |
|   //
 | |
|   // Add a trailing '\0'
 | |
|   //
 | |
|   SectionItem->ptrSection = AllocatePool (Length + 1);
 | |
|   if (SectionItem->ptrSection == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // excluding the heading '['
 | |
|   //
 | |
|   CopyMem (SectionItem->ptrSection, Buffer + 1, Length);
 | |
|   *(SectionItem->ptrSection + Length) = '\0';
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add new section entry and entry value into Section head.
 | |
| 
 | |
|   @param Buffer          Section entry data buffer.
 | |
|   @param BufferSize      Size of section entry.
 | |
|   @param SectionHead     Section item head entry.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough memory is allocated.
 | |
|   @retval EFI_SUCCESS            Section entry is NULL or Section entry is added.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ProfileGetEntry (
 | |
|   IN      UINT8                         *Buffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  SECTION_ITEM                  **SectionHead
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   SECTION_ITEM                          *SectionItem;
 | |
|   SECTION_ITEM                          *PtrSection;
 | |
|   UINTN                                 Length;
 | |
|   UINT8                                 *PtrBuf;
 | |
|   UINT8                                 *PtrEnd;
 | |
| 
 | |
|   Status      = EFI_SUCCESS;
 | |
|   PtrBuf      = Buffer;
 | |
|   PtrEnd      = (UINT8 *) ((UINTN)Buffer + BufferSize - 1);
 | |
| 
 | |
|   //
 | |
|   // First search for '='
 | |
|   //
 | |
|   while (PtrBuf <= PtrEnd) {
 | |
|     if (*PtrBuf == '=') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf++;
 | |
|   }
 | |
|   if (PtrBuf > PtrEnd) {
 | |
|     //
 | |
|     // Not found. Omit this line
 | |
|     //
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // excluding the tailing '='
 | |
|   //
 | |
|   Length      = PtrBuf - Buffer;
 | |
|   ProfileTrim (
 | |
|     Buffer,
 | |
|     &Length
 | |
|   );
 | |
| 
 | |
|   //
 | |
|   // Omit this line if the entry name is null
 | |
|   //
 | |
|   if (Length == 0) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Omit this line if no section header has been found before
 | |
|   //
 | |
|   if (*SectionHead == NULL) {
 | |
|     return Status;
 | |
|   }
 | |
|   PtrSection  = *SectionHead;
 | |
| 
 | |
|   SectionItem = AllocatePool (sizeof (SECTION_ITEM));
 | |
|   if (SectionItem == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   SectionItem->ptrSection = NULL;
 | |
|   SectionItem->ptrEntry   = NULL;
 | |
|   SectionItem->ptrValue   = NULL;
 | |
|   SectionItem->SecNameLen = PtrSection->SecNameLen;
 | |
|   SectionItem->ptrNext    = *SectionHead;
 | |
|   *SectionHead            = SectionItem;
 | |
| 
 | |
|   //
 | |
|   // SectionName, add a trailing '\0'
 | |
|   //
 | |
|   SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1);
 | |
|   if (SectionItem->ptrSection == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1);
 | |
| 
 | |
|   //
 | |
|   // EntryName, add a trailing '\0'
 | |
|   //
 | |
|   SectionItem->ptrEntry = AllocatePool (Length + 1);
 | |
|   if (SectionItem->ptrEntry == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   CopyMem (SectionItem->ptrEntry, Buffer, Length);
 | |
|   *(SectionItem->ptrEntry + Length) = '\0';
 | |
| 
 | |
|   //
 | |
|   // Next search for '#'
 | |
|   //
 | |
|   PtrBuf      = PtrBuf + 1;
 | |
|   Buffer      = PtrBuf;
 | |
|   while (PtrBuf <= PtrEnd) {
 | |
|     if (*PtrBuf == '#') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuf++;
 | |
|   }
 | |
|   Length      = PtrBuf - Buffer;
 | |
|   ProfileTrim (
 | |
|     Buffer,
 | |
|     &Length
 | |
|   );
 | |
| 
 | |
|   if (Length > 0) {
 | |
|     //
 | |
|     // EntryValue, add a trailing '\0'
 | |
|     //
 | |
|     SectionItem->ptrValue = AllocatePool (Length + 1);
 | |
|     if (SectionItem->ptrValue == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     CopyMem (SectionItem->ptrValue, Buffer, Length);
 | |
|     *(SectionItem->ptrValue + Length) = '\0';
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free all comment entry and section entry.
 | |
| 
 | |
|   @param Section         Section entry list.
 | |
|   @param Comment         Comment entry list.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FreeAllList (
 | |
|   IN      SECTION_ITEM                  *Section,
 | |
|   IN      COMMENT_LINE                  *Comment
 | |
|   )
 | |
| {
 | |
|   SECTION_ITEM                          *PtrSection;
 | |
|   COMMENT_LINE                          *PtrComment;
 | |
| 
 | |
|   while (Section != NULL) {
 | |
|     PtrSection    = Section;
 | |
|     Section       = Section->ptrNext;
 | |
|     if (PtrSection->ptrEntry != NULL) {
 | |
|       FreePool (PtrSection->ptrEntry);
 | |
|     }
 | |
|     if (PtrSection->ptrSection != NULL) {
 | |
|       FreePool (PtrSection->ptrSection);
 | |
|     }
 | |
|     if (PtrSection->ptrValue != NULL) {
 | |
|       FreePool (PtrSection->ptrValue);
 | |
|     }
 | |
|     FreePool (PtrSection);
 | |
|   }
 | |
| 
 | |
|   while (Comment != NULL) {
 | |
|     PtrComment    = Comment;
 | |
|     Comment       = Comment->ptrNext;
 | |
|     if (PtrComment->ptrComment != NULL) {
 | |
|       FreePool (PtrComment->ptrComment);
 | |
|     }
 | |
|     FreePool (PtrComment);
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get section entry value.
 | |
| 
 | |
|   @param Section         Section entry list.
 | |
|   @param SectionName     Section name.
 | |
|   @param EntryName       Section entry name.
 | |
|   @param EntryValue      Point to the got entry value.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND  Section is not found.
 | |
|   @retval EFI_SUCCESS    Section entry value is got.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UpdateGetProfileString (
 | |
|   IN      SECTION_ITEM                  *Section,
 | |
|   IN      UINT8                         *SectionName,
 | |
|   IN      UINT8                         *EntryName,
 | |
|   OUT     UINT8                         **EntryValue
 | |
|   )
 | |
| {
 | |
|   *EntryValue   = NULL;
 | |
| 
 | |
|   while (Section != NULL) {
 | |
|     if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) {
 | |
|       if (Section->ptrEntry != NULL) {
 | |
|         if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     Section     = Section->ptrNext;
 | |
|   }
 | |
| 
 | |
|   if (Section == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *EntryValue   = (UINT8 *) Section->ptrValue;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert the dec or hex ascii string to value.
 | |
| 
 | |
|   @param Str             ascii string to be converted.
 | |
| 
 | |
|   @return the converted value.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| UpdateAtoi (
 | |
|   IN      UINT8                         *Str
 | |
|   )
 | |
| {
 | |
|   UINTN Number;
 | |
| 
 | |
|   Number = 0;
 | |
| 
 | |
|   //
 | |
|   // Skip preceeding while spaces
 | |
|   //
 | |
|   while (*Str != '\0') {
 | |
|     if (*Str != 0x20) {
 | |
|       break;
 | |
|     }
 | |
|     Str++;
 | |
|   }
 | |
| 
 | |
|   if (*Str == '\0') {
 | |
|     return Number;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Find whether the string is prefixed by 0x.
 | |
|   // That is, it should be xtoi or atoi.
 | |
|   //
 | |
|   if (*Str == '0') {
 | |
|     if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) {
 | |
|       return AsciiStrHexToUintn ((CONST CHAR8 *) Str);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   while (*Str != '\0') {
 | |
|     if ((*Str >= '0') && (*Str <= '9')) {
 | |
|       Number  = Number * 10 + *Str - '0';
 | |
|     } else {
 | |
|       break;
 | |
|     }
 | |
|     Str++;
 | |
|   }
 | |
| 
 | |
|   return Number;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Converts a decimal value to a Null-terminated ascii string.
 | |
| 
 | |
|   @param  Buffer  Pointer to the output buffer for the produced Null-terminated
 | |
|                   ASCII string.
 | |
|   @param  Value   The 64-bit sgned value to convert to a string.
 | |
| 
 | |
|   @return The number of ASCII characters in Buffer not including the Null-terminator.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| UpdateValueToString (
 | |
|   IN  OUT UINT8                         *Buffer,
 | |
|   IN      INT64                         Value
 | |
|   )
 | |
| {
 | |
|   UINT8                                 TempBuffer[30];
 | |
|   UINT8                                 *TempStr;
 | |
|   UINT8                                 *BufferPtr;
 | |
|   UINTN                                 Count;
 | |
|   UINT32                                Remainder;
 | |
| 
 | |
|   TempStr           = TempBuffer;
 | |
|   BufferPtr         = Buffer;
 | |
|   Count             = 0;
 | |
| 
 | |
|   if (Value < 0) {
 | |
|     *BufferPtr      = '-';
 | |
|     BufferPtr++;
 | |
|     Value           = -Value;
 | |
|     Count++;
 | |
|   }
 | |
| 
 | |
|   do {
 | |
|     Value = (INT64) DivU64x32Remainder  ((UINT64)Value, 10, &Remainder);
 | |
|     //
 | |
|     // The first item of TempStr is not occupied. It's kind of flag
 | |
|     //
 | |
|     TempStr++;
 | |
|     Count++;
 | |
|     *TempStr        = (UINT8) ((UINT8)Remainder + '0');
 | |
|   } while (Value != 0);
 | |
| 
 | |
|   //
 | |
|   // Reverse temp string into Buffer.
 | |
|   //
 | |
|   while (TempStr != TempBuffer) {
 | |
|     *BufferPtr      = *TempStr;
 | |
|     BufferPtr++;
 | |
|     TempStr --;
 | |
|   }
 | |
| 
 | |
|   *BufferPtr = 0;
 | |
| 
 | |
|   return Count;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert the input value to a ascii string, 
 | |
|   and concatenates this string to the input string.
 | |
| 
 | |
|   @param Str             Pointer to a Null-terminated ASCII string.
 | |
|   @param Number          The unsgned value to convert to a string.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| UpdateStrCatNumber (
 | |
|   IN OUT  UINT8                         *Str,
 | |
|   IN      UINTN                         Number
 | |
|   )
 | |
| {
 | |
|   UINTN                                 Count;
 | |
| 
 | |
|   while (*Str != '\0') {
 | |
|     Str++;
 | |
|   }
 | |
| 
 | |
|   Count = UpdateValueToString (Str, (INT64)Number);
 | |
| 
 | |
|   *(Str + Count) = '\0';
 | |
| 
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert the input ascii string into GUID value.
 | |
| 
 | |
|   @param Str             Ascii GUID string to be converted.
 | |
|   @param Guid            Pointer to the converted GUID value.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
 | |
|   @retval EFI_NOT_FOUND         The input ascii string is not a valid GUID format string.
 | |
|   @retval EFI_SUCCESS           GUID value is got.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UpdateStringToGuid (
 | |
|   IN      UINT8                         *Str,
 | |
|   IN OUT  EFI_GUID                      *Guid
 | |
|   )
 | |
| {
 | |
|   UINT8                                 *PtrBuffer;
 | |
|   UINT8                                 *PtrPosition;
 | |
|   UINT8                                 *Buffer;
 | |
|   UINTN                                 Data;
 | |
|   UINTN                                 StrLen;
 | |
|   UINTN                                 Index;
 | |
|   UINT8                                 Digits[3];
 | |
| 
 | |
|   StrLen          = AsciiStrLen  ((CONST CHAR8 *) Str);
 | |
|   Buffer          = AllocatePool (StrLen + 1);
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   AsciiStrCpy ((CHAR8 *)Buffer, (CHAR8 *)Str);
 | |
| 
 | |
|   //
 | |
|   // Data1
 | |
|   //
 | |
|   PtrBuffer       = Buffer;
 | |
|   PtrPosition     = PtrBuffer;
 | |
|   while (*PtrBuffer != '\0') {
 | |
|     if (*PtrBuffer == '-') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuffer++;
 | |
|   }
 | |
|   if (*PtrBuffer == '\0') {
 | |
|     FreePool (Buffer);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *PtrBuffer      = '\0';
 | |
|   Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
 | |
|   Guid->Data1     = (UINT32)Data;
 | |
| 
 | |
|   //
 | |
|   // Data2
 | |
|   //
 | |
|   PtrBuffer++;
 | |
|   PtrPosition     = PtrBuffer;
 | |
|   while (*PtrBuffer != '\0') {
 | |
|     if (*PtrBuffer == '-') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuffer++;
 | |
|   }
 | |
|   if (*PtrBuffer == '\0') {
 | |
|     FreePool (Buffer);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   *PtrBuffer      = '\0';
 | |
|   Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
 | |
|   Guid->Data2     = (UINT16)Data;
 | |
| 
 | |
|   //
 | |
|   // Data3
 | |
|   //
 | |
|   PtrBuffer++;
 | |
|   PtrPosition     = PtrBuffer;
 | |
|   while (*PtrBuffer != '\0') {
 | |
|     if (*PtrBuffer == '-') {
 | |
|       break;
 | |
|     }
 | |
|     PtrBuffer++;
 | |
|   }
 | |
|   if (*PtrBuffer == '\0') {
 | |
|     FreePool (Buffer);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   *PtrBuffer      = '\0';
 | |
|   Data            = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
 | |
|   Guid->Data3     = (UINT16)Data;
 | |
| 
 | |
|   //
 | |
|   // Data4[0..1]
 | |
|   //
 | |
|   for ( Index = 0 ; Index < 2 ; Index++) {
 | |
|     PtrBuffer++;
 | |
|     if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
 | |
|       FreePool (Buffer);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     Digits[0]     = *PtrBuffer;
 | |
|     PtrBuffer++;
 | |
|     Digits[1]     = *PtrBuffer;
 | |
|     Digits[2]     = '\0';
 | |
|     Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
 | |
|     Guid->Data4[Index] = (UINT8)Data;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // skip the '-'
 | |
|   //
 | |
|   PtrBuffer++;
 | |
|   if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Data4[2..7]
 | |
|   //
 | |
|   for ( ; Index < 8; Index++) {
 | |
|     PtrBuffer++;
 | |
|     if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
 | |
|       FreePool (Buffer);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     Digits[0]     = *PtrBuffer;
 | |
|     PtrBuffer++;
 | |
|     Digits[1]     = *PtrBuffer;
 | |
|     Digits[2]     = '\0';
 | |
|     Data          = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
 | |
|     Guid->Data4[Index] = (UINT8)Data;
 | |
|   }
 | |
| 
 | |
|   FreePool (Buffer);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Pre process config data buffer into Section entry list and Comment entry list.
 | |
|  
 | |
|   @param DataBuffer      Config raw file buffer.
 | |
|   @param BufferSize      Size of raw buffer.
 | |
|   @param SectionHead     Pointer to the section entry list.
 | |
|   @param CommentHead     Pointer to the comment entry list.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
 | |
|   @retval EFI_SUCCESS           Config data buffer is preprocessed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PreProcessDataFile (
 | |
|   IN      UINT8                         *DataBuffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  SECTION_ITEM                  **SectionHead,
 | |
|   IN OUT  COMMENT_LINE                  **CommentHead
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   CHAR8                                 *Source;
 | |
|   CHAR8                                 *CurrentPtr;
 | |
|   CHAR8                                 *BufferEnd;
 | |
|   CHAR8                                 *PtrLine;
 | |
|   UINTN                                 LineLength;
 | |
|   UINTN                                 SourceLength;
 | |
|   UINTN                                 MaxLineLength;
 | |
| 
 | |
|   *SectionHead          = NULL;
 | |
|   *CommentHead          = NULL;
 | |
|   BufferEnd             = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize);
 | |
|   CurrentPtr            = (CHAR8 *) DataBuffer;
 | |
|   MaxLineLength         = MAX_LINE_LENGTH;
 | |
|   Status                = EFI_SUCCESS;
 | |
| 
 | |
|   PtrLine = AllocatePool (MaxLineLength);
 | |
|   if (PtrLine == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   while (CurrentPtr < BufferEnd) {
 | |
|     Source              = CurrentPtr;
 | |
|     SourceLength        = (UINTN)BufferEnd - (UINTN)CurrentPtr;
 | |
|     LineLength          = MaxLineLength;
 | |
|     //
 | |
|     // With the assumption that line length is less than 512
 | |
|     // characters. Otherwise BUFFER_TOO_SMALL will be returned.
 | |
|     //
 | |
|     Status              = ProfileGetLine (
 | |
|                             (UINT8 *) Source,
 | |
|                             SourceLength,
 | |
|                             (UINT8 *) PtrLine,
 | |
|                             &LineLength
 | |
|                             );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|         //
 | |
|         // If buffer too small, re-allocate the buffer according
 | |
|         // to the returned LineLength and try again.
 | |
|         //
 | |
|         FreePool (PtrLine);
 | |
|         PtrLine         = NULL;
 | |
|         PtrLine = AllocatePool (LineLength);
 | |
|         if (PtrLine == NULL) {
 | |
|           Status        = EFI_OUT_OF_RESOURCES;
 | |
|           break;
 | |
|         }
 | |
|         SourceLength    = LineLength;
 | |
|         Status          = ProfileGetLine (
 | |
|                             (UINT8 *) Source,
 | |
|                             SourceLength,
 | |
|                             (UINT8 *) PtrLine,
 | |
|                             &LineLength
 | |
|                             );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           break;
 | |
|         }
 | |
|         MaxLineLength   = LineLength;
 | |
|       } else {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     CurrentPtr          = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength);
 | |
| 
 | |
|     //
 | |
|     // Line got. Trim the line before processing it.
 | |
|     //
 | |
|     ProfileTrim (
 | |
|       (UINT8 *) PtrLine,
 | |
|       &LineLength
 | |
|    );
 | |
| 
 | |
|     //
 | |
|     // Blank line
 | |
|     //
 | |
|     if (LineLength == 0) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (PtrLine[0] == '#') {
 | |
|       Status            = ProfileGetComments (
 | |
|                             (UINT8 *) PtrLine,
 | |
|                             LineLength,
 | |
|                             CommentHead
 | |
|                             );
 | |
|     } else if (PtrLine[0] == '[') {
 | |
|       Status            = ProfileGetSection (
 | |
|                             (UINT8 *) PtrLine,
 | |
|                             LineLength,
 | |
|                             SectionHead
 | |
|                             );
 | |
|     } else {
 | |
|       Status            = ProfileGetEntry (
 | |
|                             (UINT8 *) PtrLine,
 | |
|                             LineLength,
 | |
|                             SectionHead
 | |
|                             );
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free buffer
 | |
|   //
 | |
|   FreePool (PtrLine);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse Config data file to get the updated data array.
 | |
| 
 | |
|   @param DataBuffer      Config raw file buffer.
 | |
|   @param BufferSize      Size of raw buffer.
 | |
|   @param NumOfUpdates    Pointer to the number of update data.
 | |
|   @param UpdateArray     Pointer to the config of update data.
 | |
| 
 | |
|   @retval EFI_NOT_FOUND         No config data is found.
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
 | |
|   @retval EFI_SUCCESS           Parse the config file successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ParseUpdateDataFile (
 | |
|   IN      UINT8                         *DataBuffer,
 | |
|   IN      UINTN                         BufferSize,
 | |
|   IN OUT  UINTN                         *NumOfUpdates,
 | |
|   IN OUT  UPDATE_CONFIG_DATA            **UpdateArray
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   CHAR8                                 *Value;
 | |
|   CHAR8                                 *SectionName;
 | |
|   CHAR8                                 Entry[MAX_LINE_LENGTH];
 | |
|   SECTION_ITEM                          *SectionHead;
 | |
|   COMMENT_LINE                          *CommentHead;
 | |
|   UINTN                                 Num;
 | |
|   UINTN                                 Index;
 | |
|   EFI_GUID                              FileGuid;
 | |
| 
 | |
|   SectionHead           = NULL;
 | |
|   CommentHead           = NULL;
 | |
| 
 | |
|   //
 | |
|   // First process the data buffer and get all sections and entries
 | |
|   //
 | |
|   Status                = PreProcessDataFile (
 | |
|                             DataBuffer,
 | |
|                             BufferSize,
 | |
|                             &SectionHead,
 | |
|                             &CommentHead
 | |
|                             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreeAllList (SectionHead, CommentHead);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Now get NumOfUpdate
 | |
|   //
 | |
|   Value                 = NULL;
 | |
|   Status                = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) "Head",
 | |
|                             (UINT8 *) "NumOfUpdate",
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|   if (Value == NULL) {
 | |
|     FreeAllList (SectionHead, CommentHead);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   Num                   = UpdateAtoi((UINT8 *) Value);
 | |
|   if (Num <= 0) {
 | |
|     FreeAllList (SectionHead, CommentHead);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *NumOfUpdates         = Num;
 | |
|   *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num));
 | |
|   if (*UpdateArray == NULL) {
 | |
|     FreeAllList (SectionHead, CommentHead);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   for ( Index = 0 ; Index < *NumOfUpdates ; Index++) {
 | |
|     //
 | |
|     // Get the section name of each update
 | |
|     //
 | |
|     AsciiStrCpy (Entry, "Update");
 | |
|     UpdateStrCatNumber ((UINT8 *) Entry, Index);
 | |
|     Value               = NULL;
 | |
|     Status              = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) "Head",
 | |
|                             (UINT8 *) Entry,
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|     if (Value == NULL) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // The section name of this update has been found.
 | |
|     // Now looks for all the config data of this update
 | |
|     //
 | |
|     SectionName         = Value;
 | |
| 
 | |
|     //
 | |
|     // UpdateType
 | |
|     //
 | |
|     Value               = NULL;
 | |
|     Status              = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) SectionName,
 | |
|                             (UINT8 *) "UpdateType",
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|     if (Value == NULL) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     Num                 = UpdateAtoi((UINT8 *) Value);
 | |
|     if (( Num >= (UINTN) UpdateOperationMaximum)) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return Status;
 | |
|     }
 | |
|     (*UpdateArray)[Index].Index       = Index;
 | |
|     (*UpdateArray)[Index].UpdateType  = (UPDATE_OPERATION_TYPE) Num;
 | |
| 
 | |
|     //
 | |
|     // FvBaseAddress
 | |
|     //
 | |
|     Value               = NULL;
 | |
|     Status              = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) SectionName,
 | |
|                             (UINT8 *) "FvBaseAddress",
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|     if (Value == NULL) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     Num                 = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
 | |
|     (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num;
 | |
| 
 | |
|     //
 | |
|     // FileBuid
 | |
|     //
 | |
|     Value               = NULL;
 | |
|     Status              = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) SectionName,
 | |
|                             (UINT8 *) "FileGuid",
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|     if (Value == NULL) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     Status              = UpdateStringToGuid ((UINT8 *) Value, &FileGuid);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return Status;
 | |
|     }
 | |
|     CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID));
 | |
| 
 | |
|     //
 | |
|     // FaultTolerant
 | |
|     // Default value is FALSE
 | |
|     //
 | |
|     Value               = NULL;
 | |
|     (*UpdateArray)[Index].FaultTolerant = FALSE;
 | |
|     Status              = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) SectionName,
 | |
|                             (UINT8 *) "FaultTolerant",
 | |
|                             (UINT8 **) &Value
 | |
|                            );
 | |
|     if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
 | |
|       FreeAllList (SectionHead, CommentHead);
 | |
|       return Status;
 | |
|     } else if (Value != NULL) {
 | |
|       if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) {
 | |
|         (*UpdateArray)[Index].FaultTolerant = TRUE;
 | |
|       } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) {
 | |
|         (*UpdateArray)[Index].FaultTolerant = FALSE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) {
 | |
|       //
 | |
|       // Length
 | |
|       //
 | |
|       Value             = NULL;
 | |
|       Status            = UpdateGetProfileString (
 | |
|                             SectionHead,
 | |
|                             (UINT8 *) SectionName,
 | |
|                             (UINT8 *) "Length",
 | |
|                             (UINT8 **) &Value
 | |
|                             );
 | |
|       if (Value == NULL) {
 | |
|         FreeAllList (SectionHead, CommentHead);
 | |
|         return EFI_NOT_FOUND;
 | |
|       }
 | |
| 
 | |
|       Num               = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
 | |
|       (*UpdateArray)[Index].Length = (UINTN) Num;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Now all configuration data got. Free those temporary buffers
 | |
|   //
 | |
|   FreeAllList (SectionHead, CommentHead);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |