+}\r
+\r
+\r
+/**\r
+ Safely append (on the left) with automatic string resizing given length of Destination and \r
+ desired length of copy from Source.\r
+\r
+ append the first D characters of Source to the end of Destination, where D is \r
+ the lesser of Count and the StrLen() of Source. If appending those D characters \r
+ will fit within Destination (whose Size is given as CurrentSize) and \r
+ still leave room for a null terminator, then those characters are appended, \r
+ starting at the original terminating null of Destination, and a new terminating \r
+ null is appended.\r
+\r
+ If appending D characters onto Destination will result in a overflow of the size\r
+ given in CurrentSize the string will be grown such that the copy can be performed\r
+ and CurrentSize will be updated to the new size.\r
+\r
+ If Source is NULL, there is nothing to append, just return the current buffer in \r
+ Destination.\r
+\r
+ if Destination is NULL, then ASSERT()\r
+ if Destination's current length (including NULL terminator) is already more then \r
+ CurrentSize, then ASSERT()\r
+\r
+ @param[in,out] Destination The String to append onto\r
+ @param[in,out] CurrentSize on call the number of bytes in Destination. On \r
+ return possibly the new size (still in bytes). if NULL\r
+ then allocate whatever is needed.\r
+ @param[in] Source The String to append from\r
+ @param[in] Count Maximum number of characters to append. if 0 then \r
+ all are appended.\r
+\r
+ @return Destination return the resultant string.\r
+**/\r
+CHAR16* \r
+EFIAPI\r
+StrnCatGrowLeft (\r
+ IN OUT CHAR16 **Destination,\r
+ IN OUT UINTN *CurrentSize,\r
+ IN CONST CHAR16 *Source,\r
+ IN UINTN Count\r
+ ){\r
+ UINTN DestinationStartSize;\r
+ UINTN NewSize;\r
+ UINTN CopySize;\r
+\r
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT(Destination != NULL);\r
+\r
+ //\r
+ // If there's nothing to do then just return Destination\r
+ //\r
+ if (Source == NULL) {\r
+ return (*Destination);\r
+ }\r
+\r
+ //\r
+ // allow for NULL pointers address as Destination\r
+ //\r
+ if (*Destination != NULL) {\r
+ ASSERT(CurrentSize != 0);\r
+ DestinationStartSize = StrSize(*Destination);\r
+ ASSERT(DestinationStartSize <= *CurrentSize);\r
+ } else {\r
+ DestinationStartSize = 0;\r
+// ASSERT(*CurrentSize == 0);\r
+ }\r
+\r
+ //\r
+ // Append all of Source?\r
+ //\r
+ if (Count == 0) {\r
+ Count = StrSize(Source);\r
+ }\r
+\r
+ //\r
+ // Test and grow if required\r
+ //\r
+ if (CurrentSize != NULL) {\r
+ NewSize = *CurrentSize;\r
+ while (NewSize < (DestinationStartSize + Count)) {\r
+ NewSize += 2 * Count;\r
+ }\r
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+ *CurrentSize = NewSize;\r
+ } else {\r
+ *Destination = AllocateZeroPool(Count+sizeof(CHAR16));\r
+ }\r
+\r
+ CopySize = StrSize(*Destination);\r
+ CopyMem((*Destination)+((Count-2)/sizeof(CHAR16)), *Destination, CopySize);\r
+ CopyMem(*Destination, Source, Count-2);\r
+ return (*Destination);\r
+}\r
+\r
+/**\r
+ Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the \r
+ directory 'stack'.\r
+\r
+ if Handle is NULL, return EFI_INVALID_PARAMETER\r
+\r
+ @param[in] Handle Handle to the Directory or File to create path to.\r
+ @param[out] FullFileName pointer to pointer to generated full file name. It \r
+ is the responsibility of the caller to free this memory\r
+ with a call to FreePool().\r
+ @retval EFI_SUCCESS the operation was sucessful and the FullFileName is valid.\r
+ @retval EFI_INVALID_PARAMETER Handle was NULL.\r
+ @retval EFI_INVALID_PARAMETER FullFileName was NULL.\r
+ @retval EFI_OUT_OF_RESOURCES a memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileHandleGetFileName (\r
+ IN CONST EFI_FILE_HANDLE Handle,\r
+ OUT CHAR16 **FullFileName\r
+ ){\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ EFI_FILE_HANDLE CurrentHandle;\r
+ EFI_FILE_HANDLE NextHigherHandle;\r
+ EFI_FILE_INFO *FileInfo;\r
+\r
+ Size = 0;\r
+\r
+ //\r
+ // Check our parameters\r
+ //\r
+ if (FullFileName == NULL || Handle == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ *FullFileName = NULL;\r
+\r
+ Status = Handle->Open(Handle, &CurrentHandle, L".", EFI_FILE_MODE_READ, 0);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // Reverse out the current directory on the device\r
+ //\r
+ for (;;) {\r
+ FileInfo = FileHandleGetInfo(CurrentHandle);\r
+ if (FileInfo == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ } else {\r
+ //\r
+ // We got info... do we have a name? if yes preceed the current path with it...\r
+ //\r
+ if (StrLen (FileInfo->FileName) == 0) {\r
+ if (*FullFileName == NULL) {\r
+ *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);\r
+ }\r
+ FreePool(FileInfo);\r
+ break;\r
+ } else {\r
+ if (*FullFileName == NULL) {\r
+ *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);\r
+ }\r
+ *FullFileName = StrnCatGrowLeft(FullFileName, &Size, FileInfo->FileName, 0);\r
+ *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);\r
+ FreePool(FileInfo);\r
+ }\r
+ }\r
+ //\r
+ // Move to the parent directory\r
+ //\r
+ Status = CurrentHandle->Open (CurrentHandle, &NextHigherHandle, L"..", EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ FileHandleClose(CurrentHandle);\r
+ CurrentHandle = NextHigherHandle;\r
+ }\r
+ }\r
+\r
+ if (CurrentHandle != NULL) {\r
+ CurrentHandle->Close (CurrentHandle);\r
+ }\r
+\r
+ if (EFI_ERROR(Status) && *FullFileName != NULL) {\r
+ FreePool(*FullFileName);\r
+ }\r
+\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Function to read a single line (up to but not including the \n) from a file.\r
+\r
+ @param[in] Handle FileHandle to read from\r
+ @param[in,out] Buffer pointer to buffer to read into\r
+ @param[in,out] Size pointer to number of bytes in buffer\r
+ @param[in[ Truncate if TRUE then allows for truncation of the line to fit.\r
+ if FALSE will reset the position to the begining of the \r
+ line if the buffer is not large enough.\r
+\r
+ @retval EFI_SUCCESS the operation was sucessful. the line is stored in \r
+ Buffer.\r
+ @retval EFI_INVALID_PARAMETER Handle was NULL.\r
+ @retval EFI_INVALID_PARAMETER Buffer was NULL.\r
+ @retval EFI_INVALID_PARAMETER Size was NULL.\r
+ @retval EFI_BUFFER_TOO_SMALL Size was not enough space to store the line. \r
+ Size was updated to minimum space required.\r
+ @sa FileHandleRead\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileHandleReadLine(\r
+ IN EFI_FILE_HANDLE Handle,\r
+ IN OUT VOID *Buffer,\r
+ IN OUT UINTN *Size,\r
+ IN BOOLEAN Truncate\r
+ ){\r
+ EFI_STATUS Status;\r
+ CHAR16 CharBuffer;\r
+ UINTN CharSize;\r
+ UINTN CountSoFar;\r
+ UINT64 Position;\r
+\r
+\r
+ if (Handle == NULL\r
+ ||Buffer == NULL\r
+ ||Size == NULL\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ FileHandleGetPosition(Handle, &Position);\r
+\r
+ for (CountSoFar = 0;;CountSoFar++){\r
+ CharSize = sizeof(CharBuffer);\r
+ Status = FileHandleRead(Handle, &CharSize, &CharBuffer);\r
+ if ( EFI_ERROR(Status) \r
+ || CharSize == 0 \r
+ || CharBuffer == '\n'\r
+ ){\r
+ break;\r
+ }\r
+ //\r
+ // if we have space save it...\r
+ //\r
+ if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
+ ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
+ ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
+ }\r
+ }\r
+\r
+ //\r
+ // if we ran out of space tell when...\r
+ //\r
+ if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
+ *Size = (CountSoFar+1)*sizeof(CHAR16);\r
+ if (Truncate == FALSE) {\r
+ FileHandleSetPosition(Handle, Position);\r
+ } else {\r
+ DEBUG((DEBUG_WARN, "The line was truncated in ReadLine"));\r
+ }\r
+ return (EFI_BUFFER_TOO_SMALL);\r
+ }\r
+ *Size = (CountSoFar+1)*sizeof(CHAR16);\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ function to write a line of unicode text to a file.\r
+\r
+ if Handle is NULL, ASSERT.\r
+ if Buffer is NULL, do nothing. (return SUCCESS)\r
+\r
+ @param[in] Handle FileHandle to write to\r
+ @param[in] Buffer Buffer to write\r
+\r
+ @retval EFI_SUCCESS the data was written.\r
+ @retval other failure.\r
+\r
+ @sa FileHandleWrite\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileHandleWriteLine(\r
+ IN EFI_FILE_HANDLE Handle,\r
+ IN CHAR16 *Buffer\r
+ ){\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+\r
+ ASSERT(Handle != NULL);\r
+\r
+ if (Buffer == NULL) {\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ Size = StrLen(Buffer);\r
+ Status = FileHandleWrite(Handle, &Size, Buffer);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+ Size = StrLen(L"\r\n");\r
+ return FileHandleWrite(Handle, &Size, L"\r\n");\r
+}\r