UEFI Shell scandalizes the help message in spec level so that a standalone UEFI shell application can never get "-?" switch, instead the Shell core (interpreter) detects the "-?" and finds .MAN file for that shell application in certain spec defined paths, then show the help extracted from that .MAN file.
But it means distributing a UEFI shell application not only means distributing a .EFI file but also distributing a .MAN file. If the text formatted .MAN file is corrupted (edited by user by mistake), or is missing (deleted by user by mistake), no help will be shown to user. So this patch enhance the Shell to make it support finding help message imbedded in resource section of application image. Cc: Jaben Carsey <[email protected]> Cc: Ruiyu Ni <[email protected]> Cc: Liming Gao <[email protected]> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin <[email protected]> --- ShellPkg/Application/Shell/Shell.h | 3 +- ShellPkg/Application/Shell/ShellManParser.c | 739 +++++++++++++++++++++++++++- 2 files changed, 726 insertions(+), 16 deletions(-) diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index 351b941..df7199b 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -2,7 +2,7 @@ function definitions for internal to shell functions. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> - Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2009 - 2016, 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 @@ -29,6 +29,7 @@ #include <Protocol/EfiShellEnvironment2.h> #include <Protocol/EfiShellParameters.h> #include <Protocol/BlockIo.h> +#include <Protocol/HiiPackageList.h> #include <Library/BaseLib.h> #include <Library/UefiApplicationEntryPoint.h> diff --git a/ShellPkg/Application/Shell/ShellManParser.c b/ShellPkg/Application/Shell/ShellManParser.c index 222cdaf..cb91582 100644 --- a/ShellPkg/Application/Shell/ShellManParser.c +++ b/ShellPkg/Application/Shell/ShellManParser.c @@ -1,7 +1,7 @@ /** @file Provides interface to shell MAN file parser. - Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR> Copyright 2015 Dell Inc. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -37,6 +37,58 @@ InternalShellCharToUpper ( ); /** + Verifies that the filename has .EFI on the end. + + allocates a new buffer and copies the name (appending .EFI if necessary). + Caller to free the buffer. + + @param[in] NameString original name string + + @return the new filename with .efi as the extension. +**/ +CHAR16 * +EFIAPI +GetExecuatableFileName ( + IN CONST CHAR16 *NameString + ) +{ + CHAR16 *Buffer; + CHAR16 *SuffixStr; + if (NameString == NULL) { + return (NULL); + } + + // + // Fix the file name + // + if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".efi"), L".efi", StrLen(L".efi"))==0) { + Buffer = AllocateCopyPool(StrSize(NameString), NameString); + } else if (StrnCmp(NameString+StrLen(NameString)-StrLen(L".man"), L".man", StrLen(L".man"))==0) { + Buffer = AllocateCopyPool(StrSize(NameString), NameString); + if (Buffer != NULL) { + SuffixStr = Buffer+StrLen(Buffer)-StrLen(L".man"); + StrnCpyS (SuffixStr, StrSize(L".man")/sizeof(CHAR16), L".efi", StrLen(L".efi")); + } + } else { + Buffer = AllocateZeroPool(StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16)); + if (Buffer != NULL) { + StrnCpyS( Buffer, + (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16), + NameString, + StrLen(NameString) + ); + StrnCatS( Buffer, + (StrSize(NameString) + StrLen(L".efi")*sizeof(CHAR16))/sizeof(CHAR16), + L".efi", + StrLen(L".efi") + ); + } + } + return (Buffer); + +} + +/** Verifies that the filename has .MAN on the end. allocates a new buffer and copies the name (appending .MAN if necessary) @@ -381,7 +433,7 @@ ManFileFindSections( Upon a sucessful return the caller is responsible to free the memory in *BriefDesc - @param[in] Handle Buffer to read from + @param[in] Buffer Buffer to read from @param[in] Command name of command's section to find @param[in] BriefDesc pointer to pointer to string where description goes. @param[in] BriefSize pointer to size of allocated BriefDesc @@ -404,6 +456,7 @@ ManBufferFindTitleSection( CHAR16 *TitleEnd; CHAR16 *CurrentLocation; UINTN TitleLength; + UINTN Start; CONST CHAR16 StartString[] = L".TH "; CONST CHAR16 EndString[] = L" 0 "; @@ -417,15 +470,26 @@ ManBufferFindTitleSection( Status = EFI_SUCCESS; // + // Do not pass any leading path information that may be present to IsTitleHeader(). + // + Start = StrLen(Command); + while ((Start != 0) + && (*(Command + Start - 1) != L'\\') + && (*(Command + Start - 1) != L'/') + && (*(Command + Start - 1) != L':')) { + --Start; + } + + // // more characters for StartString and EndString // - TitleLength = StrSize(Command) + (StrLen(StartString) + StrLen(EndString)) * sizeof(CHAR16); + TitleLength = StrSize(Command + Start) + (StrLen(StartString) + StrLen(EndString)) * sizeof(CHAR16); TitleString = AllocateZeroPool(TitleLength); if (TitleString == NULL) { return (EFI_OUT_OF_RESOURCES); } StrCpyS(TitleString, TitleLength/sizeof(CHAR16), StartString); - StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command); + StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command + Start); StrCatS(TitleString, TitleLength/sizeof(CHAR16), EndString); CurrentLocation = StrStr(*Buffer, TitleString); @@ -679,6 +743,560 @@ ManFileFindTitleSection( } /** + Calculate the size of StringSrc and output it. If StringDest is not NULL, + copy string text from src to dest. + + This is a internal function. + + @param StringDest Buffer to store the string text. If it is NULL, + only the size will be returned. + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + + @retval EFI_SUCCESS The string text was outputed successfully. + @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string + text. BufferSize is updated to the required buffer + size. +**/ +EFI_STATUS +ShellManGetUnicodeStringTextOrSize ( + OUT EFI_STRING StringDest, OPTIONAL + IN UINT8 *StringSrc, + IN OUT UINTN *BufferSize + ) +{ + UINTN StringSize; + UINT8 *StringPtr; + + ASSERT (StringSrc != NULL && BufferSize != NULL); + + StringSize = sizeof (CHAR16); + StringPtr = StringSrc; + while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) { + StringSize += sizeof (CHAR16); + StringPtr += sizeof (CHAR16); + } + + if (*BufferSize < StringSize) { + *BufferSize = StringSize; + return EFI_BUFFER_TOO_SMALL; + } + if (StringDest != NULL) { + CopyMem (StringDest, StringSrc, StringSize); + } + + *BufferSize = StringSize; + return EFI_SUCCESS; +} + +/** + Convert Ascii string text to unicode string test. + + This is a internal function. + + + @param StringDest Buffer to store the string text. If it is NULL, + only the size will be returned. + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + + @retval EFI_SUCCESS The string text was outputed successfully. + @retval EFI_BUFFER_TOO_SMALL Buffer is insufficient to store the found string + text. BufferSize is updated to the required buffer + size. +**/ +EFI_STATUS +ShellManConvertToUnicodeText ( + OUT EFI_STRING StringDest, + IN CHAR8 *StringSrc, + IN OUT UINTN *BufferSize + ) +{ + UINTN StringSize; + UINTN Index; + + ASSERT (StringSrc != NULL && BufferSize != NULL); + + StringSize = AsciiStrSize (StringSrc) * 2; + if (*BufferSize < StringSize || StringDest == NULL) { + *BufferSize = StringSize; + return EFI_BUFFER_TOO_SMALL; + } + + for (Index = 0; Index < AsciiStrLen (StringSrc); Index++) { + StringDest[Index] = (CHAR16) StringSrc[Index]; + } + + StringDest[Index] = 0; + return EFI_SUCCESS; +} + +/** + Parse all string blocks to find a String block specified by StringId. + If StringId = (EFI_STRING_ID) (-1), find out all string blocks + within this string package and backup its information. If LastStringId is + specified, the string id of last string block will also be output. + If StringId = 0, output the string id of last string block (EFI_HII_SIBT_STRING). + + @param StringBlockArray Hii string block to parse. + @param StringId The string's id, which is unique within + PackageList. + @param BlockType Output the block type of found string block. + @param StringBlockAddr Output the block address of found string block. + @param StringTextOffset Offset, relative to the found block address, of + the string text information. + @param LastStringId Output the last string id when StringId = 0 or StringId = -1. + @param StartStringId The first id in the skip block which StringId in the block. + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. + @retval EFI_INVALID_PARAMETER The specified text or font info can not be found + out. + +**/ +EFI_STATUS +ParseStrBlkArrWorker ( + IN UINT8 *StringBlockArray, + IN EFI_STRING_ID StringId, + OUT UINT8 *BlockType, + OUT UINT8 **StringBlockAddr, + OUT UINTN *StringTextOffset, + OUT EFI_STRING_ID *LastStringId, + OUT EFI_STRING_ID *StartStringId + ) +{ + EFI_STRING_ID CurrentStringId; + UINT8 *BlockHdr; + UINTN BlockSize; + UINTN Offset; + UINTN StringSize; + UINT8 *StringTextPtr; + UINT8 Length8; + UINT16 StringCount; + UINT16 Index; + UINT16 SkipCount; + UINT16 FontSize; + UINT32 Length32; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT8 FontId; + EFI_HII_FONT_STYLE FontStyle; + + + CurrentStringId = 1; + BlockHdr = NULL; + StringTextPtr = NULL; + StringSize = 0; + + if (StringBlockArray == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (StringId != (EFI_STRING_ID)(-1) && StringId != 0) { + if (BlockType == NULL || StringBlockAddr == NULL || StringTextOffset == NULL){ + return EFI_INVALID_PARAMETER; + } + } else { + if (StringId == 0 && LastStringId != NULL) { + return EFI_SUCCESS; + } + } + + // + // Parse the string blocks to get the string only. + // + BlockHdr = StringBlockArray; + BlockSize = 0; + Offset = 0; + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr){ + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_SCSU_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_SCSU: + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + ShellManGetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + ShellManGetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + ShellManGetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += StringSize; + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + ShellManGetUnicodeStringTextOrSize (NULL, StringTextPtr, &StringSize); + BlockSize += StringSize; + if (CurrentStringId == StringId) { + ASSERT (BlockType != NULL && StringBlockAddr != NULL && StringTextOffset != NULL); + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = StringTextPtr - BlockHdr; + return EFI_SUCCESS; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + if (CurrentStringId == StringId) { + CopyMem ( + &StringId, + BlockHdr + sizeof (EFI_HII_STRING_BLOCK), + sizeof (EFI_STRING_ID) + ); + ASSERT (StringId != CurrentStringId); + CurrentStringId = 1; + BlockSize = 0; + } else { + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + if (Ext2.BlockType2 == EFI_HII_SIBT_FONT && StringId == (EFI_STRING_ID) (-1)) { + BlockHdr += sizeof (EFI_HII_SIBT_EXT2_BLOCK); + CopyMem (&FontId, BlockHdr, sizeof (UINT8)); + BlockHdr ++; + CopyMem (&FontSize, BlockHdr, sizeof (UINT16)); + BlockHdr += sizeof (UINT16); + CopyMem (&FontStyle, BlockHdr, sizeof (EFI_HII_FONT_STYLE)); + BlockHdr += sizeof (EFI_HII_FONT_STYLE); + } + BlockSize += Ext2.Length; + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + BlockSize += Length32; + break; + + default: + break; + } + + // + // If we want to get the specified StringId string. + // + if (StringId > 0 && StringId != (EFI_STRING_ID)(-1)){ + *BlockType = *BlockHdr; + *StringBlockAddr = BlockHdr; + *StringTextOffset = Offset; + + // + // If found the specified StringId + // + if (StringId == CurrentStringId - 1) { + // + // if only one skip item, return EFI_NOT_FOUND. + // + if(*BlockType == EFI_HII_SIBT_SKIP2 || *BlockType == EFI_HII_SIBT_SKIP1) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } + } + + if (StringId < CurrentStringId - 1) { + return EFI_NOT_FOUND; + } + } + + BlockHdr = StringBlockArray + BlockSize; + if (StartStringId != NULL) { + *StartStringId = CurrentStringId; + } + } + + // + // Get last string ID + // + if (StringId == (EFI_STRING_ID) (-1) && LastStringId != NULL) { + *LastStringId = (EFI_STRING_ID) (CurrentStringId - 1); + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; + +} + +/** + Get all the strings text from the PacakgeList. The strings arrays are delimited by + CHAR_NULL. + + @param PackageListHdr Hii package list header. + @param StringBuffer The strings text buffer. Free by caller + @param BufferSize The StringBuffer size in bytes + + @retval EFI_SUCCESS Get strings success. + @retval EFI_NOT_FOUND None strings are found. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. +**/ +EFI_STATUS +ParseStringPackageList( + IN EFI_HII_PACKAGE_LIST_HEADER *PackageListHdr, + OUT CHAR16 **StringBuffer, + OUT UINTN *BufferSize + ) +{ + EFI_HII_PACKAGE_HEADER *PackageHdrPtr; + EFI_HII_PACKAGE_HEADER PackageHeader; + EFI_HII_STRING_PACKAGE_HDR *StrPkgHdrPtr; + EFI_STRING_ID LastStringId; + EFI_STRING_ID StrIdIndex; + EFI_STATUS Status; + BOOLEAN AtLeastOneFound; + UINT32 StrPkgHdrSize; + UINT8 *StringBlockArray; + UINT8 *StringTextPtr; + UINT8 BlockType; + UINT8 *StringBlockAddr; + UINTN StringTextOffset; + UINTN TempStringSize; + CHAR16 *TempString; + CHAR16 *StrBufferWalker; + + + PackageHdrPtr = NULL; + StrPkgHdrPtr = NULL; + AtLeastOneFound = FALSE; + StringBlockArray = NULL; + StringTextPtr = NULL; + TempStringSize = 0; + TempString = NULL; + *BufferSize = 0; + *StringBuffer = NULL; + StrBufferWalker = NULL; + + PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *)((UINT8 *)PackageListHdr + sizeof(EFI_HII_PACKAGE_LIST_HEADER)); + CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); + + while (PackageHeader.Type != EFI_HII_PACKAGE_END) { + if (PackageHeader.Type == EFI_HII_PACKAGE_STRINGS) { + // + // Parse every string packages + // + StrPkgHdrPtr = (EFI_HII_STRING_PACKAGE_HDR *)PackageHdrPtr; + CopyMem (&StrPkgHdrSize, (UINT8 *) StrPkgHdrPtr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32)); + StringBlockArray = (UINT8 *)StrPkgHdrPtr + StrPkgHdrSize; + + // + // Get the max StringID in this package + // + Status = ParseStrBlkArrWorker(StringBlockArray, (EFI_STRING_ID) (-1), NULL, NULL, NULL, &LastStringId, NULL); + if (EFI_ERROR(Status)) { + PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length); + CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); + continue; + } + // + // Parse every string in string package + // + for (StrIdIndex = 0; StrIdIndex <= LastStringId; StrIdIndex++) { + Status = ParseStrBlkArrWorker ( + StringBlockArray, + StrIdIndex, + &BlockType, + &StringBlockAddr, + &StringTextOffset, + NULL, + NULL + ); + if EFI_ERROR(Status) { + continue; + } else { + // + // Get string successfully & draw content. + // + StringTextPtr = StringBlockAddr + StringTextOffset; + switch (BlockType) { + case EFI_HII_SIBT_STRING_SCSU: + case EFI_HII_SIBT_STRING_SCSU_FONT: + case EFI_HII_SIBT_STRINGS_SCSU: + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + TempStringSize = 0; + Status = ShellManConvertToUnicodeText (TempString, (CHAR8 *) StringTextPtr, &TempStringSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + TempString = (CHAR16 *)AllocateZeroPool(TempStringSize); + if (TempString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = ShellManConvertToUnicodeText (TempString, (CHAR8 *) StringTextPtr, &TempStringSize); + ASSERT (Status == EFI_SUCCESS); + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + case EFI_HII_SIBT_STRING_UCS2_FONT: + case EFI_HII_SIBT_STRINGS_UCS2: + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + TempStringSize = 0; + Status = ShellManGetUnicodeStringTextOrSize (TempString, StringTextPtr, &TempStringSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + TempString = (CHAR16 *)AllocateZeroPool(TempStringSize); + if (TempString == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = ShellManGetUnicodeStringTextOrSize (TempString, StringTextPtr, &TempStringSize); + ASSERT (Status == EFI_SUCCESS); + } + break; + } + + // + // Append the string into StringBuffer + // + *StringBuffer = (CHAR16 *)ReallocatePool(*BufferSize, *BufferSize + TempStringSize, *StringBuffer); + *BufferSize += TempStringSize; + if (*StringBuffer == NULL) { + SHELL_FREE_NON_NULL(TempString); + return EFI_OUT_OF_RESOURCES; + } + StrBufferWalker = *StringBuffer; + StrBufferWalker += (*BufferSize - TempStringSize) / sizeof(CHAR16); + CopyMem((VOID*)StrBufferWalker, (VOID*)TempString, TempStringSize); + + SHELL_FREE_NON_NULL(TempString); + AtLeastOneFound = TRUE; + } + } + } + + // + // goto header of next package + // + PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length); + CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); + } + + if (AtLeastOneFound) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + +} + +/** This function returns the help information for the specified command. The help text will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B) @@ -720,13 +1338,20 @@ ProcessManFile( { CHAR16 *TempString; SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE CmdFileImgHandle; EFI_STATUS Status; UINTN HelpSize; UINTN BriefSize; BOOLEAN Ascii; CHAR16 *TempString2; - EFI_DEVICE_PATH_PROTOCOL *FileDevPath; - EFI_DEVICE_PATH_PROTOCOL *DevPath; + CHAR16 *CmdFileName; + CHAR16 *CmdFilePathName; + CHAR16 *StrArrBuff; + CHAR16 *StrArrWalker; + UINTN StrArrBuffSize; + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader; if ( ManFileName == NULL || Command == NULL @@ -735,10 +1360,19 @@ ProcessManFile( return (EFI_INVALID_PARAMETER); } - HelpSize = 0; - BriefSize = 0; - TempString = NULL; - Ascii = FALSE; + HelpSize = 0; + BriefSize = 0; + StrArrBuffSize = 0; + TempString = NULL; + Ascii = FALSE; + CmdFileName = NULL; + CmdFilePathName = NULL; + CmdFileImgHandle = NULL; + StrArrBuff = NULL; + PackageListHeader = NULL; + FileDevPath = NULL; + DevPath = NULL; + // // See if it's in HII first // @@ -750,6 +1384,9 @@ ProcessManFile( Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize); } } else { + // + // If the image is a external app, check .MAN file first. + // FileHandle = NULL; TempString = GetManFileName(ManFileName); if (TempString == NULL) { @@ -761,8 +1398,8 @@ ProcessManFile( FileDevPath = FileDevicePath(NULL, TempString); DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath); Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0); - FreePool(FileDevPath); - FreePool(DevPath); + SHELL_FREE_NON_NULL(FileDevPath); + SHELL_FREE_NON_NULL(DevPath); } if (!EFI_ERROR(Status)) { @@ -773,13 +1410,85 @@ ProcessManFile( Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii); } ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle); - } else { + if (!EFI_ERROR(Status)) { + // + // Get help text from .MAN file success. + // + goto Done; + } + } + + // + // Load the app image to check EFI_HII_PACKAGE_LIST_PROTOCOL. + // + CmdFileName = GetExecuatableFileName(TempString); + // + // If the file in CWD then use the file name, else use the full + // path name. + // + CmdFilePathName = ShellFindFilePath(CmdFileName); + if (CmdFilePathName == NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CmdFilePathName); + Status = gBS->LoadImage(FALSE, gImageHandle, DevPath, NULL, 0, &CmdFileImgHandle); + if(EFI_ERROR(Status)) { *HelpText = NULL; + goto Done; } + Status = gBS->OpenProtocol( CmdFileImgHandle, + &gEfiHiiPackageListProtocolGuid, + (VOID**)&PackageListHeader, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if(EFI_ERROR(Status)) { + *HelpText = NULL; + goto Done; + } + + // + // If get package list on image handle, find help info in it. + // + Status = ParseStringPackageList(PackageListHeader, &StrArrBuff, &StrArrBuffSize); + if (EFI_ERROR(Status)) { + goto Done; + } else { + for ( StrArrWalker = StrArrBuff; + (UINTN)(StrArrWalker - StrArrBuff) < (StrArrBuffSize)/sizeof(CHAR16); + StrArrWalker = StrArrWalker + StrLen(StrArrWalker) + 1 + ) { + // + // StrArrWalker is a string to be checked + // + Status = ManBufferFindTitleSection(&StrArrWalker, Command, BriefDesc, &BriefSize); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManBufferFindSections(StrArrWalker, Sections, HelpText, &HelpSize); + } + if (!EFI_ERROR(Status)){ + // + // Found what we need and return + // + goto Done; + } + } + } + *HelpText = NULL; } - if (TempString != NULL) { - FreePool(TempString); + +Done: + if (CmdFileImgHandle != NULL) { + Status = gBS->UnloadImage (CmdFileImgHandle); } + SHELL_FREE_NON_NULL(StrArrBuff); + SHELL_FREE_NON_NULL(TempString); + SHELL_FREE_NON_NULL(CmdFileName); + SHELL_FREE_NON_NULL(CmdFilePathName); + SHELL_FREE_NON_NULL(FileDevPath); + SHELL_FREE_NON_NULL(DevPath); return (Status); } + -- 1.9.5.msysgit.1 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

