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
|