Matter SDK Coverage Report
Current view: top level - lib/support/jsontlv - TlvJson.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 98.0 % 98 96
Test Date: 2025-01-17 19:00:11 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : #include "lib/support/CHIPMemString.h"
      19              : #include "lib/support/ScopedBuffer.h"
      20              : #include <lib/core/DataModelTypes.h>
      21              : #include <lib/support/Base64.h>
      22              : #include <lib/support/jsontlv/TlvJson.h>
      23              : 
      24              : namespace {
      25              : /*
      26              :  * Encapsulates the different types of keys permissible.
      27              :  *
      28              :  * Root Key = Key with a name of 'value'. This is the top-most key in a given JSON object generated from TLV.
      29              :  * Struct Field = Key containing the 32-bit field ID of an item in a struct.
      30              :  * Array Item = Key containing the 16-bit list index of an item in a list.
      31              :  *
      32              :  * In the latter two modes, the actual field ID/list index is encapsulated within the 'key' member.
      33              :  *
      34              :  */
      35              : struct KeyContext
      36              : {
      37              :     enum KeyType
      38              :     {
      39              :         kRoot,
      40              :         kStructField,
      41              :         kArrayItem
      42              :     };
      43              : 
      44              :     KeyContext() = default;
      45              : 
      46           24 :     KeyContext(chip::FieldId fieldId)
      47           24 :     {
      48           24 :         keyType = kStructField;
      49           24 :         key     = fieldId;
      50           24 :     }
      51              : 
      52            6 :     KeyContext(chip::ListIndex listIndex)
      53            6 :     {
      54            6 :         keyType = kArrayItem;
      55            6 :         key     = listIndex;
      56            6 :     }
      57              : 
      58              :     KeyType keyType  = kRoot;
      59              :     unsigned int key = 0;
      60              : };
      61              : } // namespace
      62              : 
      63              : //
      64              : // For now, let's put a bound of the maximum length of a byte/char string to be the size of an IPv6
      65              : // MTU. While this is smaller than that of the limit defined in the data model specification,
      66              : // strings by virtue of not being chunked are intrinsically limited in size to the size of the encompassing packet.
      67              : //
      68              : static constexpr uint16_t kMaxStringLen = 1280;
      69              : 
      70              : constexpr char kBase64Header[]    = "base64:";
      71              : constexpr size_t kBase64HeaderLen = ArraySize(kBase64Header) - 1;
      72              : 
      73              : namespace chip {
      74              : 
      75              : /*
      76              :  * This templated function inserts a key/value pair into the Json value object.
      77              :  * The value is templated to be of type T and accepts any of the following primitive
      78              :  * types:
      79              :  *      bool, uint*_t, int*_t, char *, float, double.
      80              :  *
      81              :  * This method uses the provided key context to deduce the type of element being added.
      82              :  *
      83              :  */
      84              : template <typename T>
      85           43 : void InsertKeyValue(Json::Value & json, const KeyContext & keyContext, T val)
      86              : {
      87              :     //
      88              :     // This needs to accomodate either the string 'value', or a 32-bit integer.
      89              :     // The size of the largest 32-bit integer key represented as a string is 11 characters long.
      90              :     // Tack on 1 byte for the null character.
      91              :     //
      92              :     char keyBuf[12];
      93              : 
      94           43 :     if (keyContext.keyType == KeyContext::kRoot)
      95              :     {
      96           13 :         Platform::CopyString(keyBuf, sizeof(keyBuf), "value");
      97           13 :         json[keyBuf] = val;
      98              :     }
      99           30 :     else if (keyContext.keyType == KeyContext::kStructField)
     100              :     {
     101           24 :         snprintf(keyBuf, sizeof(keyBuf), "%u", keyContext.key);
     102           24 :         json[keyBuf] = val;
     103              :     }
     104              :     else
     105              :     {
     106            6 :         json[keyContext.key] = val;
     107              :     }
     108           43 : }
     109              : 
     110           13 : std::string JsonToString(Json::Value & json)
     111              : {
     112           13 :     Json::FastWriter writer;
     113           13 :     writer.omitEndingLineFeed();
     114           13 :     return writer.write(json);
     115           13 : }
     116              : 
     117           43 : CHIP_ERROR TlvToJson(TLV::TLVReader & reader, KeyContext context, Json::Value & parent)
     118              : {
     119           43 :     switch (reader.GetType())
     120              :     {
     121           14 :     case TLV::kTLVType_UnsignedInteger: {
     122              :         uint64_t v;
     123           14 :         ReturnErrorOnFailure(reader.Get(v));
     124           14 :         InsertKeyValue(parent, context, v);
     125           14 :         break;
     126              :     }
     127              : 
     128            1 :     case TLV::kTLVType_SignedInteger: {
     129              :         int64_t v;
     130            1 :         ReturnErrorOnFailure(reader.Get(v));
     131            1 :         InsertKeyValue(parent, context, v);
     132            1 :         break;
     133              :     }
     134              : 
     135            5 :     case TLV::kTLVType_Boolean: {
     136              :         bool v;
     137            5 :         ReturnErrorOnFailure(reader.Get(v));
     138            5 :         InsertKeyValue(parent, context, v);
     139            5 :         break;
     140              :     }
     141              : 
     142            7 :     case TLV::kTLVType_FloatingPointNumber: {
     143              :         double v;
     144            7 :         ReturnErrorOnFailure(reader.Get(v));
     145            7 :         InsertKeyValue(parent, context, v);
     146            7 :         break;
     147              :     }
     148              : 
     149            4 :     case TLV::kTLVType_ByteString: {
     150            4 :         ByteSpan span;
     151              : 
     152            4 :         ReturnErrorOnFailure(reader.Get(span));
     153            4 :         VerifyOrReturnError(span.size() < kMaxStringLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
     154              : 
     155            4 :         Platform::ScopedMemoryBuffer<char> byteString;
     156            4 :         byteString.Alloc(kBase64HeaderLen + BASE64_ENCODED_LEN(span.size()) + 1);
     157            4 :         VerifyOrReturnError(byteString.Get() != nullptr, CHIP_ERROR_NO_MEMORY);
     158              : 
     159            4 :         auto encodedLen = Base64Encode(span.data(), static_cast<uint16_t>(span.size()), byteString.Get() + kBase64HeaderLen);
     160            4 :         if (encodedLen)
     161              :         {
     162            4 :             memcpy(byteString.Get(), kBase64Header, kBase64HeaderLen);
     163            4 :             encodedLen = static_cast<uint16_t>(encodedLen + kBase64HeaderLen);
     164              :         }
     165            4 :         byteString.Get()[encodedLen] = '\0';
     166              : 
     167            4 :         InsertKeyValue(parent, context, byteString.Get());
     168            4 :         break;
     169            4 :     }
     170              : 
     171            4 :     case TLV::kTLVType_UTF8String: {
     172            4 :         CharSpan span;
     173              : 
     174            4 :         ReturnErrorOnFailure(reader.Get(span));
     175            4 :         VerifyOrReturnError(span.size() < kMaxStringLen, CHIP_ERROR_INVALID_TLV_ELEMENT);
     176              : 
     177            4 :         Platform::ScopedMemoryString charString(span.data(), span.size());
     178            4 :         InsertKeyValue(parent, context, charString.Get());
     179            4 :         break;
     180            4 :     }
     181              : 
     182            2 :     case TLV::kTLVType_Null: {
     183            2 :         InsertKeyValue(parent, context, Json::Value());
     184            2 :         break;
     185              :     }
     186              : 
     187            3 :     case TLV::kTLVType_Structure: {
     188              :         TLV::TLVType containerType;
     189            3 :         ReturnErrorOnFailure(reader.EnterContainer(containerType));
     190              : 
     191              :         CHIP_ERROR err;
     192            3 :         Json::Value value;
     193              : 
     194           27 :         while ((err = reader.Next()) == CHIP_NO_ERROR)
     195              :         {
     196           24 :             VerifyOrReturnError(TLV::IsContextTag(reader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG);
     197           24 :             KeyContext context2(static_cast<chip::FieldId>(TLV::TagNumFromTag(reader.GetTag())));
     198              : 
     199              :             //
     200              :             // Recursively convert to JSON the encompassing item within the struct.
     201              :             //
     202           24 :             ReturnErrorOnFailure(TlvToJson(reader, context2, value));
     203              :         }
     204              : 
     205            3 :         VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     206            3 :         ReturnErrorOnFailure(reader.ExitContainer(containerType));
     207            3 :         InsertKeyValue(parent, context, value);
     208            3 :         break;
     209            3 :     }
     210              : 
     211            3 :     case TLV::kTLVType_Array: {
     212              :         TLV::TLVType containerType;
     213            3 :         ReturnErrorOnFailure(reader.EnterContainer(containerType));
     214              : 
     215              :         CHIP_ERROR err;
     216            3 :         Json::Value value = Json::Value(Json::arrayValue);
     217            3 :         size_t listIndex  = 0;
     218              : 
     219            9 :         while ((err = reader.Next()) == CHIP_NO_ERROR)
     220              :         {
     221            6 :             KeyContext context2(static_cast<chip::ListIndex>(listIndex++));
     222              : 
     223              :             //
     224              :             // Recursively convert to JSON the encompassing item within the array.
     225              :             //
     226            6 :             ReturnErrorOnFailure(TlvToJson(reader, context2, value));
     227              :         }
     228              : 
     229            3 :         VerifyOrReturnError(err == CHIP_END_OF_TLV, err);
     230            3 :         ReturnErrorOnFailure(reader.ExitContainer(containerType));
     231            3 :         InsertKeyValue(parent, context, value);
     232            3 :         break;
     233            3 :     }
     234              : 
     235            0 :     default:
     236            0 :         return CHIP_ERROR_INVALID_TLV_ELEMENT;
     237              :         break;
     238              :     }
     239              : 
     240           43 :     return CHIP_NO_ERROR;
     241              : }
     242              : 
     243           13 : CHIP_ERROR TlvToJson(TLV::TLVReader & reader, Json::Value & root)
     244              : {
     245           13 :     KeyContext context;
     246           13 :     return TlvToJson(reader, context, root);
     247              : }
     248              : 
     249              : } // namespace chip
        

Generated by: LCOV version 2.0-1