]> git.proxmox.com Git - mirror_edk2.git/commitdiff
RedfishPkg/library: EDK2 port of jansson library
authorAbner Chang <abner.chang@hpe.com>
Fri, 4 Dec 2020 15:59:59 +0000 (23:59 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Sat, 9 Jan 2021 03:08:51 +0000 (03:08 +0000)
edk2 JsonLib which is the edk2 port of open source
jansson library.
(https://github.com/akheron/jansson)
jansson library is the open source project to manipulate
JSON data structure.

Signed-off-by: Abner Chang <abner.chang@hpe.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Nickle Wang <nickle.wang@hpe.com>
Cc: Peter O'Hanley <peter.ohanley@hpe.com>
Reviewed-by: Nickle Wang <nickle.wang@hpe.com>
Acked-by: Leif Lindholm <leif@nuviainc.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
RedfishPkg/Include/Library/JsonLib.h [new file with mode: 0644]
RedfishPkg/Library/JsonLib/JsonLib.c [new file with mode: 0644]
RedfishPkg/Library/JsonLib/JsonLib.inf [new file with mode: 0644]
RedfishPkg/Library/JsonLib/Readme.rst [new file with mode: 0644]
RedfishPkg/Library/JsonLib/jansson_config.h [new file with mode: 0644]
RedfishPkg/Library/JsonLib/jansson_private_config.h [new file with mode: 0644]
RedfishPkg/Library/JsonLib/load.c [new file with mode: 0644]
RedfishPkg/RedfishPkg.ci.yaml
RedfishPkg/RedfishPkg.dec

diff --git a/RedfishPkg/Include/Library/JsonLib.h b/RedfishPkg/Include/Library/JsonLib.h
new file mode 100644 (file)
index 0000000..3c10f67
--- /dev/null
@@ -0,0 +1,779 @@
+/** @file\r
+  APIs for JSON operations.\r
+\r
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#ifndef JSON_LIB_H_\r
+#define JSON_LIB_H_\r
+\r
+typedef    VOID*    EDKII_JSON_VALUE;\r
+typedef    VOID*    EDKII_JSON_ARRAY;\r
+typedef    VOID*    EDKII_JSON_OBJECT;\r
+\r
+///\r
+/// Map to json_int_t in jansson.h\r
+///\r
+typedef    INT64   EDKII_JSON_INT_T; // #JSON_INTEGER_IS_LONG_LONG is set to 1\r
+                                     // in jansson_Config.h\r
+\r
+///\r
+/// Map to the definitions in jansson.h\r
+/// See below URI for the JSON encoding flags reference.\r
+/// https://jansson.readthedocs.io/en/2.13/apiref.html#encoding\r
+///\r
+#define EDKII_JSON_MAX_INDENT        0x1F\r
+#define EDKII_JSON_INDENT(n)         ((n) & EDKII_JSON_MAX_INDENT)\r
+\r
+#define EDKII_JSON_COMPACT           0x20\r
+#define EDKII_JSON_ENSURE_ASCII      0x40\r
+#define EDKII_JSON_SORT_KEYS         0x80\r
+#define EDKII_JSON_PRESERVE_ORDER    0x100\r
+#define EDKII_JSON_ENCODE_ANY        0x200\r
+#define EDKII_JSON_ESCAPE_SLASH      0x400\r
+#define EDKII_JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)\r
+#define EDKII_JSON_EMBED             0x10000\r
+\r
+///\r
+/// Map to the definitions in jansson.h\r
+/// See below URI for the JSON decoding flags reference.\r
+/// https://jansson.readthedocs.io/en/2.13/apiref.html?highlight=json_loadb#decoding\r
+///\r
+#define EDKII_JSON_REJECT_DUPLICATES  0x1\r
+#define EDKII_JSON_DISABLE_EOF_CHECK  0x2\r
+#define EDKII_JSON_DECODE_ANY         0x4\r
+#define EDKII_JSON_DECODE_INT_AS_REAL 0x8\r
+#define EDKII_JSON_ALLOW_NUL          0x10\r
+\r
+#define EDKII_JSON_ARRAY_FOREACH(Array, Index, Value) \\r
+  for(Index = 0; \\r
+    Index < JsonArrayCount(Array) && (Value = JsonArrayGetValue(Array, Index)); \\r
+    Index++)\r
+\r
+///\r
+///  Map to the json_error_t in jansson.h\r
+///\r
+#define EDKII_JSON_ERROR_TEXT_LENGTH   160\r
+#define EDKII_JSON_ERROR_SOURCE_LENGTH 80\r
+typedef struct {\r
+    INTN    Line;\r
+    INTN    Column;\r
+    INTN    Position;\r
+    CHAR8   Source [EDKII_JSON_ERROR_SOURCE_LENGTH];\r
+    CHAR8   Text [EDKII_JSON_ERROR_TEXT_LENGTH];\r
+} EDKII_JSON_ERROR;\r
+\r
+///\r
+///  Map to the json_type in jansson.h\r
+///\r
+typedef enum {\r
+    EdkiiJsonTypeObject,\r
+    EdkiiJsonTypeArray,\r
+    EdkiiJsonTypeString,\r
+    EdkiiJsonTypeInteger,\r
+    EdkiiJsonTypeReal,\r
+    EdkiiJsonTypeTrue,\r
+    EdkiiJsonTypeFalse,\r
+    EdkiiJsonTypeNull\r
+} EDKII_JSON_TYPE;\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON array,\r
+  or NULL on error. Initially, the array is empty.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @retval      The created JSON value which contains a JSON array or NULL if intial a JSON array\r
+               is failed.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitArray (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON object,\r
+  or NULL on error. Initially, the object is empty.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @retval      The created JSON value which contains a JSON object or NULL if intial a JSON object\r
+               is failed.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitObject (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON string,\r
+  or NULL on error.\r
+\r
+  The input string must be NULL terminated Ascii format, non-Ascii characters will\r
+  be processed as an error. Unicode characters can also be represented by Ascii string\r
+  as the format: \u + 4 hexadecimal digits, like \u3E5A, or \u003F.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   String      The Ascii string to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON string or NULL. Select a\r
+               Getter API for a specific encoding format.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitAsciiString (\r
+  IN    CONST CHAR8    *String\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON string,\r
+  or NULL on error.\r
+\r
+  The input must be a NULL terminated UCS2 format Unicode string.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   String      The Unicode string to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON string or NULL. Select a\r
+               Getter API for a specific encoding format.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitUnicodeString (\r
+  IN    CHAR16    *String\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON integer,\r
+  or NULL on error.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   Value       The integer to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON number or NULL.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitNumber (\r
+  IN    INT64    Value\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON boolean,\r
+  or NULL on error.\r
+\r
+  Boolean JSON value is kept as static value, and no need to do any cleanup work.\r
+\r
+  @param[in]   Value       The boolean value to initialize.\r
+\r
+  @retval      The created JSON value which contains a JSON boolean or NULL.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitBoolean (\r
+  IN    BOOLEAN    Value\r
+  );\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON NULL,\r
+  or NULL on error.\r
+\r
+  NULL JSON value is kept as static value, and no need to do any cleanup work.\r
+\r
+  @retval      The created NULL JSON value.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitNull (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The function is used to decrease the reference count of a JSON value by one, and once\r
+  this reference count drops to zero, the value is destroyed and it can no longer be used.\r
+  If this destroyed value is object type or array type, reference counts for all containing\r
+  JSON values will be decreased by 1. Boolean JSON value and NULL JSON value won't be destroyed\r
+  since they are static values kept in memory.\r
+\r
+  Reference Count Strategy: BaseJsonLib uses this strategy to track whether a value is still\r
+  in use or not. When a value is created, it's reference count is set to 1. If a reference to a\r
+  value is kept for use, its reference count is incremented, and when the value is no longer\r
+  needed, the reference count is decremented. When the reference count drops to zero, there are\r
+  no references left, and the value can be destroyed.\r
+\r
+  The given JSON value maybe NULL and not causing any problem. Just output the debug message\r
+  to inform caller the NULL value is passed in.\r
+\r
+  @param[in]   Json             The JSON value to be freed. json_decref may return without any\r
+                                changes if Json is NULL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+JsonValueFree (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to create a fresh copy of a JSON value, and all child values are deep\r
+  copied in a recursive fashion. It should be called when this JSON value might be modified\r
+  in later use, but the original still wants to be used in somewhere else.\r
+\r
+  Reference counts of the returned root JSON value and all child values will be set to 1, and\r
+  caller needs to cleanup the root value by calling JsonValueFree().\r
+\r
+  * Note: Since this function performs a copy from bottom to up, too many calls may cause some\r
+  performance issues, user should avoid unnecessary calls to this function unless it is really\r
+  needed.\r
+\r
+  @param[in]   Json             The JSON value to be cloned.\r
+\r
+  @retval      Return the cloned JSON value, or NULL on error.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueClone (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON array.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON array.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON array.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsArray (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON object.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON object.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON object.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsObject (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON Value contains a string, Ascii or\r
+  Unicode format is not differentiated.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON string.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON string.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON number.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value is contains JSON number.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON number.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsNumber (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON boolean.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON boolean.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON boolean.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsBoolean (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON NULL.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON NULL.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON NULL.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsNull (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated array in an array type JSON value.\r
+\r
+  Any changes to the returned array will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated array in JSON value or NULL.\r
+\r
+**/\r
+EDKII_JSON_ARRAY\r
+EFIAPI\r
+JsonValueGetArray (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated object in an object type JSON value.\r
+\r
+  Any changes to the returned object will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated object in JSON value or NULL.\r
+\r
+**/\r
+EDKII_JSON_OBJECT\r
+EFIAPI\r
+JsonValueGetObject (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated Ascii string in a string type JSON value.\r
+\r
+  Any changes to the returned string will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated Ascii string in JSON value or NULL.\r
+\r
+**/\r
+CONST CHAR8 *\r
+EFIAPI\r
+JsonValueGetAsciiString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated Unicode string in a string type JSON value.\r
+\r
+  Caller can do any changes to the returned string without any impact to the original JSON\r
+  value, and caller needs to free the returned string using FreePool().\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated Unicode string in JSON value or NULL.\r
+\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+JsonValueGetUnicodeString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated integer in a number type JSON value.\r
+\r
+  The input JSON value should not be NULL or contain no JSON number, otherwise it will\r
+  ASSERT() and return 0.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated number in JSON value.\r
+\r
+**/\r
+INT64\r
+EFIAPI\r
+JsonValueGetNumber (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated boolean in a boolean type JSON value.\r
+\r
+  The input JSON value should not be NULL or contain no JSON boolean, otherwise it will\r
+  ASSERT() and return FALSE.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated value of JSON boolean.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueGetBoolean (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to retrieve the associated string in a string type JSON value.\r
+\r
+  Any changes to the returned string will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated Ascii string in JSON value or NULL on errors.\r
+\r
+**/\r
+CONST CHAR8*\r
+EFIAPI\r
+JsonValueGetString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to get the number of elements in a JSON object, or 0 if it is NULL or\r
+  not a JSON object.\r
+\r
+  @param[in]   JsonObject              The provided JSON object.\r
+\r
+  @retval      Return the number of elements in this JSON object or 0.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+JsonObjectSize (\r
+  IN    EDKII_JSON_OBJECT    JsonObject\r
+  );\r
+\r
+/**\r
+  The function is used to enumerate all keys in a JSON object.\r
+\r
+  Caller should be responsible to free the returned key array reference using\r
+  FreePool(). But contained keys are read only and must not be modified or freed.\r
+\r
+  @param[in]   JsonObj                The provided JSON object for enumeration.\r
+  @param[out]  KeyCount               The count of keys in this JSON object.\r
+\r
+  @retval      Return an array of the enumerated keys in this JSON object or NULL if\r
+               JsonObj is not an JSON object, key count is zero or on other errors.\r
+\r
+**/\r
+CHAR8**\r
+JsonObjectGetKeys (\r
+  IN    EDKII_JSON_OBJECT    JsonObj,\r
+  OUT   UINTN                *KeyCount\r
+  );\r
+\r
+/**\r
+  The function is used to get a JSON value corresponding to the input key from a JSON object.\r
+\r
+  It only returns a reference to this value and any changes on this value will impact the\r
+  original JSON object. If that is not expected, please call JsonValueClone() to clone it to\r
+  use.\r
+\r
+  Input key must be a valid NULL terminated UTF8 encoded string. NULL will be returned when\r
+  Key-Value is not found in this JSON object.\r
+\r
+  @param[in]   JsonObj           The provided JSON object.\r
+  @param[in]   Key               The key of the JSON value to be retrieved.\r
+\r
+  @retval      Return the corresponding JSON value to key, or NULL on error.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonObjectGetValue (\r
+  IN    CONST EDKII_JSON_OBJECT    JsonObj,\r
+  IN    CONST CHAR8                *Key\r
+  );\r
+\r
+/**\r
+  The function is used to set a JSON value corresponding to the input key from a JSON object,\r
+  and the reference count of this value will be increased by 1.\r
+\r
+  Input key must be a valid NULL terminated UTF8 encoded string. If there already is a value for\r
+  this key, this key will be assigned to the new JSON value. The old JSON value will be removed\r
+  from this object and thus its' reference count will be decreased by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonObj                The provided JSON object.\r
+  @param[in]   Key                    The key of the JSON value to be set.\r
+  @param[in]   Json                   The JSON value to set to this JSON object mapped by key.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            The JSON value has been set to this JSON object.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonObjectSetValue (\r
+  IN    EDKII_JSON_OBJECT    JsonObj,\r
+  IN    CONST CHAR8          *Key,\r
+  IN    EDKII_JSON_VALUE     Json\r
+  );\r
+\r
+/**\r
+  The function is used to get the number of elements in a JSON array. Returns or 0 if JsonArray\r
+  is NULL or not a JSON array.\r
+\r
+  @param[in]   JsonArray              The provided JSON array.\r
+\r
+  @retval      Return the number of elements in this JSON array or 0.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+JsonArrayCount (\r
+  IN    EDKII_JSON_ARRAY    JsonArray\r
+  );\r
+\r
+/**\r
+  The function is used to return the JSON value in the array at position index. The valid range\r
+  for this index is from 0 to the return value of JsonArrayCount() minus 1.\r
+\r
+  It only returns a reference to this value and any changes on this value will impact the\r
+  original JSON object. If that is not expected, please call JsonValueClone() to clone it to\r
+  use.\r
+\r
+  If this array is NULL or not a JSON array, or if index is out of range, NULL will be returned.\r
+\r
+  @param[in]   JsonArray         The provided JSON Array.\r
+\r
+  @retval      Return the JSON value located in the Index position or\r
+               NULL if JsonArray is not an array or no items in the array.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonArrayGetValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    UINTN               Index\r
+  );\r
+\r
+/**\r
+  The function is used to append a JSON value to the end of the JSON array, and grow the size of\r
+  array by 1. The reference count of this value will be increased by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonArray              The provided JSON object.\r
+  @param[in]   Json                   The JSON value to append.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            JSON value has been appended to the end of the JSON array.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonArrayAppendValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    EDKII_JSON_VALUE    Json\r
+  );\r
+\r
+/**\r
+  The function is used to remove a JSON value at position index, shifting the elements after index\r
+  one position towards the start of the array. The reference count of this value will be decreased\r
+  by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonArray              The provided JSON array.\r
+  @param[in]   Index                  The Index position before removement.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            The JSON array has been removed at position index.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonArrayRemoveValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    UINTN               Index\r
+  );\r
+\r
+/**\r
+  Dump JSON to a buffer.\r
+\r
+  @param[in]   JsonValue       The provided JSON value.\r
+  @param[in]   Flags           The Index position before removement. The value\r
+                               could be the combination of below flags.\r
+                                 - EDKII_JSON_INDENT(n)\r
+                                 - EDKII_JSON_COMPACT\r
+                                 - EDKII_JSON_ENSURE_ASCII\r
+                                 - EDKII_JSON_SORT_KEYS\r
+                                 - EDKII_JSON_PRESERVE_ORDER\r
+                                 - EDKII_JSON_ENCODE_ANY\r
+                                 - EDKII_JSON_ESCAPE_SLASH\r
+                                 - EDKII_JSON_REAL_PRECISION(n)\r
+                                 - EDKII_JSON_EMBED\r
+                               See below URI for the JSON encoding flags reference.\r
+                               https://jansson.readthedocs.io/en/2.13/apiref.html#encoding\r
+\r
+  @retval      CHAR8 *         Dump fail if NULL returned, otherwise the buffer\r
+                               contain JSON paylaod in ASCII string. The return\r
+                               value must be freed by the caller FreePool().\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+JsonDumpString (\r
+  IN    EDKII_JSON_VALUE    JsonValue,\r
+  IN    UINTN               Flags\r
+  );\r
+\r
+/**\r
+  Load JSON from a buffer.\r
+\r
+  @param[in]   Buffer        Bufffer to the JSON payload\r
+  @param[in]   BufferLen     Length of the buffer\r
+  @param[in]   Flags         Flag of loading JSON buffer, the value\r
+                             could be the combination of below flags.\r
+                               - EDKII_JSON_REJECT_DUPLICATES\r
+                               - EDKII_JSON_DISABLE_EOF_CHECK\r
+                               - EDKII_JSON_DECODE_ANY\r
+                               - EDKII_JSON_DECODE_INT_AS_REAL\r
+                               - EDKII_JSON_ALLOW_NUL\r
+                             See below URI for the JSON encoding flags reference.\r
+                             https://jansson.readthedocs.io/en/2.13/apiref.html?highlight=json_loadb#decoding\r
+\r
+  @param[in,out]   Error     Pointer EDKII_JSON_ERROR structure\r
+\r
+  @retval      EDKII_JSON_VALUE  NULL means fail to load JSON payload.\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonLoadBuffer (\r
+  IN    CONST CHAR8       *Buffer,\r
+  IN    UINTN              BufferLen,\r
+  IN    UINTN              Flags,\r
+  IN OUT EDKII_JSON_ERROR  *Error\r
+  );\r
+\r
+/**\r
+  The reference count is used to track whether a value is still in use or not.\r
+  When a value is created, it's reference count is set to 1.\r
+  when the value is no longer needed, the reference count is decremented.\r
+  When the reference count drops to zero, there are no references left and the\r
+  value can be destroyed.\r
+\r
+  This funciton decrement the reference count of EDKII_JSON_VALUE. As soon as\r
+  a call to json_decref() drops the reference count to zero, the value is\r
+  destroyed and it can no longer be used.\r
+\r
+  @param[in]   JsonValue      JSON value\r
+**/\r
+VOID\r
+EFIAPI\r
+JsonDecreaseReference (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  );\r
+\r
+/**\r
+  The reference count is used to track whether a value is still in use or not.\r
+  When a value is created, it's reference count is set to 1.\r
+  If a reference to a value is kept (e.g. a value is stored somewhere for later use),\r
+  its reference count is incremented.\r
+\r
+  This function increment the reference count of json if it's not NULL.\r
+  Returns EDKII_JSON_VALUE.\r
+\r
+  @param[in]   JsonValue      JSON value\r
+  @retval      EDKII_JSON_VALUE of itself\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonIncreaseReference (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  );\r
+/**\r
+  Returns an opaque iterator which can be used to iterate over all key-value pairs\r
+  in object, or NULL if object is empty\r
+\r
+  @param[in]   JsonValue      JSON value\r
+**/\r
+VOID *\r
+EFIAPI\r
+JsonObjectIterator (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  );\r
+\r
+/**\r
+  Extract the associated value from iterator.\r
+\r
+  @param[in]   Iterator   Iterator pointer\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonObjectIteratorValue (\r
+  IN VOID *Iterator\r
+  );\r
+\r
+/**\r
+  Returns an iterator pointing to the next key-value pair in object after iter,\r
+  or NULL if the whole object has been iterated through.\r
+\r
+  @param[in]   JsonValue  JSON value\r
+  @param[in]   Iterator   Iterator pointer\r
+  @retval      Iterator pointer\r
+**/\r
+VOID *\r
+JsonObjectIteratorNext (\r
+  IN EDKII_JSON_VALUE JsonValue,\r
+  IN VOID             *Iterator\r
+  );\r
+\r
+/**\r
+  Returns the json type of this json value\r
+\r
+  @param[in]   JsonValue  JSON value\r
+  @retval      JSON type returned\r
+**/\r
+EDKII_JSON_TYPE\r
+EFIAPI\r
+JsonGetType(\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  );\r
+#endif\r
diff --git a/RedfishPkg/Library/JsonLib/JsonLib.c b/RedfishPkg/Library/JsonLib/JsonLib.c
new file mode 100644 (file)
index 0000000..34ff381
--- /dev/null
@@ -0,0 +1,957 @@
+/** @file\r
+  APIs for JSON operations. The fuctions provided by this library are the\r
+  wrapper to native open source jansson library. See below document for\r
+  the API reference.\r
+  https://jansson.readthedocs.io/en/2.13/apiref.html\r
+\r
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/JsonLib.h>\r
+#include <Library/BaseUcs2Utf8Lib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include "jansson.h"\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON array,\r
+  or NULL on error. Initially, the array is empty.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @retval      The created JSON value which contains a JSON array or NULL if intial a JSON array\r
+               is failed.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitArray (\r
+  VOID\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_array();\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON object,\r
+  or NULL on error. Initially, the object is empty.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @retval      The created JSON value which contains a JSON object or NULL if intial a JSON object\r
+               is failed.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitObject (\r
+  VOID\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_object();\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON string,\r
+  or NULL on error.\r
+\r
+  The input string must be NULL terminated Ascii format, non-Ascii characters will\r
+  be processed as an error. Unicode characters can also be represented by Ascii string\r
+  as the format: \u + 4 hexadecimal digits, like \u3E5A, or \u003F.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   String      The Ascii string to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON string or NULL. Select a\r
+               Getter API for a specific encoding format.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitAsciiString (\r
+  IN    CONST CHAR8    *String\r
+  )\r
+{\r
+  UINTN    Index;\r
+\r
+  if (String == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Index = 0;\r
+  while (*(String + Index) != '\0') {\r
+    if (((*(String + Index)) & 0x80) != 0x00) {\r
+      return NULL;\r
+    }\r
+\r
+    Index++;\r
+  }\r
+\r
+  return (EDKII_JSON_VALUE)json_string (String);\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON string,\r
+  or NULL on error.\r
+\r
+  The input must be a NULL terminated UCS2 format Unicode string.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   String      The Unicode string to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON string or NULL. Select a\r
+               Getter API for a specific encoding format.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitUnicodeString (\r
+  IN    CHAR16    *String\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  CHAR8         *Utf8Str;\r
+\r
+  if (String == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Utf8Str = NULL;\r
+  Status  = UCS2StrToUTF8 (String, &Utf8Str);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  return (EDKII_JSON_VALUE)json_string (Utf8Str);\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON integer,\r
+  or NULL on error.\r
+\r
+  The reference count of this value will be set to 1, and caller needs to cleanup the\r
+  value by calling JsonValueFree().\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   Value       The integer to initialize to JSON value\r
+\r
+  @retval      The created JSON value which contains a JSON number or NULL.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitNumber (\r
+  IN    INT64    Value\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_integer (Value);\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON boolean,\r
+  or NULL on error.\r
+\r
+  Boolean JSON value is kept as static value, and no need to do any cleanup work.\r
+\r
+  @param[in]   Value       The boolean value to initialize.\r
+\r
+  @retval      The created JSON value which contains a JSON boolean or NULL.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitBoolean (\r
+  IN    BOOLEAN    Value\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_boolean (Value);\r
+}\r
+\r
+/**\r
+  The function is used to initialize a JSON value which contains a new JSON NULL,\r
+  or NULL on error.\r
+\r
+  NULL JSON value is kept as static value, and no need to do any cleanup work.\r
+\r
+  @retval      The created NULL JSON value.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueInitNull (\r
+  VOID\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_null();\r
+}\r
+\r
+/**\r
+  The function is used to decrease the reference count of a JSON value by one, and once\r
+  this reference count drops to zero, the value is destroyed and it can no longer be used.\r
+  If this destroyed value is object type or array type, reference counts for all containing\r
+  JSON values will be decreased by 1. Boolean JSON value and NULL JSON value won't be destroyed\r
+  since they are static values kept in memory.\r
+\r
+  Reference Count Strategy: BaseJsonLib uses this strategy to track whether a value is still\r
+  in use or not. When a value is created, it's reference count is set to 1. If a reference to a\r
+  value is kept for use, its reference count is incremented, and when the value is no longer\r
+  needed, the reference count is decremented. When the reference count drops to zero, there are\r
+  no references left, and the value can be destroyed.\r
+\r
+  The given JSON value maybe NULL and not causing any problem. Just output the debug message\r
+  to inform caller the NULL value is passed in.\r
+\r
+  @param[in]   Json             The JSON value to be freed. json_decref may return without any\r
+                                changes if Json is NULL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+JsonValueFree (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  json_decref((json_t *)Json);\r
+}\r
+\r
+/**\r
+  The function is used to create a fresh copy of a JSON value, and all child values are deep\r
+  copied in a recursive fashion. It should be called when this JSON value might be modified\r
+  in later use, but the original still wants to be used in somewhere else.\r
+\r
+  Reference counts of the returned root JSON value and all child values will be set to 1, and\r
+  caller needs to cleanup the root value by calling JsonValueFree().\r
+\r
+  * Note: Since this function performs a copy from bottom to up, too many calls may cause some\r
+  performance issues, user should avoid unnecessary calls to this function unless it is really\r
+  needed.\r
+\r
+  @param[in]   Json             The JSON value to be cloned.\r
+\r
+  @retval      Return the cloned JSON value, or NULL on error.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonValueClone (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_deep_copy ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON array.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON array.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON array.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsArray (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_array ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON object.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON object.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON object.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsObject (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_object ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON Value contains a string, Ascii or\r
+  Unicode format is not differentiated.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON string.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON string.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_string ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON number.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value is contains JSON number.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON number.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsNumber (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_integer ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON boolean.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON boolean.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON boolean.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsBoolean (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_boolean ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to return if the provided JSON value contains a JSON NULL.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      TRUE             The JSON value contains a JSON NULL.\r
+  @retval      FALSE            The JSON value doesn't contain a JSON NULL.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueIsNull (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_is_null ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated array in an array type JSON value.\r
+\r
+  Any changes to the returned array will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated array in JSON value or NULL.\r
+\r
+**/\r
+EDKII_JSON_ARRAY\r
+EFIAPI\r
+JsonValueGetArray (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  if (Json == NULL || !JsonValueIsArray (Json)) {\r
+    return NULL;\r
+  }\r
+\r
+  return (EDKII_JSON_ARRAY)Json;\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated object in an object type JSON value.\r
+\r
+  Any changes to the returned object will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated object in JSON value or NULL.\r
+\r
+**/\r
+EDKII_JSON_OBJECT\r
+EFIAPI\r
+JsonValueGetObject (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  if (Json == NULL || !JsonValueIsObject (Json)) {\r
+    return NULL;\r
+  }\r
+\r
+  return (EDKII_JSON_OBJECT)Json;\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated Ascii string in a string type JSON value.\r
+\r
+  Any changes to the returned string will impact the original JSON value.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated Ascii string in JSON value or NULL.\r
+\r
+**/\r
+CONST CHAR8 *\r
+EFIAPI\r
+JsonValueGetAsciiString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  CHAR8          *AsciiStr;\r
+  UINTN          Index;\r
+\r
+  AsciiStr = (CHAR8 *)  ((json_t *) Json);\r
+  if (AsciiStr == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Index = 0;\r
+  while (*(AsciiStr + Index) != '\0') {\r
+    if (((*(AsciiStr + Index)) & 0x80) != 0x00) {\r
+      return NULL;\r
+    }\r
+\r
+    Index++;\r
+  }\r
+\r
+  return AsciiStr;\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated Unicode string in a string type JSON value.\r
+\r
+  Caller can do any changes to the returned string without any impact to the original JSON\r
+  value, and caller needs to free the returned string using FreePool().\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated Unicode string in JSON value or NULL.\r
+\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+JsonValueGetUnicodeString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+  CONST CHAR8    *Utf8Str;\r
+  CHAR16         *Ucs2Str;\r
+\r
+  Utf8Str = json_string_value ((json_t *) Json);\r
+  if (Utf8Str == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = UTF8StrToUCS2 ((CHAR8*)Utf8Str, &Ucs2Str);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  return Ucs2Str;\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated integer in a number type JSON value.\r
+\r
+  The input JSON value should not be NULL or contain no JSON number, otherwise it will\r
+  ASSERT() and return 0.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated number in JSON value.\r
+\r
+**/\r
+INT64\r
+EFIAPI\r
+JsonValueGetNumber (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  ASSERT (Json != NULL && JsonValueIsNumber (Json));\r
+  if (Json == NULL || !JsonValueIsNumber (Json)) {\r
+    return 0;\r
+  }\r
+\r
+  return json_integer_value ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated boolean in a boolean type JSON value.\r
+\r
+  The input JSON value should not be NULL or contain no JSON boolean, otherwise it will\r
+  ASSERT() and return FALSE.\r
+\r
+  @param[in]   Json             The provided JSON value.\r
+\r
+  @retval      Return the associated value of JSON boolean.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+JsonValueGetBoolean (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  ASSERT (Json != NULL && JsonValueIsBoolean (Json));\r
+  if (Json == NULL || !JsonValueIsBoolean (Json)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return json_is_true ((json_t *) Json);\r
+}\r
+\r
+/**\r
+  The function is used to retrieve the associated string in a string type JSON value.\r
+\r
+  Any changes to the returned string will impact the original JSON value.\r
+\r
+  @param[in]   Json The provided JSON value.\r
+\r
+  @retval      Return the associated Ascii string in JSON value or NULL on errors.\r
+\r
+**/\r
+CONST CHAR8*\r
+EFIAPI\r
+JsonValueGetString (\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  return json_string_value ((const json_t *)Json);\r
+}\r
+\r
+/**\r
+  The function is used to get the number of elements in a JSON object, or 0 if it is NULL or\r
+  not a JSON object.\r
+\r
+  @param[in]   JsonObject              The provided JSON object.\r
+\r
+  @retval      Return the number of elements in this JSON object or 0.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+JsonObjectSize (\r
+  IN    EDKII_JSON_OBJECT    JsonObject\r
+  )\r
+{\r
+  return json_object_size ((json_t *) JsonObject);\r
+}\r
+\r
+/**\r
+  The function is used to enumerate all keys in a JSON object.\r
+\r
+  Caller should be responsible to free the returned key array reference using\r
+  FreePool(). But contained keys are read only and must not be modified or freed.\r
+\r
+  @param[in]   JsonObj                The provided JSON object for enumeration.\r
+  @param[out]  KeyCount               The count of keys in this JSON object.\r
+\r
+  @retval      Return an array of the enumerated keys in this JSON object or NULL if\r
+               JsonObj is not an JSON object, key count is zero or on other errors.\r
+\r
+**/\r
+CHAR8**\r
+JsonObjectGetKeys (\r
+  IN    EDKII_JSON_OBJECT    JsonObj,\r
+  OUT   UINTN                *KeyCount\r
+  )\r
+{\r
+\r
+  UINTN               Index;\r
+  CONST CHAR8         **KeyArray;\r
+  CONST CHAR8         *Key;\r
+  EDKII_JSON_VALUE    Value;\r
+\r
+  if (JsonObj == NULL || KeyCount == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Index = 0;\r
+  json_object_foreach(JsonObj, Key, Value) {\r
+    Index++;\r
+  }\r
+  if (Index == 0) {\r
+    *KeyCount = 0;\r
+    return NULL;\r
+  }\r
+\r
+  *KeyCount = Index;\r
+  KeyArray = (CONST CHAR8 **) AllocateZeroPool (*KeyCount * sizeof (CHAR8 *));\r
+  if (KeyArray == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Key   = NULL;\r
+  Value = NULL;\r
+  Index = 0;\r
+  json_object_foreach((json_t *) JsonObj, Key, Value) {\r
+    KeyArray[Index] = Key;\r
+    Index++;\r
+  }\r
+\r
+  return (CHAR8 **)KeyArray;\r
+}\r
+\r
+/**\r
+  The function is used to get a JSON value corresponding to the input key from a JSON object.\r
+\r
+  It only returns a reference to this value and any changes on this value will impact the\r
+  original JSON object. If that is not expected, please call JsonValueClone() to clone it to\r
+  use.\r
+\r
+  Input key must be a valid NULL terminated UTF8 encoded string. NULL will be returned when\r
+  Key-Value is not found in this JSON object.\r
+\r
+  @param[in]   JsonObj           The provided JSON object.\r
+  @param[in]   Key               The key of the JSON value to be retrieved.\r
+\r
+  @retval      Return the corresponding JSON value to key, or NULL on error.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonObjectGetValue (\r
+  IN    CONST EDKII_JSON_OBJECT    JsonObj,\r
+  IN    CONST CHAR8                *Key\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_object_get ((const json_t *)JsonObj, (const char *)Key);\r
+}\r
+\r
+/**\r
+  The function is used to set a JSON value corresponding to the input key from a JSON object,\r
+  and the reference count of this value will be increased by 1.\r
+\r
+  Input key must be a valid NULL terminated UTF8 encoded string. If there already is a value for\r
+  this key, this key will be assigned to the new JSON value. The old JSON value will be removed\r
+  from this object and thus its' reference count will be decreased by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonObj                The provided JSON object.\r
+  @param[in]   Key                    The key of the JSON value to be set.\r
+  @param[in]   Json                   The JSON value to set to this JSON object mapped by key.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            The JSON value has been set to this JSON object.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonObjectSetValue (\r
+  IN    EDKII_JSON_OBJECT    JsonObj,\r
+  IN    CONST CHAR8          *Key,\r
+  IN    EDKII_JSON_VALUE     Json\r
+  )\r
+{\r
+  if (json_object_set ((json_t *) JsonObj, Key, (json_t *) Json) != 0) {\r
+    return EFI_ABORTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  The function is used to get the number of elements in a JSON array. Returns or 0 if JsonArray\r
+  is NULL or not a JSON array.\r
+\r
+  @param[in]   JsonArray              The provided JSON array.\r
+\r
+  @retval      Return the number of elements in this JSON array or 0.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+JsonArrayCount (\r
+  IN    EDKII_JSON_ARRAY    JsonArray\r
+  )\r
+{\r
+  return json_array_size ((json_t *) JsonArray);\r
+}\r
+\r
+/**\r
+  The function is used to return the JSON value in the array at position index. The valid range\r
+  for this index is from 0 to the return value of JsonArrayCount() minus 1.\r
+\r
+  It only returns a reference to this value and any changes on this value will impact the\r
+  original JSON object. If that is not expected, please call JsonValueClone() to clone it to\r
+  use.\r
+\r
+  If this array is NULL or not a JSON array, or if index is out of range, NULL will be returned.\r
+\r
+  @param[in]   JsonArray         The provided JSON Array.\r
+\r
+  @retval      Return the JSON value located in the Index position or\r
+               NULL if JsonArray is not an array or no items in the array.\r
+\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonArrayGetValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    UINTN               Index\r
+  )\r
+{\r
+  return (EDKII_JSON_VALUE)json_array_get ((json_t *) JsonArray, Index);\r
+}\r
+\r
+/**\r
+  The function is used to append a JSON value to the end of the JSON array, and grow the size of\r
+  array by 1. The reference count of this value will be increased by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonArray              The provided JSON object.\r
+  @param[in]   Json                   The JSON value to append.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            JSON value has been appended to the end of the JSON array.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonArrayAppendValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    EDKII_JSON_VALUE    Json\r
+  )\r
+{\r
+  if (json_array_append ((json_t *) JsonArray, (json_t *) Json) != 0) {\r
+    return EFI_ABORTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  The function is used to remove a JSON value at position index, shifting the elements after index\r
+  one position towards the start of the array. The reference count of this value will be decreased\r
+  by 1.\r
+\r
+  More details for reference count strategy can refer to the API description for JsonValueFree().\r
+\r
+  @param[in]   JsonArray              The provided JSON array.\r
+  @param[in]   Index                  The Index position before removement.\r
+\r
+  @retval      EFI_ABORTED            Some error occur and operation aborted.\r
+  @retval      EFI_SUCCESS            The JSON array has been removed at position index.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+JsonArrayRemoveValue (\r
+  IN    EDKII_JSON_ARRAY    JsonArray,\r
+  IN    UINTN               Index\r
+  )\r
+{\r
+  if (json_array_remove ((json_t *) JsonArray, Index) != 0) {\r
+    return EFI_ABORTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Dump JSON to a buffer.\r
+\r
+  @param[in]   JsonValue       The provided JSON value.\r
+  @param[in]   Flags           The Index position before removement. The value\r
+                               could be the combination of below flags.\r
+                                 - EDKII_JSON_INDENT(n)\r
+                                 - EDKII_JSON_COMPACT\r
+                                 - EDKII_JSON_ENSURE_ASCII\r
+                                 - EDKII_JSON_SORT_KEYS\r
+                                 - EDKII_JSON_PRESERVE_ORDER\r
+                                 - EDKII_JSON_ENCODE_ANY\r
+                                 - EDKII_JSON_ESCAPE_SLASH\r
+                                 - EDKII_JSON_REAL_PRECISION(n)\r
+                                 - EDKII_JSON_EMBED\r
+                               See below URI for the JSON encoding flags reference.\r
+                               https://jansson.readthedocs.io/en/2.13/apiref.html#encoding\r
+\r
+  @retval      CHAR8 *         Dump fail if NULL returned, otherwise the buffer\r
+                               contain JSON paylaod in ASCII string. The return\r
+                               value must be freed by the caller using FreePool().\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+JsonDumpString (\r
+  IN    EDKII_JSON_VALUE    JsonValue,\r
+  IN    UINTN               Flags\r
+  )\r
+{\r
+    if (JsonValue == NULL) {\r
+      return NULL;\r
+    }\r
+    return json_dumps((json_t *)JsonValue, Flags);\r
+}\r
+\r
+/**\r
+  Load JSON from a buffer.\r
+\r
+  @param[in]   Buffer        Bufffer to the JSON payload\r
+  @param[in]   BufferLen     Length of the buffer\r
+  @param[in]   Flags         Flag of loading JSON buffer, the value\r
+                             could be the combination of below flags.\r
+                               - EDKII_JSON_REJECT_DUPLICATES\r
+                               - EDKII_JSON_DISABLE_EOF_CHECK\r
+                               - EDKII_JSON_DECODE_ANY\r
+                               - EDKII_JSON_DECODE_INT_AS_REAL\r
+                               - EDKII_JSON_ALLOW_NUL\r
+                             See below URI for the JSON encoding flags reference.\r
+                             https://jansson.readthedocs.io/en/2.13/apiref.html?highlight=json_loadb#decoding\r
+\r
+  @param[in,out]   Error     Pointer EDKII_JSON_ERROR structure\r
+\r
+  @retval      EDKII_JSON_VALUE  NULL means fail to load JSON payload.\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonLoadBuffer (\r
+  IN    CONST CHAR8       *Buffer,\r
+  IN    UINTN              BufferLen,\r
+  IN    UINTN              Flags,\r
+  IN OUT EDKII_JSON_ERROR  *Error\r
+  )\r
+{\r
+  return json_loadb(Buffer, BufferLen, Flags, (json_error_t *)Error);\r
+}\r
+\r
+/**\r
+  The reference count is used to track whether a value is still in use or not.\r
+  When a value is created, it's reference count is set to 1.\r
+  when the value is no longer needed, the reference count is decremented.\r
+  When the reference count drops to zero, there are no references left and the\r
+  value can be destroyed.\r
+\r
+  This funciton decrement the reference count of EDKII_JSON_VALUE. As soon as\r
+  a call to json_decref() drops the reference count to zero, the value is\r
+  destroyed and it can no longer be used.\r
+\r
+  @param[in]   JsonValue      JSON value\r
+**/\r
+VOID\r
+EFIAPI\r
+JsonDecreaseReference (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  )\r
+{\r
+  json_decref (JsonValue);\r
+}\r
+\r
+/**\r
+  The reference count is used to track whether a value is still in use or not.\r
+  When a value is created, it's reference count is set to 1.\r
+  If a reference to a value is kept (e.g. a value is stored somewhere for later use),\r
+  its reference count is incremented.\r
+\r
+  This function increment the reference count of json if it's not NULL.\r
+  Returns EDKII_JSON_VALUE.\r
+\r
+  @param[in]   JsonValue      JSON value\r
+  @retval      EDKII_JSON_VALUE of itself\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonIncreaseReference (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  )\r
+{\r
+  return json_incref (JsonValue);\r
+}\r
+\r
+/**\r
+  Returns an opaque iterator which can be used to iterate over all key-value pairs\r
+  in object, or NULL if object is empty.\r
+\r
+  @param[in]   JsonValue      JSON value\r
+  @retval      Iterator pointer\r
+**/\r
+VOID *\r
+EFIAPI\r
+JsonObjectIterator (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  )\r
+{\r
+  return json_object_iter (JsonValue);\r
+}\r
+\r
+/**\r
+  Extract the associated value from iterator.\r
+\r
+  @param[in]   Iterator   Iterator pointer\r
+  @retval      EDKII_JSON_VALUE\r
+**/\r
+EDKII_JSON_VALUE\r
+EFIAPI\r
+JsonObjectIteratorValue (\r
+  IN VOID *Iterator\r
+  )\r
+{\r
+  return json_object_iter_value(Iterator);\r
+}\r
+\r
+/**\r
+  Returns an iterator pointing to the next key-value pair in object after iter,\r
+  or NULL if the whole object has been iterated through.\r
+\r
+  @param[in]   JsonValue  JSON value\r
+  @param[in]   Iterator   Iterator pointer\r
+  @retval      Iterator pointer\r
+**/\r
+VOID *\r
+JsonObjectIteratorNext (\r
+  IN EDKII_JSON_VALUE JsonValue,\r
+  IN VOID             *Iterator\r
+  )\r
+{\r
+  return json_object_iter_next(JsonValue, Iterator);\r
+}\r
+\r
+/**\r
+  Returns the json type of this json value.\r
+\r
+  @param[in]   JsonValue  JSON value\r
+  @retval      JSON type returned\r
+**/\r
+EDKII_JSON_TYPE\r
+EFIAPI\r
+JsonGetType (\r
+  IN EDKII_JSON_VALUE JsonValue\r
+  )\r
+{\r
+  return ((json_t *)JsonValue)->type;\r
+}\r
diff --git a/RedfishPkg/Library/JsonLib/JsonLib.inf b/RedfishPkg/Library/JsonLib/JsonLib.inf
new file mode 100644 (file)
index 0000000..48b094a
--- /dev/null
@@ -0,0 +1,86 @@
+## @file\r
+# Thirty party Jansson library for JSON operations.\r
+#\r
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+#\r
+#    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x0001001b\r
+  BASE_NAME                      = JsonLib\r
+  FILE_GUID                      = F5E36815-305A-4C5A-9D75-4F2149E45255\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = JsonLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER\r
+\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64\r
+#\r
+\r
+[Sources]\r
+  #\r
+  # Below are the source code of third\r
+  # party jansson library.\r
+  #\r
+  jansson/src/dump.c\r
+  jansson/src/error.c\r
+  jansson/src/hashtable.c\r
+  jansson/src/hashtable_seed.c\r
+  jansson/src/memory.c\r
+  jansson/src/pack_unpack.c\r
+  jansson/src/strbuffer.c\r
+  jansson/src/strconv.c\r
+  jansson/src/utf.c\r
+  jansson/src/value.c\r
+  jansson/src/version.c\r
+  #\r
+  # Below are the source of edk2 JsonLib.\r
+  #\r
+  JsonLib.c\r
+  jansson_config.h\r
+  jansson_private_config.h\r
+  #\r
+  # Below is the source code override to fix the build issue.\r
+  # Add code in load.c to conditionally use stdin according\r
+  # to HAVE_UNISTD_H macro. The PR is submitted to jansson\r
+  # open source community.\r
+  # https://github.com/akheron/jansson/pull/558\r
+  #\r
+  load.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  RedfishPkg/RedfishPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  Ucs2Utf8Lib\r
+  RedfishCrtLib\r
+  DebugLib\r
+  MemoryAllocationLib\r
+  PrintLib\r
+  UefiRuntimeServicesTableLib\r
+  UefiLib\r
+\r
+[BuildOptions]\r
+  #\r
+  # Disables the following Visual Studio compiler warnings\r
+  # so we do not break the build with /WX option:\r
+  #   C4090: 'function' : different 'const' qualifiers\r
+  #   C4244: conversion from type1 to type2, possible loss of data\r
+  #   C4334: 32-bit shift implicitly converted to 64-bit\r
+  #   C4204: nonstandard extension used: non-constant aggregate initializer\r
+  #\r
+  # Define macro HAVE_CONFIG_H to include jansson_private_config.h to build.\r
+  # Undefined _WIN32, WIN64, _MSC_VER macros\r
+  # On GCC, no error on the unused-function and unused-but-set-variable.\r
+  #\r
+  MSFT:*_*_X64_CC_FLAGS = /wd4204 /wd4244 /wd4090 /wd4334 /DHAVE_CONFIG_H=1 /U_WIN32 /UWIN64 /U_MSC_VER\r
+  MSFT:*_*_IA32_CC_FLAGS = /wd4204 /wd4244 /wd4090 /DHAVE_CONFIG_H=1 /U_WIN32 /UWIN64 /U_MSC_VER\r
+  GCC:*_*_*_CC_FLAGS = -Wno-unused-function -Wno-unused-but-set-variable\r
+\r
diff --git a/RedfishPkg/Library/JsonLib/Readme.rst b/RedfishPkg/Library/JsonLib/Readme.rst
new file mode 100644 (file)
index 0000000..1c65259
--- /dev/null
@@ -0,0 +1,35 @@
+=============================================================================\r
+                             Introduction\r
+=============================================================================\r
+  Jansson is a C library for encoding, decoding and manipulating JSON data.\r
+Its main features and design principles are:\r
+\r
+  - Simple and intuitive API and data model\r
+  - Comprehensive documentation\r
+  - No dependencies on other libraries\r
+  - Full Unicode support (UTF-8)\r
+  - Extensive test suite\r
+\r
+  Jansson is licensed under the MIT license(refer to ReadMe.rst under edk2).\r
+It is used in production and its API is stable. It works on numerous\r
+platforms, including numerous Unix like systems and Windows. It's suitable\r
+for use on any system, including desktop, server, and small embedded systems.\r
+\r
+  In UEFI/EDKII environment, Redfish project consumes jansson to achieve JSON\r
+operations.\r
+\r
+* Jansson version on edk2: 2.13.1, API reference is on the below URL,\r
+  https://jansson.readthedocs.io/en/2.13/apiref.html\r
+\r
+* EDKII jansson library wrapper:\r
+   - JsonLib.h:\r
+     This is the denifitions of EDKII JSON APIs which are mapped to\r
+     jannson funcitons accordingly.\r
+\r
+*Known issue:\r
+   Build fail with jansson/src/load.c, add code in load.c to conditionally\r
+   use stdin according to HAVE_UNISTD_H macro. The PR is submitted to\r
+   jansson open source community.\r
+   https://github.com/akheron/jansson/pull/558\r
+\r
+\r
diff --git a/RedfishPkg/Library/JsonLib/jansson_config.h b/RedfishPkg/Library/JsonLib/jansson_config.h
new file mode 100644 (file)
index 0000000..c66d3ce
--- /dev/null
@@ -0,0 +1,41 @@
+/** @file This is the configuration file for building jansson library.\r
+\r
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+ **/\r
+\r
+#ifndef JANSSON_CONFIG_H_\r
+#define JANSSON_CONFIG_H_\r
+\r
+///\r
+/// We don't support inline JSON on edk2\r
+///\r
+#define JSON_INLINE\r
+\r
+///\r
+/// We support long long on edk2\r
+///\r
+#define JSON_INTEGER_IS_LONG_LONG 1\r
+\r
+///\r
+/// We don't support locale on edk2\r
+///\r
+#define JSON_HAVE_LOCALECONV 0\r
+\r
+///\r
+/// We don't support atomic builtins on edk2\r
+///\r
+#define JSON_HAVE_ATOMIC_BUILTINS 0\r
+\r
+///\r
+/// We don't support sync builtins on edk2\r
+///\r
+#define JSON_HAVE_SYNC_BUILTINS 0\r
+\r
+///\r
+/// Mzximum deepth is set to 2048\r
+///\r
+#define JSON_PARSER_MAX_DEPTH 2048\r
+\r
+#endif\r
diff --git a/RedfishPkg/Library/JsonLib/jansson_private_config.h b/RedfishPkg/Library/JsonLib/jansson_private_config.h
new file mode 100644 (file)
index 0000000..268f91e
--- /dev/null
@@ -0,0 +1,19 @@
+/** @file\r
+  Jansson private configurations for UEFI support.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef JANSSON_PRIVATE_CONFIG_H_\r
+#define JANSSON_PRIVATE_CONFIG_H_\r
+\r
+#define HAVE_SYS_TIME_H 1\r
+#define HAVE_SYS_TYPES_H 1\r
+\r
+#define INITIAL_HASHTABLE_ORDER 3\r
+\r
+#endif\r
diff --git a/RedfishPkg/Library/JsonLib/load.c b/RedfishPkg/Library/JsonLib/load.c
new file mode 100644 (file)
index 0000000..37e0ba4
--- /dev/null
@@ -0,0 +1,1111 @@
+/*\r
+ * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>\r
+ *\r
+ * Jansson is free software; you can redistribute it and/or modify\r
+ * it under the terms of the MIT license. See LICENSE for details.\r
+\r
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>\r
+\r
+    SPDX-License-Identifier: BSD-2-Clause-Patent AND MIT\r
+ */\r
+\r
+#ifndef _GNU_SOURCE\r
+#define _GNU_SOURCE\r
+#endif\r
+\r
+#include "jansson_private.h"\r
+\r
+#include <assert.h>\r
+#include <errno.h>\r
+#include <limits.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include "jansson.h"\r
+#include "strbuffer.h"\r
+#include "utf.h"\r
+\r
+#define STREAM_STATE_OK    0\r
+#define STREAM_STATE_EOF   -1\r
+#define STREAM_STATE_ERROR -2\r
+\r
+#define TOKEN_INVALID -1\r
+#define TOKEN_EOF     0\r
+#define TOKEN_STRING  256\r
+#define TOKEN_INTEGER 257\r
+#define TOKEN_REAL    258\r
+#define TOKEN_TRUE    259\r
+#define TOKEN_FALSE   260\r
+#define TOKEN_NULL    261\r
+\r
+/* Locale independent versions of isxxx() functions */\r
+#define l_isupper(c) ('A' <= (c) && (c) <= 'Z')\r
+#define l_islower(c) ('a' <= (c) && (c) <= 'z')\r
+#define l_isalpha(c) (l_isupper(c) || l_islower(c))\r
+#define l_isdigit(c) ('0' <= (c) && (c) <= '9')\r
+#define l_isxdigit(c)                                                                    \\r
+    (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f'))\r
+\r
+/* Read one byte from stream, convert to unsigned char, then int, and\r
+   return. return EOF on end of file. This corresponds to the\r
+   behaviour of fgetc(). */\r
+typedef int (*get_func)(void *data);\r
+\r
+typedef struct {\r
+    get_func get;\r
+    void *data;\r
+    char buffer[5];\r
+    size_t buffer_pos;\r
+    int state;\r
+    int line;\r
+    int column, last_column;\r
+    size_t position;\r
+} stream_t;\r
+\r
+typedef struct {\r
+    stream_t stream;\r
+    strbuffer_t saved_text;\r
+    size_t flags;\r
+    size_t depth;\r
+    int token;\r
+    union {\r
+        struct {\r
+            char *val;\r
+            size_t len;\r
+        } string;\r
+        json_int_t integer;\r
+        double real;\r
+    } value;\r
+} lex_t;\r
+\r
+#define stream_to_lex(stream) container_of(stream, lex_t, stream)\r
+\r
+/*** error reporting ***/\r
+\r
+static void error_set(json_error_t *error, const lex_t *lex, enum json_error_code code,\r
+                      const char *msg, ...) {\r
+    va_list ap;\r
+    char msg_text[JSON_ERROR_TEXT_LENGTH];\r
+    char msg_with_context[JSON_ERROR_TEXT_LENGTH];\r
+\r
+    int line = -1, col = -1;\r
+    size_t pos = 0;\r
+    const char *result = msg_text;\r
+\r
+    if (!error)\r
+        return;\r
+\r
+    va_start(ap, msg);\r
+    vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap);\r
+    msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0';\r
+    va_end(ap);\r
+\r
+    if (lex) {\r
+        const char *saved_text = strbuffer_value(&lex->saved_text);\r
+\r
+        line = lex->stream.line;\r
+        col = lex->stream.column;\r
+        pos = lex->stream.position;\r
+\r
+        if (saved_text && saved_text[0]) {\r
+            if (lex->saved_text.length <= 20) {\r
+                snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near '%s'",\r
+                         msg_text, saved_text);\r
+                msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';\r
+                result = msg_with_context;\r
+            }\r
+        } else {\r
+            if (code == json_error_invalid_syntax) {\r
+                /* More specific error code for premature end of file. */\r
+                code = json_error_premature_end_of_input;\r
+            }\r
+            if (lex->stream.state == STREAM_STATE_ERROR) {\r
+                /* No context for UTF-8 decoding errors */\r
+                result = msg_text;\r
+            } else {\r
+                snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near end of file",\r
+                         msg_text);\r
+                msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0';\r
+                result = msg_with_context;\r
+            }\r
+        }\r
+    }\r
+\r
+    jsonp_error_set(error, line, col, pos, code, "%s", result);\r
+}\r
+\r
+/*** lexical analyzer ***/\r
+\r
+static void stream_init(stream_t *stream, get_func get, void *data) {\r
+    stream->get = get;\r
+    stream->data = data;\r
+    stream->buffer[0] = '\0';\r
+    stream->buffer_pos = 0;\r
+\r
+    stream->state = STREAM_STATE_OK;\r
+    stream->line = 1;\r
+    stream->column = 0;\r
+    stream->position = 0;\r
+}\r
+\r
+static int stream_get(stream_t *stream, json_error_t *error) {\r
+    int c;\r
+\r
+    if (stream->state != STREAM_STATE_OK)\r
+        return stream->state;\r
+\r
+    if (!stream->buffer[stream->buffer_pos]) {\r
+        c = stream->get(stream->data);\r
+        if (c == EOF) {\r
+            stream->state = STREAM_STATE_EOF;\r
+            return STREAM_STATE_EOF;\r
+        }\r
+\r
+        stream->buffer[0] = c;\r
+        stream->buffer_pos = 0;\r
+\r
+        if (0x80 <= c && c <= 0xFF) {\r
+            /* multi-byte UTF-8 sequence */\r
+            size_t i, count;\r
+\r
+            count = utf8_check_first(c);\r
+            if (!count)\r
+                goto out;\r
+\r
+            assert(count >= 2);\r
+\r
+            for (i = 1; i < count; i++)\r
+                stream->buffer[i] = stream->get(stream->data);\r
+\r
+            if (!utf8_check_full(stream->buffer, count, NULL))\r
+                goto out;\r
+\r
+            stream->buffer[count] = '\0';\r
+        } else\r
+            stream->buffer[1] = '\0';\r
+    }\r
+\r
+    c = stream->buffer[stream->buffer_pos++];\r
+\r
+    stream->position++;\r
+    if (c == '\n') {\r
+        stream->line++;\r
+        stream->last_column = stream->column;\r
+        stream->column = 0;\r
+    } else if (utf8_check_first(c)) {\r
+        /* track the Unicode character column, so increment only if\r
+           this is the first character of a UTF-8 sequence */\r
+        stream->column++;\r
+    }\r
+\r
+    return c;\r
+\r
+out:\r
+    stream->state = STREAM_STATE_ERROR;\r
+    error_set(error, stream_to_lex(stream), json_error_invalid_utf8,\r
+              "unable to decode byte 0x%x", c);\r
+    return STREAM_STATE_ERROR;\r
+}\r
+\r
+static void stream_unget(stream_t *stream, int c) {\r
+    if (c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR)\r
+        return;\r
+\r
+    stream->position--;\r
+    if (c == '\n') {\r
+        stream->line--;\r
+        stream->column = stream->last_column;\r
+    } else if (utf8_check_first(c))\r
+        stream->column--;\r
+\r
+    assert(stream->buffer_pos > 0);\r
+    stream->buffer_pos--;\r
+    assert(stream->buffer[stream->buffer_pos] == c);\r
+}\r
+\r
+static int lex_get(lex_t *lex, json_error_t *error) {\r
+    return stream_get(&lex->stream, error);\r
+}\r
+\r
+static void lex_save(lex_t *lex, int c) { strbuffer_append_byte(&lex->saved_text, c); }\r
+\r
+static int lex_get_save(lex_t *lex, json_error_t *error) {\r
+    int c = stream_get(&lex->stream, error);\r
+    if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR)\r
+        lex_save(lex, c);\r
+    return c;\r
+}\r
+\r
+static void lex_unget(lex_t *lex, int c) { stream_unget(&lex->stream, c); }\r
+\r
+static void lex_unget_unsave(lex_t *lex, int c) {\r
+    if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {\r
+/* Since we treat warnings as errors, when assertions are turned\r
+ * off the "d" variable would be set but never used. Which is\r
+ * treated as an error by GCC.\r
+ */\r
+#ifndef NDEBUG\r
+        char d;\r
+#endif\r
+        stream_unget(&lex->stream, c);\r
+#ifndef NDEBUG\r
+        d =\r
+#endif\r
+            strbuffer_pop(&lex->saved_text);\r
+        assert(c == d);\r
+    }\r
+}\r
+\r
+static void lex_save_cached(lex_t *lex) {\r
+    while (lex->stream.buffer[lex->stream.buffer_pos] != '\0') {\r
+        lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]);\r
+        lex->stream.buffer_pos++;\r
+        lex->stream.position++;\r
+    }\r
+}\r
+\r
+static void lex_free_string(lex_t *lex) {\r
+    jsonp_free(lex->value.string.val);\r
+    lex->value.string.val = NULL;\r
+    lex->value.string.len = 0;\r
+}\r
+\r
+/* assumes that str points to 'u' plus at least 4 valid hex digits */\r
+static int32_t decode_unicode_escape(const char *str) {\r
+    int i;\r
+    int32_t value = 0;\r
+\r
+    assert(str[0] == 'u');\r
+\r
+    for (i = 1; i <= 4; i++) {\r
+        char c = str[i];\r
+        value <<= 4;\r
+        if (l_isdigit(c))\r
+            value += c - '0';\r
+        else if (l_islower(c))\r
+            value += c - 'a' + 10;\r
+        else if (l_isupper(c))\r
+            value += c - 'A' + 10;\r
+        else\r
+            return -1;\r
+    }\r
+\r
+    return value;\r
+}\r
+\r
+static void lex_scan_string(lex_t *lex, json_error_t *error) {\r
+    int c;\r
+    const char *p;\r
+    char *t;\r
+    int i;\r
+\r
+    lex->value.string.val = NULL;\r
+    lex->token = TOKEN_INVALID;\r
+\r
+    c = lex_get_save(lex, error);\r
+\r
+    while (c != '"') {\r
+        if (c == STREAM_STATE_ERROR)\r
+            goto out;\r
+\r
+        else if (c == STREAM_STATE_EOF) {\r
+            error_set(error, lex, json_error_premature_end_of_input,\r
+                      "premature end of input");\r
+            goto out;\r
+        }\r
+\r
+        else if (0 <= c && c <= 0x1F) {\r
+            /* control character */\r
+            lex_unget_unsave(lex, c);\r
+            if (c == '\n')\r
+                error_set(error, lex, json_error_invalid_syntax, "unexpected newline");\r
+            else\r
+                error_set(error, lex, json_error_invalid_syntax, "control character 0x%x",\r
+                          c);\r
+            goto out;\r
+        }\r
+\r
+        else if (c == '\\') {\r
+            c = lex_get_save(lex, error);\r
+            if (c == 'u') {\r
+                c = lex_get_save(lex, error);\r
+                for (i = 0; i < 4; i++) {\r
+                    if (!l_isxdigit(c)) {\r
+                        error_set(error, lex, json_error_invalid_syntax,\r
+                                  "invalid escape");\r
+                        goto out;\r
+                    }\r
+                    c = lex_get_save(lex, error);\r
+                }\r
+            } else if (c == '"' || c == '\\' || c == '/' || c == 'b' || c == 'f' ||\r
+                       c == 'n' || c == 'r' || c == 't')\r
+                c = lex_get_save(lex, error);\r
+            else {\r
+                error_set(error, lex, json_error_invalid_syntax, "invalid escape");\r
+                goto out;\r
+            }\r
+        } else\r
+            c = lex_get_save(lex, error);\r
+    }\r
+\r
+    /* the actual value is at most of the same length as the source\r
+       string, because:\r
+         - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte\r
+         - a single \uXXXX escape (length 6) is converted to at most 3 bytes\r
+         - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair\r
+           are converted to 4 bytes\r
+    */\r
+    t = jsonp_malloc(lex->saved_text.length + 1);\r
+    if (!t) {\r
+        /* this is not very nice, since TOKEN_INVALID is returned */\r
+        goto out;\r
+    }\r
+    lex->value.string.val = t;\r
+\r
+    /* + 1 to skip the " */\r
+    p = strbuffer_value(&lex->saved_text) + 1;\r
+\r
+    while (*p != '"') {\r
+        if (*p == '\\') {\r
+            p++;\r
+            if (*p == 'u') {\r
+                size_t length;\r
+                int32_t value;\r
+\r
+                value = decode_unicode_escape(p);\r
+                if (value < 0) {\r
+                    error_set(error, lex, json_error_invalid_syntax,\r
+                              "invalid Unicode escape '%.6s'", p - 1);\r
+                    goto out;\r
+                }\r
+                p += 5;\r
+\r
+                if (0xD800 <= value && value <= 0xDBFF) {\r
+                    /* surrogate pair */\r
+                    if (*p == '\\' && *(p + 1) == 'u') {\r
+                        int32_t value2 = decode_unicode_escape(++p);\r
+                        if (value2 < 0) {\r
+                            error_set(error, lex, json_error_invalid_syntax,\r
+                                      "invalid Unicode escape '%.6s'", p - 1);\r
+                            goto out;\r
+                        }\r
+                        p += 5;\r
+\r
+                        if (0xDC00 <= value2 && value2 <= 0xDFFF) {\r
+                            /* valid second surrogate */\r
+                            value =\r
+                                ((value - 0xD800) << 10) + (value2 - 0xDC00) + 0x10000;\r
+                        } else {\r
+                            /* invalid second surrogate */\r
+                            error_set(error, lex, json_error_invalid_syntax,\r
+                                      "invalid Unicode '\\u%04X\\u%04X'", value, value2);\r
+                            goto out;\r
+                        }\r
+                    } else {\r
+                        /* no second surrogate */\r
+                        error_set(error, lex, json_error_invalid_syntax,\r
+                                  "invalid Unicode '\\u%04X'", value);\r
+                        goto out;\r
+                    }\r
+                } else if (0xDC00 <= value && value <= 0xDFFF) {\r
+                    error_set(error, lex, json_error_invalid_syntax,\r
+                              "invalid Unicode '\\u%04X'", value);\r
+                    goto out;\r
+                }\r
+\r
+                if (utf8_encode(value, t, &length))\r
+                    assert(0);\r
+                t += length;\r
+            } else {\r
+                switch (*p) {\r
+                    case '"':\r
+                    case '\\':\r
+                    case '/':\r
+                        *t = *p;\r
+                        break;\r
+                    case 'b':\r
+                        *t = '\b';\r
+                        break;\r
+                    case 'f':\r
+                        *t = '\f';\r
+                        break;\r
+                    case 'n':\r
+                        *t = '\n';\r
+                        break;\r
+                    case 'r':\r
+                        *t = '\r';\r
+                        break;\r
+                    case 't':\r
+                        *t = '\t';\r
+                        break;\r
+                    default:\r
+                        assert(0);\r
+                }\r
+                t++;\r
+                p++;\r
+            }\r
+        } else\r
+            *(t++) = *(p++);\r
+    }\r
+    *t = '\0';\r
+    lex->value.string.len = t - lex->value.string.val;\r
+    lex->token = TOKEN_STRING;\r
+    return;\r
+\r
+out:\r
+    lex_free_string(lex);\r
+}\r
+\r
+#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */\r
+#if JSON_INTEGER_IS_LONG_LONG\r
+#ifdef _MSC_VER /* Microsoft Visual Studio */\r
+#define json_strtoint _strtoi64\r
+#else\r
+#define json_strtoint strtoll\r
+#endif\r
+#else\r
+#define json_strtoint strtol\r
+#endif\r
+#endif\r
+\r
+static int lex_scan_number(lex_t *lex, int c, json_error_t *error) {\r
+    const char *saved_text;\r
+    char *end;\r
+    double doubleval;\r
+\r
+    lex->token = TOKEN_INVALID;\r
+\r
+    if (c == '-')\r
+        c = lex_get_save(lex, error);\r
+\r
+    if (c == '0') {\r
+        c = lex_get_save(lex, error);\r
+        if (l_isdigit(c)) {\r
+            lex_unget_unsave(lex, c);\r
+            goto out;\r
+        }\r
+    } else if (l_isdigit(c)) {\r
+        do\r
+            c = lex_get_save(lex, error);\r
+        while (l_isdigit(c));\r
+    } else {\r
+        lex_unget_unsave(lex, c);\r
+        goto out;\r
+    }\r
+\r
+    if (!(lex->flags & JSON_DECODE_INT_AS_REAL) && c != '.' && c != 'E' && c != 'e') {\r
+        json_int_t intval;\r
+\r
+        lex_unget_unsave(lex, c);\r
+\r
+        saved_text = strbuffer_value(&lex->saved_text);\r
+\r
+        errno = 0;\r
+        intval = json_strtoint(saved_text, &end, 10);\r
+        if (errno == ERANGE) {\r
+            if (intval < 0)\r
+                error_set(error, lex, json_error_numeric_overflow,\r
+                          "too big negative integer");\r
+            else\r
+                error_set(error, lex, json_error_numeric_overflow, "too big integer");\r
+            goto out;\r
+        }\r
+\r
+        assert(end == saved_text + lex->saved_text.length);\r
+\r
+        lex->token = TOKEN_INTEGER;\r
+        lex->value.integer = intval;\r
+        return 0;\r
+    }\r
+\r
+    if (c == '.') {\r
+        c = lex_get(lex, error);\r
+        if (!l_isdigit(c)) {\r
+            lex_unget(lex, c);\r
+            goto out;\r
+        }\r
+        lex_save(lex, c);\r
+\r
+        do\r
+            c = lex_get_save(lex, error);\r
+        while (l_isdigit(c));\r
+    }\r
+\r
+    if (c == 'E' || c == 'e') {\r
+        c = lex_get_save(lex, error);\r
+        if (c == '+' || c == '-')\r
+            c = lex_get_save(lex, error);\r
+\r
+        if (!l_isdigit(c)) {\r
+            lex_unget_unsave(lex, c);\r
+            goto out;\r
+        }\r
+\r
+        do\r
+            c = lex_get_save(lex, error);\r
+        while (l_isdigit(c));\r
+    }\r
+\r
+    lex_unget_unsave(lex, c);\r
+\r
+    if (jsonp_strtod(&lex->saved_text, &doubleval)) {\r
+        error_set(error, lex, json_error_numeric_overflow, "real number overflow");\r
+        goto out;\r
+    }\r
+\r
+    lex->token = TOKEN_REAL;\r
+    lex->value.real = doubleval;\r
+    return 0;\r
+\r
+out:\r
+    return -1;\r
+}\r
+\r
+static int lex_scan(lex_t *lex, json_error_t *error) {\r
+    int c;\r
+\r
+    strbuffer_clear(&lex->saved_text);\r
+\r
+    if (lex->token == TOKEN_STRING)\r
+        lex_free_string(lex);\r
+\r
+    do\r
+        c = lex_get(lex, error);\r
+    while (c == ' ' || c == '\t' || c == '\n' || c == '\r');\r
+\r
+    if (c == STREAM_STATE_EOF) {\r
+        lex->token = TOKEN_EOF;\r
+        goto out;\r
+    }\r
+\r
+    if (c == STREAM_STATE_ERROR) {\r
+        lex->token = TOKEN_INVALID;\r
+        goto out;\r
+    }\r
+\r
+    lex_save(lex, c);\r
+\r
+    if (c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',')\r
+        lex->token = c;\r
+\r
+    else if (c == '"')\r
+        lex_scan_string(lex, error);\r
+\r
+    else if (l_isdigit(c) || c == '-') {\r
+        if (lex_scan_number(lex, c, error))\r
+            goto out;\r
+    }\r
+\r
+    else if (l_isalpha(c)) {\r
+        /* eat up the whole identifier for clearer error messages */\r
+        const char *saved_text;\r
+\r
+        do\r
+            c = lex_get_save(lex, error);\r
+        while (l_isalpha(c));\r
+        lex_unget_unsave(lex, c);\r
+\r
+        saved_text = strbuffer_value(&lex->saved_text);\r
+\r
+        if (strcmp(saved_text, "true") == 0)\r
+            lex->token = TOKEN_TRUE;\r
+        else if (strcmp(saved_text, "false") == 0)\r
+            lex->token = TOKEN_FALSE;\r
+        else if (strcmp(saved_text, "null") == 0)\r
+            lex->token = TOKEN_NULL;\r
+        else\r
+            lex->token = TOKEN_INVALID;\r
+    }\r
+\r
+    else {\r
+        /* save the rest of the input UTF-8 sequence to get an error\r
+           message of valid UTF-8 */\r
+        lex_save_cached(lex);\r
+        lex->token = TOKEN_INVALID;\r
+    }\r
+\r
+out:\r
+    return lex->token;\r
+}\r
+\r
+static char *lex_steal_string(lex_t *lex, size_t *out_len) {\r
+    char *result = NULL;\r
+    if (lex->token == TOKEN_STRING) {\r
+        result = lex->value.string.val;\r
+        *out_len = lex->value.string.len;\r
+        lex->value.string.val = NULL;\r
+        lex->value.string.len = 0;\r
+    }\r
+    return result;\r
+}\r
+\r
+static int lex_init(lex_t *lex, get_func get, size_t flags, void *data) {\r
+    stream_init(&lex->stream, get, data);\r
+    if (strbuffer_init(&lex->saved_text))\r
+        return -1;\r
+\r
+    lex->flags = flags;\r
+    lex->token = TOKEN_INVALID;\r
+    return 0;\r
+}\r
+\r
+static void lex_close(lex_t *lex) {\r
+    if (lex->token == TOKEN_STRING)\r
+        lex_free_string(lex);\r
+    strbuffer_close(&lex->saved_text);\r
+}\r
+\r
+/*** parser ***/\r
+\r
+static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error);\r
+\r
+static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {\r
+    json_t *object = json_object();\r
+    if (!object)\r
+        return NULL;\r
+\r
+    lex_scan(lex, error);\r
+    if (lex->token == '}')\r
+        return object;\r
+\r
+    while (1) {\r
+        char *key;\r
+        size_t len;\r
+        json_t *value;\r
+\r
+        if (lex->token != TOKEN_STRING) {\r
+            error_set(error, lex, json_error_invalid_syntax, "string or '}' expected");\r
+            goto error;\r
+        }\r
+\r
+        key = lex_steal_string(lex, &len);\r
+        if (!key)\r
+            return NULL;\r
+        if (memchr(key, '\0', len)) {\r
+            jsonp_free(key);\r
+            error_set(error, lex, json_error_null_byte_in_key,\r
+                      "NUL byte in object key not supported");\r
+            goto error;\r
+        }\r
+\r
+        if (flags & JSON_REJECT_DUPLICATES) {\r
+            if (json_object_get(object, key)) {\r
+                jsonp_free(key);\r
+                error_set(error, lex, json_error_duplicate_key, "duplicate object key");\r
+                goto error;\r
+            }\r
+        }\r
+\r
+        lex_scan(lex, error);\r
+        if (lex->token != ':') {\r
+            jsonp_free(key);\r
+            error_set(error, lex, json_error_invalid_syntax, "':' expected");\r
+            goto error;\r
+        }\r
+\r
+        lex_scan(lex, error);\r
+        value = parse_value(lex, flags, error);\r
+        if (!value) {\r
+            jsonp_free(key);\r
+            goto error;\r
+        }\r
+\r
+        if (json_object_set_new_nocheck(object, key, value)) {\r
+            jsonp_free(key);\r
+            goto error;\r
+        }\r
+\r
+        jsonp_free(key);\r
+\r
+        lex_scan(lex, error);\r
+        if (lex->token != ',')\r
+            break;\r
+\r
+        lex_scan(lex, error);\r
+    }\r
+\r
+    if (lex->token != '}') {\r
+        error_set(error, lex, json_error_invalid_syntax, "'}' expected");\r
+        goto error;\r
+    }\r
+\r
+    return object;\r
+\r
+error:\r
+    json_decref(object);\r
+    return NULL;\r
+}\r
+\r
+static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) {\r
+    json_t *array = json_array();\r
+    if (!array)\r
+        return NULL;\r
+\r
+    lex_scan(lex, error);\r
+    if (lex->token == ']')\r
+        return array;\r
+\r
+    while (lex->token) {\r
+        json_t *elem = parse_value(lex, flags, error);\r
+        if (!elem)\r
+            goto error;\r
+\r
+        if (json_array_append_new(array, elem)) {\r
+            goto error;\r
+        }\r
+\r
+        lex_scan(lex, error);\r
+        if (lex->token != ',')\r
+            break;\r
+\r
+        lex_scan(lex, error);\r
+    }\r
+\r
+    if (lex->token != ']') {\r
+        error_set(error, lex, json_error_invalid_syntax, "']' expected");\r
+        goto error;\r
+    }\r
+\r
+    return array;\r
+\r
+error:\r
+    json_decref(array);\r
+    return NULL;\r
+}\r
+\r
+static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) {\r
+    json_t *json;\r
+\r
+    lex->depth++;\r
+    if (lex->depth > JSON_PARSER_MAX_DEPTH) {\r
+        error_set(error, lex, json_error_stack_overflow, "maximum parsing depth reached");\r
+        return NULL;\r
+    }\r
+\r
+    switch (lex->token) {\r
+        case TOKEN_STRING: {\r
+            const char *value = lex->value.string.val;\r
+            size_t len = lex->value.string.len;\r
+\r
+            if (!(flags & JSON_ALLOW_NUL)) {\r
+                if (memchr(value, '\0', len)) {\r
+                    error_set(error, lex, json_error_null_character,\r
+                              "\\u0000 is not allowed without JSON_ALLOW_NUL");\r
+                    return NULL;\r
+                }\r
+            }\r
+\r
+            json = jsonp_stringn_nocheck_own(value, len);\r
+            lex->value.string.val = NULL;\r
+            lex->value.string.len = 0;\r
+            break;\r
+        }\r
+\r
+        case TOKEN_INTEGER: {\r
+            json = json_integer(lex->value.integer);\r
+            break;\r
+        }\r
+\r
+        case TOKEN_REAL: {\r
+            json = json_real(lex->value.real);\r
+            break;\r
+        }\r
+\r
+        case TOKEN_TRUE:\r
+            json = json_true();\r
+            break;\r
+\r
+        case TOKEN_FALSE:\r
+            json = json_false();\r
+            break;\r
+\r
+        case TOKEN_NULL:\r
+            json = json_null();\r
+            break;\r
+\r
+        case '{':\r
+            json = parse_object(lex, flags, error);\r
+            break;\r
+\r
+        case '[':\r
+            json = parse_array(lex, flags, error);\r
+            break;\r
+\r
+        case TOKEN_INVALID:\r
+            error_set(error, lex, json_error_invalid_syntax, "invalid token");\r
+            return NULL;\r
+\r
+        default:\r
+            error_set(error, lex, json_error_invalid_syntax, "unexpected token");\r
+            return NULL;\r
+    }\r
+\r
+    if (!json)\r
+        return NULL;\r
+\r
+    lex->depth--;\r
+    return json;\r
+}\r
+\r
+static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) {\r
+    json_t *result;\r
+\r
+    lex->depth = 0;\r
+\r
+    lex_scan(lex, error);\r
+    if (!(flags & JSON_DECODE_ANY)) {\r
+        if (lex->token != '[' && lex->token != '{') {\r
+            error_set(error, lex, json_error_invalid_syntax, "'[' or '{' expected");\r
+            return NULL;\r
+        }\r
+    }\r
+\r
+    result = parse_value(lex, flags, error);\r
+    if (!result)\r
+        return NULL;\r
+\r
+    if (!(flags & JSON_DISABLE_EOF_CHECK)) {\r
+        lex_scan(lex, error);\r
+        if (lex->token != TOKEN_EOF) {\r
+            error_set(error, lex, json_error_end_of_input_expected,\r
+                      "end of file expected");\r
+            json_decref(result);\r
+            return NULL;\r
+        }\r
+    }\r
+\r
+    if (error) {\r
+        /* Save the position even though there was no error */\r
+        error->position = (int)lex->stream.position;\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+typedef struct {\r
+    const char *data;\r
+    size_t pos;\r
+} string_data_t;\r
+\r
+static int string_get(void *data) {\r
+    char c;\r
+    string_data_t *stream = (string_data_t *)data;\r
+    c = stream->data[stream->pos];\r
+    if (c == '\0')\r
+        return EOF;\r
+    else {\r
+        stream->pos++;\r
+        return (unsigned char)c;\r
+    }\r
+}\r
+\r
+json_t *json_loads(const char *string, size_t flags, json_error_t *error) {\r
+    lex_t lex;\r
+    json_t *result;\r
+    string_data_t stream_data;\r
+\r
+    jsonp_error_init(error, "<string>");\r
+\r
+    if (string == NULL) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    stream_data.data = string;\r
+    stream_data.pos = 0;\r
+\r
+    if (lex_init(&lex, string_get, flags, (void *)&stream_data))\r
+        return NULL;\r
+\r
+    result = parse_json(&lex, flags, error);\r
+\r
+    lex_close(&lex);\r
+    return result;\r
+}\r
+\r
+typedef struct {\r
+    const char *data;\r
+    size_t len;\r
+    size_t pos;\r
+} buffer_data_t;\r
+\r
+static int buffer_get(void *data) {\r
+    char c;\r
+    buffer_data_t *stream = data;\r
+    if (stream->pos >= stream->len)\r
+        return EOF;\r
+\r
+    c = stream->data[stream->pos];\r
+    stream->pos++;\r
+    return (unsigned char)c;\r
+}\r
+\r
+json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) {\r
+    lex_t lex;\r
+    json_t *result;\r
+    buffer_data_t stream_data;\r
+\r
+    jsonp_error_init(error, "<buffer>");\r
+\r
+    if (buffer == NULL) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    stream_data.data = buffer;\r
+    stream_data.pos = 0;\r
+    stream_data.len = buflen;\r
+\r
+    if (lex_init(&lex, buffer_get, flags, (void *)&stream_data))\r
+        return NULL;\r
+\r
+    result = parse_json(&lex, flags, error);\r
+\r
+    lex_close(&lex);\r
+    return result;\r
+}\r
+\r
+json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) {\r
+    lex_t lex;\r
+    const char *source;\r
+    json_t *result;\r
+#ifdef HAVE_UNISTD_H\r
+    if (input == stdin)\r
+        source = "<stdin>";\r
+    else\r
+#endif\r
+        source = "<stream>";\r
+\r
+    jsonp_error_init(error, source);\r
+\r
+    if (input == NULL) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    if (lex_init(&lex, (get_func)fgetc, flags, input))\r
+        return NULL;\r
+\r
+    result = parse_json(&lex, flags, error);\r
+\r
+    lex_close(&lex);\r
+    return result;\r
+}\r
+\r
+static int fd_get_func(int *fd) {\r
+#ifdef HAVE_UNISTD_H\r
+    uint8_t c;\r
+    if (read(*fd, &c, 1) == 1)\r
+        return c;\r
+#endif\r
+    return EOF;\r
+}\r
+\r
+json_t *json_loadfd(int input, size_t flags, json_error_t *error) {\r
+    lex_t lex;\r
+    const char *source;\r
+    json_t *result;\r
+\r
+#ifdef HAVE_UNISTD_H\r
+    if (input == STDIN_FILENO)\r
+        source = "<stdin>";\r
+    else\r
+#endif\r
+        source = "<stream>";\r
+\r
+    jsonp_error_init(error, source);\r
+\r
+    if (input < 0) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    if (lex_init(&lex, (get_func)fd_get_func, flags, &input))\r
+        return NULL;\r
+\r
+    result = parse_json(&lex, flags, error);\r
+\r
+    lex_close(&lex);\r
+    return result;\r
+}\r
+\r
+json_t *json_load_file(const char *path, size_t flags, json_error_t *error) {\r
+    json_t *result;\r
+    FILE *fp;\r
+\r
+    jsonp_error_init(error, path);\r
+\r
+    if (path == NULL) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    fp = fopen(path, "rb");\r
+    if (!fp) {\r
+        error_set(error, NULL, json_error_cannot_open_file, "unable to open %s: %s", path,\r
+                  strerror(errno));\r
+        return NULL;\r
+    }\r
+\r
+    result = json_loadf(fp, flags, error);\r
+\r
+    fclose(fp);\r
+    return result;\r
+}\r
+\r
+#define MAX_BUF_LEN 1024\r
+\r
+typedef struct {\r
+    char data[MAX_BUF_LEN];\r
+    size_t len;\r
+    size_t pos;\r
+    json_load_callback_t callback;\r
+    void *arg;\r
+} callback_data_t;\r
+\r
+static int callback_get(void *data) {\r
+    char c;\r
+    callback_data_t *stream = data;\r
+\r
+    if (stream->pos >= stream->len) {\r
+        stream->pos = 0;\r
+        stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg);\r
+        if (stream->len == 0 || stream->len == (size_t)-1)\r
+            return EOF;\r
+    }\r
+\r
+    c = stream->data[stream->pos];\r
+    stream->pos++;\r
+    return (unsigned char)c;\r
+}\r
+\r
+json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags,\r
+                           json_error_t *error) {\r
+    lex_t lex;\r
+    json_t *result;\r
+\r
+    callback_data_t stream_data;\r
+\r
+    memset(&stream_data, 0, sizeof(stream_data));\r
+    stream_data.callback = callback;\r
+    stream_data.arg = arg;\r
+\r
+    jsonp_error_init(error, "<callback>");\r
+\r
+    if (callback == NULL) {\r
+        error_set(error, NULL, json_error_invalid_argument, "wrong arguments");\r
+        return NULL;\r
+    }\r
+\r
+    if (lex_init(&lex, (get_func)callback_get, flags, &stream_data))\r
+        return NULL;\r
+\r
+    result = parse_json(&lex, flags, error);\r
+\r
+    lex_close(&lex);\r
+    return result;\r
+}\r
index e410d1a608f75c2c904b2f189ef239b140f7743c..fde6fa89bcb4815ec118b1b41795a8b6bc5762e2 100644 (file)
             "PrivateInclude/Crt/string.h",\r
             "PrivateInclude/Crt/time.h",\r
             "PrivateInclude/Library/RedfishCrtLib.h",\r
-            "PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c"\r
+            "PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c",\r
+            ##\r
+            ## For jansson library open source\r
+            ## load.c is overrided from open source.\r
+            "Library/JsonLib/load.c",\r
+            "Library/JsonLib/jansson_config.h",\r
+            "Library/JsonLib/jansson_private_config.h"\r
         ]\r
     },\r
     "CompilerPlugin": {\r
index 9f8b85778d96da1a511656ef61775b68857c2869..2985676b60af7465ba3293172801825ec4ad036d 100644 (file)
 [Includes.Common.Private]\r
   PrivateInclude                # Private header files for C RTL.\r
   PrivateInclude/Crt            # Private header files for C RTL.\r
+  Library/JsonLib               # Private header files for jansson\r
+                                # configuration files.\r
+                                #  - jansson_config.h\r
+                                #  - jansson_private_config.h\r
+                                # jansson.h refers to above two configuration\r
+                                # files for building platform jansson library.\r
+  Library/JsonLib/jansson/src   # For referring to jannson.h\r
 \r
 [LibraryClasses]\r
   ##  @libraryclass Platform Redfish Host Interface Library\r
   #   This library is only intended to be used by UEFI network stack modules.\r
   RestExLib|Include/Library/RestExLib.h\r
 \r
+  ##  @libraryclass  Provides the library functions based on third party\r
+  #  jansson library to manipulate JSON data structure.\r
+  #\r
+  JsonLib|Include/Library/JsonLib.h\r
+\r
 [LibraryClasses.Common.Private]\r
   ##  @libraryclass  Provides the private C runtime library functions.\r
   #   CRT library is currently used by edk2 JsonLib (open source\r