strings.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,275 行 · 第 1/3 页

C
1,275
字号
/*++

Copyright (c) 2004 - 2005, Intel Corporation                                                         
All rights reserved. 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.             

Module Name:

  Strings.c

Abstract:

  This file contains the string processing code to the HII database.

--*/

#include "HiiDatabase.h"

VOID
AsciiToUnicode (
  IN    UINT8     *Lang,
  IN    UINT16    *Language
  )
{
  UINT8 Count;

  //
  // Convert the ASCII Lang variable to a Unicode Language variable
  //
  for (Count = 0; Count < 3; Count++) {
    Language[Count] = (CHAR16) Lang[Count];
  }
}

EFI_STATUS
EFIAPI
HiiTestString (
  IN     EFI_HII_PROTOCOL   *This,
  IN     CHAR16             *StringToTest,
  IN OUT UINT32             *FirstMissing,
  OUT    UINT32             *GlyphBufferSize
  )
/*++

Routine Description:
  Test if all of the characters in a string have corresponding font characters.
  
Arguments:

Returns: 

--*/
{
  EFI_HII_GLOBAL_DATA *GlobalData;
  EFI_HII_DATA        *HiiData;
  UINTN               Count;
  BOOLEAN             Narrow;
  UINTN               Location;
  UINT8               GlyphCol1[19];

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  HiiData     = EFI_HII_DATA_FROM_THIS (This);

  GlobalData  = HiiData->GlobalData;
  Count       = 0;
  Narrow      = TRUE;

  EfiZeroMem (GlyphCol1, sizeof (GlyphCol1));

  //
  // Walk through the string until you hit the null terminator
  //
  for (; StringToTest[*FirstMissing] != 0x00; (*FirstMissing)++) {
    Location = *FirstMissing;
    //
    // Rewind through the string looking for a glyph width identifier
    //
    for (; Location != 0; Location--) {
      if (StringToTest[Location] == NARROW_CHAR || StringToTest[Location] == WIDE_CHAR) {
        //
        // We found something that identifies what glyph database to look in
        //
        if (StringToTest[Location] == WIDE_CHAR) {
          Narrow = FALSE;
        } else {
          Narrow = TRUE;
        }
      }
    }

    if (Narrow) {
      if (EfiCompareMem (
          GlobalData->NarrowGlyphs[StringToTest[*FirstMissing]].GlyphCol1,
          &mUnknownGlyph,
          NARROW_GLYPH_ARRAY_SIZE
          ) == 0
          ) {
        //
        // Break since this glyph isn't defined
        //
        return EFI_NOT_FOUND;
      }
    } else {
      //
      // Can compare wide glyph against only GlyphCol1 since GlyphCol1 and GlyphCol2 are contiguous - just give correct size
      //
      if (EfiCompareMem (
          GlobalData->WideGlyphs[StringToTest[*FirstMissing]].GlyphCol1,
          &mUnknownGlyph,
          WIDE_GLYPH_ARRAY_SIZE
          ) == 0
          ) {
        //
        // Break since this glyph isn't defined
        //
        return EFI_NOT_FOUND;
      }
    }

    Count++;
  }

  if (Narrow) {
    *GlyphBufferSize = (UINT32) (Count * sizeof (EFI_NARROW_GLYPH));
  } else {
    *GlyphBufferSize = (UINT32) (Count * sizeof (EFI_WIDE_GLYPH));
  }

  return EFI_SUCCESS;
}

EFI_STATUS
HiiNewString2 (
  IN     EFI_HII_PROTOCOL       *This,
  IN     CHAR16                 *Language,
  IN     EFI_HII_HANDLE         Handle,
  IN OUT STRING_REF             *Reference,
  IN     CHAR16                 *NewString,
  IN     BOOLEAN                ResetStrings
  )
