]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.c
fix operator order.
[mirror_edk2.git] / ShellPkg / Library / BaseFileHandleLib / BaseFileHandleLib.c
index 87b57724886281775a4c10be87ab43024ab9ac17..3200385ee58b0e63f23105b66ff8e0e1f0c12abb 100644 (file)
@@ -14,11 +14,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 #include <Uefi.h>\r
 \r
-#include <Library/ShellLib.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+\r
+#include <Guid/FileInfo.h>\r
+\r
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
-\r
-#include <Protocol/SimpleFileSystem.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
 \r
 #define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)\r
 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)\r
@@ -620,4 +623,299 @@ FileHandleGetSize (
   FreePool(FileInfo);\r
 \r
   return (EFI_SUCCESS);\r
-}
\ No newline at end of file
+}\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 = StrLen(Source);\r
+  }\r
+\r
+  //\r
+  // Test and grow if required\r
+  //\r
+  if (CurrentSize != NULL) {\r
+    NewSize = *CurrentSize;\r
+    while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {\r
+      NewSize += 2 * Count * sizeof(CHAR16);\r
+    }\r
+    *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+    *CurrentSize = NewSize;\r
+  } else {\r
+    *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));\r
+  }\r
+\r
+  CopySize = StrSize(*Destination);\r
+  *Destination = CopyMem((*Destination)+StrLen(Source), *Destination, CopySize);\r
+  *Destination = CopyMem(*Destination, Source, StrLen(Source));\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
+  *FullFileName = NULL;\r
+\r
+  //\r
+  // Check our parameters\r
+  //\r
+  if (FullFileName == NULL || Handle == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\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
+          *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0);\r
+          FreePool(FileInfo);\r
+          break;\r
+        } else {\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] = '\0';\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