[edk2-devel] [edk2-redfish-client][PATCH 4/4] RedfishClientPkg: Update Redfish feature utility library

Chang, Abner via groups.io abner.chang=amd.com at groups.io
Wed May 10 08:26:21 UTC 2023


[AMD Official Use Only - General]

Reviewed-by: Abner Chang <abner.chang at amd.com>

> -----Original Message-----
> From: Nickle Wang <nicklew at nvidia.com>
> Sent: Wednesday, May 10, 2023 4:24 PM
> To: devel at edk2.groups.io
> Cc: Chang, Abner <Abner.Chang at amd.com>; Igor Kulchytskyy
> <igork at ami.com>
> Subject: [edk2-redfish-client][PATCH 4/4] RedfishClientPkg: Update Redfish
> feature utility library
> 
> Caution: This message originated from an External Source. Use proper
> caution when opening attachments, clicking links, or responding.
> 
> 
> Update Redfish feature utility library in order to support array type
> of resource. Some helper functions are introduced to get Redfish data.
> Also expose RedfishCsCommon.h so that feature utility library can work
> with Redfish C data structure without redundant structure conversion.
> 
> Signed-off-by: Nickle Wang <nicklew at nvidia.com>
> Cc: Abner Chang <abner.chang at amd.com>
> Cc: Igor Kulchytskyy <igork at ami.com>
> ---
>  .../RedfishFeatureUtilityLib.inf              |   20 +-
>  .../Library/RedfishFeatureUtilityLib.h        |  759 +++-
>  .../RedfishJsonStructure/RedfishCsCommon.h    |   14 +
>  .../RedfishFeatureUtilityInternal.h           |   20 +-
>  .../RedfishFeatureUtilityLib.c                | 3700 +++++++++++++----
>  5 files changed, 3533 insertions(+), 980 deletions(-)
>  create mode 100644
> RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h
> 
> diff --git
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .inf
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .inf
> index f9f283fd..84f338e6 100644
> ---
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .inf
> +++
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .inf
> @@ -1,6 +1,6 @@
>  ## @file
>  #
> -#  (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> +#  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development
> LP<BR>
>  #
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -27,6 +27,7 @@
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
>    RedfishPkg/RedfishPkg.dec
>    RedfishClientPkg/RedfishClientPkg.dec
> 
> @@ -35,16 +36,25 @@
>    BaseMemoryLib
>    DebugLib
>    MemoryAllocationLib
> -  PrintLib
>    RedfishLib
>    RedfishPlatformConfigLib
>    UefiLib
>    UefiBootServicesTableLib
>    UefiRuntimeServicesTableLib
> +  PrintLib
> +  HttpLib
> 
>  [Protocols]
> -  gEdkIIRedfishETagProtocolGuid   ## CONSUMED ##
> +  gEdkIIRedfishETagProtocolGuid           ## CONSUMED ##
> +  gEdkIIRedfishConfigLangMapProtocolGuid  ## CONSUMED ##
> 
>  [Pcd]
> -  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaStringSize
> -  gEfiRedfishClientPkgTokenSpaceGuid.PcdMaxRedfishSchemaVersionSize
> +
> +[Guids]
> +
> +[BuildOptions]
> +  #
> +  # NOTE: /wd4706 disables the following Visual Studio compiler warning in
> Jansson:
> +  #       "C4706: assignment within conditional expression"
> +  #
> +  MSFT:*_*_*_CC_FLAGS = /wd4706
> diff --git a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
> b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
> index 928fa4e8..d2733476 100644
> --- a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
> +++ b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
> @@ -1,7 +1,7 @@
>  /** @file
>    This file defines the Redfish Feature Utility Library interface.
> 
> -  (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -10,8 +10,9 @@
>  #ifndef REDFISH_FEATURE_UTILITY_LIB_H_
>  #define REDFISH_FEATURE_UTILITY_LIB_H_
> 
> -#include <Protocol/EdkIIRedfishResourceConfigProtocol.h>
> -#include <Protocol/RestJsonStructure.h>
> +#include <Library/RedfishLib.h>
> +#include <Protocol/EdkIIRedfishPlatformConfig.h>
> +#include <RedfishJsonStructure/RedfishCsCommon.h>
> 
>  //
>  // Definition of REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG
> @@ -31,10 +32,10 @@ typedef struct {
> 
>  /**
> 
> -  Read redfish resource by given resource path.
> +  Read redfish resource by given resource URI.
> 
>    @param[in]  Service       Redfish srvice instacne to make query.
> -  @param[in]  ResourcePath  Target resource path.
> +  @param[in]  ResourceUri   Target resource URI.
>    @param[out] Response      HTTP response from redfish service.
> 
>    @retval     EFI_SUCCESS     Resrouce is returned successfully.
> @@ -42,12 +43,34 @@ typedef struct {
> 
>  **/
>  EFI_STATUS
> -GetResourceByPath (
> +GetResourceByUri (
>    IN  REDFISH_SERVICE   *Service,
> -  IN  CHAR8             *ResourcePath,
> +  IN  EFI_STRING        ResourceUri,
>    OUT REDFISH_RESPONSE  *Response
>    );
> 
> +/**
> +
> +  Check if this is the Redpath array. Usually the Redpath array represents
> +  the collection member. Return
> +
> +  @param[in]  ConfigureLang             The Redpath to check
> +  @param[out] ArraySignatureOpen        String to the open of array signature.
> +  @param[out] ArraySignatureClose       String to the close of array signature.
> +
> +  @retval     EFI_SUCCESS            Index is found.
> +  @retval     EFI_NOT_FOUND          The non-array configure language string is
> retured.
> +  @retval     EFI_INVALID_PARAMETER  The format of input ConfigureLang is
> wrong.
> +  @retval     Others                 Errors occur.
> +
> +**/
> +EFI_STATUS
> +IsRedpathArray (
> +  IN EFI_STRING   ConfigureLang,
> +  OUT EFI_STRING  *ArraySignatureOpen,
> +  OUT EFI_STRING  *ArraySignatureClose
> +  );
> +
>  /**
> 
>    Search HII database with given Configure Language pattern. Data is handled
> and
> @@ -72,76 +95,142 @@ RedfishFeatureGetUnifiedArrayTypeConfigureLang (
> 
>  /**
> 
> -  Get array key by parsing the URI.
> +  Clone the configure language list.
> 
> -  @param[in]  Uri     URI with array key.
> -  @param[out] ArrayKey  Array key in given URI string.
> +  @param[in]  ConfigureLangList      The source
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST.
> +  @param[out] DestConfigureLangList  The destination
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST.
> 
> -  @retval     EFI_SUCCESS         Array key is found.
> -  @retval     Others              Errors occur.
> +  @retval     EFI_SUCCESS
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied.
> +  @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -GetArraykeyFromUri (
> -  IN  CHAR8  *Uri,
> -  OUT CHAR8  **ArrayKey
> +CopyConfiglanguageList (
> +  IN   REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *SourceConfigureLangList,
> +  OUT  REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *DestConfigureLangList
>    );
> 
>  /**
> 
> -  Keep configure language with given key in UEFI variable.
> +  Get number of node from the string. Node is seperated by '/'.
> 
> -  @param[in]  Schema              Schema name.
> -  @param[in]  Version             Schema version.
> -  @param[in]  Key                 Key string.
> -  @param[in]  ConfigureLangIndex  Index value.
> +  @param[in]  NodeString             The node string to parse.
> 
> -  @retval     EFI_SUCCESS         Data is saved in UEFI variable.
> -  @retval     Others              Errors occur.
> +  @retval     UINTN                  Number of nodes in the string.
> +
> +**/
> +UINTN
> +GetNumberOfRedpathNodes (
> +  IN EFI_STRING  NodeString
> +  );
> +
> +/**
> +
> +  Get the node string by index
> +
> +  @param[in]  NodeString             The node string to parse.
> +  @param[in]  Index                  Index of the node.
> +  @param[out] EndOfNodePtr           Pointer to receive the poitner to
> +                                     the last character of node string.
> +
> +  @retval     EFI_STRING             the begining of the node string.
> +
> +**/
> +EFI_STRING
> +GetRedpathNodeByIndex (
> +  IN  EFI_STRING  NodeString,
> +  IN  UINTN       Index,
> +  OUT EFI_STRING  *EndOfNodePtr OPTIONAL
> +  );
> +
> +/**
> +
> +  Find array index from given configure language string.
> +
> +  @param[in]  ConfigureLang         Configure language string to parse.
> +  @param[out] UnifiedConfigureLang  The configure language in array.
> +  @param[out] Index                 The array index number.
> +
> +  @retval     EFI_SUCCESS            Index is found.
> +  @retval     EFI_NOT_FOUND          The non-array configure language string is
> retured.
> +  @retval     EFI_INVALID_PARAMETER  The format of input ConfigureLang is
> wrong.
> +  @retval     Others                 Errors occur.
> 
>  **/
>  EFI_STATUS
> -SetConfigureLangWithkey (
> -  IN  CHAR8  *Schema,
> -  IN  CHAR8  *Version,
> -  IN  CHAR8  *Key,
> -  IN  UINTN  ConfigureLangIndex
> +GetArrayIndexFromArrayTypeConfigureLang (
> +  IN  CHAR16  *ConfigureLang,
> +  OUT CHAR16  **UnifiedConfigureLang,
> +  OUT UINTN   *Index
>    );
> 
>  /**
> 
> -  Find configure language with input key string.
> +  Clone the configure language list.
> 
> -  @param[in]  Schema    Schema name.
> -  @param[in]  Version   Schema version.
> -  @param[in]  Property  Property name.
> -  @param[in]  Key       Key string.
> +  @param[in]  ConfigureLang      The pointer to configuration language.
> 
> -  @retval     CHAR16 *  Corresponding configure langauge
> -  @retval     NULL      No configure language is found
> +  @retval     UINTN       The index of collection member instance.
> +                          Value of 0 means no instance is found.
> +**/
> +UINTN
> +ConfiglanguageGetInstanceIndex (
> +  IN EFI_STRING  ConfigureLang
> +  );
> +
> +/**
> +
> +  Destroy the configure language list.
> +
> +  @param[in]  ConfigureLangList      The
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> +                                     instance to destroy.
> +
> +  @retval     EFI_SUCCESS
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied.
> +  @retval     Others          Errors occur.
> 
>  **/
> -CHAR16 *
> -GetConfigureLangByKey (
> -  IN  CHAR8  *Schema,
> -  IN  CHAR8  *Version,
> -  IN  CHAR8  *Property,
> -  IN  CHAR8  *Key
> +EFI_STATUS
> +DestroyConfiglanguageList (
> +  IN   REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *ConfigureLangList
>    );
> 
>  /**
> 
> -  Convert HII string value to string value in JSON format.
> +  Set the node instance.
> 
> -  @param[in]  HiiStringValue  String in HII format.
> +  @param[in]  DestConfigLang        Pointer to the node's configure language
> string.
> +                                    The memory pointed by ConfigLang must be allocated
> +                                    through memory allocation interface. Becasue we will
> replace
> +                                    the pointer in this function.
> +  @param[in]  MaxtLengthConfigLang  The maximum length of ConfigLang.
> +  @param[in]  ConfigLangInstance    Pointer to Collection member instance.
> 
> -  @retval     CHAR8 *         String in JSON format.
> -  @retval     NULL            Errors occur.
> +  @retval     EFI_SUCCESS     The instance is inserted to the configure
> language.
> +  @retval     Others          Errors occur.
> 
>  **/
> -CHAR8 *
> -ConvertHiiStringValueToJsonStringValue (
> -  IN EFI_STRING  HiiStringValue
> +EFI_STATUS
> +SetResourceConfigLangMemberInstance (
> +  IN EFI_STRING                              *DestConfigLang,
> +  IN UINTN                                   MaxtLengthConfigLang,
> +  IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG  *ConfigLangInstance
> +  );
> +
> +/**
> +
> +  Get array key by parsing the URI.
> +
> +  @param[in]  Uri     URI with array key.
> +  @param[out] ArrayKey  Array key in given URI string.
> +
> +  @retval     EFI_SUCCESS         Array key is found.
> +  @retval     Others              Errors occur.
> +
> +**/
> +EFI_STATUS
> +GetArraykeyFromUri (
> +  IN  CHAR8  *Uri,
> +  OUT CHAR8  **ArrayKey
>    );
> 
>  /**
> @@ -209,125 +298,157 @@ ApplyFeatureSettingsBooleanType (
> 
>  /**
> 
> -  Create HTTP payload and send them to redfish service with POST method.
> +  Apply property value to UEFI HII database in vague type.
> 
> -  @param[in]  Service         Redfish service.
> -  @param[in]  TargetPayload   Target payload
> -  @param[in]  Json            Data in JSON format.
> -  @param[out] Location        Returned location string from Redfish service.
> -  @param[out] Etag            Returned ETAG string from Redfish service.
> +  @param[in]  Schema          Property schema.
> +  @param[in]  Version         Property schema version.
> +  @param[in]  ConfigureLang   Configure language refers to this property.
> +  @param[in]  VagueValuePtr   Pointer of vague values to to set.
> +  @param[in]  NumVagueValues  Number of vague values.
> 
> -  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
>    @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -CreatePayloadToPostResource (
> -  IN  REDFISH_SERVICE  *Service,
> -  IN  REDFISH_PAYLOAD  *TargetPayload,
> -  IN  CHAR8            *Json,
> -  OUT CHAR8            **Location,
> -  OUT CHAR8            **Etag
> +ApplyFeatureSettingsVagueType (
> +  IN  CHAR8                         *Schema,
> +  IN  CHAR8                         *Version,
> +  IN  EFI_STRING                    ConfigureLang,
> +  IN  RedfishCS_EmptyProp_KeyValue  *VagueValuePtr,
> +  IN  UINT32                        NumberOfVagueValues
>    );
> 
>  /**
> 
> -  Create HTTP payload and send them to redfish service with PATCH method.
> +  Apply property value to UEFI HII database in string array type.
> 
> -  @param[in]  Service         Redfish service.
> -  @param[in]  TargetPayload   Target payload
> -  @param[in]  Json            Data in JSON format.
> -  @param[out] Etag            Returned ETAG string from Redfish service.
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of array value.
> 
> -  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
>    @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -CreatePayloadToPatchResource (
> -  IN  REDFISH_SERVICE  *Service,
> -  IN  REDFISH_PAYLOAD  *TargetPayload,
> -  IN  CHAR8            *Json,
> -  OUT CHAR8            **Etag
> +ApplyFeatureSettingsStringArrayType (
> +  IN  CHAR8                 *Schema,
> +  IN  CHAR8                 *Version,
> +  IN  EFI_STRING            ConfigureLang,
> +  IN  RedfishCS_char_Array  *ArrayHead
>    );
> 
>  /**
> 
> -  Find Redfish Resource Config Protocol that supports given schema and
> version.
> +  Apply property value to UEFI HII database in numeric array type (INT64).
> 
> -  @param[in]  Schema      Schema name.
> -  @param[in]  Major       Schema version major number.
> -  @param[in]  Minor       Schema version minor number.
> -  @param[in]  Errata      Schema version errata number.
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of array value.
> 
> -  @retval     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL *    Pointer to
> protocol
> -  @retval     NULL                                        No protocol found.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
> +  @retval     Others          Errors occur.
> 
>  **/
> -EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *
> -GetRedfishResourceConfigProtocol (
> -  IN  CHAR8  *Schema,
> -  IN  CHAR8  *Major,
> -  IN  CHAR8  *Minor,
> -  IN  CHAR8  *Errata
> +EFI_STATUS
> +ApplyFeatureSettingsNumericArrayType (
> +  IN  CHAR8                  *Schema,
> +  IN  CHAR8                  *Version,
> +  IN  EFI_STRING             ConfigureLang,
> +  IN  RedfishCS_int64_Array  *ArrayHead
>    );
> 
>  /**
> 
> -  Get supported schema list by given specify schema name.
> +  Apply property value to UEFI HII database in boolean array type (INT64).
> 
> -  @param[in]  Schema      Schema type name.
> -  @param[out] SchemaInfo  Returned schema information.
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of Redfich CS boolean array value.
> 
> -  @retval     EFI_SUCCESS         Schema information is returned successfully.
> -  @retval     Others              Errors occur.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
> +  @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -GetSupportedSchemaVersion (
> -  IN   CHAR8                *Schema,
> -  OUT  REDFISH_SCHEMA_INFO  *SchemaInfo
> +ApplyFeatureSettingsBooleanArrayType (
> +  IN  CHAR8                 *Schema,
> +  IN  CHAR8                 *Version,
> +  IN  EFI_STRING            ConfigureLang,
> +  IN  RedfishCS_bool_Array  *ArrayHead
>    );
> 
>  /**
> 
> -  Return system root path
> +  Create HTTP payload and send them to redfish service with POST method.
> +
> +  @param[in]  Service         Redfish service.
> +  @param[in]  TargetPayload   Target payload
> +  @param[in]  Json            Data in JSON format.
> +  @param[out] Location        Returned location string from Redfish service.
> +  @param[out] Etag            Returned ETAG string from Redfish service.
> 
> -  @retval  NULL     Can not find system root path.
> -  @retval  Other    System root path is returned.
> +  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     Others          Errors occur.
> 
>  **/
> -CHAR8 *
> -RedfishGetSystemRootPath (
> -  VOID
> +EFI_STATUS
> +CreatePayloadToPostResource (
> +  IN  REDFISH_SERVICE  *Service,
> +  IN  REDFISH_PAYLOAD  *TargetPayload,
> +  IN  CHAR8            *Json,
> +  OUT EFI_STRING       *Location,
> +  OUT CHAR8            **Etag
>    );
> 
>  /**
> 
> -  Get schema information by given protocol and service instance.
> +  Create HTTP payload and send them to redfish service with PATCH method.
> 
> -  @param[in]  RedfishService      Pointer to Redfish service instance.
> -  @param[in]  JsonStructProtocol  Json Structure protocol instance.
> -  @param[in]  Uri                 Target URI.
> -  @param[out] SchemaInfo          Returned schema information.
> +  @param[in]  Service         Redfish service.
> +  @param[in]  TargetPayload   Target payload
> +  @param[in]  Json            Data in JSON format.
> +  @param[out] Etag            Returned ETAG string from Redfish service.
> 
> -  @retval     EFI_SUCCESS         Schema information is returned successfully.
> -  @retval     Others              Errors occur.
> +  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -GetRedfishSchemaInfo (
> -  IN  REDFISH_SERVICE                   *RedfishService,
> -  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
> -  IN  CHAR8                             *Uri,
> -  OUT REDFISH_SCHEMA_INFO               *SchemaInfo
> +CreatePayloadToPatchResource (
> +  IN  REDFISH_SERVICE  *Service,
> +  IN  REDFISH_PAYLOAD  *TargetPayload,
> +  IN  CHAR8            *Json,
> +  OUT CHAR8            **Etag
> +  );
> +
> +/**
> +
> +  Save Redfish URI in database for further use.
> +
> +  @param[in]    ConfigLang        ConfigLang to save
> +  @param[in]    Uri               Redfish Uri to save
> +
> +  @retval  EFI_INVALID_PARAMETR   SystemId is NULL or EMPTY
> +  @retval  EFI_SUCCESS            Redfish uri is saved
> +
> +**/
> +EFI_STATUS
> +RedfisSetRedfishUri (
> +  IN    EFI_STRING  ConfigLang,
> +  IN    EFI_STRING  Uri
>    );
> 
>  /**
> 
>    Get the property name by given Configure Langauge.
> 
> -  @param[in]  ConfigureLang   Configure Language string.
> +  @param[in]  ResourceUri              URI of root of resource.
> +  @param[in]  ConfigureLang            Configure Language string.
> 
>    @retval     EFI_STRING      Pointer to property name.
>    @retval     NULL            There is error.
> @@ -335,6 +456,7 @@ GetRedfishSchemaInfo (
>  **/
>  EFI_STRING
>  GetPropertyFromConfigureLang (
> +  IN EFI_STRING  ResourceUri,
>    IN EFI_STRING  ConfigureLang
>    );
> 
> @@ -417,25 +539,6 @@ PropertyChecker (
>    IN BOOLEAN  ProvisionMode
>    );
> 
> -/**
> -
> -  Check and see if we need to do provisioning for this two properties.
> -
> -  @param[in]  PropertyBuffer1   Pointer to property instance 1.
> -  @param[in]  PropertyBuffer2   Pointer to property instance 2.
> -  @param[in]  ProvisionMode     TRUE if we are in provision mode. FALSE
> otherwise.
> -
> -  @retval     TRUE             Provision is required.
> -  @retval     FALSE            Provision is not required.
> -
> -**/
> -BOOLEAN
> -PropertyChecker2Parm (
> -  IN VOID     *PropertyBuffer1,
> -  IN VOID     *PropertyBuffer2,
> -  IN BOOLEAN  ProvisionMode
> -  );
> -
>  /**
> 
>    Keep ETAG string and URI string in database.
> @@ -449,8 +552,8 @@ PropertyChecker2Parm (
>  **/
>  EFI_STATUS
>  SetEtagWithUri (
> -  IN  CHAR8  *EtagStr,
> -  IN  CHAR8  *Uri
> +  IN  CHAR8       *EtagStr,
> +  IN  EFI_STRING  Uri
>    );
> 
>  /**
> @@ -465,7 +568,397 @@ SetEtagWithUri (
>  **/
>  CHAR8 *
>  GetEtagWithUri (
> -  IN  CHAR8  *Uri
> +  IN  EFI_STRING  Uri
> +  );
> +
> +/**
> +
> +  Get @odata.id from give HTTP payload. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  Payload             HTTP payload
> +
> +  @retval     NULL                Can not find @odata.id from given payload.
> +  @retval     Others              odata.id string is returned.
> +
> +**/
> +EFI_STRING
> +GetOdataId (
> +  IN  REDFISH_PAYLOAD  *Payload
> +  );
> +
> +/**
> +
> +  Return config language from given URI and prperty name. It's call
> responsibility to release returned buffer.
> +
> +  @param[in] Uri            The URI to match
> +  @param[in] PropertyName   The property name of resource. This is
> optional.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +GetConfigureLang (
> +  IN  CHAR8  *Uri,
> +  IN  CHAR8  *PropertyName   OPTIONAL
> +  );
> +
> +/**
> +
> +  Return redfish URI by given config language. It's call responsibility to
> release returned buffer.
> +
> +  @param[in]  ConfigLang    ConfigLang to search.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +RedfishGetUri (
> +  IN  EFI_STRING  ConfigLang
> +  );
> +
> +/**
> +
> +  Return config language by given URI. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  Uri   Uri to search.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +RedfishGetConfigLanguage (
> +  IN  EFI_STRING  Uri
> +  );
> +
> +/**
> +
> +  Convert Unicode string to ASCII string. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  UnicodeStr      Unicode string to convert.
> +
> +  @retval     CHAR8 *         ASCII string returned.
> +  @retval     NULL            Errors occur.
> +
> +**/
> +CHAR8 *
> +StrUnicodeToAscii (
> +  IN EFI_STRING  UnicodeStr
> +  );
> +
> +/**
> +
> +  Convert ASCII string to Unicode string. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  AsciiStr        ASCII string to convert.
> +
> +  @retval     EFI_STRING      Unicode string returned.
> +  @retval     NULL            Errors occur.
> +
> +**/
> +EFI_STRING
> +StrAsciiToUnicode (
> +  IN CHAR8  *AsciiStr
> +  );
> +
> +/**
> +
> +  Check and see if ETAG is identical to what we keep in system.
> +
> +  @param[in]  Uri           URI requested
> +  @param[in]  EtagInHeader  ETAG string returned from HTTP request.
> +  @param[in]  EtagInJson    ETAG string in JSON body.
> +
> +  @retval     TRUE          ETAG is identical.
> +  @retval     FALSE         ETAG is changed.
> +
> +**/
> +BOOLEAN
> +CheckEtag (
> +  IN EFI_STRING  Uri,
> +  IN CHAR8       *EtagInHeader,
> +  IN CHAR8       *EtagInJson
> +  );
> +
> +/**
> +
> +  Get the property string value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     CHAR8 **      Returned string array. NULL while error happens.
> +
> +**/
> +CHAR8 **
> +GetPropertyStringArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  );
> +
> +/**
> +
> +  Get the property numeric value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     INT64 **      Returned integer array. NULL while error happens.
> +
> +**/
> +INT64 *
> +GetPropertyNumericArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  );
> +
> +/**
> +
> +  Get the property boolean value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     BOOLEAN *      Returned boolean array. NULL while error
> happens.
> +
> +**/
> +BOOLEAN *
> +GetPropertyBooleanArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  );
> +
> +/**
> +
> +  Get the property value in the vague type.
> +
> +  @param[in]  Schema          Schema of this property.
> +  @param[in]  Version         Schema version.
> +  @param[in]  PropertyName    Property name.
> +  @param[in]  ConfigureLang   Configure Language of this property.
> +  @param[out] NumberOfValues  Return the number of vague type of
> values
> +
> +  @retval     RedfishCS_EmptyProp_KeyValue   The pointer to the structure
> +                                             of vague type of values.
> +
> +**/
> +RedfishCS_EmptyProp_KeyValue *
> +GetPropertyVagueValue (
> +  IN CHAR8       *Schema,
> +  IN CHAR8       *Version,
> +  IN EFI_STRING  PropertyName,
> +  IN EFI_STRING  ConfigureLang,
> +  OUT UINT32     *NumberOfValues
> +  );
> +
> +/**
> +
> +  Free the list of empty property key values.
> +
> +  @param[in]  EmptyPropKeyValueListHead  The head of
> RedfishCS_EmptyProp_KeyValue
> +
> +**/
> +VOID
> +FreeEmptyPropKeyValueList (
> +  RedfishCS_EmptyProp_KeyValue  *EmptyPropKeyValueListHead
> +  );
> +
> +/**
> +
> +  Check and see if given property is in JSON context or not
> +
> +  @param[in]  Property      Property name string
> +  @param[in]  Json          The JSON context to search.
> +
> +  @retval     TRUE          Property is found in JSON context
> +  @retval     FALSE         Property is not in JSON context
> +
> +**/
> +BOOLEAN
> +MatchPropertyWithJsonContext (
> +  IN  EFI_STRING  Property,
> +  IN  CHAR8       *Json
> +  );
> +
> +/**
> +
> +  Create string array and append to arry node in Redfish JSON convert
> format.
> +
> +  @param[in,out]  Head          The head of string array.
> +  @param[in]      StringArray   Input string array.
> +  @param[in]      ArraySize     The size of StringArray.
> +
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> +
> +**/
> +EFI_STATUS
> +AddRedfishCharArray (
> +  IN OUT  RedfishCS_char_Array  **Head,
> +  IN      CHAR8                 **StringArray,
> +  IN      UINTN                 ArraySize
> +  );
> +
> +/**
> +
> +  Create numeric array and append to arry node in Redfish JSON convert
> format.
> +
> +  @param[in,out]  Head           The head of string array.
> +  @param[in]      NumericArray   Input numeric array.
> +  @param[in]      ArraySize      The size of StringArray.
> +
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> +
> +**/
> +EFI_STATUS
> +AddRedfishNumericArray (
> +  IN OUT  RedfishCS_int64_Array  **Head,
> +  IN      INT64                  *NumericArray,
> +  IN      UINTN                  ArraySize
> +  );
> +
> +/**
> +
> +  Create boolean array and append to arry node in Redfish JSON convert
> format.
> +
> +  @param[in,out]  Head           The head of string array.
> +  @param[in]      BooleanArray   Input boolean array.
> +  @param[in]      ArraySize      The size of BooleanArray.
> +
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> +
> +**/
> +EFI_STATUS
> +AddRedfishBooleanArray (
> +  IN OUT  RedfishCS_bool_Array  **Head,
> +  IN      BOOLEAN               *BooleanArray,
> +  IN      UINTN                 ArraySize
> +  );
> +
> +/**
> +
> +  Check and see if value in Redfish string array are all the same as the one
> +  from HII configuration.
> +
> +  @param[in]  Head          The head of string array.
> +  @param[in]  StringArray   Input string array.
> +  @param[in]  ArraySize     The size of StringArray.
> +
> +  @retval     TRUE          All string in Redfish array are as same as string
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> +
> +**/
> +BOOLEAN
> +CompareRedfishStringArrayValues (
> +  IN RedfishCS_char_Array  *Head,
> +  IN CHAR8                 **StringArray,
> +  IN UINTN                 ArraySize
> +  );
> +
> +/**
> +
> +  Check and see if value in Redfish numeric array are all the same as the one
> +  from HII configuration.
> +
> +  @param[in]  Head          The head of Redfish CS numeraic array.
> +  @param[in]  NumericArray  Input numeric array.
> +  @param[in]  ArraySize     The size of NumericArray.
> +
> +  @retval     TRUE          All string in Redfish array are as same as integer
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> +
> +**/
> +BOOLEAN
> +CompareRedfishNumericArrayValues (
> +  IN RedfishCS_int64_Array  *Head,
> +  IN INT64                  *NumericArray,
> +  IN UINTN                  ArraySize
> +  );
> +
> +/**
> +
> +  Check and see if value in Redfish boolean array are all the same as the one
> +  from HII configuration.
> +
> +  @param[in]  Head          The head of Redfish CS boolean array.
> +  @param[in]  BooleanArray  Input boolean array.
> +  @param[in]  ArraySize     The size of BooleanArray.
> +
> +  @retval     TRUE          All string in Redfish array are as same as integer
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> +
> +**/
> +BOOLEAN
> +CompareRedfishBooleanArrayValues (
> +  IN RedfishCS_bool_Array  *Head,
> +  IN BOOLEAN               *BooleanArray,
> +  IN UINTN                 ArraySize
> +  );
> +
> +/**
> +
> +  Check and see if any difference between two vague value set.
> +  This is just a simple check.
> +
> +  @param[in]  RedfishVagueKeyValuePtr     The vague key value sets on
> Redfish service.
> +  @param[in]  RedfishVagueKeyValueNumber  The numebr of vague key
> value sets
> +  @param[in]  ConfigVagueKeyValuePtr      The vague configuration on
> platform.
> +  @param[in]  ConfigVagueKeyValueNumber   The numebr of vague key
> value sets
> +
> +  @retval     TRUE          All values are the same.
> +              FALSE         There is some difference.
> +
> +**/
> +BOOLEAN
> +CompareRedfishPropertyVagueValues (
> +  IN RedfishCS_EmptyProp_KeyValue  *RedfishVagueKeyValuePtr,
> +  IN UINT32                        RedfishVagueKeyValueNumber,
> +  IN RedfishCS_EmptyProp_KeyValue  *ConfigVagueKeyValuePtr,
> +  IN UINT32                        ConfigVagueKeyValueNumber
> +  );
> +
> +/**
> +
> +  Find "ETag" and "Location" from either HTTP header or Redfish response.
> +
> +  @param[in]  Response    HTTP response
> +  @param[out] Etag        String buffer to return ETag
> +  @param[out] Location    String buffer to return Location
> +
> +  @retval     EFI_SUCCESS     Data is found and returned.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +GetEtagAndLocation (
> +  IN  REDFISH_RESPONSE *Response,
> +  OUT CHAR8 **Etag, OPTIONAL
> +  OUT EFI_STRING        *Location    OPTIONAL
>    );
> 
>  #endif
> diff --git
> a/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h
> b/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h
> new file mode 100644
> index 00000000..4d0ae50f
> --- /dev/null
> +++ b/RedfishClientPkg/Include/RedfishJsonStructure/RedfishCsCommon.h
> @@ -0,0 +1,14 @@
> +/** @file
> +  Wrapper file for RedfishCsCommon.h
> +
> +  (C) Copyright 2021-2022 Hewlett Packard Enterprise Development LP<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef WRAPPER_REDFISH_CS_COMMON_H_
> +#define WRAPPER_REDFISH_CS_COMMON_H_
> +
> +#include "ConverterLib/include/RedfishCsCommon.h"
> +
> +#endif
> diff --git
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInt
> ernal.h
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInt
> ernal.h
> index 8ded4ac6..d2bd6507 100644
> ---
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInt
> ernal.h
> +++
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityInt
> ernal.h
> @@ -1,7 +1,7 @@
>  /** @file
>    Common header file for RedfishFeatureUtilityLib driver.
> 
> -  (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -11,33 +11,39 @@
>  #define REDFISH_FEATURE_INTERNAL_H_
> 
>  #include <Uefi.h>
> +#include <RedfishBase.h>
> +
> +#include <IndustryStandard/Http11.h>
> 
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/JsonLib.h>
>  #include <Library/MemoryAllocationLib.h>
> -#include <Library/PrintLib.h>
> -#include <Library/PcdLib.h>
>  #include <Library/RedfishLib.h>
>  #include <Library/RedfishFeatureUtilityLib.h>
>  #include <Library/RedfishPlatformConfigLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiRuntimeServicesTableLib.h>
>  #include <Library/UefiLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/HttpLib.h>
> 
>  #include <Guid/VariableFormat.h>
> 
>  #include <Protocol/EdkIIRedfishETagProtocol.h>
> +#include <Protocol/EdkIIRedfishConfigLangMapProtocol.h>
> 
> -#define INDEX_VARIABLE_SIZE  64
> -#define INDEX_STRING_SIZE    16
> -#define IS_EMPTY_STRING(a)  (a == NULL || a[0] == '\0')
> +#define INDEX_VARIABLE_SIZE        64
> +#define INDEX_STRING_SIZE          16
>  #define INDEX_STRING               L"{%d}"
>  #define SCHEMA_NAME_PREFIX         "x-uefi-redfish-"
>  #define SCHEMA_NAME_PREFIX_OFFSET  (AsciiStrLen
> (SCHEMA_NAME_PREFIX))
> -#define REDFISH_SYSTEM_ROOT_PATH   "/v1/Systems[UUID~%g]"
> +#define REDFISH_ROOT_PATH          "/v1"
> +#define REDFISH_ROOT_PATH_UNICODE  L"/v1"
>  #define MAX_CONF_LANG_LEN          128
> +#define MAX_REDFISH_URL_LEN        255
> +#define REGULAR_EXPRESSION_ARRAY   L"\\[.*\\]/.*"
> 
>  #define BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE
> L"{"
>  #define BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE
> L"}"
> diff --git
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .c
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .c
> index 605283b9..b93a9e18 100644
> ---
> a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .c
> +++
> b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib
> .c
> @@ -1,7 +1,7 @@
>  /** @file
>    Redfish feature utility library implementation
> 
> -  (C) Copyright 2020-2021 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2020-2022 Hewlett Packard Enterprise Development LP<BR>
> 
>    SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> @@ -9,7 +9,44 @@
> 
>  #include "RedfishFeatureUtilityInternal.h"
> 
> -EDKII_REDFISH_ETAG_PROTOCOL  *mEtagProtocol;
> +EDKII_REDFISH_ETAG_PROTOCOL             *mEtagProtocol          = NULL;
> +EDKII_REDFISH_CONFIG_LANG_MAP_PROTOCOL
> *mConfigLangMapProtocol = NULL;
> +
> +/**
> +
> +  This function locates protocol with given protocol GUID and return
> +  protocol instance back to caller.
> +
> +  @param[in,out]  ProtocolInstance  Protocol instances to keep located
> protocol.
> +  @param[in]      ProtocolGuid      Protocol GUID to locate protocol.
> +
> +  @retval     EFI_SUCCESS         Protocol is located and returned.
> +  @retval     Others              Errors occur.
> +
> +**/
> +EFI_STATUS
> +RedfishLocateProtocol (
> +  IN OUT  VOID      **ProtocolInstance,
> +  IN      EFI_GUID  *ProtocolGuid
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if ((ProtocolInstance == NULL) || (ProtocolGuid == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (*ProtocolInstance != NULL) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  ProtocolGuid,
> +                  NULL,
> +                  ProtocolInstance
> +                  );
> +  return Status;
> +}
> 
>  /**
> 
> @@ -71,228 +108,168 @@ GetArraykeyFromUri (
> 
>  /**
> 
> -  Keep configure language with given key in UEFI variable.
> +  Keep ETAG string and URI string in database.
> 
> -  @param[in]  Schema              Schema name.
> -  @param[in]  Version             Schema version.
> -  @param[in]  Key                 Key string.
> -  @param[in]  ConfigureLangIndex  Index value.
> +  @param[in]  EtagStr   ETAG string.
> +  @param[in]  Uri       URI string.
> 
> -  @retval     EFI_SUCCESS         Data is saved in UEFI variable.
> -  @retval     Others              Errors occur.
> +  @retval     EFI_SUCCESS     ETAG and URI are applied successfully.
> +  @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -SetConfigureLangWithkey (
> -  IN  CHAR8  *Schema,
> -  IN  CHAR8  *Version,
> -  IN  CHAR8  *Key,
> -  IN  UINTN  ConfigureLangIndex
> +SetEtagWithUri (
> +  IN  CHAR8       *EtagStr,
> +  IN  EFI_STRING  Uri
>    )
>  {
> -  CHAR16      IndexString[INDEX_STRING_SIZE];
> -  CHAR16      VarName[INDEX_VARIABLE_SIZE];
> -  CHAR16      *VarData;
>    EFI_STATUS  Status;
> +  CHAR8       *AsciiUri;
> 
> -  //
> -  // Variable content.
> -  //
> -  UnicodeSPrint (IndexString, sizeof (IndexString), INDEX_STRING,
> ConfigureLangIndex);
> +  if (IS_EMPTY_STRING (EtagStr) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> 
> -  //
> -  // Variable name.
> -  //
> -  UnicodeSPrint (VarName, sizeof (VarName), L"%a_%a_%a", Schema,
> Version, Key);
> +  Status = RedfishLocateProtocol ((VOID **)&mEtagProtocol,
> &gEdkIIRedfishETagProtocolGuid);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, fail to locate
> gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }
> 
> -  //
> -  // Check if it exists already.
> -  //
> -  Status = GetVariable2 (
> -             VarName,
> -             &gEfiCallerIdGuid,
> -             (VOID *)&VarData,
> -             NULL
> -             );
> -  if (!EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_INFO, "%a, remove stale data: %s\n", __FUNCTION__,
> VarData));
> -    FreePool (VarData);
> -    gRT->SetVariable (VarName, &gEfiCallerIdGuid,
> VARIABLE_ATTRIBUTE_NV_BS, 0, NULL);
> +  AsciiUri = StrUnicodeToAscii (Uri);
> +  if (AsciiUri == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
>    }
> 
> -  return gRT->SetVariable (VarName, &gEfiCallerIdGuid,
> VARIABLE_ATTRIBUTE_NV_BS, StrSize (IndexString), (VOID *)&IndexString);
> +  mEtagProtocol->Set (mEtagProtocol, AsciiUri, EtagStr);
> +  mEtagProtocol->Flush (mEtagProtocol);
> +
> +  FreePool (AsciiUri);
> +
> +  return EFI_SUCCESS;
>  }
> 
>  /**
> 
> -  Find configure language with input key string.
> +  Find ETAG string that refers to given URI.
> 
> -  @param[in]  Schema    Schema name.
> -  @param[in]  Version   Schema version.
> -  @param[in]  Property  Property name.
> -  @param[in]  Key       Key string.
> +  @param[in]  Uri       Target URI string.
> 
> -  @retval     CHAR16 *  Corresponding configure langauge
> -  @retval     NULL      No configure language is found
> +  @retval     CHAR8 *   ETAG string
> +  @retval     NULL      No ETAG is found.
> 
>  **/
> -CHAR16 *
> -GetConfigureLangByKey (
> -  IN  CHAR8 *Schema,
> -  IN  CHAR8 *Version,
> -  IN  CHAR8 *Property, OPTIONAL
> -  IN  CHAR8        *Key
> +CHAR8 *
> +GetEtagWithUri (
> +  IN  EFI_STRING  Uri
>    )
>  {
>    EFI_STATUS  Status;
> -  CHAR16      VariableName[64];
> -  UINTN       VariableSize;
> -  CHAR16      *CollectionIndex;
> -  CHAR16      *ConfigureLang;
> -  UINTN       ConfigureLangLen;
> +  CHAR8       *AsciiUri;
> +  CHAR8       *EtagStr;
> 
> -  if ((Schema == NULL) || (Version == NULL) || (Key == NULL)) {
> +  if (IS_EMPTY_STRING (Uri)) {
>      return NULL;
>    }
> 
> -  CollectionIndex = NULL;
> -  ConfigureLang   = NULL;
> -
> -  UnicodeSPrint (VariableName, 64, L"%a_%a_%a", Schema, Version, Key);
> -
> -  Status = GetVariable2 (
> -             VariableName,
> -             &gEfiCallerIdGuid,
> -             (VOID *)&CollectionIndex,
> -             &VariableSize
> -             );
> +  Status = RedfishLocateProtocol ((VOID **)&mEtagProtocol,
> &gEdkIIRedfishETagProtocolGuid);
>    if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, fail to locate
> gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status));
>      return NULL;
>    }
> 
> -  ConfigureLangLen = AsciiStrLen (Schema) + StrLen (CollectionIndex) +
> (Property == NULL ? 0 : AsciiStrLen (Property)) + 3 + 1;
> -  ConfigureLang    = AllocatePool (sizeof (CHAR16) * ConfigureLangLen);
> -  ASSERT (ConfigureLang);
> -
> -  if (Property != NULL) {
> -    UnicodeSPrint (ConfigureLang, sizeof (CHAR16) * ConfigureLangLen,
> L"/%a/%s/%a", Schema, CollectionIndex, Property);
> -  } else {
> -    UnicodeSPrint (ConfigureLang, sizeof (CHAR16) * ConfigureLangLen,
> L"/%a/%s", Schema, CollectionIndex);
> +  AsciiUri = StrUnicodeToAscii (Uri);
> +  if (AsciiUri == NULL) {
> +    return NULL;
>    }
> 
> -  FreePool (CollectionIndex);
> -
> -  return ConfigureLang;
> -}
> -
> -/**
> -
> -  Keep ETAG string and URI string in database.
> -
> -  @param[in]  EtagStr   ETAG string.
> -  @param[in]  Uri       URI string.
> -
> -  @retval     EFI_SUCCESS     ETAG and URI are applied successfully.
> -  @retval     Others          Errors occur.
> -
> -**/
> -EFI_STATUS
> -SetEtagWithUri (
> -  IN  CHAR8  *EtagStr,
> -  IN  CHAR8  *Uri
> -  )
> -{
> -  EFI_STATUS  Status;
> +  Status = mEtagProtocol->Get (mEtagProtocol, AsciiUri, &EtagStr);
> 
> -  if (IS_EMPTY_STRING (EtagStr) || IS_EMPTY_STRING (Uri)) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> +  FreePool (AsciiUri);
> 
> -  if (mEtagProtocol == NULL) {
> -    Status = gBS->LocateProtocol (
> -                    &gEdkIIRedfishETagProtocolGuid,
> -                    NULL,
> -                    (VOID **)&mEtagProtocol
> -                    );
> -    if (EFI_ERROR (Status)) {
> -      return Status;
> -    }
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
>    }
> 
> -  mEtagProtocol->Set (mEtagProtocol, Uri, EtagStr);
> -  mEtagProtocol->Flush (mEtagProtocol);
> -
> -  return EFI_SUCCESS;
> +  return EtagStr;
>  }
> 
>  /**
> 
> -  Find ETAG string that refers to given URI.
> +  Convert Unicode string to ASCII string. It's call responsibility to release
> returned buffer.
> 
> -  @param[in]  Uri       Target URI string.
> +  @param[in]  UnicodeStr      Unicode string to convert.
> 
> -  @retval     CHAR8 *   ETAG string
> -  @retval     NULL      No ETAG is found.
> +  @retval     CHAR8 *         ASCII string returned.
> +  @retval     NULL            Errors occur.
> 
>  **/
>  CHAR8 *
> -GetEtagWithUri (
> -  IN  CHAR8  *Uri
> +StrUnicodeToAscii (
> +  IN EFI_STRING  UnicodeStr
>    )
>  {
> +  CHAR8       *AsciiStr;
> +  UINTN       AsciiStrSize;
>    EFI_STATUS  Status;
> -  CHAR8       *EtagStr;
> 
> -  if (IS_EMPTY_STRING (Uri)) {
> +  if (IS_EMPTY_STRING (UnicodeStr)) {
>      return NULL;
>    }
> 
> -  if (mEtagProtocol == NULL) {
> -    Status = gBS->LocateProtocol (
> -                    &gEdkIIRedfishETagProtocolGuid,
> -                    NULL,
> -                    (VOID **)&mEtagProtocol
> -                    );
> -    if (EFI_ERROR (Status)) {
> -      return NULL;
> -    }
> +  AsciiStrSize = StrLen (UnicodeStr) + 1;
> +  AsciiStr     = AllocatePool (AsciiStrSize);
> +  if (AsciiStr == NULL) {
> +    return NULL;
>    }
> 
> -  Status = mEtagProtocol->Get (mEtagProtocol, Uri, &EtagStr);
> +  Status = UnicodeStrToAsciiStrS (UnicodeStr, AsciiStr, AsciiStrSize);
>    if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "UnicodeStrToAsciiStrS failed: %r\n", Status));
> +    FreePool (AsciiStr);
>      return NULL;
>    }
> 
> -  return EtagStr;
> +  return AsciiStr;
>  }
> 
>  /**
> 
> -  Convert HII string value to string value in JSON format.
> +  Convert ASCII string to Unicode string. It's call responsibility to release
> returned buffer.
> 
> -  @param[in]  HiiStringValue  String in HII format.
> +  @param[in]  AsciiStr        ASCII string to convert.
> 
> -  @retval     CHAR8 *         String in JSON format.
> +  @retval     EFI_STRING      Unicode string returned.
>    @retval     NULL            Errors occur.
> 
>  **/
> -CHAR8 *
> -ConvertHiiStringValueToJsonStringValue (
> -  IN EFI_STRING  HiiStringValue
> +EFI_STRING
> +StrAsciiToUnicode (
> +  IN CHAR8  *AsciiStr
>    )
>  {
> -  CHAR8  *JsonValue;
> -  UINTN  JsonValueSize;
> +  EFI_STRING  UnicodeStr;
> +  UINTN       UnicodeStrSize;
> +  EFI_STATUS  Status;
> 
> -  if (IS_EMPTY_STRING (HiiStringValue)) {
> +  if (IS_EMPTY_STRING (AsciiStr)) {
>      return NULL;
>    }
> 
> -  JsonValueSize = StrLen (HiiStringValue) + 1;
> -  JsonValue     = AllocatePool (JsonValueSize);
> -  UnicodeStrToAsciiStrS (HiiStringValue, JsonValue, JsonValueSize);
> +  UnicodeStrSize = (AsciiStrLen (AsciiStr) + 1) * sizeof (CHAR16);
> +  UnicodeStr     = AllocatePool (UnicodeStrSize);
> +  if (UnicodeStr == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = AsciiStrToUnicodeStrS (AsciiStr, UnicodeStr, UnicodeStrSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "t failed: %r\n", Status));
> +    FreePool (UnicodeStr);
> +    return NULL;
> +  }
> 
> -  return JsonValue;
> +  return UnicodeStr;
>  }
> 
>  /**
> @@ -478,51 +455,192 @@ ApplyFeatureSettingsBooleanType (
> 
>  /**
> 
> -  Read redfish resource by given resource path.
> +  Apply property value to UEFI HII database in vague type.
> 
> -  @param[in]  Service       Redfish srvice instacne to make query.
> -  @param[in]  ResourcePath  Target resource path.
> -  @param[out] Response      HTTP response from redfish service.
> +  @param[in]  Schema          Property schema.
> +  @param[in]  Version         Property schema version.
> +  @param[in]  ConfigureLang   Configure language refers to this property.
> +  @param[in]  VagueValuePtr   Pointer of vague values to to set.
> +  @param[in]  NumVagueValues  Number of vague values.
> 
> -  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
>    @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -GetResourceByPath (
> -  IN  REDFISH_SERVICE   *Service,
> -  IN  CHAR8             *ResourcePath,
> -  OUT REDFISH_RESPONSE  *Response
> +ApplyFeatureSettingsVagueType (
> +  IN  CHAR8                         *Schema,
> +  IN  CHAR8                         *Version,
> +  IN  EFI_STRING                    ConfigureLang,
> +  IN  RedfishCS_EmptyProp_KeyValue  *VagueValuePtr,
> +  IN  UINT32                        NumberOfVagueValues
>    )
>  {
> -  EFI_STATUS  Status;
> -
> -  if ((Service == NULL) || (Response == NULL) || IS_EMPTY_STRING
> (ResourcePath)) {
> +  EFI_STATUS                    Status;
> +  UINTN                         StrSize;
> +  CHAR8                         *ConfigureLangAscii;
> +  CHAR8                         *ConfigureLangKeyAscii;
> +  EFI_STRING                    ConfigureKeyLang;
> +  EDKII_REDFISH_VALUE           RedfishValue;
> +  EDKII_REDFISH_VALUE_TYPES     PropertyDatatype;
> +  RedfishCS_EmptyProp_KeyValue  *CurrentVagueValuePtr;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || (VagueValuePtr == NULL) ||
> (NumberOfVagueValues == 0)) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> -  //
> -  // Get resource from redfish service.
> -  //
> -  Status = RedfishGetByService (
> -             Service,
> -             ResourcePath,
> -             Response
> -             );
> +  ConfigureLangAscii = AllocatePool (StrLen (ConfigureLang) + 1);
> +  if (ConfigureLangAscii == NULL) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((DEBUG_ERROR, "%a, Allocate memory for generate
> ConfigureLang of vague key of %a.%a %s failed: %r\n", __FUNCTION__,
> Schema, Version, ConfigureLang, Status));
> +    return Status;
> +  }
> +
> +  Status = UnicodeStrToAsciiStrS (ConfigureLang, ConfigureLangAscii, StrLen
> (ConfigureLang) + 1);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, RedfishGetByService to %a failed: %r\n",
> __FUNCTION__, ResourcePath, Status));
> -    if (Response->Payload != NULL) {
> -      RedfishDumpPayload (Response->Payload);
> -      RedfishFreeResponse (
> -        NULL,
> -        0,
> -        NULL,
> -        Response->Payload
> -        );
> -      Response->Payload = NULL;
> +    DEBUG ((DEBUG_ERROR, "%a, Convert the configureLang of vague key of
> %a.%a %s failed: %r\n", __FUNCTION__, Schema, Version, ConfigureLang,
> Status));
> +    return Status;
> +  }
> +
> +  CurrentVagueValuePtr = VagueValuePtr;
> +  while (CurrentVagueValuePtr != NULL) {
> +    //
> +    // Generate ConfigureLang with the key name
> +    //
> +    // ConfigureKeyLang = GetConfigureLang (ConfigureLangAscii,
> CurrentVagueValuePtr->KeyNamePtr);
> +    StrSize               = AsciiStrLen (ConfigureLangAscii) + AsciiStrLen
> (CurrentVagueValuePtr->KeyNamePtr) + 2;
> +    ConfigureLangKeyAscii = AllocateZeroPool (StrSize);
> +    ConfigureKeyLang      = AllocateZeroPool (StrSize * sizeof (CHAR16));
> +    if ((ConfigureLangKeyAscii == NULL) || (ConfigureKeyLang == NULL)) {
> +      DEBUG ((DEBUG_ERROR, "%a, Generate ConfigureLang of vague key of
> %a.%a %s %a failed!\n", __FUNCTION__, Schema, Version, ConfigureLang,
> CurrentVagueValuePtr->KeyNamePtr));
> +      goto ErrorContinue;
>      }
> 
> -    return Status;
> +    AsciiStrCatS (ConfigureLangKeyAscii, StrSize, ConfigureLangAscii);
> +    AsciiStrCatS (ConfigureLangKeyAscii, StrSize, "/");
> +    AsciiStrCatS (ConfigureLangKeyAscii, StrSize, CurrentVagueValuePtr-
> >KeyNamePtr);
> +    AsciiStrToUnicodeStrS (ConfigureLangKeyAscii, ConfigureKeyLang,
> StrSize);
> +    FreePool (ConfigureLangKeyAscii);
> +    ConfigureLangKeyAscii = NULL;
> +    //
> +    // Initial property data type and value.
> +    //
> +    if (CurrentVagueValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_String) {
> +      PropertyDatatype = REDFISH_VALUE_TYPE_STRING;
> +    } else if (CurrentVagueValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_Bool) {
> +      PropertyDatatype = REDFISH_VALUE_TYPE_BOOLEAN;
> +    } else if (CurrentVagueValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_Int64) {
> +      PropertyDatatype = REDFISH_VALUE_TYPE_INTEGER;
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s Unsupported Redfish property
> data type\n", __FUNCTION__, Schema, Version, ConfigureLang));
> +      goto ErrorContinue;
> +    }
> +
> +    //
> +    // Get the current value from HII
> +    //
> +    Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureKeyLang, &RedfishValue);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__,
> Schema, Version, ConfigureKeyLang, Status));
> +    } else {
> +      if (RedfishValue.Type != PropertyDatatype) {
> +        DEBUG ((DEBUG_ERROR, "%a, %a.%a %s mismatched data type\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang));
> +        goto ErrorContinue;
> +      }
> +
> +      if (PropertyDatatype == REDFISH_VALUE_TYPE_STRING) {
> +        //
> +        // This is a string property.
> +        //
> +        if (AsciiStrCmp (CurrentVagueValuePtr->Value->DataValue.CharPtr,
> RedfishValue.Value.Buffer) != 0) {
> +          //
> +          // Apply settings from redfish
> +          //
> +          DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s from %a to %a\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang,
> RedfishValue.Value.Buffer, CurrentVagueValuePtr->Value-
> >DataValue.CharPtr));
> +          FreePool (RedfishValue.Value.Buffer);
> +          RedfishValue.Value.Buffer = CurrentVagueValuePtr->Value-
> >DataValue.CharPtr;
> +          Status                    = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureKeyLang, RedfishValue);
> +          if (EFI_ERROR (Status)) {
> +            DEBUG ((DEBUG_ERROR, "%a, apply %a to %a failed: %r\n",
> __FUNCTION__, ConfigureKeyLang, CurrentVagueValuePtr->Value-
> >DataValue.CharPtr, Status));
> +          }
> +        } else {
> +          DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: %a\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang,
> RedfishValue.Value.Buffer, Status));
> +        }
> +      } else if (PropertyDatatype == REDFISH_VALUE_TYPE_BOOLEAN) {
> +        //
> +        // This is a boolean property.
> +        //
> +        if (RedfishValue.Value.Boolean != *CurrentVagueValuePtr->Value-
> >DataValue.BoolPtr) {
> +          //
> +          // Apply settings from redfish
> +          //
> +          DEBUG ((
> +            DEBUG_INFO,
> +            "%a, %a.%a apply %s from %a to %a\n",
> +            __FUNCTION__,
> +            Schema,
> +            Version,
> +            ConfigureKeyLang,
> +            (RedfishValue.Value.Boolean ? "True" : "False"),
> +            (*CurrentVagueValuePtr->Value->DataValue.BoolPtr ? "True" :
> "False")
> +            ));
> +
> +          RedfishValue.Value.Boolean = (BOOLEAN)*CurrentVagueValuePtr-
> >Value->DataValue.BoolPtr;
> +          Status                     = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureKeyLang, RedfishValue);
> +          if (EFI_ERROR (Status)) {
> +            DEBUG ((DEBUG_ERROR, "%a, apply %s to %a failed: %r\n",
> __FUNCTION__, ConfigureKeyLang, (*CurrentVagueValuePtr->Value-
> >DataValue.BoolPtr ? "True" : "False"), Status));
> +          }
> +        } else {
> +          DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: %a\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang,
> (RedfishValue.Value.Boolean ? "True" : "False"), Status));
> +        }
> +      } else if (PropertyDatatype == REDFISH_VALUE_TYPE_INTEGER) {
> +        //
> +        // This is a integer property.
> +        //
> +        if (RedfishValue.Value.Integer != *CurrentVagueValuePtr->Value-
> >DataValue.Int64Ptr) {
> +          //
> +          // Apply settings from redfish
> +          //
> +          DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s from 0x%x to 0x%x\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang,
> RedfishValue.Value.Integer, *CurrentVagueValuePtr->Value-
> >DataValue.Int64Ptr));
> +
> +          RedfishValue.Value.Integer = (INT64)*CurrentVagueValuePtr->Value-
> >DataValue.Int64Ptr;
> +          Status                     = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureKeyLang, RedfishValue);
> +          if (EFI_ERROR (Status)) {
> +            DEBUG ((DEBUG_ERROR, "%a, apply %s to 0x%x failed: %r\n",
> __FUNCTION__, ConfigureKeyLang, *CurrentVagueValuePtr->Value-
> >DataValue.Int64Ptr, Status));
> +          }
> +        } else {
> +          DEBUG ((DEBUG_INFO, "%a, %a.%a %s value is: 0x%x\n",
> __FUNCTION__, Schema, Version, ConfigureKeyLang,
> RedfishValue.Value.Integer, Status));
> +        }
> +      } else {
> +        DEBUG ((DEBUG_ERROR, "%a, %a.%a %s Unsupported Redfish
> property data type\n", __FUNCTION__, Schema, Version, ConfigureLang));
> +        goto ErrorContinue;
> +      }
> +    }
> +
> +ErrorContinue:;
> +    if (ConfigureLangKeyAscii != NULL) {
> +      FreePool (ConfigureLangKeyAscii);
> +      ConfigureLangKeyAscii = NULL;
> +    }
> +
> +    if (ConfigureKeyLang != NULL) {
> +      FreePool (ConfigureKeyLang);
> +      ConfigureKeyLang = NULL;
> +    }
> +
> +    CurrentVagueValuePtr = CurrentVagueValuePtr->NextKeyValuePtr;
> +  }
> +
> +  if (ConfigureLangAscii != NULL) {
> +    FreePool (ConfigureLangAscii);
> +  }
> +
> +  if (ConfigureLangKeyAscii != NULL) {
> +    FreePool (ConfigureLangKeyAscii);
> +  }
> +
> +  if (ConfigureKeyLang != NULL) {
> +    FreePool (ConfigureKeyLang);
>    }
> 
>    return EFI_SUCCESS;
> @@ -530,946 +648,2858 @@ GetResourceByPath (
> 
>  /**
> 
> -  Find array index from given configure language string.
> -
> -  @param[in]  ConfigureLang         Configure language string to parse.
> -  @param[out] UnifiedConfigureLang  The configure language in array.
> -  @param[out] Index                 The array index number.
> +  Release the memory in RedfishValue while value type is array.
> 
> -  @retval     EFI_SUCCESS     Index is found.
> -  @retval     Others          Errors occur.
> +  @param[in]  RedfishValue   Pointer to Redfish value
> 
>  **/
> -EFI_STATUS
> -GetArrayIndexFromArrayTypeConfigureLang (
> -  IN  CHAR16  *ConfigureLang,
> -  OUT CHAR16  **UnifiedConfigureLang,
> -  OUT UINTN   *Index
> +VOID
> +FreeArrayTypeRedfishValue (
> +  EDKII_REDFISH_VALUE  *RedfishValue
>    )
>  {
> -  CHAR16  *TmpConfigureLang;
> -  CHAR16  *IndexString;
> -  CHAR16  *TmpString;
> -
> -  if ((ConfigureLang == NULL) || (UnifiedConfigureLang == NULL) || (Index
> == NULL)) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> +  UINTN  Index;
> 
> -  TmpConfigureLang = AllocateCopyPool (StrSize (ConfigureLang),
> ConfigureLang);
> -  if (TmpConfigureLang == NULL) {
> -    return EFI_OUT_OF_RESOURCES;
> +  if (RedfishValue == NULL) {
> +    return;
>    }
> 
> -  //
> -  // looking for index signature "{""
> -  //
> -  IndexString = StrStr (TmpConfigureLang,
> BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE);
> -  if (IndexString == NULL) {
> -    return EFI_NOT_FOUND;
> +  if ((RedfishValue->Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY) &&
> (RedfishValue->Type != REDFISH_VALUE_TYPE_STRING_ARRAY)) {
> +    return;
>    }
> 
> -  //
> -  // Skip "{"
> -  //
> -  TmpString = IndexString + StrLen
> (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE);
> -
> -  //
> -  // Looking for "}"
> -  //
> -  TmpString = StrStr (TmpString,
> BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE);
> -  if (TmpString == NULL) {
> -    return EFI_NOT_FOUND;
> -  }
> +  switch (RedfishValue->Type) {
> +    case REDFISH_VALUE_TYPE_STRING_ARRAY:
> +      for (Index = 0; Index < RedfishValue->ArrayCount; Index++) {
> +        FreePool (RedfishValue->Value.StringArray[Index]);
> +      }
> 
> -  //
> -  // Append '\0' for converting decimal string to integer.
> -  //
> -  TmpString[0] = '\0';
> +      FreePool (RedfishValue->Value.StringArray);
> +      RedfishValue->Value.StringArray = NULL;
> +      break;
> 
> -  //
> -  // Convert decimal string to integer
> -  //
> -  *Index = StrDecimalToUintn (IndexString + StrLen
> (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE));
> +    case REDFISH_VALUE_TYPE_INTEGER_ARRAY:
> +      FreePool (RedfishValue->Value.IntegerArray);
> +      RedfishValue->Value.IntegerArray = NULL;
> +      break;
> 
> -  //
> -  // Resotre the '}' character and remove rest of string.
> -  //
> -  TmpString[0] = L'}';
> -  TmpString[1] = '\0';
> +    case REDFISH_VALUE_TYPE_BOOLEAN_ARRAY:
> +      FreePool (RedfishValue->Value.BooleanArray);
> +      RedfishValue->Value.BooleanArray = NULL;
> +      break;
> 
> -  *UnifiedConfigureLang = TmpConfigureLang;
> +    default:
> +      return;
> +  }
> 
> -  return EFI_SUCCESS;
> +  RedfishValue->ArrayCount = 0;
>  }
> 
>  /**
> 
> -  Search HII database with given Configure Language pattern. Data is handled
> and
> -  returned in array.
> +  Apply property value to UEFI HII database in string array type.
> 
> -  @param[in]  Schema                    The schema to search.
> -  @param[in]  Version                   The schema version.
> -  @param[in]  Pattern                   Configure Language pattern to search.
> -  @param[out] UnifiedConfigureLangList  The data returned by HII database.
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of array value.
> 
> -  @retval     EFI_SUCCESS     Data is found and returned.
> +  @retval     EFI_SUCCESS     New value is applied successfully.
>    @retval     Others          Errors occur.
> 
>  **/
>  EFI_STATUS
> -RedfishFeatureGetUnifiedArrayTypeConfigureLang (
> -  IN     CHAR8 *Schema,
> -  IN     CHAR8 *Version,
> -  IN     EFI_STRING Pattern, OPTIONAL
> -  OUT    REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *UnifiedConfigureLangList
> +ApplyFeatureSettingsStringArrayType (
> +  IN  CHAR8                 *Schema,
> +  IN  CHAR8                 *Version,
> +  IN  EFI_STRING            ConfigureLang,
> +  IN  RedfishCS_char_Array  *ArrayHead
>    )
>  {
> -  EFI_STATUS                              Status;
> -  EFI_STRING                              *ConfigureLangList;
> -  UINTN                                   Count;
> -  UINTN                                   Index;
> -  UINTN                                   Index2;
> -  UINTN                                   ArrayIndex;
> -  EFI_STRING                              UnifiedConfigureLang;
> -  BOOLEAN                                 Duplicated;
> -  REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG
> UnifiedConfigureLangPool[BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZ
> E];
> +  EFI_STATUS            Status;
> +  EDKII_REDFISH_VALUE   RedfishValue;
> +  UINTN                 Index;
> +  RedfishCS_char_Array  *Buffer;
> 
> -  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> (UnifiedConfigureLangList == NULL)) {
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || (ArrayHead == NULL)) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> -  UnifiedConfigureLangList->Count = 0;
> -  UnifiedConfigureLangList->List  = NULL;
> -  ZeroMem (UnifiedConfigureLangPool, sizeof (UnifiedConfigureLangPool));
> -
> -  Status = RedfishPlatformConfigGetConfigureLang (Schema, Version,
> Pattern, &ConfigureLangList, &Count);
> +  //
> +  // Get the current value from HII
> +  //
> +  Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang,
> &RedfishValue);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, RedfishFeatureGetConfigureLangRegex
> failed: %r\n", __FUNCTION__, Status));
> -    return Status;
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__,
> Schema, Version, ConfigureLang, Status));
> +  } else {
> +    if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING_ARRAY) {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      return EFI_DEVICE_ERROR;
> +    }
> +
> +    //
> +    // If there is no change in array, do nothing
> +    //
> +    if (!CompareRedfishStringArrayValues (ArrayHead,
> RedfishValue.Value.StringArray, RedfishValue.ArrayCount)) {
> +      //
> +      // Apply settings from redfish
> +      //
> +      DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      FreeArrayTypeRedfishValue (&RedfishValue);
> +
> +      //
> +      // Convert array from RedfishCS_char_Array to EDKII_REDFISH_VALUE
> +      //
> +      RedfishValue.ArrayCount = 0;
> +      Buffer                  = ArrayHead;
> +      while (Buffer != NULL) {
> +        RedfishValue.ArrayCount += 1;
> +        Buffer                   = Buffer->Next;
> +      }
> +
> +      //
> +      // Allocate pool for new values
> +      //
> +      RedfishValue.Value.StringArray = AllocatePool
> (RedfishValue.ArrayCount *sizeof (CHAR8 *));
> +      if (RedfishValue.Value.StringArray == NULL) {
> +        ASSERT (FALSE);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      Buffer = ArrayHead;
> +      Index  = 0;
> +      while (Buffer != NULL) {
> +        RedfishValue.Value.StringArray[Index] = AllocateCopyPool (AsciiStrSize
> (Buffer->ArrayValue), Buffer->ArrayValue);
> +        if (RedfishValue.Value.StringArray[Index] == NULL) {
> +          ASSERT (FALSE);
> +          return EFI_OUT_OF_RESOURCES;
> +        }
> +
> +        Buffer = Buffer->Next;
> +        Index++;
> +      }
> +
> +      ASSERT (Index <= RedfishValue.ArrayCount);
> +
> +      Status = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureLang, RedfishValue);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n",
> __FUNCTION__, ConfigureLang, Status));
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    }
>    }
> 
> -  if (Count == 0) {
> -    return EFI_NOT_FOUND;
> +  return Status;
> +}
> +
> +/**
> +
> +  Apply property value to UEFI HII database in numeric array type (INT64).
> +
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of array value.
> +
> +  @retval     EFI_SUCCESS     New value is applied successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ApplyFeatureSettingsNumericArrayType (
> +  IN  CHAR8                  *Schema,
> +  IN  CHAR8                  *Version,
> +  IN  EFI_STRING             ConfigureLang,
> +  IN  RedfishCS_int64_Array  *ArrayHead
> +  )
> +{
> +  EFI_STATUS             Status;
> +  EDKII_REDFISH_VALUE    RedfishValue;
> +  UINTN                  Index;
> +  RedfishCS_int64_Array  *Buffer;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || (ArrayHead == NULL)) {
> +    return EFI_INVALID_PARAMETER;
>    }
> 
> -  for (Index = 0; Index < Count; Index++) {
> -    Status = GetArrayIndexFromArrayTypeConfigureLang
> (ConfigureLangList[Index], &UnifiedConfigureLang, &ArrayIndex);
> -    if (EFI_ERROR (Status)) {
> -      ASSERT (FALSE);
> -      continue;
> +  //
> +  // Get the current value from HII
> +  //
> +  Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang,
> &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__,
> Schema, Version, ConfigureLang, Status));
> +  } else {
> +    if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY) {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      return EFI_DEVICE_ERROR;
>      }
> 
>      //
> -    // Check if this configure language is duplicated.
> +    // If there is no change in array, do nothing
>      //
> -    Duplicated = FALSE;
> -    for (Index2 = 0; Index2 <
> BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE; Index2++) {
> -      if (UnifiedConfigureLangPool[Index2].ConfigureLang == NULL) {
> -        break;
> +    if (!CompareRedfishNumericArrayValues (ArrayHead,
> RedfishValue.Value.IntegerArray, RedfishValue.ArrayCount)) {
> +      //
> +      // Apply settings from redfish
> +      //
> +      DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      FreeArrayTypeRedfishValue (&RedfishValue);
> +
> +      //
> +      // Convert array from RedfishCS_int64_Array to EDKII_REDFISH_VALUE
> +      //
> +      RedfishValue.ArrayCount = 0;
> +      Buffer                  = ArrayHead;
> +      while (Buffer != NULL) {
> +        RedfishValue.ArrayCount += 1;
> +        Buffer                   = Buffer->Next;
>        }
> 
> -      if (StrCmp (UnifiedConfigureLangPool[Index2].ConfigureLang,
> UnifiedConfigureLang) == 0) {
> -        Duplicated = TRUE;
> -        break;
> +      //
> +      // Allocate pool for new values
> +      //
> +      RedfishValue.Value.IntegerArray = AllocatePool
> (RedfishValue.ArrayCount * sizeof (INT64));
> +      if (RedfishValue.Value.IntegerArray == NULL) {
> +        ASSERT (FALSE);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      Buffer = ArrayHead;
> +      Index  = 0;
> +      while (Buffer != NULL) {
> +        RedfishValue.Value.IntegerArray[Index] = (INT64)*Buffer->ArrayValue;
> +        Buffer                                 = Buffer->Next;
> +        Index++;
> +      }
> +
> +      ASSERT (Index <= RedfishValue.ArrayCount);
> +
> +      Status = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureLang, RedfishValue);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n",
> __FUNCTION__, ConfigureLang, Status));
>        }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
>      }
> +  }
> 
> -    if (Duplicated) {
> -      FreePool (UnifiedConfigureLang);
> -      continue;
> +  return Status;
> +}
> +
> +/**
> +
> +  Apply property value to UEFI HII database in boolean array type (INT64).
> +
> +  @param[in]  Schema        Property schema.
> +  @param[in]  Version       Property schema version.
> +  @param[in]  ConfigureLang Configure language refers to this property.
> +  @param[in]  ArrayHead     Head of Redfich CS boolean array value.
> +
> +  @retval     EFI_SUCCESS     New value is applied successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +ApplyFeatureSettingsBooleanArrayType (
> +  IN  CHAR8                 *Schema,
> +  IN  CHAR8                 *Version,
> +  IN  EFI_STRING            ConfigureLang,
> +  IN  RedfishCS_bool_Array  *ArrayHead
> +  )
> +{
> +  EFI_STATUS            Status;
> +  EDKII_REDFISH_VALUE   RedfishValue;
> +  UINTN                 Index;
> +  RedfishCS_bool_Array  *Buffer;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || (ArrayHead == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // Get the current value from HII
> +  //
> +  Status = RedfishPlatformConfigGetValue (Schema, Version, ConfigureLang,
> &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s failed: %r\n", __FUNCTION__,
> Schema, Version, ConfigureLang, Status));
> +  } else {
> +    if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN_ARRAY) {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      return EFI_DEVICE_ERROR;
>      }
> 
> -    if (UnifiedConfigureLangList->Count >=
> BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE) {
> -      FreePool (UnifiedConfigureLang);
> -      Status = EFI_BUFFER_TOO_SMALL;
> -      break;
> +    //
> +    // If there is no change in array, do nothing
> +    //
> +    if (!CompareRedfishBooleanArrayValues (ArrayHead,
> RedfishValue.Value.BooleanArray, RedfishValue.ArrayCount)) {
> +      //
> +      // Apply settings from redfish
> +      //
> +      DEBUG ((DEBUG_INFO, "%a, %a.%a apply %s for array\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +      FreeArrayTypeRedfishValue (&RedfishValue);
> +
> +      //
> +      // Convert array from RedfishCS_int64_Array to EDKII_REDFISH_VALUE
> +      //
> +      RedfishValue.ArrayCount = 0;
> +      Buffer                  = ArrayHead;
> +      while (Buffer != NULL) {
> +        RedfishValue.ArrayCount += 1;
> +        Buffer                   = Buffer->Next;
> +      }
> +
> +      //
> +      // Allocate pool for new values
> +      //
> +      RedfishValue.Value.BooleanArray = AllocatePool
> (RedfishValue.ArrayCount * sizeof (BOOLEAN));
> +      if (RedfishValue.Value.BooleanArray == NULL) {
> +        ASSERT (FALSE);
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +
> +      Buffer = ArrayHead;
> +      Index  = 0;
> +      while (Buffer != NULL) {
> +        RedfishValue.Value.BooleanArray[Index] = (BOOLEAN)*Buffer-
> >ArrayValue;
> +        Buffer                                 = Buffer->Next;
> +        Index++;
> +      }
> +
> +      ASSERT (Index <= RedfishValue.ArrayCount);
> +
> +      Status = RedfishPlatformConfigSetValue (Schema, Version,
> ConfigureLang, RedfishValue);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a, apply %s array failed: %r\n",
> __FUNCTION__, ConfigureLang, Status));
> +      }
> +    } else {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a %s array value has no change\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Read redfish resource by given resource URI.
> +
> +  @param[in]  Service       Redfish srvice instacne to make query.
> +  @param[in]  ResourceUri   Target resource URI.
> +  @param[out] Response      HTTP response from redfish service.
> +
> +  @retval     EFI_SUCCESS     Resrouce is returned successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +GetResourceByUri (
> +  IN  REDFISH_SERVICE   *Service,
> +  IN  EFI_STRING        ResourceUri,
> +  OUT REDFISH_RESPONSE  *Response
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR8       *AsciiResourceUri;
> +
> +  if ((Service == NULL) || (Response == NULL) || IS_EMPTY_STRING
> (ResourceUri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  AsciiResourceUri = StrUnicodeToAscii (ResourceUri);
> +  if (AsciiResourceUri == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Get resource from redfish service.
> +  //
> +  Status = RedfishGetByUri (
> +             Service,
> +             AsciiResourceUri,
> +             Response
> +             );
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, RedfishGetByUri to %a failed: %r\n",
> __FUNCTION__, AsciiResourceUri, Status));
> +    if (Response->Payload != NULL) {
> +      RedfishDumpPayload (Response->Payload);
> +      RedfishFreeResponse (
> +        NULL,
> +        0,
> +        NULL,
> +        Response->Payload
> +        );
> +      Response->Payload = NULL;
> +    }
> +  }
> +
> +  if (AsciiResourceUri != NULL) {
> +    FreePool (AsciiResourceUri);
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Check if this is the Redpath array. Usually the Redpath array represents
> +  the collection member. Return
> +
> +  @param[in]  ConfigureLang             The Redpath to check
> +  @param[out] ArraySignatureOpen        String to the open of array signature.
> +  @param[out] ArraySignatureClose       String to the close of array signature.
> +
> +  @retval     EFI_SUCCESS            Index is found.
> +  @retval     EFI_NOT_FOUND          The non-array configure language string is
> retured.
> +  @retval     EFI_INVALID_PARAMETER  The format of input ConfigureLang is
> wrong.
> +  @retval     Others                 Errors occur.
> +
> +**/
> +EFI_STATUS
> +IsRedpathArray (
> +  IN EFI_STRING   ConfigureLang,
> +  OUT EFI_STRING  *ArraySignatureOpen OPTIONAL,
> +  OUT EFI_STRING  *ArraySignatureClose OPTIONAL
> +  )
> +{
> +  CHAR16  *IndexString;
> +
> +  if (ConfigureLang == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (ArraySignatureOpen != NULL) {
> +    *ArraySignatureOpen = NULL;
> +  }
> +
> +  if (ArraySignatureClose != NULL) {
> +    *ArraySignatureClose = NULL;
> +  }
> +
> +  //
> +  // looking for index signature "{""
> +  //
> +  IndexString = StrStr (ConfigureLang,
> BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE);
> +  if (IndexString != NULL) {
> +    if (ArraySignatureOpen != NULL) {
> +      *ArraySignatureOpen = IndexString;
>      }
> 
>      //
> -    // New configure language. Keep it in Pool
> +    // Skip "{"
> +    //
> +    IndexString = IndexString + StrLen
> (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE);
>      //
> +    // Looking for "}"
> +    //
> +    IndexString = StrStr (IndexString,
> BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_END_SIGNATURE);
> +    if (IndexString == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    if (ArraySignatureClose != NULL) {
> +      *ArraySignatureClose = IndexString;
> +    }
> +
> +    return EFI_SUCCESS;
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +
> +  Get number of node from the string. Node is seperated by '/'.
> +
> +  @param[in]  NodeString             The node string to parse.
> +
> +  @retval     UINTN                  Number of nodes in the string.
> +
> +**/
> +UINTN
> +GetNumberOfRedpathNodes (
> +  IN EFI_STRING  NodeString
> +  )
> +{
> +  UINTN  Index;
> +  UINTN  NumberNodes;
> +  UINTN  StringLen;
> +
> +  NumberNodes = 0;
> +  StringLen   = StrLen (NodeString);
> +  Index       = 1; // ConfigLang always starts with '/'.
> +  while (Index < StringLen) {
> +    if (*(NodeString + Index) == L'/') {
> +      NumberNodes++;
> +    }
> +
> +    Index++;
> +  }
> +
> +  NumberNodes++;
> +
> +  return (NumberNodes);
> +}
> +
> +/**
> +
> +  Get the node string by index
> +
> +  @param[in]  NodeString             The node string to parse.
> +  @param[in]  Index                  Zero-based index of the node.
> +  @param[out] EndOfNodePtr           Pointer to receive the poitner to
> +                                     the last character of node string.
> +
> +  @retval     EFI_STRING             the begining of the node string.
> +
> +**/
> +EFI_STRING
> +GetRedpathNodeByIndex (
> +  IN  EFI_STRING  NodeString,
> +  IN  UINTN       Index,
> +  OUT EFI_STRING  *EndOfNodePtr OPTIONAL
> +  )
> +{
> +  UINTN       NumberNodes;
> +  UINTN       StringLen;
> +  UINTN       StringIndex;
> +  EFI_STRING  NodeStart;
> +  EFI_STRING  NodeEnd;
> +
> +  NumberNodes = 0;
> +  StringLen   = StrLen (NodeString);
> +  StringIndex = 1; // ConfigLang always starts with '/'.
> +  NodeStart   = NodeString;
> +  if (EndOfNodePtr != NULL) {
> +    *EndOfNodePtr = NULL;
> +  }
> +
> +  while (StringIndex < StringLen) {
> +    if (*(NodeString + StringIndex) == L'/') {
> +      NodeEnd = NodeString + StringIndex - 1;
> +      if (NumberNodes == Index) {
> +        if (EndOfNodePtr != NULL) {
> +          *EndOfNodePtr = NodeEnd;
> +        }
> +
> +        return NodeStart;
> +      } else {
> +        NodeStart = NodeString + StringIndex + 1;
> +      }
> +    }
> +
> +    StringIndex++;
> +  }
> +
> +  return (NULL);
> +}
> +
> +/**
> +
> +  Find array index from given configure language string.
> +
> +  @param[in]  ConfigureLang         Configure language string to parse.
> +  @param[out] UnifiedConfigureLang  The configure language in array.
> +  @param[out] Index                 The array index number.
> +
> +  @retval     EFI_SUCCESS            Index is found.
> +  @retval     EFI_NOT_FOUND          The non-array configure language string is
> retured.
> +  @retval     EFI_INVALID_PARAMETER  The format of input ConfigureLang is
> wrong.
> +  @retval     Others                 Errors occur.
> +
> +**/
> +EFI_STATUS
> +GetArrayIndexFromArrayTypeConfigureLang (
> +  IN  CHAR16  *ConfigureLang,
> +  OUT CHAR16  **UnifiedConfigureLang,
> +  OUT UINTN   *Index
> +  )
> +{
> +  EFI_STATUS  Status;
> +  CHAR16      *TmpConfigureLang;
> +  CHAR16      *ArrayOpenStr;
> +  CHAR16      *ArrayCloseStr;
> +  INTN        StringIndex;
> +
> +  if ((ConfigureLang == NULL) || (UnifiedConfigureLang == NULL) || (Index
> == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  TmpConfigureLang = AllocateCopyPool (StrSize (ConfigureLang),
> ConfigureLang);
> +  if (TmpConfigureLang == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Status = IsRedpathArray (TmpConfigureLang, &ArrayOpenStr,
> &ArrayCloseStr);
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Append '\0' for converting decimal string to integer.
> +    //
> +    ArrayCloseStr[0] = '\0';
> +
> +    //
> +    // Convert decimal string to integer
> +    //
> +    *Index = StrDecimalToUintn (ArrayOpenStr + StrLen
> (BIOS_CONFIG_TO_REDFISH_REDPATH_ARRAY_START_SIGNATURE));
> +
> +    //
> +    // Resotre the '}' character and remove rest of string.
> +    //
> +    ArrayCloseStr[0]      = L'}';
> +    ArrayCloseStr[1]      = '\0';
> +    *UnifiedConfigureLang = TmpConfigureLang;
> +  } else {
> +    if (Status == EFI_NOT_FOUND) {
> +      //
> +      // This is not the redpath array. Search "/" for the parent root.
> +      //
> +      *Index      = 0;
> +      StringIndex = StrLen (TmpConfigureLang) - 1;
> +      while (StringIndex >= 0 && *(TmpConfigureLang + StringIndex) != '/') {
> +        StringIndex--;
> +      }
> +
> +      if (StringIndex >= 0 ) {
> +        *(TmpConfigureLang + StringIndex) = '\0';
> +        *UnifiedConfigureLang             = TmpConfigureLang;
> +        Status                            = EFI_SUCCESS;
> +      } else {
> +        Status = EFI_INVALID_PARAMETER;
> +      }
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Clone the configure language list.
> +
> +  @param[in]  ConfigureLangList      The source
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST.
> +  @param[out] DestConfigureLangList  The destination
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST.
> +
> +  @retval     EFI_SUCCESS
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +CopyConfiglanguageList (
> +  IN   REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *SourceConfigureLangList,
> +  OUT  REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *DestConfigureLangList
> +  )
> +{
> +  UINTN  Index;
> +
> +  if ((SourceConfigureLangList == NULL) || (DestConfigureLangList == NULL))
> {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  DestConfigureLangList->Count = SourceConfigureLangList->Count;
> +  DestConfigureLangList->List  =
> +    (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG *)AllocateZeroPool
> (sizeof (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) *
> DestConfigureLangList->Count);
> +  if (DestConfigureLangList->List == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Fail to allocate memory for
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG.\n", __FUNCTION__));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  for (Index = 0; Index < SourceConfigureLangList->Count; Index++) {
> +    DestConfigureLangList->List[Index].Index         = SourceConfigureLangList-
> >List[Index].Index;
> +    DestConfigureLangList->List[Index].ConfigureLang =
> +      (EFI_STRING)AllocateCopyPool (StrSize (SourceConfigureLangList-
> >List[Index].ConfigureLang), (VOID *)SourceConfigureLangList-
> >List[Index].ConfigureLang);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Clone the configure language list.
> +
> +  @param[in]  ConfigureLang      The pointer to configuration language.
> +
> +  @retval     UINTN       The index of collection member instance.
> +                          Value of 0 means no instance is found.
> +**/
> +UINTN
> +ConfiglanguageGetInstanceIndex (
> +  IN EFI_STRING  ConfigureLang
> +  )
> +{
> +  INTN        LeftBracketIndex;
> +  INTN        RightBracketIndex;
> +  INTN        Index;
> +  UINT64      Instance;
> +  EFI_STATUS  Status;
> +
> +  if (ConfigureLang == NULL) {
> +    return 0;
> +  }
> +
> +  LeftBracketIndex  = 0;
> +  RightBracketIndex = 0;
> +  Index             = StrLen (ConfigureLang) - 1;
> +  while (Index >= 0) {
> +    if (*(ConfigureLang + Index) == L'{') {
> +      LeftBracketIndex = Index;
> +      break;
> +    }
> +
> +    if (*(ConfigureLang + Index) == L'}') {
> +      RightBracketIndex = Index;
> +    }
> +
> +    Index--;
> +  }
> +
> +  if ((RightBracketIndex - LeftBracketIndex) <= 1) {
> +    return 0;
> +  }
> +
> +  *(ConfigureLang + RightBracketIndex) = 0;
> +  Status                               = StrDecimalToUint64S (ConfigureLang +
> LeftBracketIndex + 1, NULL, &Instance);
> +  if (EFI_ERROR (Status)) {
> +    Instance = 0;
> +  }
> +
> +  //
> +  // Restore right curly bracket.
> +  //
> +  *(ConfigureLang + RightBracketIndex) = L'}';
> +  return (UINTN)Instance;
> +}
> +
> +/**
> +
> +  Destroy the configure language list.
> +
> +  @param[in]  ConfigureLangList      The
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> +                                     instance to destroy.
> +
> +  @retval     EFI_SUCCESS
> REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST is copied.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +DestroyConfiglanguageList (
> +  IN   REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *ConfigureLangList
> +  )
> +{
> +  UINTN  Index;
> +
> +  if (ConfigureLangList == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (ConfigureLangList->List != NULL) {
> +    for (Index = 0; Index < ConfigureLangList->Count; Index++) {
> +      if (ConfigureLangList->List[Index].ConfigureLang != NULL) {
> +        FreePool (ConfigureLangList->List[Index].ConfigureLang);
> +      }
> +    }
> +
> +    FreePool (ConfigureLangList->List);
> +    ConfigureLangList->List = NULL;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Set the node instance.
> +
> +  @param[in]  DestConfigLang        Pointer to the node's configure language
> string.
> +                                    The memory pointed by ConfigLang must be allocated
> +                                    through memory allocation interface. Becasue we will
> replace
> +                                    the pointer in this function.
> +  @param[in]  MaxtLengthConfigLang  The maximum length of ConfigLang.
> +  @param[in]  ConfigLangInstance    Pointer to Collection member instance.
> +
> +  @retval     EFI_SUCCESS     The instance is inserted to the configure
> language.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +SetResourceConfigLangMemberInstance (
> +  IN EFI_STRING                              *DestConfigLang,
> +  IN UINTN                                   MaxtLengthConfigLang,
> +  IN REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG  *ConfigLangInstance
> +  )
> +{
> +  EFI_STRING  ThisConfigLang;
> +  EFI_STRING  NewConfigLang;
> +  CHAR16      InstanceStr[10];
> +  INTN        Index;
> +  UINTN       Length;
> +  UINTN       MaxStrLength;
> +
> +  if ((DestConfigLang == NULL) || (ConfigLangInstance == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  UnicodeSPrint ((CHAR16 *)&InstanceStr, 10, L"%d", ConfigLangInstance-
> >Index);
> +
> +  ThisConfigLang = *DestConfigLang;
> +  if (ThisConfigLang[0] == 0) {
> +    //
> +    // Return ConfigLangInstance->ConfigureLang
> +    //
> +    if (ConfigLangInstance->ConfigureLang == NULL) {
> +      return EFI_INVALID_PARAMETER;
> +    } else {
> +      StrCatS (*DestConfigLang, MaxtLengthConfigLang, ConfigLangInstance-
> >ConfigureLang);
> +      return EFI_SUCCESS;
> +    }
> +  }
> +
> +  MaxStrLength  = StrSize (ThisConfigLang) + StrSize
> ((EFI_STRING)&InstanceStr);
> +  NewConfigLang = ThisConfigLang;
> +  if (MaxtLengthConfigLang < MaxStrLength) {
> +    NewConfigLang = (EFI_STRING)AllocateZeroPool (MaxStrLength);
> +    if (NewConfigLang == NULL) {
> +      DEBUG ((DEBUG_ERROR, "%a, Fail to allocate memory for
> NewConfigLang.\n", __FUNCTION__));
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +  }
> +
> +  //
> +  // Search the last "{"
> +  //
> +  Index = StrLen (ThisConfigLang) - 1;
> +  while ((ThisConfigLang[Index] != '{') && (Index >= 0)) {
> +    Index--;
> +  }
> +
> +  if (Index == -1) {
> +    if (NewConfigLang != ThisConfigLang) {
> +      FreePool (NewConfigLang);
> +    }
> +
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Copy the string to a new string.
> +  //
> +  Length = 0;
> +  while (Index >= 0) {
> +    NewConfigLang[Index] = ThisConfigLang[Index];
> +    Index--;
> +    Length++;
> +  }
> +
> +  UnicodeSPrint ((CHAR16 *)(NewConfigLang + Length), MaxStrLength,
> L"%d", ConfigLangInstance->Index);
> +  StrCatS (NewConfigLang, MaxStrLength, L"}");
> +  if (NewConfigLang != ThisConfigLang) {
> +    FreePool (ThisConfigLang);
> +  }
> +
> +  *DestConfigLang = NewConfigLang;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +
> +  Search HII database with given Configure Language pattern. Data is
> handled and
> +  returned in array.
> +
> +  @param[in]  Schema                    The schema to search.
> +  @param[in]  Version                   The schema version.
> +  @param[in]  Pattern                   Configure Language pattern to search.
> +  @param[out] UnifiedConfigureLangList  The data returned by HII database.
> +
> +  @retval     EFI_SUCCESS     Data is found and returned.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +RedfishFeatureGetUnifiedArrayTypeConfigureLang (
> +  IN     CHAR8 *Schema,
> +  IN     CHAR8 *Version,
> +  IN     EFI_STRING Pattern, OPTIONAL
> +  OUT    REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG_LIST
> *UnifiedConfigureLangList
> +  )
> +{
> +  EFI_STATUS                              Status;
> +  EFI_STRING                              *ConfigureLangList;
> +  UINTN                                   Count;
> +  UINTN                                   Index;
> +  UINTN                                   Index2;
> +  UINTN                                   ArrayIndex;
> +  EFI_STRING                              UnifiedConfigureLang;
> +  BOOLEAN                                 Duplicated;
> +  REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG
> UnifiedConfigureLangPool[BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZ
> E];
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> (UnifiedConfigureLangList == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  UnifiedConfigureLangList->Count = 0;
> +  UnifiedConfigureLangList->List  = NULL;
> +  ZeroMem (UnifiedConfigureLangPool, sizeof (UnifiedConfigureLangPool));
> +
> +  Status = RedfishPlatformConfigGetConfigureLang (Schema, Version,
> Pattern, &ConfigureLangList, &Count);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, RedfishFeatureGetConfigureLangRegex
> failed: %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }
> +
> +  if (Count == 0) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  for (Index = 0; Index < Count; Index++) {
> +    Status = GetArrayIndexFromArrayTypeConfigureLang
> (ConfigureLangList[Index], &UnifiedConfigureLang, &ArrayIndex);
> +    if (EFI_ERROR (Status) && (Status == EFI_INVALID_PARAMETER)) {
> +      ASSERT (FALSE);
> +      continue;
> +    }
> +
> +    //
> +    // Check if this configure language is duplicated.
> +    //
> +    Duplicated = FALSE;
> +    for (Index2 = 0; Index2 <
> BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE; Index2++) {
> +      if (UnifiedConfigureLangPool[Index2].ConfigureLang == NULL) {
> +        break;
> +      }
> +
> +      if (StrCmp (UnifiedConfigureLangPool[Index2].ConfigureLang,
> UnifiedConfigureLang) == 0) {
> +        Duplicated = TRUE;
> +        break;
> +      }
> +    }
> +
> +    if (Duplicated) {
> +      FreePool (UnifiedConfigureLang);
> +      continue;
> +    }
> +
> +    if (UnifiedConfigureLangList->Count >=
> BIOS_CONFIG_TO_REDFISH_REDPATH_POOL_SIZE) {
> +      FreePool (UnifiedConfigureLang);
> +      Status = EFI_BUFFER_TOO_SMALL;
> +      break;
> +    }
> +
> +    //
> +    // New configure language. Keep it in Pool
> +    //
> +
> +    UnifiedConfigureLangPool[UnifiedConfigureLangList-
> >Count].ConfigureLang = UnifiedConfigureLang;
> +    UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].Index         =
> ArrayIndex;
> +    ++UnifiedConfigureLangList->Count;
> +  }
> +
> +  FreePool (ConfigureLangList);
> +
> +  //
> +  // Prepare the result to caller.
> +  //
> +  UnifiedConfigureLangList->List = AllocateCopyPool (sizeof
> (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) *
> UnifiedConfigureLangList->Count, UnifiedConfigureLangPool);
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Find "ETag" and "Location" from either HTTP header or Redfish response.
> +
> +  @param[in]  Response    HTTP response
> +  @param[out] Etag        String buffer to return ETag
> +  @param[out] Location    String buffer to return Location
> +
> +  @retval     EFI_SUCCESS     Data is found and returned.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +GetEtagAndLocation (
> +  IN  REDFISH_RESPONSE *Response,
> +  OUT CHAR8 **Etag, OPTIONAL
> +  OUT EFI_STRING        *Location    OPTIONAL
> +  )
> +{
> +  EDKII_JSON_VALUE  JsonValue;
> +  EDKII_JSON_VALUE  OdataValue;
> +  CHAR8             *OdataString;
> +  CHAR8             *AsciiLocation;
> +  EFI_HTTP_HEADER   *Header;
> +  EFI_STATUS        Status;
> +
> +  if (Response == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if ((Etag == NULL) && (Location == NULL)) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Status = EFI_SUCCESS;
> +
> +  if (Etag != NULL) {
> +    *Etag = NULL;
> +
> +    if (*(Response->StatusCode) == HTTP_STATUS_200_OK) {
> +      Header = HttpFindHeader (Response->HeaderCount, Response-
> >Headers, HTTP_HEADER_ETAG);
> +      if (Header != NULL) {
> +        *Etag = AllocateCopyPool (AsciiStrSize (Header->FieldValue), Header-
> >FieldValue);
> +        ASSERT (*Etag != NULL);
> +      }
> +    }
> +
> +    //
> +    // No header is returned. Search payload for location.
> +    //
> +    if ((*Etag == NULL) && (Response->Payload != NULL)) {
> +      JsonValue = RedfishJsonInPayload (Response->Payload);
> +      if (JsonValue != NULL) {
> +        OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.etag");
> +        if (OdataValue != NULL) {
> +          OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue);
> +          if (OdataString != NULL) {
> +            *Etag = AllocateCopyPool (AsciiStrSize (OdataString), OdataString);
> +            ASSERT (*Etag != NULL);
> +          }
> +        }
> +
> +        JsonValueFree (JsonValue);
> +      }
> +    }
> +
> +    if (*Etag == NULL) {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  if (Location != NULL) {
> +    *Location = NULL;
> +
> +    if (*(Response->StatusCode) == HTTP_STATUS_200_OK) {
> +      Header = HttpFindHeader (Response->HeaderCount, Response-
> >Headers, HTTP_HEADER_LOCATION);
> +      if (Header != NULL) {
> +        AsciiLocation = AllocateCopyPool (AsciiStrSize (Header->FieldValue),
> Header->FieldValue);
> +        ASSERT (AsciiLocation != NULL);
> +      }
> +    }
> +
> +    //
> +    // No header is returned. Search payload for location.
> +    //
> +    if ((*Location == NULL) && (Response->Payload != NULL)) {
> +      JsonValue = RedfishJsonInPayload (Response->Payload);
> +      if (JsonValue != NULL) {
> +        OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.id");
> +        if (OdataValue != NULL) {
> +          OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue);
> +          if (OdataString != NULL) {
> +            AsciiLocation = AllocateCopyPool (AsciiStrSize (OdataString),
> OdataString);
> +            ASSERT (AsciiLocation != NULL);
> +          }
> +        }
> +
> +        JsonValueFree (JsonValue);
> +      }
> +    }
> +
> +    if (AsciiLocation != NULL) {
> +      *Location = StrAsciiToUnicode (AsciiLocation);
> +      FreePool (AsciiLocation);
> +    } else {
> +      Status = EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Create HTTP payload and send them to redfish service with PATCH method.
> +
> +  @param[in]  Service         Redfish service.
> +  @param[in]  TargetPayload   Target payload
> +  @param[in]  Json            Data in JSON format.
> +  @param[out] Etag            Returned ETAG string from Redfish service.
> +
> +  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +CreatePayloadToPatchResource (
> +  IN  REDFISH_SERVICE  *Service,
> +  IN  REDFISH_PAYLOAD  *TargetPayload,
> +  IN  CHAR8            *Json,
> +  OUT CHAR8            **Etag
> +  )
> +{
> +  REDFISH_PAYLOAD   Payload;
> +  EDKII_JSON_VALUE  ResourceJsonValue;
> +  REDFISH_RESPONSE  PostResponse;
> +  EFI_STATUS        Status;
> +
> +  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING
> (Json) || (Etag == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ResourceJsonValue = JsonLoadString (Json, 0, NULL);
> +  Payload           = RedfishCreatePayload (ResourceJsonValue, Service);
> +  if (Payload == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from
> JSON value!\n", __FUNCTION__, __LINE__));
> +    Status =  EFI_DEVICE_ERROR;
> +    goto EXIT_FREE_JSON_VALUE;
> +  }
> +
> +  ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE));
> +  Status = RedfishPatchToPayload (TargetPayload, Payload, &PostResponse);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a:%d Failed to PATCH payload to Redfish
> service.\n", __FUNCTION__, __LINE__));
> +    goto EXIT_FREE_JSON_VALUE;
> +  }
> +
> +  //
> +  // Find ETag
> +  //
> +  Status = GetEtagAndLocation (&PostResponse, Etag, NULL);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +
> +  RedfishFreeResponse (
> +    PostResponse.StatusCode,
> +    PostResponse.HeaderCount,
> +    PostResponse.Headers,
> +    PostResponse.Payload
> +    );
> +
> +EXIT_FREE_JSON_VALUE:
> +  if (Payload != NULL) {
> +    RedfishCleanupPayload (Payload);
> +  }
> +
> +  JsonValueFree (ResourceJsonValue);
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Create HTTP payload and send them to redfish service with POST method.
> +
> +  @param[in]  Service         Redfish service.
> +  @param[in]  TargetPayload   Target payload
> +  @param[in]  Json            Data in JSON format.
> +  @param[out] Location        Returned location string from Redfish service.
> +  @param[out] Etag            Returned ETAG string from Redfish service.
> +
> +  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> +  @retval     Others          Errors occur.
> +
> +**/
> +EFI_STATUS
> +CreatePayloadToPostResource (
> +  IN  REDFISH_SERVICE  *Service,
> +  IN  REDFISH_PAYLOAD  *TargetPayload,
> +  IN  CHAR8            *Json,
> +  OUT EFI_STRING       *Location,
> +  OUT CHAR8            **Etag
> +  )
> +{
> +  REDFISH_PAYLOAD   Payload;
> +  EDKII_JSON_VALUE  ResourceJsonValue;
> +  REDFISH_RESPONSE  PostResponse;
> +  EFI_STATUS        Status;
> +
> +  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING
> (Json) || (Location == NULL) || (Etag == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  ResourceJsonValue = JsonLoadString (Json, 0, NULL);
> +  Payload           = RedfishCreatePayload (ResourceJsonValue, Service);
> +  if (Payload == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from
> JSON value!\n", __FUNCTION__, __LINE__));
> +    Status =  EFI_DEVICE_ERROR;
> +    goto EXIT_FREE_JSON_VALUE;
> +  }
> +
> +  ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE));
> +  Status = RedfishPostToPayload (TargetPayload, Payload, &PostResponse);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a:%d Failed to POST Attribute Registry to
> Redfish service.\n", __FUNCTION__, __LINE__));
> +    goto EXIT_FREE_JSON_VALUE;
> +  }
> +
> +  //
> +  // per Redfish spec. the URL of new eresource will be returned in
> "Location" header.
> +  //
> +  Status = GetEtagAndLocation (&PostResponse, Etag, Location);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +
> +  RedfishFreeResponse (
> +    PostResponse.StatusCode,
> +    PostResponse.HeaderCount,
> +    PostResponse.Headers,
> +    PostResponse.Payload
> +    );
> +
> +  RedfishCleanupPayload (Payload);
> +
> +EXIT_FREE_JSON_VALUE:
> +  JsonValueFree (ResourceJsonValue);
> +
> +  return Status;
> +}
> +
> +/**
> +
> +  Return redfish URI by given config language. It's call responsibility to
> release returned buffer.
> +
> +  @param[in]  ConfigLang    ConfigLang to search.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +RedfishGetUri (
> +  IN  EFI_STRING  ConfigLang
> +  )
> +{
> +  EFI_STATUS  Status;
> +  EFI_STRING  Target;
> +  EFI_STRING  Found;
> +  EFI_STRING  TempStr;
> +  EFI_STRING  ResultStr;
> +  EFI_STRING  Head;
> +  EFI_STRING  CloseBracket;
> +  UINTN       TempStrSize;
> +  UINTN       RemainingLen;
> +  UINTN       ConfigLangLen;
> +
> +  Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol,
> &gEdkIIRedfishConfigLangMapProtocolGuid);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, fail to locate
> gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status));
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a, Get: %s\n", __FUNCTION__,
> ConfigLang));
> +
> +  CloseBracket = StrStr (ConfigLang, L"{");
> +  if (CloseBracket == NULL) {
> +    return AllocateCopyPool (StrSize (ConfigLang), ConfigLang);
> +  }
> +
> +  //
> +  // Remove leading "/v1" or "/redfish/v1" because we don't code
> +  // configure language in this way.
> +  //
> +  Head = StrStr (ConfigLang, REDFISH_ROOT_PATH_UNICODE);
> +  if (Head == NULL) {
> +    Head = ConfigLang;
> +  } else {
> +    Head += 3;
> +  }
> +
> +  ResultStr = AllocateZeroPool (sizeof (CHAR16) * MAX_REDFISH_URL_LEN);
> +  if (ResultStr == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Go though ConfigLang and replace each {} with URL
> +  //
> +  do {
> +    ConfigLangLen = StrLen (Head);
> +    Target        = CloseBracket;
> +
> +    //
> +    // Look for next ConfigLang
> +    //
> +    do {
> +      Target += 1;
> +    } while (*Target != '\0' && *Target != '}');
> +
> +    //
> +    // Invalid format. No '}' found
> +    //
> +    if (*Target == '\0') {
> +      DEBUG ((DEBUG_ERROR, "%a, invalid format: %s\n", __FUNCTION__,
> ConfigLang));
> +      return NULL;
> +    }
> +
> +    //
> +    // Copy current ConfigLang to temporary string and do a query
> +    //
> +    Target      += 1;
> +    RemainingLen = StrLen (Target);
> +    TempStrSize  = (ConfigLangLen - RemainingLen + 1) * sizeof (CHAR16);
> +    TempStr      = AllocateCopyPool (TempStrSize, Head);
> +    if (TempStr == NULL) {
> +      return NULL;
> +    }
> +
> +    TempStr[ConfigLangLen - RemainingLen] = '\0';
> +
> +    Status = mConfigLangMapProtocol->Get (
> +                                       mConfigLangMapProtocol,
> +                                       RedfishGetTypeConfigLang,
> +                                       TempStr,
> +                                       &Found
> +                                       );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a, Can not find: %s\n", __FUNCTION__,
> TempStr));
> +      return NULL;
> +    }
> +
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a, Found: %s\n", __FUNCTION__,
> Found));
> +
> +    //
> +    // Keep result in final string pool
> +    //
> +    StrCatS (ResultStr, MAX_REDFISH_URL_LEN, Found);
> +    FreePool (TempStr);
> +
> +    //
> +    // Prepare for next ConfigLang
> +    //
> +    Head         = Target;
> +    CloseBracket = StrStr (Head, L"{");
> +  } while (CloseBracket != NULL);
> +
> +  //
> +  // String which has no ConfigLang remaining
> +  //
> +  if (Head != '\0') {
> +    StrCatS (ResultStr, MAX_REDFISH_URL_LEN, Head);
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a, return: %s\n", __FUNCTION__,
> ResultStr));
> +
> +  return ResultStr;
> +}
> +
> +/**
> +
> +  Return config language by given URI. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  Uri   Uri to search.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +RedfishGetConfigLanguage (
> +  IN  EFI_STRING  Uri
> +  )
> +{
> +  EFI_STATUS  Status;
> +  EFI_STRING  ConfigLang;
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    return NULL;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a, search config lang for URI: %s\n",
> __FUNCTION__, Uri));
> +
> +  Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol,
> &gEdkIIRedfishConfigLangMapProtocolGuid);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, fail to locate
> gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status));
> +    return NULL;
> +  }
> +
> +  ConfigLang = NULL;
> +  Status     = mConfigLangMapProtocol->Get (
> +                                         mConfigLangMapProtocol,
> +                                         RedfishGetTypeUri,
> +                                         Uri,
> +                                         &ConfigLang
> +                                         );
> +
> +  return ConfigLang;
> +}
> +
> +/**
> +
> +  Return config language from given URI and prperty name. It's call
> responsibility to release returned buffer.
> +
> +  @param[in] Uri            The URI to match
> +  @param[in] PropertyName   The property name of resource. This is
> optional.
> +
> +  @retval  NULL     Can not find redfish uri.
> +  @retval  Other    redfish uri is returned.
> +
> +**/
> +EFI_STRING
> +GetConfigureLang (
> +  IN  CHAR8  *Uri,
> +  IN  CHAR8  *PropertyName   OPTIONAL
> +  )
> +{
> +  EFI_STRING  ConfigLang;
> +  UINTN       StringSize;
> +  EFI_STRING  ResultStr;
> +  EFI_STRING  UnicodeUri;
> +  EFI_STATUS  Status;
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    return NULL;
> +  }
> +
> +  StringSize = AsciiStrSize (Uri);
> +  UnicodeUri = AllocatePool (StringSize * sizeof (CHAR16));
> +  if (UnicodeUri == NULL) {
> +    return NULL;
> +  }
> +
> +  Status = AsciiStrToUnicodeStrS (Uri, UnicodeUri, StringSize);
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +
> +  ConfigLang = RedfishGetConfigLanguage (UnicodeUri);
> +  if (ConfigLang == NULL) {
> +    return NULL;
> +  }
> +
> +  if (IS_EMPTY_STRING (PropertyName)) {
> +    return ConfigLang;
> +  }
> +
> +  StringSize = StrSize (ConfigLang) + ((AsciiStrLen (PropertyName) + 1) *
> sizeof (CHAR16));
> +  ResultStr  = AllocatePool (StringSize);
> +  if (ResultStr == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ResultStr, StringSize, L"%s/%a", ConfigLang,
> PropertyName);
> +
> +  return ResultStr;
> +}
> +
> +/**
> +
> +  Save Redfish URI in database for further use.
> +
> +  @param[in]    ConfigLang        ConfigLang to save
> +  @param[in]    Uri               Redfish Uri to save
> +
> +  @retval  EFI_INVALID_PARAMETR   SystemId is NULL or EMPTY
> +  @retval  EFI_SUCCESS            Redfish uri is saved
> +
> +**/
> +EFI_STATUS
> +RedfisSetRedfishUri (
> +  IN    EFI_STRING  ConfigLang,
> +  IN    EFI_STRING  Uri
> +  )
> +{
> +  EFI_STATUS  Status;
> +
> +  if (IS_EMPTY_STRING (ConfigLang) || IS_EMPTY_STRING (Uri)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = RedfishLocateProtocol ((VOID **)&mConfigLangMapProtocol,
> &gEdkIIRedfishConfigLangMapProtocolGuid);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, fail to locate
> gEdkIIRedfishConfigLangMapProtocolGuid: %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }
> +
> +  DEBUG ((REDFISH_DEBUG_TRACE, "%a, Saved: %s -> %s\n",
> __FUNCTION__, ConfigLang, Uri));
> +
> +  return mConfigLangMapProtocol->Set (mConfigLangMapProtocol,
> ConfigLang, Uri);
> +}
> +
> +/**
> +
> +  Get @odata.id from give HTTP payload. It's call responsibility to release
> returned buffer.
> +
> +  @param[in]  Payload             HTTP payload
> +
> +  @retval     NULL                Can not find @odata.id from given payload.
> +  @retval     Others              odata.id string is returned.
> +
> +**/
> +EFI_STRING
> +GetOdataId (
> +  IN  REDFISH_PAYLOAD  *Payload
> +  )
> +{
> +  EDKII_JSON_VALUE  *JsonValue;
> +  EDKII_JSON_VALUE  *OdataId;
> +  EFI_STRING        OdataIdString;
> +
> +  if (Payload == NULL) {
> +    return NULL;
> +  }
> +
> +  JsonValue = RedfishJsonInPayload (Payload);
> +  if (!JsonValueIsObject (JsonValue)) {
> +    return NULL;
> +  }
> +
> +  OdataId = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.id");
> +  if (!JsonValueIsString (OdataId)) {
> +    return NULL;
> +  }
> +
> +  OdataIdString = JsonValueGetUnicodeString (OdataId);
> +  if (OdataIdString == NULL) {
> +    return NULL;
> +  }
> +
> +  return AllocateCopyPool (StrSize (OdataIdString), OdataIdString);
> +}
> +
> +/**
> +
> +  Get the property name by given Configure Langauge.
> +
> +  @param[in]  ResourceUri              URI of root of resource.
> +  @param[in]  ConfigureLang            Configure Language string.
> +
> +  @retval     EFI_STRING      Pointer to property name.
> +  @retval     NULL            There is error.
> +
> +**/
> +EFI_STRING
> +GetPropertyFromConfigureLang (
> +  IN EFI_STRING  ResourceUri,
> +  IN EFI_STRING  ConfigureLang
> +  )
> +{
> +  EFI_STATUS  Status;
> +  EFI_STRING  TempString;
> +
> +  if ((ConfigureLang == NULL) || (ResourceUri == NULL)) {
> +    return NULL;
> +  }
> +
> +  Status = IsRedpathArray (ConfigureLang, NULL, &TempString);
> +  if (!EFI_ERROR (Status)) {
> +    TempString += 2; // Advance two characters for '}' and '/'
> +    return TempString;
> +  }
> +
> +  if (Status != EFI_NOT_FOUND) {
> +    return NULL;
> +  }
> +
> +  //
> +  // The ConigLang has no '{}'
> +  //
> +  if (GetNumberOfRedpathNodes (ConfigureLang) == 1) {
> +    return NULL;
> +  }
> +
> +  if (GetRedpathNodeByIndex (ConfigureLang, 0, &TempString) == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Advance two characters to the starting
> +  // pointer of next node.
> +  //
> +  return TempString + 2;
> +}
> +
> +/**
> +
> +  Get the property value in string type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +
> +  @retval     CHAR8*        Pointer to the CHAR8 buffer.
> +  @retval     NULL          There is error.
> +
> +**/
> +CHAR8 *
> +GetPropertyStringValue (
> +  IN CHAR8       *Schema,
> +  IN CHAR8       *Version,
> +  IN EFI_STRING  PropertyName,
> +  IN EFI_STRING  ConfigureLang
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  CHAR8                *AsciiStringValue;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  AsciiStringValue = AllocateCopyPool (AsciiStrSize
> (RedfishValue.Value.Buffer), RedfishValue.Value.Buffer);
> +  ASSERT (AsciiStringValue != NULL);
> +
> +  return AsciiStringValue;
> +}
> +
> +/**
> +
> +  Get the property value in numeric type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +
> +  @retval     INT64*        Pointer to the INT64 value.
> +  @retval     NULL          There is error.
> +
> +**/
> +INT64 *
> +GetPropertyNumericValue (
> +  IN CHAR8       *Schema,
> +  IN CHAR8       *Version,
> +  IN EFI_STRING  PropertyName,
> +  IN EFI_STRING  ConfigureLang
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  INT64                *ResultValue;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not numeric type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  ResultValue = AllocatePool (sizeof (INT64));
> +  ASSERT (ResultValue != NULL);
> +  if (ResultValue == NULL) {
> +    return NULL;
> +  }
> +
> +  *ResultValue = RedfishValue.Value.Integer;
> +
> +  return ResultValue;
> +}
> +
> +/**
> +
> +  Get the property value in Boolean type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +
> +  @retval     BOOLEAN       Boolean value returned by this property.
> +
> +**/
> +BOOLEAN *
> +GetPropertyBooleanValue (
> +  IN CHAR8       *Schema,
> +  IN CHAR8       *Version,
> +  IN EFI_STRING  PropertyName,
> +  IN EFI_STRING  ConfigureLang
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  BOOLEAN              *ResultValue;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not boolean type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  ResultValue = AllocatePool (sizeof (BOOLEAN));
> +  ASSERT (ResultValue != NULL);
> +  if (ResultValue == NULL) {
> +    return NULL;
> +  }
> +
> +  *ResultValue = RedfishValue.Value.Boolean;
> +
> +  return ResultValue;
> +}
> +
> +/**
> +
> +  Return the last string of configure language. Any modification to returned
> +  string will change ConfigureLanguage.
> +
> +  @param[in]  ConfigureLanguage Configure language string
> +
> +  @retval     EFI_STRING        Attribute name is returned
> +  @retval     NULL              Error occurs
> +
> +**/
> +EFI_STRING
> +GetAttributeNameFromConfigLanguage (
> +  IN  EFI_STRING  ConfigureLanguage
> +  )
> +{
> +  UINTN  StringLen;
> +  UINTN  Index;
> +
> +  if (IS_EMPTY_STRING (ConfigureLanguage)) {
> +    return NULL;
> +  }
> +
> +  StringLen = StrLen (ConfigureLanguage);
> +  for (Index = StringLen - 1; Index >= 0; Index--) {
> +    if (ConfigureLanguage[Index] == '/') {
> +      return &ConfigureLanguage[Index + 1];
> +    }
> +  }
> +
> +  return NULL;
> +}
> +
> +/**
> +
> +  Get the property string value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     CHAR8 **      Returned string array. NULL while error happens.
> +
> +**/
> +CHAR8 **
> +GetPropertyStringArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  CHAR8                **StringArray;
> +  UINTN                Index;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)
> || (ArraySize == NULL)) {
> +    return NULL;
> +  }
> +
> +  *ArraySize = 0;
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING_ARRAY) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  StringArray = AllocatePool (sizeof (CHAR8 *) * RedfishValue.ArrayCount);
> +  if (StringArray == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  *ArraySize = RedfishValue.ArrayCount;
> +  for (Index = 0; Index < RedfishValue.ArrayCount; Index++) {
> +    StringArray[Index] = RedfishValue.Value.StringArray[Index];
> +  }
> +
> +  return StringArray;
> +}
> +
> +/**
> +
> +  Get the property numeric value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     INT64 *      Returned integer array. NULL while error happens.
> +
> +**/
> +INT64 *
> +GetPropertyNumericArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  INT64                *IntegerArray;
> +  UINTN                Index;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)
> || (ArraySize == NULL)) {
> +    return NULL;
> +  }
> +
> +  *ArraySize = 0;
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER_ARRAY) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  IntegerArray = AllocatePool (sizeof (INT64) * RedfishValue.ArrayCount);
> +  if (IntegerArray == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  *ArraySize = RedfishValue.ArrayCount;
> +  for (Index = 0; Index < RedfishValue.ArrayCount; Index++) {
> +    IntegerArray[Index] = RedfishValue.Value.IntegerArray[Index];
> +  }
> +
> +  return IntegerArray;
> +}
> +
> +/**
> +
> +  Get the property boolean value in array type.
> +
> +  @param[in]  Schema        Schema of this property.
> +  @param[in]  Version       Schema version.
> +  @param[in]  PropertyName  Property name.
> +  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[out] ArraySize     The size of returned array.
> +
> +  @retval     BOOLEAN *      Returned boolean array. NULL while error
> happens.
> +
> +**/
> +BOOLEAN *
> +GetPropertyBooleanArrayValue (
> +  IN  CHAR8       *Schema,
> +  IN  CHAR8       *Version,
> +  IN  EFI_STRING  PropertyName,
> +  IN  EFI_STRING  ConfigureLang,
> +  OUT UINTN       *ArraySize
> +  )
> +{
> +  EFI_STATUS           Status;
> +  EDKII_REDFISH_VALUE  RedfishValue;
> +  EFI_STRING           ConfigureLangBuffer;
> +  UINTN                BufferSize;
> +  BOOLEAN              *BooleanArray;
> +  UINTN                Index;
> +
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)
> || (ArraySize == NULL)) {
> +    return NULL;
> +  }
> +
> +  *ArraySize = 0;
> +
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> +    return NULL;
> +  }
> +
> +  if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN_ARRAY) {
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string array type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> +    return NULL;
> +  }
> +
> +  BooleanArray = AllocatePool (sizeof (INT64) * RedfishValue.ArrayCount);
> +  if (BooleanArray == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, out of resource\n", __FUNCTION__));
> +    return NULL;
> +  }
> +
> +  *ArraySize = RedfishValue.ArrayCount;
> +  for (Index = 0; Index < RedfishValue.ArrayCount; Index++) {
> +    BooleanArray[Index] = RedfishValue.Value.BooleanArray[Index];
> +  }
> +
> +  return BooleanArray;
> +}
> +
> +/**
> +
> +  Free the list of empty property key values.
> +
> +  @param[in]  EmptyPropKeyValueListHead  The head of
> RedfishCS_EmptyProp_KeyValue
> +
> +**/
> +VOID
> +FreeEmptyPropKeyValueList (
> +  RedfishCS_EmptyProp_KeyValue  *EmptyPropKeyValueListHead
> +  )
> +{
> +  RedfishCS_EmptyProp_KeyValue  *NextEmptyPropKeyValueList;
> 
> -    UnifiedConfigureLangPool[UnifiedConfigureLangList-
> >Count].ConfigureLang = UnifiedConfigureLang;
> -    UnifiedConfigureLangPool[UnifiedConfigureLangList->Count].Index         =
> ArrayIndex;
> -    ++UnifiedConfigureLangList->Count;
> -  }
> +  while (EmptyPropKeyValueListHead != NULL) {
> +    NextEmptyPropKeyValueList = EmptyPropKeyValueListHead-
> >NextKeyValuePtr;
> +    if (EmptyPropKeyValueListHead->Value->DataValue.CharPtr != NULL) {
> +      FreePool (EmptyPropKeyValueListHead->Value->DataValue.CharPtr);
> +    }
> 
> -  FreePool (ConfigureLangList);
> +    if (EmptyPropKeyValueListHead->Value != NULL) {
> +      FreePool (EmptyPropKeyValueListHead->Value);
> +    }
> 
> -  //
> -  // Prepare the result to caller.
> -  //
> -  UnifiedConfigureLangList->List = AllocateCopyPool (sizeof
> (REDFISH_FEATURE_ARRAY_TYPE_CONFIG_LANG) *
> UnifiedConfigureLangList->Count, UnifiedConfigureLangPool);
> +    if (EmptyPropKeyValueListHead->KeyNamePtr != NULL) {
> +      FreePool (EmptyPropKeyValueListHead->KeyNamePtr);
> +    }
> 
> -  return Status;
> +    FreePool (EmptyPropKeyValueListHead);
> +    EmptyPropKeyValueListHead = NextEmptyPropKeyValueList;
> +  }
>  }
> 
>  /**
> 
> -  Create HTTP payload and send them to redfish service with PATCH method.
> +  Create a new entry of RedfishCS_EmptyProp_KeyValue
> 
> -  @param[in]  Service         Redfish service.
> -  @param[in]  TargetPayload   Target payload
> -  @param[in]  Json            Data in JSON format.
> -  @param[out] Etag            Returned ETAG string from Redfish service.
> +  @param[in]  KeyName        The key name.
> +  @param[in]  RedfishValue   Redfish vale of this key.
> 
> -  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> -  @retval     Others          Errors occur.
> +* @retval     RedfishCS_EmptyProp_KeyValue   Return the new
> RedfishCS_EmptyProp_KeyValue.
> +*                                            NULL means no new entry is created.
> 
>  **/
> -EFI_STATUS
> -CreatePayloadToPatchResource (
> -  IN  REDFISH_SERVICE  *Service,
> -  IN  REDFISH_PAYLOAD  *TargetPayload,
> -  IN  CHAR8            *Json,
> -  OUT CHAR8            **Etag
> +RedfishCS_EmptyProp_KeyValue *
> +NewEmptyPropKeyValueFromRedfishValue (
> +  IN  EFI_STRING           KeyName,
> +  IN  EDKII_REDFISH_VALUE  *RedfishValue
>    )
>  {
> -  REDFISH_PAYLOAD   Payload;
> -  EDKII_JSON_VALUE  ResourceJsonValue;
> -  REDFISH_RESPONSE  PostResponse;
> -  EFI_STATUS        Status;
> -  UINTN             Index;
> -  EDKII_JSON_VALUE  JsonValue;
> -  EDKII_JSON_VALUE  OdataIdValue;
> -  CHAR8             *OdataIdString;
> -
> -  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING
> (Json) || (Etag == NULL)) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  ResourceJsonValue = JsonLoadString (Json, 0, NULL);
> -  Payload           = RedfishCreatePayload (ResourceJsonValue, Service);
> -  if (Payload == NULL) {
> -    DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from
> JSON value!\n", __FUNCTION__, __LINE__));
> -    Status =  EFI_DEVICE_ERROR;
> -    goto EXIT_FREE_JSON_VALUE;
> +  RedfishCS_EmptyProp_KeyValue  *EmptyPropKeyValue;
> +  RedfishCS_Vague               *VagueValue;
> +  RedfishCS_char                *KeyNameChar;
> +  VOID                          *Data;
> +  UINTN                         DataSize;
> +  INT32                         Bool32;
> +
> +  KeyNameChar = StrUnicodeToAscii (KeyName);
> +  if (KeyNameChar == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Failed to convert unicode to ASCII.\n",
> __FUNCTION__));
> +    return NULL;
>    }
> 
> -  ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE));
> -  Status = RedfishPatchToPayload (TargetPayload, Payload, &PostResponse);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a:%d Failed to PATCH payload to Redfish
> service.\n", __FUNCTION__, __LINE__));
> -    goto EXIT_FREE_JSON_VALUE;
> +  EmptyPropKeyValue = (RedfishCS_EmptyProp_KeyValue
> *)AllocateZeroPool (sizeof (RedfishCS_EmptyProp_KeyValue));
> +  if (EmptyPropKeyValue == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for
> EmptyPropKeyValue\n", __FUNCTION__));
> +    return NULL;
>    }
> 
> -  //
> -  // Keep etag.
> -  //
> -  *Etag = NULL;
> -  if (*PostResponse.StatusCode == HTTP_STATUS_200_OK) {
> -    if (PostResponse.HeaderCount != 0) {
> -      for (Index = 0; Index < PostResponse.HeaderCount; Index++) {
> -        if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName, "ETag", 4)
> == 0) {
> -          *Etag = AllocateCopyPool (AsciiStrSize
> (PostResponse.Headers[Index].FieldValue),
> PostResponse.Headers[Index].FieldValue);
> -        }
> -      }
> -    } else if (PostResponse.Payload != NULL) {
> -      //
> -      // No header is returned. Search payload for location.
> -      //
> -      JsonValue = RedfishJsonInPayload (PostResponse.Payload);
> -      if (JsonValue != NULL) {
> -        OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.etag");
> -        if (OdataIdValue != NULL) {
> -          OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue);
> -          if (OdataIdString != NULL) {
> -            *Etag = AllocateCopyPool (AsciiStrSize (OdataIdString), OdataIdString);
> -          }
> -        }
> -      }
> -    }
> +  VagueValue = (RedfishCS_Vague *)AllocateZeroPool (sizeof
> (RedfishCS_Vague));
> +  if (VagueValue == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for
> VagueValue\n", __FUNCTION__));
> +    FreePool (EmptyPropKeyValue);
> +    return NULL;
>    }
> 
> -  RedfishFreeResponse (
> -    PostResponse.StatusCode,
> -    PostResponse.HeaderCount,
> -    PostResponse.Headers,
> -    PostResponse.Payload
> -    );
> -
> -EXIT_FREE_JSON_VALUE:
> -  if (Payload != NULL) {
> -    RedfishCleanupPayload (Payload);
> +  if (RedfishValue->Type == REDFISH_VALUE_TYPE_BOOLEAN) {
> +    VagueValue->DataType = RedfishCS_Vague_DataType_Bool;
> +    DataSize             = sizeof (BOOLEAN);
> +    //
> +    // Redfish JSON to C strcuture converter uses
> +    // "int" for the BOOLEAN.
> +    //
> +    Bool32 = (INT32)RedfishValue->Value.Boolean;
> +    Data   = (VOID *)&Bool32;
> +  } else if (RedfishValue->Type == REDFISH_VALUE_TYPE_INTEGER) {
> +    VagueValue->DataType = RedfishCS_Vague_DataType_Int64;
> +    DataSize             = sizeof (INT64);
> +    Data                 = (VOID *)&RedfishValue->Value.Integer;
> +  } else if (RedfishValue->Type == REDFISH_VALUE_TYPE_STRING) {
> +    VagueValue->DataType = RedfishCS_Vague_DataType_String;
> +    DataSize             = AsciiStrSize (RedfishValue->Value.Buffer);
> +    Data                 = (VOID *)RedfishValue->Value.Buffer;
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "%a, wrong type of RedfishValue: %x\n",
> __FUNCTION__, RedfishValue->Type));
> +    FreePool (VagueValue);
> +    FreePool (EmptyPropKeyValue);
> +    return NULL;
>    }
> 
> -  JsonValueFree (ResourceJsonValue);
> -
> -  return Status;
> +  VagueValue->DataValue.CharPtr = (RedfishCS_char *)AllocateCopyPool
> (DataSize, Data);
> +  EmptyPropKeyValue->Value      = VagueValue;
> +  EmptyPropKeyValue->KeyNamePtr = KeyNameChar;
> +  return EmptyPropKeyValue;
>  }
> 
>  /**
> 
> -  Create HTTP payload and send them to redfish service with POST method.
> +  Get the property value in the vague type.
> 
> -  @param[in]  Service         Redfish service.
> -  @param[in]  TargetPayload   Target payload
> -  @param[in]  Json            Data in JSON format.
> -  @param[out] Location        Returned location string from Redfish service.
> -  @param[out] Etag            Returned ETAG string from Redfish service.
> +  @param[in]  Schema          Schema of this property.
> +  @param[in]  Version         Schema version.
> +  @param[in]  PropertyName    Property name.
> +  @param[in]  ConfigureLang   Configure Language of this property.
> +  @param[out] NumberOfValues  Return the number of vague type of
> values
> 
> -  @retval     EFI_SUCCESS     Data is sent to redfish service successfully.
> -  @retval     Others          Errors occur.
> +  @retval     RedfishCS_EmptyProp_KeyValue   The pointer to the structure
> +                                             of vague type of values.
> 
>  **/
> -EFI_STATUS
> -CreatePayloadToPostResource (
> -  IN  REDFISH_SERVICE  *Service,
> -  IN  REDFISH_PAYLOAD  *TargetPayload,
> -  IN  CHAR8            *Json,
> -  OUT CHAR8            **Location,
> -  OUT CHAR8            **Etag
> +RedfishCS_EmptyProp_KeyValue *
> +GetPropertyVagueValue (
> +  IN CHAR8       *Schema,
> +  IN CHAR8       *Version,
> +  IN EFI_STRING  PropertyName,
> +  IN EFI_STRING  ConfigureLang,
> +  OUT UINT32     *NumberOfValues
>    )
>  {
> -  REDFISH_PAYLOAD   Payload;
> -  EDKII_JSON_VALUE  ResourceJsonValue;
> -  REDFISH_RESPONSE  PostResponse;
> -  EFI_STATUS        Status;
> -  UINTN             Index;
> -  EDKII_JSON_VALUE  JsonValue;
> -  EDKII_JSON_VALUE  OdataIdValue;
> -  CHAR8             *OdataIdString;
> +  EFI_STATUS                    Status;
> +  RedfishCS_EmptyProp_KeyValue  *EmptyPropKeyValueList;
> +  RedfishCS_EmptyProp_KeyValue  *PreEmptyPropKeyValueList;
> +  RedfishCS_EmptyProp_KeyValue  *FirstEmptyPropKeyValueList;
> +  EDKII_REDFISH_VALUE           RedfishValue;
> +  EFI_STRING                    ConfigureLangBuffer;
> +  EFI_STRING                    KeyName;
> +  EFI_STRING                    *ConfigureLangList;
> +  EFI_STRING                    SearchPattern;
> +  UINTN                         BufferSize;
> +  UINTN                         ConfigListCount;
> +  UINTN                         ConfigListCountIndex;
> 
> -  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING
> (Json) || (Location == NULL) || (Etag == NULL)) {
> -    return EFI_INVALID_PARAMETER;
> +  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> +    return NULL;
>    }
> 
> -  ResourceJsonValue = JsonLoadString (Json, 0, NULL);
> -  Payload           = RedfishCreatePayload (ResourceJsonValue, Service);
> -  if (Payload == NULL) {
> -    DEBUG ((DEBUG_ERROR, "%a:%d Failed to create JSON payload from
> JSON value!\n", __FUNCTION__, __LINE__));
> -    Status =  EFI_DEVICE_ERROR;
> -    goto EXIT_FREE_JSON_VALUE;
> +  //
> +  // Configure Language buffer.
> +  //
> +  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> +  ConfigureLangBuffer = AllocatePool (BufferSize);
> +  if (ConfigureLangBuffer == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for
> ConfigureLangBuffer\n", __FUNCTION__));
> +    return NULL;
>    }
> 
> -  ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE));
> -  Status = RedfishPostToPayload (TargetPayload, Payload, &PostResponse);
> +  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> +
> +  //
> +  // Initial search pattern
> +  //
> +  BufferSize    = (StrLen (ConfigureLangBuffer) + StrLen (L"/.*") + 1) * sizeof
> (CHAR16); // Increase one for the NULL terminator.
> +  SearchPattern = AllocatePool (BufferSize);
> +  if (SearchPattern == NULL) {
> +    DEBUG ((DEBUG_ERROR, "%a, Failed to allocate memory for
> SearchPattern\n", __FUNCTION__));
> +    FreePool (ConfigureLangBuffer);
> +    return NULL;
> +  }
> +
> +  BufferSize = BufferSize / sizeof (CHAR16);
> +  StrCpyS (SearchPattern, BufferSize, ConfigureLangBuffer);
> +  StrCatS (SearchPattern, BufferSize, L"/.*");
> +  Status = RedfishPlatformConfigGetConfigureLang (Schema, Version,
> SearchPattern, &ConfigureLangList, &ConfigListCount);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a:%d Failed to POST Attribute Registry to
> Redfish service.\n", __FUNCTION__, __LINE__));
> -    goto EXIT_FREE_JSON_VALUE;
> +    DEBUG ((DEBUG_ERROR, "%a, %a.%a Get configure language of vague
> type values of %s failed: %r\n", __FUNCTION__, Schema, Version,
> ConfigureLangBuffer, Status));
> +    goto ErrorLeave;
>    }
> 
>    //
> -  // per Redfish spec. the URL of new eresource will be returned in
> "Location" header.
> +  // Build up the list of RedfishCS_EmptyProp_KeyValue.
>    //
> -  *Location = NULL;
> -  *Etag     = NULL;
> -  if (*PostResponse.StatusCode == HTTP_STATUS_200_OK) {
> -    if (PostResponse.HeaderCount != 0) {
> -      for (Index = 0; Index < PostResponse.HeaderCount; Index++) {
> -        if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName, "Location",
> 8) == 0) {
> -          *Location = AllocateCopyPool (AsciiStrSize
> (PostResponse.Headers[Index].FieldValue),
> PostResponse.Headers[Index].FieldValue);
> -        } else if (AsciiStrnCmp (PostResponse.Headers[Index].FieldName,
> "ETag", 4) == 0) {
> -          *Etag = AllocateCopyPool (AsciiStrSize
> (PostResponse.Headers[Index].FieldValue),
> PostResponse.Headers[Index].FieldValue);
> -        }
> -      }
> -    } else if (PostResponse.Payload != NULL) {
> -      //
> -      // No header is returned. Search payload for location.
> -      //
> -      JsonValue = RedfishJsonInPayload (PostResponse.Payload);
> -      if (JsonValue != NULL) {
> -        OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.id");
> -        if (OdataIdValue != NULL) {
> -          OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue);
> -          if (OdataIdString != NULL) {
> -            *Location = AllocateCopyPool (AsciiStrSize (OdataIdString),
> OdataIdString);
> -          }
> -        }
> +  ConfigListCountIndex       = 0;
> +  PreEmptyPropKeyValueList   = NULL;
> +  FirstEmptyPropKeyValueList = NULL;
> +  while (ConfigListCountIndex < ConfigListCount) {
> +    Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangList[ConfigListCountIndex], &RedfishValue);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version,
> ConfigureLangList[ConfigListCountIndex], Status));
> +      goto ErrorLeave;
> +    }
> 
> -        OdataIdValue = JsonObjectGetValue (JsonValueGetObject (JsonValue),
> "@odata.etag");
> -        if (OdataIdValue != NULL) {
> -          OdataIdString = (CHAR8 *)JsonValueGetAsciiString (OdataIdValue);
> -          if (OdataIdString != NULL) {
> -            *Etag = AllocateCopyPool (AsciiStrSize (OdataIdString), OdataIdString);
> -          }
> -        }
> -      }
> +    //
> +    // Get the key name.
> +    //
> +    KeyName = GetAttributeNameFromConfigLanguage
> (ConfigureLangList[ConfigListCountIndex]);
> +    //
> +    // Create an entry of RedfishCS_EmptyProp_KeyValue.
> +    //
> +    EmptyPropKeyValueList = NewEmptyPropKeyValueFromRedfishValue
> (KeyName, &RedfishValue);
> +    if (EmptyPropKeyValueList == NULL) {
> +      DEBUG ((DEBUG_ERROR, "%a, Failed to create an entry of
> EmptyPropKeyValueList\n", __FUNCTION__));
> +      ConfigListCountIndex++;
> +      continue;
> +    }
> +
> +    //
> +    // Link the RedfishCS_EmptyProp_KeyValue list.
> +    //
> +    if (PreEmptyPropKeyValueList != NULL) {
> +      PreEmptyPropKeyValueList->NextKeyValuePtr =
> EmptyPropKeyValueList;
> +    } else {
> +      FirstEmptyPropKeyValueList = EmptyPropKeyValueList;
>      }
> +
> +    PreEmptyPropKeyValueList = EmptyPropKeyValueList;
> +    ConfigListCountIndex++;
>    }
> 
> -  //
> -  // This is not expected as service does not follow spec.
> -  //
> -  if (*Location == NULL) {
> -    Status = EFI_DEVICE_ERROR;
> +  goto LeaveFunction;
> +
> +ErrorLeave:;
> +  if (FirstEmptyPropKeyValueList != NULL) {
> +    FreeEmptyPropKeyValueList (FirstEmptyPropKeyValueList);
>    }
> 
> -  RedfishFreeResponse (
> -    PostResponse.StatusCode,
> -    PostResponse.HeaderCount,
> -    PostResponse.Headers,
> -    PostResponse.Payload
> -    );
> +  FirstEmptyPropKeyValueList = NULL;
> 
> -  RedfishCleanupPayload (Payload);
> +LeaveFunction:
> +  if (SearchPattern != NULL) {
> +    FreePool (SearchPattern);
> +  }
> 
> -EXIT_FREE_JSON_VALUE:
> -  JsonValueFree (JsonValue);
> -  JsonValueFree (ResourceJsonValue);
> +  if (ConfigureLangBuffer != NULL) {
> +    FreePool (ConfigureLangBuffer);
> +  }
> 
> -  return Status;
> +  FreePool (ConfigureLangList);
> +
> +  *NumberOfValues = (UINT32)ConfigListCount;
> +  return FirstEmptyPropKeyValueList;
>  }
> 
>  /**
> 
> -  Find Redfish Resource Config Protocol that supports given schema and
> version.
> +  Check and see if we need to do provisioning for this property.
> 
> -  @param[in]  Schema      Schema name.
> -  @param[in]  Major       Schema version major number.
> -  @param[in]  Minor       Schema version minor number.
> -  @param[in]  Errata      Schema version errata number.
> +  @param[in]  PropertyBuffer   Pointer to property instance.
> +  @param[in]  ProvisionMode    TRUE if we are in provision mode. FALSE
> otherwise.
> 
> -  @retval     EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL *    Pointer to
> protocol
> -  @retval     NULL                                        No protocol found.
> +  @retval     TRUE             Provision is required.
> +  @retval     FALSE            Provision is not required.
> 
>  **/
> -EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *
> -GetRedfishResourceConfigProtocol (
> -  IN  CHAR8  *Schema,
> -  IN  CHAR8  *Major,
> -  IN  CHAR8  *Minor,
> -  IN  CHAR8  *Errata
> +BOOLEAN
> +PropertyChecker (
> +  IN VOID     *PropertyBuffer,
> +  IN BOOLEAN  ProvisionMode
>    )
>  {
> -  EFI_STATUS                              Status;
> -  EFI_HANDLE                              *HandleBuffer;
> -  UINTN                                   NumberOfHandles;
> -  UINTN                                   Index;
> -  EDKII_REDFISH_RESOURCE_CONFIG_PROTOCOL  *Protocol;
> -  REDFISH_SCHEMA_INFO                     SchemaInfo;
> -  BOOLEAN                                 Found;
> +  if (ProvisionMode) {
> +    return TRUE;
> +  }
> 
> -  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Major) ||
> IS_EMPTY_STRING (Minor) || IS_EMPTY_STRING (Errata)) {
> -    return NULL;
> +  if (!ProvisionMode && (PropertyBuffer != NULL)) {
> +    return TRUE;
>    }
> 
> -  Status = gBS->LocateHandleBuffer (
> -                  ByProtocol,
> -                  &gEdkIIRedfishResourceConfigProtocolGuid,
> -                  NULL,
> -                  &NumberOfHandles,
> -                  &HandleBuffer
> -                  );
> -  if (EFI_ERROR (Status)) {
> -    return NULL;
> +  return FALSE;
> +}
> +
> +/**
> +
> +  Check and see if ETAG is identical to what we keep in system.
> +
> +  @param[in]  Uri           URI requested
> +  @param[in]  EtagInHeader  ETAG string returned from HTTP request.
> +  @param[in]  EtagInJson    ETAG string in JSON body.
> +
> +  @retval     TRUE          ETAG is identical.
> +  @retval     FALSE         ETAG is changed.
> +
> +**/
> +BOOLEAN
> +CheckEtag (
> +  IN EFI_STRING  Uri,
> +  IN CHAR8       *EtagInHeader,
> +  IN CHAR8       *EtagInJson
> +  )
> +{
> +  CHAR8  *EtagInDb;
> +
> +  if (IS_EMPTY_STRING (Uri)) {
> +    return FALSE;
>    }
> 
> -  Found = FALSE;
> +  if (IS_EMPTY_STRING (EtagInHeader) && IS_EMPTY_STRING (EtagInJson))
> {
> +    return FALSE;
> +  }
> 
> -  for (Index = 0; Index < NumberOfHandles; Index++) {
> -    Status = gBS->HandleProtocol (
> -                    HandleBuffer[Index],
> -                    &gEdkIIRedfishResourceConfigProtocolGuid,
> -                    (VOID **)&Protocol
> -                    );
> -    if (EFI_ERROR (Status)) {
> -      continue;
> -    }
> +  //
> +  // Check ETAG to see if we need to consume it
> +  //
> +  EtagInDb = NULL;
> +  EtagInDb = GetEtagWithUri (Uri);
> +  if (EtagInDb == NULL) {
> +    DEBUG ((REDFISH_DEBUG_TRACE, "%a, no ETAG record cound be found
> for: %s\n", __FUNCTION__, Uri));
> +    return FALSE;
> +  }
> 
> -    Status = Protocol->GetInfo (Protocol, &SchemaInfo);
> -    if (EFI_ERROR (Status)) {
> -      continue;
> +  if (EtagInHeader != NULL) {
> +    if (AsciiStrCmp (EtagInDb, EtagInHeader) == 0) {
> +      FreePool (EtagInDb);
> +      return TRUE;
>      }
> +  }
> 
> -    if ((AsciiStrCmp (Schema, SchemaInfo.Schema) == 0) &&
> -        (AsciiStrCmp (Major, SchemaInfo.Major) == 0) &&
> -        (AsciiStrCmp (Minor, SchemaInfo.Minor) == 0) &&
> -        (AsciiStrCmp (Errata, SchemaInfo.Errata) == 0))
> -    {
> -      Found = TRUE;
> -      break;
> +  if (EtagInJson != NULL) {
> +    if (AsciiStrCmp (EtagInDb, EtagInJson) == 0) {
> +      FreePool (EtagInDb);
> +      return TRUE;
>      }
>    }
> 
> -  FreePool (HandleBuffer);
> +  FreePool (EtagInDb);
> 
> -  return (Found ? Protocol : NULL);
> +  return FALSE;
>  }
> 
>  /**
> +  Check and see if given ObjectName can be found in JsonObj or not
> 
> -  Get supported schema list by given specify schema name.
> +  @param[in]  JsonObj       JSON object to search
> +  @param[in]  ObjectName    Object name
> 
> -  @param[in]  Schema      Schema type name.
> -  @param[out] SchemaInfo  Returned schema information.
> -
> -  @retval     EFI_SUCCESS         Schema information is returned successfully.
> -  @retval     Others              Errors occur.
> +  @retval     EDKII_JSON_VALUE *  Pointer to Json object is found. NULL
> otherwise.
> 
>  **/
> -EFI_STATUS
> -GetSupportedSchemaVersion (
> -  IN   CHAR8                *Schema,
> -  OUT  REDFISH_SCHEMA_INFO  *SchemaInfo
> +EDKII_JSON_VALUE *
> +MatchJsonObject (
> +  IN EDKII_JSON_VALUE  *JsonObj,
> +  IN CHAR8             *ObjectName
>    )
>  {
> -  EFI_STATUS  Status;
> -  CHAR8       *SupportSchema;
> -  CHAR8       *SchemaName;
> -  UINTN       Index;
> -  UINTN       Index2;
> -  BOOLEAN     Found;
> +  EDKII_JSON_VALUE  N;
> +  CHAR8             *Key;
> +  EDKII_JSON_VALUE  Value;
> 
> -  if (IS_EMPTY_STRING (Schema) || (SchemaInfo == NULL)) {
> -    return EFI_INVALID_PARAMETER;
> +  if ((JsonObj == NULL) || IS_EMPTY_STRING (ObjectName)) {
> +    return NULL;
>    }
> 
> -  Status = RedfishPlatformConfigGetSupportedSchema (NULL,
> &SupportSchema);
> -  if (EFI_ERROR (Status)) {
> -    return Status;
> +  if (!JsonValueIsObject (JsonObj)) {
> +    return NULL;
>    }
> 
> -  DEBUG ((DEBUG_INFO, "Supported schema: %a\n", SupportSchema));
> -
> -  Index      = 0;
> -  Found      = FALSE;
> -  SchemaName = SupportSchema;
> -  while (TRUE) {
> -    if ((SupportSchema[Index] == ';') || (SupportSchema[Index] == '\0')) {
> -      if (AsciiStrnCmp (&SchemaName[SCHEMA_NAME_PREFIX_OFFSET],
> Schema, AsciiStrLen (Schema)) == 0) {
> -        Found                = TRUE;
> -        SupportSchema[Index] = '\0';
> -        break;
> -      }
> -
> -      SchemaName = &SupportSchema[Index + 1];
> +  EDKII_JSON_OBJECT_FOREACH_SAFE (JsonObj, N, Key, Value) {
> +    if (AsciiStrCmp (Key, ObjectName) == 0) {
> +      return Value;
>      }
> +  }
> 
> -    if (SupportSchema[Index] == '\0') {
> -      break;
> -    }
> +  return NULL;
> +}
> 
> -    ++Index;
> -  }
> +/**
> 
> -  if (Found) {
> -    AsciiStrCpyS (SchemaInfo->Schema, REDFISH_SCHEMA_STRING_SIZE,
> Schema);
> +  Check and see if given property is in JSON context or not
> 
> -    //
> -    // forward to '.'
> -    //
> -    Index = 0;
> -    while (SchemaName[Index] != '\0' && SchemaName[Index] != '.') {
> -      ++Index;
> -    }
> +  @param[in]  Property      Property name string
> +  @param[in]  Json          The JSON context to search.
> 
> -    ASSERT (SchemaName[Index] != '\0');
> +  @retval     TRUE          Property is found in JSON context
> +  @retval     FALSE         Property is not in JSON context
> 
> -    //
> -    // Skip '.' and 'v'
> -    //
> -    Index += 2;
> +**/
> +BOOLEAN
> +MatchPropertyWithJsonContext (
> +  IN  EFI_STRING  Property,
> +  IN  CHAR8       *Json
> +  )
> +{
> +  CHAR8             *AsciiProperty;
> +  CHAR8             *PropertyNode;
> +  UINTN             Index;
> +  EDKII_JSON_VALUE  *JsonObj;
> +  EDKII_JSON_VALUE  *MatchObj;
> +  EDKII_JSON_TYPE   JsonType;
> 
> -    //
> -    // forward to '_'
> -    //
> -    Index2 = Index;
> -    while (SchemaName[Index2] != '\0' && SchemaName[Index2] != '_') {
> -      ++Index2;
> -    }
> +  if (IS_EMPTY_STRING (Property) || IS_EMPTY_STRING (Json)) {
> +    return FALSE;
> +  }
> +
> +  JsonObj = JsonLoadString (Json, 0, NULL);
> +  if ((JsonObj == NULL) || !JsonValueIsObject (JsonObj)) {
> +    return FALSE;
> +  }
> 
> -    ASSERT (SchemaName[Index2] != '\0');
> +  AsciiProperty = StrUnicodeToAscii (Property);
> +  if (AsciiProperty == NULL) {
> +    return FALSE;
> +  }
> 
> -    AsciiStrnCpyS (SchemaInfo->Major, REDFISH_SCHEMA_VERSION_SIZE,
> &SchemaName[Index], (Index2 - Index));
> -    Index = Index2;
> +  Index        = 0;
> +  PropertyNode = AsciiProperty;
> +  MatchObj     = JsonObj;
> 
> -    //
> -    // Skip '_'
> -    //
> -    ++Index;
> +  //
> +  // Walk through property and find corresponding object in JSON input
> +  //
> +  while (AsciiProperty[Index] != '\0') {
> +    if (AsciiProperty[Index] == '/') {
> +      AsciiProperty[Index] = '\0';
> +      MatchObj             = MatchJsonObject (MatchObj, PropertyNode);
> +      if (MatchObj == NULL) {
> +        PropertyNode = NULL;
> +        break;
> +      }
> 
> -    //
> -    // forward to '_'
> -    //
> -    Index2 = Index;
> -    while (SchemaName[Index2] != '\0' && SchemaName[Index2] != '_') {
> -      ++Index2;
> +      PropertyNode = &AsciiProperty[Index + 1];
>      }
> 
> -    ASSERT (SchemaName[Index2] != '\0');
> +    Index++;
> +  }
> 
> -    AsciiStrnCpyS (SchemaInfo->Minor, REDFISH_SCHEMA_VERSION_SIZE,
> &SchemaName[Index], (Index2 - Index));
> -    Index = Index2;
> +  if (PropertyNode != NULL) {
> +    MatchObj = MatchJsonObject (MatchObj, PropertyNode);
> +  }
> 
> +  //
> +  // Value check
> +  //
> +  if (MatchObj != NULL) {
>      //
> -    // Skip '_'
> +    // If object has empty value, treat it as not matching
>      //
> -    ++Index;
> -
> -    AsciiStrCpyS (SchemaInfo->Errata, REDFISH_SCHEMA_VERSION_SIZE,
> &SchemaName[Index]);
> -  }
> -
> -  FreePool (SupportSchema);
> +    JsonType = JsonGetType (MatchObj);
> +    switch (JsonType) {
> +      case EdkiiJsonTypeObject:
> +        if (JsonValueIsNull (MatchObj)) {
> +          MatchObj = NULL;
> +        }
> 
> -  return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
> -}
> +        break;
> +      case EdkiiJsonTypeArray:
> +        if (JsonArrayCount (MatchObj) == 0) {
> +          MatchObj = NULL;
> +        }
> 
> -/**
> +        break;
> +      case EdkiiJsonTypeString:
> +        if (IS_EMPTY_STRING (JsonValueGetString (MatchObj))) {
> +          MatchObj = NULL;
> +        }
> 
> -  Return system root path. This is dummy function now.
> +        break;
> +      case EdkiiJsonTypeNull:
> +        MatchObj = NULL;
> +        break;
> +      default:
> +        break;
> +    }
> +  }
> 
> -  @retval  NULL     Can not find system root path.
> -  @retval  Other    System root path is returned.
> +  FreePool (AsciiProperty);
> 
> -**/
> -CHAR8 *
> -RedfishGetSystemRootPath (
> -  VOID
> -  )
> -{
> -  return AllocateCopyPool (AsciiStrSize (REDFISH_SYSTEM_ROOT_PATH),
> REDFISH_SYSTEM_ROOT_PATH);
> +  return (MatchObj == NULL ? FALSE : TRUE);
>  }
> 
>  /**
> 
> -  Get schema information by given protocol and service instance.
> +  Create string array and append to arry node in Redfish JSON convert
> format.
> 
> -  @param[in]  RedfishService      Pointer to Redfish service instance.
> -  @param[in]  JsonStructProtocol  Json Structure protocol instance.
> -  @param[in]  Uri                 Target URI.
> -  @param[out] SchemaInfo          Returned schema information.
> +  @param[in,out]  Head          The head of string array.
> +  @param[in]      StringArray   Input string array.
> +  @param[in]      ArraySize     The size of StringArray.
> 
> -  @retval     EFI_SUCCESS         Schema information is returned successfully.
> -  @retval     Others              Errors occur.
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> 
>  **/
>  EFI_STATUS
> -GetRedfishSchemaInfo (
> -  IN  REDFISH_SERVICE                   *RedfishService,
> -  IN  EFI_REST_JSON_STRUCTURE_PROTOCOL  *JsonStructProtocol,
> -  IN  CHAR8                             *Uri,
> -  OUT REDFISH_SCHEMA_INFO               *SchemaInfo
> +AddRedfishCharArray (
> +  IN OUT  RedfishCS_char_Array  **Head,
> +  IN      CHAR8                 **StringArray,
> +  IN      UINTN                 ArraySize
>    )
>  {
> -  EFI_STATUS                      Status;
> -  REDFISH_RESPONSE                Response;
> -  REDFISH_PAYLOAD                 Payload;
> -  CHAR8                           *JsonText;
> -  EFI_REST_JSON_STRUCTURE_HEADER  *Header;
> +  UINTN                 Index;
> +  RedfishCS_char_Array  *CharArrayBuffer;
> +  RedfishCS_char_Array  *PreArrayBuffer;
> 
> -  if ((RedfishService == NULL) || (JsonStructProtocol == NULL) ||
> IS_EMPTY_STRING (Uri) || (SchemaInfo == NULL)) {
> +  if ((Head == NULL) || (StringArray == NULL) || (ArraySize == 0)) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> -  Status = GetResourceByPath (RedfishService, Uri, &Response);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, failed to get resource from %a %r",
> __FUNCTION__, Uri, Status));
> -    return Status;
> -  }
> +  PreArrayBuffer = NULL;
> +  for (Index = 0; Index < ArraySize; Index++) {
> +    CharArrayBuffer = AllocatePool (sizeof (RedfishCS_char_Array));
> +    if (CharArrayBuffer == NULL) {
> +      ASSERT (CharArrayBuffer != NULL);
> +      continue;
> +    }
> 
> -  Payload = Response.Payload;
> -  ASSERT (Payload != NULL);
> +    if (Index == 0) {
> +      *Head = CharArrayBuffer;
> +    }
> 
> -  JsonText = JsonDumpString (RedfishJsonInPayload (Payload),
> EDKII_JSON_COMPACT);
> -  ASSERT (JsonText != NULL);
> +    CharArrayBuffer->ArrayValue = StringArray[Index];
> +    CharArrayBuffer->Next       = NULL;
> +    if (PreArrayBuffer != NULL) {
> +      PreArrayBuffer->Next = CharArrayBuffer;
> +    }
> 
> -  //
> -  // Convert JSON text to C structure.
> -  //
> -  Status = JsonStructProtocol->ToStructure (
> -                                 JsonStructProtocol,
> -                                 NULL,
> -                                 JsonText,
> -                                 &Header
> -                                 );
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, ToStructure() failed: %r\n",
> __FUNCTION__, Status));
> -    return Status;
> +    PreArrayBuffer = CharArrayBuffer;
>    }
> 
> -  AsciiStrCpyS (SchemaInfo->Schema, REDFISH_SCHEMA_STRING_SIZE,
> Header->JsonRsrcIdentifier.NameSpace.ResourceTypeName);
> -  AsciiStrCpyS (SchemaInfo->Major, REDFISH_SCHEMA_VERSION_SIZE,
> Header->JsonRsrcIdentifier.NameSpace.MajorVersion);
> -  AsciiStrCpyS (SchemaInfo->Minor, REDFISH_SCHEMA_VERSION_SIZE,
> Header->JsonRsrcIdentifier.NameSpace.MinorVersion);
> -  AsciiStrCpyS (SchemaInfo->Errata, REDFISH_SCHEMA_VERSION_SIZE,
> Header->JsonRsrcIdentifier.NameSpace.ErrataVersion);
> -
> -  //
> -  // Release resource.
> -  //
> -  JsonStructProtocol->DestoryStructure (JsonStructProtocol, Header);
> -  FreePool (JsonText);
> -  RedfishFreeResponse (Response.StatusCode, Response.HeaderCount,
> Response.Headers, Response.Payload);
> -
>    return EFI_SUCCESS;
>  }
> 
>  /**
> 
> -  Get the property name by given Configure Langauge.
> +  Create numeric array and append to arry node in Redfish JSON convert
> format.
> 
> -  @param[in]  ConfigureLang   Configure Language string.
> +  @param[in,out]  Head           The head of string array.
> +  @param[in]      NumericArray   Input numeric array.
> +  @param[in]      ArraySize      The size of NumericArray.
> 
> -  @retval     EFI_STRING      Pointer to property name.
> -  @retval     NULL            There is error.
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> 
>  **/
> -EFI_STRING
> -GetPropertyFromConfigureLang (
> -  IN EFI_STRING  ConfigureLang
> +EFI_STATUS
> +AddRedfishNumericArray (
> +  IN OUT  RedfishCS_int64_Array  **Head,
> +  IN      INT64                  *NumericArray,
> +  IN      UINTN                  ArraySize
>    )
>  {
> -  EFI_STRING  Property;
> -  UINTN       Index;
> +  UINTN                  Index;
> +  RedfishCS_int64_Array  *NumericArrayBuffer;
> +  RedfishCS_int64_Array  *PreArrayBuffer;
> 
> -  if (ConfigureLang == NULL) {
> -    return NULL;
> +  if ((Head == NULL) || (NumericArray == NULL) || (ArraySize == 0)) {
> +    return EFI_INVALID_PARAMETER;
>    }
> 
> -  Index    = 0;
> -  Property = ConfigureLang;
> +  PreArrayBuffer = NULL;
> +  for (Index = 0; Index < ArraySize; Index++) {
> +    NumericArrayBuffer = AllocatePool (sizeof (RedfishCS_int64_Array));
> +    if (NumericArrayBuffer == NULL) {
> +      ASSERT (NumericArrayBuffer != NULL);
> +      continue;
> +    }
> 
> -  while (ConfigureLang[Index] != '\0') {
> -    if (ConfigureLang[Index] == L'/') {
> -      Property = &ConfigureLang[Index];
> +    if (Index == 0) {
> +      *Head = NumericArrayBuffer;
>      }
> 
> -    ++Index;
> -  }
> +    NumericArrayBuffer->ArrayValue =  AllocatePool (sizeof
> (RedfishCS_int64));
> +    if (NumericArrayBuffer->ArrayValue == NULL) {
> +      ASSERT (NumericArrayBuffer->ArrayValue != NULL);
> +      continue;
> +    }
> +
> +    *NumericArrayBuffer->ArrayValue = NumericArray[Index];
> +    NumericArrayBuffer->Next        = NULL;
> +    if (PreArrayBuffer != NULL) {
> +      PreArrayBuffer->Next = NumericArrayBuffer;
> +    }
> 
> -  ++Property;
> +    PreArrayBuffer = NumericArrayBuffer;
> +  }
> 
> -  return Property;
> +  return EFI_SUCCESS;
>  }
> 
>  /**
> 
> -  Get the property value in string type.
> +  Create boolean array and append to arry node in Redfish JSON convert
> format.
> 
> -  @param[in]  Schema        Schema of this property.
> -  @param[in]  Version       Schema version.
> -  @param[in]  PropertyName  Property name.
> -  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[in,out]  Head           The head of string array.
> +  @param[in]      BooleanArray   Input boolean array.
> +  @param[in]      ArraySize      The size of BooleanArray.
> 
> -  @retval     CHAR8*        Pointer to the CHAR8 buffer.
> -  @retval     NULL          There is error.
> +  @retval     EFI_SUCCESS       String array is created successfully.
> +  @retval     Others            Error happens
> 
>  **/
> -CHAR8 *
> -GetPropertyStringValue (
> -  IN CHAR8       *Schema,
> -  IN CHAR8       *Version,
> -  IN EFI_STRING  PropertyName,
> -  IN EFI_STRING  ConfigureLang
> +EFI_STATUS
> +AddRedfishBooleanArray (
> +  IN OUT  RedfishCS_bool_Array  **Head,
> +  IN      BOOLEAN               *BooleanArray,
> +  IN      UINTN                 ArraySize
>    )
>  {
> -  EFI_STATUS           Status;
> -  EDKII_REDFISH_VALUE  RedfishValue;
> -  EFI_STRING           ConfigureLangBuffer;
> -  UINTN                BufferSize;
> -  CHAR8                *AsciiStringValue;
> +  UINTN                 Index;
> +  RedfishCS_bool_Array  *BooleanArrayBuffer;
> +  RedfishCS_bool_Array  *PreArrayBuffer;
> 
> -  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> -    return NULL;
> +  if ((Head == NULL) || (BooleanArrayBuffer == NULL) || (ArraySize == 0)) {
> +    return EFI_INVALID_PARAMETER;
>    }
> 
> -  //
> -  // Configure Language buffer.
> -  //
> -  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> -  ConfigureLangBuffer = AllocatePool (BufferSize);
> -  if (ConfigureLangBuffer == NULL) {
> -    return NULL;
> -  }
> +  PreArrayBuffer = NULL;
> +  for (Index = 0; Index < ArraySize; Index++) {
> +    BooleanArrayBuffer = AllocatePool (sizeof (RedfishCS_bool_Array));
> +    if (BooleanArrayBuffer == NULL) {
> +      ASSERT (BooleanArrayBuffer != NULL);
> +      continue;
> +    }
> 
> -  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> -  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> -    return NULL;
> -  }
> +    if (Index == 0) {
> +      *Head = BooleanArrayBuffer;
> +    }
> 
> -  if (RedfishValue.Type != REDFISH_VALUE_TYPE_STRING) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not string type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> -    return NULL;
> -  }
> +    BooleanArrayBuffer->ArrayValue =  AllocatePool (sizeof
> (RedfishCS_bool));
> +    if (BooleanArrayBuffer->ArrayValue == NULL) {
> +      ASSERT (BooleanArrayBuffer->ArrayValue != NULL);
> +      continue;
> +    }
> 
> -  AsciiStringValue = AllocateCopyPool (AsciiStrSize
> (RedfishValue.Value.Buffer), RedfishValue.Value.Buffer);
> -  ASSERT (AsciiStringValue != NULL);
> +    *BooleanArrayBuffer->ArrayValue = BooleanArray[Index];
> +    BooleanArrayBuffer->Next        = NULL;
> +    if (PreArrayBuffer != NULL) {
> +      PreArrayBuffer->Next = BooleanArrayBuffer;
> +    }
> 
> -  return AsciiStringValue;
> +    PreArrayBuffer = BooleanArrayBuffer;
> +  }
> +
> +  return EFI_SUCCESS;
>  }
> 
>  /**
> 
> -  Get the property value in numeric type.
> +  Check and see if value in Redfish string array are all the same as the one
> +  from HII configuration.
> 
> -  @param[in]  Schema        Schema of this property.
> -  @param[in]  Version       Schema version.
> -  @param[in]  PropertyName  Property name.
> -  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[in]  Head          The head of string array.
> +  @param[in]  StringArray   Input string array.
> +  @param[in]  ArraySize     The size of StringArray.
> 
> -  @retval     INT64*        Pointer to the INT64 value.
> -  @retval     NULL          There is error.
> +  @retval     TRUE          All string in Redfish array are as same as string
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> 
>  **/
> -INT64 *
> -GetPropertyNumericValue (
> -  IN CHAR8       *Schema,
> -  IN CHAR8       *Version,
> -  IN EFI_STRING  PropertyName,
> -  IN EFI_STRING  ConfigureLang
> +BOOLEAN
> +CompareRedfishStringArrayValues (
> +  IN RedfishCS_char_Array  *Head,
> +  IN CHAR8                 **StringArray,
> +  IN UINTN                 ArraySize
>    )
>  {
> -  EFI_STATUS           Status;
> -  EDKII_REDFISH_VALUE  RedfishValue;
> -  EFI_STRING           ConfigureLangBuffer;
> -  UINTN                BufferSize;
> -  INT64                *ResultValue;
> -
> -  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> -    return NULL;
> -  }
> +  UINTN                 Index;
> +  RedfishCS_char_Array  *CharArrayBuffer;
> 
> -  //
> -  // Configure Language buffer.
> -  //
> -  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> -  ConfigureLangBuffer = AllocatePool (BufferSize);
> -  if (ConfigureLangBuffer == NULL) {
> -    return NULL;
> +  if ((Head == NULL) || (StringArray == NULL) || (ArraySize == 0)) {
> +    return FALSE;
>    }
> 
> -  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> -  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> -    return NULL;
> -  }
> +  CharArrayBuffer = Head;
> +  Index           = 0;
> +  while (CharArrayBuffer != NULL && Index < ArraySize) {
> +    if (AsciiStrCmp (StringArray[Index], CharArrayBuffer->ArrayValue) != 0) {
> +      break;
> +    }
> 
> -  if (RedfishValue.Type != REDFISH_VALUE_TYPE_INTEGER) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not numeric type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> -    return NULL;
> +    Index++;
> +    CharArrayBuffer = CharArrayBuffer->Next;
>    }
> 
> -  ResultValue = AllocatePool (sizeof (INT64));
> -  ASSERT (ResultValue != NULL);
> -  if (ResultValue == NULL) {
> -    return NULL;
> +  if ((CharArrayBuffer != NULL) || (Index < ArraySize)) {
> +    return FALSE;
>    }
> 
> -  *ResultValue = RedfishValue.Value.Integer;
> -
> -  return ResultValue;
> +  return TRUE;
>  }
> 
>  /**
> 
> -  Get the property value in Boolean type.
> +  Check and see if value in Redfish numeric array are all the same as the one
> +  from HII configuration.
> 
> -  @param[in]  Schema        Schema of this property.
> -  @param[in]  Version       Schema version.
> -  @param[in]  PropertyName  Property name.
> -  @param[in]  ConfigureLang Configure Language of this property.
> +  @param[in]  Head          The head of Redfish CS numeraic array.
> +  @param[in]  NumericArray  Input numeric array.
> +  @param[in]  ArraySize     The size of NumericArray.
> 
> -  @retval     BOOLEAN       Boolean value returned by this property.
> +  @retval     TRUE          All string in Redfish array are as same as integer
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> 
>  **/
> -BOOLEAN *
> -GetPropertyBooleanValue (
> -  IN CHAR8       *Schema,
> -  IN CHAR8       *Version,
> -  IN EFI_STRING  PropertyName,
> -  IN EFI_STRING  ConfigureLang
> +BOOLEAN
> +CompareRedfishNumericArrayValues (
> +  IN RedfishCS_int64_Array  *Head,
> +  IN INT64                  *NumericArray,
> +  IN UINTN                  ArraySize
>    )
>  {
> -  EFI_STATUS           Status;
> -  EDKII_REDFISH_VALUE  RedfishValue;
> -  EFI_STRING           ConfigureLangBuffer;
> -  UINTN                BufferSize;
> -  BOOLEAN              *ResultValue;
> +  UINTN                  Index;
> +  RedfishCS_int64_Array  *NumericArrayBuffer;
> 
> -  if (IS_EMPTY_STRING (Schema) || IS_EMPTY_STRING (Version) ||
> IS_EMPTY_STRING (ConfigureLang) || IS_EMPTY_STRING (PropertyName)) {
> -    return NULL;
> -  }
> -
> -  //
> -  // Configure Language buffer.
> -  //
> -  BufferSize          = sizeof (CHAR16) * MAX_CONF_LANG_LEN;
> -  ConfigureLangBuffer = AllocatePool (BufferSize);
> -  if (ConfigureLangBuffer == NULL) {
> -    return NULL;
> +  if ((Head == NULL) || (NumericArray == NULL) || (ArraySize == 0)) {
> +    return FALSE;
>    }
> 
> -  UnicodeSPrint (ConfigureLangBuffer, BufferSize, L"%s/%s", ConfigureLang,
> PropertyName);
> -  Status = RedfishPlatformConfigGetValue (Schema, Version,
> ConfigureLangBuffer, &RedfishValue);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a query current setting for %s failed:
> %r\n", __FUNCTION__, Schema, Version, ConfigureLangBuffer, Status));
> -    return NULL;
> -  }
> +  NumericArrayBuffer = Head;
> +  Index              = 0;
> +  while (NumericArrayBuffer != NULL && Index < ArraySize) {
> +    if (NumericArray[Index] != *NumericArrayBuffer->ArrayValue) {
> +      break;
> +    }
> 
> -  if (RedfishValue.Type != REDFISH_VALUE_TYPE_BOOLEAN) {
> -    DEBUG ((DEBUG_ERROR, "%a, %a.%a %s value is not boolean type\n",
> __FUNCTION__, Schema, Version, ConfigureLang));
> -    return NULL;
> +    Index++;
> +    NumericArrayBuffer = NumericArrayBuffer->Next;
>    }
> 
> -  ResultValue = AllocatePool (sizeof (BOOLEAN));
> -  ASSERT (ResultValue != NULL);
> -  if (ResultValue == NULL) {
> -    return NULL;
> +  if ((NumericArrayBuffer != NULL) || (Index < ArraySize)) {
> +    return FALSE;
>    }
> 
> -  *ResultValue = RedfishValue.Value.Boolean;
> -
> -  return ResultValue;
> +  return TRUE;
>  }
> 
>  /**
> 
> -  Check and see if we need to do provisioning for this property.
> +  Check and see if value in Redfish boolean array are all the same as the one
> +  from HII configuration.
> 
> -  @param[in]  PropertyBuffer   Pointer to property instance.
> -  @param[in]  ProvisionMode    TRUE if we are in provision mode. FALSE
> otherwise.
> +  @param[in]  Head          The head of Redfish CS boolean array.
> +  @param[in]  BooleanArray  Input boolean array.
> +  @param[in]  ArraySize     The size of BooleanArray.
> 
> -  @retval     TRUE             Provision is required.
> -  @retval     FALSE            Provision is not required.
> +  @retval     TRUE          All string in Redfish array are as same as integer
> +                            in HII configuration array.
> +              FALSE         These two array are not identical.
> 
>  **/
>  BOOLEAN
> -PropertyChecker (
> -  IN VOID     *PropertyBuffer,
> -  IN BOOLEAN  ProvisionMode
> +CompareRedfishBooleanArrayValues (
> +  IN RedfishCS_bool_Array  *Head,
> +  IN BOOLEAN               *BooleanArray,
> +  IN UINTN                 ArraySize
>    )
>  {
> -  if (ProvisionMode && (PropertyBuffer == NULL)) {
> -    return TRUE;
> +  UINTN                 Index;
> +  RedfishCS_bool_Array  *BooleanArrayBuffer;
> +
> +  if ((Head == NULL) || (BooleanArray == NULL) || (ArraySize == 0)) {
> +    return FALSE;
>    }
> 
> -  if (!ProvisionMode && (PropertyBuffer != NULL)) {
> -    return TRUE;
> +  BooleanArrayBuffer = Head;
> +  Index              = 0;
> +  while (BooleanArrayBuffer != NULL && Index < ArraySize) {
> +    if (BooleanArray[Index] != *BooleanArrayBuffer->ArrayValue) {
> +      break;
> +    }
> +
> +    Index++;
> +    BooleanArrayBuffer = BooleanArrayBuffer->Next;
>    }
> 
> -  return FALSE;
> +  if ((BooleanArrayBuffer != NULL) || (Index < ArraySize)) {
> +    return FALSE;
> +  }
> +
> +  return TRUE;
>  }
> 
>  /**
> 
> -  Check and see if we need to do provisioning for this two properties.
> +  Check and see if any difference between two vague value set.
> +  This is just a simple check.
> 
> -  @param[in]  PropertyBuffer1   Pointer to property instance 1.
> -  @param[in]  PropertyBuffer2   Pointer to property instance 2.
> -  @param[in]  ProvisionMode     TRUE if we are in provision mode. FALSE
> otherwise.
> +  @param[in]  RedfishVagueKeyValuePtr     The vague key value sets on
> Redfish service.
> +  @param[in]  RedfishVagueKeyValueNumber  The numebr of vague key
> value sets
> +  @param[in]  ConfigVagueKeyValuePtr      The vague configuration on
> platform.
> +  @param[in]  ConfigVagueKeyValueNumber   The numebr of vague key
> value sets
> 
> -  @retval     TRUE             Provision is required.
> -  @retval     FALSE            Provision is not required.
> +  @retval     TRUE          All values are the same.
> +              FALSE         There is some difference.
> 
>  **/
>  BOOLEAN
> -PropertyChecker2Parm (
> -  IN VOID     *PropertyBuffer1,
> -  IN VOID     *PropertyBuffer2,
> -  IN BOOLEAN  ProvisionMode
> +CompareRedfishPropertyVagueValues (
> +  IN RedfishCS_EmptyProp_KeyValue  *RedfishVagueKeyValuePtr,
> +  IN UINT32                        RedfishVagueKeyValueNumber,
> +  IN RedfishCS_EmptyProp_KeyValue  *ConfigVagueKeyValuePtr,
> +  IN UINT32                        ConfigVagueKeyValueNumber
>    )
>  {
> -  if (ProvisionMode && ((PropertyBuffer1 == NULL) || (PropertyBuffer2 ==
> NULL))) {
> -    return TRUE;
> +  RedfishCS_EmptyProp_KeyValue  *ThisConfigVagueKeyValuePtr;
> +  RedfishCS_EmptyProp_KeyValue  *ThisRedfishVagueKeyValuePtr;
> +
> +  if (RedfishVagueKeyValueNumber != ConfigVagueKeyValueNumber) {
> +    return FALSE;
>    }
> 
> -  if (!ProvisionMode && (PropertyBuffer1 != NULL) && (PropertyBuffer2 !=
> NULL)) {
> -    return TRUE;
> +  ThisConfigVagueKeyValuePtr = ConfigVagueKeyValuePtr;
> +  //
> +  // Loop through all key/value on system.
> +  //
> +  while (ThisConfigVagueKeyValuePtr != NULL) {
> +    ThisRedfishVagueKeyValuePtr = RedfishVagueKeyValuePtr;
> +    //
> +    // Loop through all key/value on Redfish service..
> +    //
> +    while (ThisRedfishVagueKeyValuePtr != NULL) {
> +      if (AsciiStrCmp (ThisConfigVagueKeyValuePtr->KeyNamePtr,
> ThisRedfishVagueKeyValuePtr->KeyNamePtr) == 0) {
> +        //
> +        // Check the type of value.
> +        //
> +        if (ThisConfigVagueKeyValuePtr->Value->DataType !=
> ThisRedfishVagueKeyValuePtr->Value->DataType) {
> +          return FALSE;
> +        }
> +
> +        //
> +        // Check the value.
> +        //
> +        if (ThisConfigVagueKeyValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_String) {
> +          //
> +          // Is the string identical?
> +          //
> +          if (AsciiStrCmp (
> +                ThisConfigVagueKeyValuePtr->Value->DataValue.CharPtr,
> +                ThisRedfishVagueKeyValuePtr->Value->DataValue.CharPtr
> +                ) == 0)
> +          {
> +            break;
> +          } else {
> +            return FALSE;
> +          }
> +        } else if (ThisConfigVagueKeyValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_Int64) {
> +          if (*ThisConfigVagueKeyValuePtr->Value->DataValue.Int64Ptr ==
> *ThisRedfishVagueKeyValuePtr->Value->DataValue.Int64Ptr) {
> +            break;
> +          } else {
> +            return FALSE;
> +          }
> +        } else if (ThisConfigVagueKeyValuePtr->Value->DataType ==
> RedfishCS_Vague_DataType_Bool) {
> +          if ((UINT8)*ThisConfigVagueKeyValuePtr->Value->DataValue.BoolPtr
> == (UINT8)*ThisRedfishVagueKeyValuePtr->Value->DataValue.BoolPtr) {
> +            break;
> +          } else {
> +            return FALSE;
> +          }
> +        } else {
> +          return FALSE;
> +        }
> +      }
> +
> +      ThisRedfishVagueKeyValuePtr = ThisRedfishVagueKeyValuePtr-
> >NextKeyValuePtr;
> +    }
> +
> +    if (ThisRedfishVagueKeyValuePtr == NULL) {
> +      //
> +      // No matched key name. Threat these two vague value set is different.
> +      //
> +      return FALSE;
> +    }
> +
> +    ThisConfigVagueKeyValuePtr = ThisConfigVagueKeyValuePtr-
> >NextKeyValuePtr;
>    }
> 
> -  return FALSE;
> +  return TRUE;
>  }
> 
>  /**
> --
> 2.17.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#104516): https://edk2.groups.io/g/devel/message/104516
Mute This Topic: https://groups.io/mt/98801718/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list