/*++

Routine Description:

  This function allows a new String to be added to an already existing String Package.
  We will make a buffer the size of the package + EfiStrSize of the new string.  We will
  copy the string package that first gets changed and the following language packages until
  we encounter the NULL string package.  All this time we will ensure that the offsets have
  been adjusted.  

Arguments:
  
  This         -  Pointer to the HII protocol.
  Language     -  Pointer to buffer which contains the language code of this NewString.
  Handle       -  Handle of the package instance to be processed.
  Reference    -  The token number for the string. If 0, new string token to be returned through this parameter.
  NewString    -  Buffer pointer for the new string. 
  ResetStrings -  Indicate if we are resetting a string.
  
Returns: 

  EFI_SUCCESS            - The string has been added or reset to Hii database.
  EFI_INVALID_PARAMETER  - Some parameter passed in is invalid.

--*/
{
  EFI_HII_PACKAGE_INSTANCE  *PackageInstance;
  EFI_HII_PACKAGE_INSTANCE  *StringPackageInstance;
  EFI_HII_DATA              *HiiData;
  EFI_HII_STRING_PACK       *StringPack;
  EFI_HII_STRING_PACK       *NewStringPack;
  EFI_HII_HANDLE_DATABASE   *HandleDatabase;
  EFI_HII_PACKAGE_INSTANCE  *NewBuffer;
  UINT8                     *Location;
  UINT8                     *StringLocation;
  RELOFST                   *StringPointer;
  UINTN                     Count;
  UINTN                     Size;
  UINTN                     Index;
  UINTN                     SecondIndex;
  BOOLEAN                   AddString;
  EFI_STATUS                Status;
  UINTN                     Increment;
  UINTN                     StringCount;
  UINT32                    TotalStringCount;
  UINT32                    OriginalStringCount;
  RELOFST                   StringSize;
  UINT32                    Length;
  RELOFST                   Offset;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  HiiData             = EFI_HII_DATA_FROM_THIS (This);

  HandleDatabase      = HiiData->DatabaseHead;
  PackageInstance     = NULL;
  AddString           = FALSE;
  Increment           = 0;
  StringCount         = 0;
  TotalStringCount    = 0;
  OriginalStringCount = 0;

  //
  // Check numeric value against the head of the database
  //
  for (; HandleDatabase != NULL; HandleDatabase = HandleDatabase->NextHandleDatabase) {
    //
    // Match the numeric value with the database entry - if matched, extract PackageInstance
    //
    if (Handle == HandleDatabase->Handle) {
      PackageInstance = HandleDatabase->Buffer;
      if (ResetStrings) {
        TotalStringCount = HandleDatabase->NumberOfTokens;
      }
      break;
    }
  }
  //
  // No handle was found - error condition
  //
  if (PackageInstance == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Status = ValidatePack (This, PackageInstance, &StringPackageInstance, &TotalStringCount);

  //
  // This sets Count to 0 or the size of the IfrData.  We intend to use Count as an offset value
  //
  Count = StringPackageInstance->IfrSize;

  //
  // This is the size of the complete series of string packs
  //
  Size = StringPackageInstance->StringSize;

  //
  // Based on if there is IFR data in this package instance, determine
  // what the location is of the beginning of the string data.
  //
  if (StringPackageInstance->IfrSize > 0) {
    Location = (CHAR8 *) (&StringPackageInstance->IfrData) + StringPackageInstance->IfrSize;
  } else {
    Location = (CHAR8 *) (&StringPackageInstance->IfrData);
  }
  //
  // We allocate a buffer which is big enough for both adding and resetting string.
  // The size is slightly larger than the real size of the packages when we are resetting a string.
  //
  NewBuffer = EfiLibAllocateZeroPool (
                sizeof (EFI_HII_PACKAGE_INSTANCE) -
                2 * sizeof (VOID *) +
                StringPackageInstance->IfrSize +
                StringPackageInstance->StringSize +
                sizeof (RELOFST) +
                EfiStrSize (NewString)
                );
  ASSERT (NewBuffer);

  //
  // Copy data to new buffer
  //
  NewBuffer->Handle   = StringPackageInstance->Handle;
  NewBuffer->IfrSize  = StringPackageInstance->IfrSize;

  //
  // The worst case scenario for sizing is that we are adding a new string (not replacing one) and there was not a string
  // package to begin with.
  //
  NewBuffer->StringSize = StringPackageInstance->StringSize + EfiStrSize (NewString) + sizeof (EFI_HII_STRING_PACK);

  if (StringPackageInstance->IfrSize > 0) {
    EfiCopyMem (&NewBuffer->IfrData, &StringPackageInstance->IfrData, StringPackageInstance->IfrSize);
  }

  StringPack = (EFI_HII_STRING_PACK *) Location;

  //
  // There may be multiple instances packed together of strings
  // so we must walk the self describing structures until we encounter
  // what we are looking for.  In the meantime, copy everything we encounter
  // to the new buffer.
  //
  EfiCopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
  for (; Length != 0;) {
    //
    // If passed in Language ISO value is in this string pack's language string
    // then we are dealing with the strings we want.
    //
    EfiCopyMem (&Offset, &StringPack->LanguageNameString, sizeof (RELOFST));
    Status = CompareLanguage ((CHAR16 *) ((CHAR8 *) (StringPack) + Offset), Language);

    if (!EFI_ERROR (Status)) {
      break;
    }

    EfiCopyMem (((CHAR8 *) (&NewBuffer->IfrData) + Count), StringPack, Length);

    Count       = Count + Length;
    StringPack  = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + Length);
    EfiCopyMem (&Length, &StringPack->Header.Length, sizeof (UINT32));
  }
  //
  // Found the language pack to update on a particular handle
  // We need to Copy the Contents of this pack and adjust the offset values associated
  // with adding/changing a string.  This is a particular piece of code that screams for
  // it being prone to programming error.
  //
  //
  // Copy the string package up to the string data
  //
  StringPointer = (RELOFST *) (StringPack + 1);
  EfiCopyMem (
    ((CHAR8 *) (&NewBuffer->IfrData) + Count),
    StringPack,
    (UINTN) ((UINTN) (StringPointer) - (UINTN) (StringPack))
    );

  //
  // Determine the number of StringPointers
  //
  if (!ResetStrings) {
    EfiCopyMem (&TotalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST));
  } else {
    //
    // If we are resetting the strings, use the original value when exported
    //
    EfiCopyMem (&OriginalStringCount, &StringPack->NumStringPointers, sizeof (RELOFST));
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString -=
      (
        (RELOFST) (OriginalStringCount - TotalStringCount) *
        sizeof (RELOFST)
      );
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName -=
      (
        (RELOFST) (OriginalStringCount - TotalStringCount) *
        sizeof (RELOFST)
      );
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers  = TotalStringCount;
    *Reference = (STRING_REF) (TotalStringCount);
  }
  //
  // If the token value is not valid, error out
  //
  if ((*Reference >= TotalStringCount) && !ResetStrings) {
    gBS->FreePool (NewBuffer);
    return EFI_INVALID_PARAMETER;
  }
  //
  // If Reference is 0, update it with what the new token reference will be and turn the AddString flag on
  //
  if (*Reference == 0) {
    *Reference  = (STRING_REF) (TotalStringCount);
    AddString   = TRUE;
  }

  if (AddString) {
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->LanguageNameString += sizeof (RELOFST);
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->PrintableLanguageName += sizeof (RELOFST);
    ((EFI_HII_STRING_PACK *) ((CHAR8 *) (&NewBuffer->IfrData) + Count))->NumStringPointers++;
  }
  //
  // Increment offset by amount of copied data
  //
  Count = Count + ((UINTN) (StringPointer) - (UINTN) StringPack);

  for (Index = 0; Index < TotalStringCount; Index++) {
    //
    // If we are pointing to the size of the changing string value
    // then cache the old string value so you know what the difference is
    //
    if (Index == *Reference) {
      EfiCopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));

      StringLocation = ((CHAR8 *) (StringPack) + Offset);
      for (SecondIndex = 0;
           (StringLocation[SecondIndex] != 0) || (StringLocation[SecondIndex + 1] != 0);
           SecondIndex = SecondIndex + 2
          )
        ;
      SecondIndex = SecondIndex + 2;

      Size        = SecondIndex;

      //
      // NewString is a passed in local string which is assumed to be aligned
      //
      Size = EfiStrSize (NewString) - Size;
    }
    //
    // If we are about to copy the offset of the string that follows the changed string make
    // sure that the offsets are adjusted accordingly
    //
    if ((Index > *Reference) && !ResetStrings) {
      EfiCopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));
      Offset = (RELOFST) (Offset + Size);
      EfiCopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST));
    }
    //
    // If we are adding a string that means we will have an extra string pointer that will affect all string offsets
    //
    if (AddString) {
      EfiCopyMem (&Offset, &StringPointer[Index], sizeof (RELOFST));
      Offset = (UINT32) (Offset + sizeof (RELOFST));
      EfiCopyMem (&StringPointer[Index], &Offset, sizeof (RELOFST));
    }
    //
    // If resetting the strings, we need to reduce the offset by the difference in the strings
    //
    if (ResetStrings) {
      EfiCopyMem (&Length, &StringPointer[Index], sizeof (RELOFST));
      Length = Length - ((RELOFST) (OriginalStringCount - TotalStringCount) * sizeof (RELOFST));
      EfiCopyMem (&StringPointer[Index], &Length, sizeof (RELOFST));
    }
    //

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?