blob: 745775c79ccdc16e4e01d3cb648654b55314b03c [file] [log] [blame]
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07001/*==============================================================================
2 example.c -- Example code for QCBOR
3
4 Copyright (c) 2020, Laurence Lundblade. All rights reserved.
5
6 SPDX-License-Identifier: BSD-3-Clause
7
8 See BSD-3-Clause license in README.md
9
10 Created on 6/30/2020
11=============================================================================*/
12
13
14#include <stdio.h>
15#include "example.h"
16#include "qcbor/qcbor_encode.h"
17#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070018#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070019
20#define MAX_CYLINDERS 16
21
Laurence Lundbladeda319282020-07-06 23:04:58 -070022
23/**
24 The data structure representing a car engine that is encoded and decoded in this examples.
25 */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070026typedef struct
27{
28 UsefulBufC Manufacturer;
Laurence Lundblade1818e632020-07-26 04:14:08 -070029 int64_t uDisplacement;
30 int64_t uHorsePower;
31 double dDesignedCompresion;
32 int64_t uNumCylinders;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070033 struct {
34 double uMeasuredCompression;
Laurence Lundblade1818e632020-07-26 04:14:08 -070035 } cylinders[MAX_CYLINDERS];
36 bool bTurboCharged;
Laurence Lundbladeda319282020-07-06 23:04:58 -070037} CarEngine;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070038
39
Laurence Lundbladeda319282020-07-06 23:04:58 -070040/**
41 Initialize the Engine data structure with some values to encode/decode.
42 */
43void EngineInit(CarEngine *pE)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070044{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070045 pE->Manufacturer = UsefulBuf_FROM_SZ_LITERAL("Porsche");
46 pE->uDisplacement = 3296;
47 pE->uHorsePower = 210;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -070048 pE->dDesignedCompresion = 9.1;
Laurence Lundbladeda319282020-07-06 23:04:58 -070049 pE->uNumCylinders = 6;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070050 pE->cylinders[0].uMeasuredCompression = 9.0;
51 pE->cylinders[1].uMeasuredCompression = 9.2;
52 pE->cylinders[2].uMeasuredCompression = 8.9;
53 pE->cylinders[3].uMeasuredCompression = 8.9;
54 pE->cylinders[4].uMeasuredCompression = 9.1;
55 pE->cylinders[5].uMeasuredCompression = 9.0;
Laurence Lundbladeda319282020-07-06 23:04:58 -070056 pE->bTurboCharged = false;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070057}
58
59
Laurence Lundbladeda319282020-07-06 23:04:58 -070060/**
61 Return @c true if the two Engined data structures are exactly the same.
62 */
63bool EngineCompare(CarEngine *pE1, CarEngine *pE2)
Laurence Lundbladee6bbf552020-07-05 22:57:57 -070064{
65 if(pE1->uNumCylinders != pE2->uNumCylinders) {
66 return false;
67 }
68 if(pE1->bTurboCharged != pE2->bTurboCharged) {
69 return false;
70 }
71 if(pE1->uDisplacement != pE2->uDisplacement) {
72 return false;
73 }
74 if(pE1->uHorsePower != pE2->uHorsePower) {
75 return false;
76 }
77 if(pE1->dDesignedCompresion != pE2->dDesignedCompresion) {
78 return false;
79 }
80 for(int64_t i = 0; i < pE2->uNumCylinders; i++) {
81 if(pE1->cylinders[i].uMeasuredCompression !=
82 pE2->cylinders[i].uMeasuredCompression) {
83 return false;
84 }
85 }
86
87 if(UsefulBuf_Compare(pE1->Manufacturer, pE2->Manufacturer)) {
88 return false;
89 }
90
91 return true;
92}
93
94
Laurence Lundbladeda319282020-07-06 23:04:58 -070095/**
96 @brief Encode an initialized Engine data structure in CBOR.
97
98 @param[in] pEngine The data structure to encode.
99 @param[in] Buffer Pointer and length of buffer to output to.
100
101 @return The pointer and length of the encoded CBOR or @ref NULLUsefulBufC on error.
102
103 @c Buffer must be big enough to hold the output. If it is not @ref NULLUsefulBufC
104 will be returned. @ref @ref NULLUsefulBufC will be returned for any other encoding
105 errors.
106
107 This encoding will use definite CBOR lengths.
108 */
109UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700110{
Laurence Lundblade06c83042020-07-03 23:04:53 -0700111 /* Initialize th encoder with the buffer big enough to hold the expected output.
112 If it is too small, QCBOREncode_Finish() will return an error. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700113 QCBOREncodeContext EncodeCtx;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700114 QCBOREncode_Init(&EncodeCtx, Buffer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700115
116 /* Proceed output all the items, letting the internal error
117 tracking do its work. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700118 QCBOREncode_OpenMap(&EncodeCtx);
119 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700120 QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
121 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
122 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700123 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700124 QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders");
Laurence Lundblade06c83042020-07-03 23:04:53 -0700125 for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700126 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
127 }
128 QCBOREncode_CloseArray(&EncodeCtx);
Laurence Lundbladeda319282020-07-06 23:04:58 -0700129 QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700130 QCBOREncode_CloseMap(&EncodeCtx);
131
Laurence Lundblade06c83042020-07-03 23:04:53 -0700132 /* Get the pointer and length of the encoded output. If there was
133 anny error it will be returned here. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700134 UsefulBufC EncodedCBOR;
135 QCBORError uErr;
136 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
137 if(uErr != QCBOR_SUCCESS) {
138 return NULLUsefulBufC;
139 } else {
140 return EncodedCBOR;
141 }
142}
143
144
Laurence Lundbladeda319282020-07-06 23:04:58 -0700145/**
146 @brief Encode an initialized Engine data structure in CBOR using indefinite lengths..
147
148 @param[in] pEngine The data structure to encode.
149 @param[in] Buffer Pointer and length of buffer to output to.
150
151 @return The pointer and length of the encoded CBOR or @ref NULLUsefulBufC on error.
152
153 This is virtually the same as EncodeEngine(). The encoded CBOR is slightly different as the
154 map and array use indefinite lengths, rather than definite lengths.
155
156 There is little practical use for this function as definite lengths are generally preferred for
157 CBOR and QCBOR always easily encodes definite lengths. (The advantage of indefinite
158 lengths are that they are simpler to encode, but that doesn't come into effect here).
159 */
160UsefulBufC EncodeEngineIndefinteLen(const CarEngine *pEngine, UsefulBuf Buffer)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700161{
162 QCBOREncodeContext EncodeCtx;
163
164 QCBOREncode_Init(&EncodeCtx, Buffer);
165 QCBOREncode_OpenMapIndefiniteLength(&EncodeCtx);
166 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700167 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
168 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700169 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700170 QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700171 QCBOREncode_OpenArrayIndefiniteLengthInMap(&EncodeCtx, "Cylinders");
Laurence Lundblade06c83042020-07-03 23:04:53 -0700172 for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700173 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
174 }
175 QCBOREncode_CloseArrayIndefiniteLength(&EncodeCtx);
Laurence Lundbladeda319282020-07-06 23:04:58 -0700176 QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700177 QCBOREncode_CloseMapIndefiniteLength(&EncodeCtx);
178
179 UsefulBufC EncodedCBOR;
180 QCBORError uErr;
181 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
182 if(uErr != QCBOR_SUCCESS) {
183 return NULLUsefulBufC;
184 } else {
185 return EncodedCBOR;
186 }
187}
188
189
Laurence Lundbladeda319282020-07-06 23:04:58 -0700190/**
191 Error results when decoding an Engine data structure.
192 */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700193typedef enum {
194 EngineSuccess,
195 CBORNotWellFormed,
196 TooManyCylinders,
197 EngineProtocolerror,
198 WrongNumberOfCylinders
199} EngineDecodeErrors;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700200
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700201
Laurence Lundbladeda319282020-07-06 23:04:58 -0700202/**
203 Convert \ref QCBORError to \ref EngineDecodeErrors.
204 */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700205EngineDecodeErrors ConvertError(QCBORError uErr)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700206{
Laurence Lundblade06c83042020-07-03 23:04:53 -0700207 EngineDecodeErrors uReturn;
208
209 switch(uErr)
210 {
211 case QCBOR_SUCCESS:
212 uReturn = EngineSuccess;
213 break;
214
215 case QCBOR_ERR_HIT_END:
216 uReturn = CBORNotWellFormed;
217 break;
218
219 default:
220 uReturn = EngineProtocolerror;
221 break;
222 }
223
224 return uReturn;
225}
226
227
Laurence Lundbladeda319282020-07-06 23:04:58 -0700228/**
229 @brief Simplest engine decode using advanced decoe features.
230
231 @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
232 @param[out] pE The structure filled in from the decoding.
233
234 @return The decode error or success.
235
236 This verssion of the decoder has the simplest implementation, but
237 pulls in more code from the QCBOR library. This version uses
238 the most CPU because it scanns the all the CBOR each time
239 a data item is decoded. The CPU used for a data structure as small
240 as this is probably insignificant. CPU use for this style of decode is
241 probably only a factor on slow CPUs with big CBOR inputs.
242
243 Code size is yet to be measured, but this is probably the smallest total
244 code size if multiple protocols are being decoded in one application because
245 the complex parsing of a map and array is done be shared code from the
246 CBOR library rather than by individual protocol-specific chunks of code.
247 Similarly, this may be the smallest for complex CBOR with multiple
248 maps that need to be processed..
249
250 See also DecodeEngineAdvancedFaster() and DecodeEngineBasic().
Laurence Lundblade06c83042020-07-03 23:04:53 -0700251 */
Laurence Lundblade67257dc2020-07-27 03:33:37 -0700252EngineDecodeErrors DecodeEngineSpiffy(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundblade06c83042020-07-03 23:04:53 -0700253{
254 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700255 QCBORDecodeContext DecodeCtx;
256
257 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
258 QCBORDecode_EnterMap(&DecodeCtx);
259 QCBORDecode_GetTextInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer));
Laurence Lundblade06c83042020-07-03 23:04:53 -0700260 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement));
261 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower));
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700262 QCBORDecode_GetDoubleInMapSZ(&DecodeCtx, "DesignedCompression", &(pE->dDesignedCompresion));
Laurence Lundbladeda319282020-07-06 23:04:58 -0700263 QCBORDecode_GetBoolInMapSZ(&DecodeCtx, "Turbo", &(pE->bTurboCharged));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700264
Laurence Lundblade06c83042020-07-03 23:04:53 -0700265 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "NumCylinders", &(pE->uNumCylinders));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700266
267 /* Must check error before referencing pE->uNumCylinders to be sure it
268 is valid. If any of the above errored, it won't be valid. */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700269 uErr = QCBORDecode_GetError(&DecodeCtx);
270 if(uErr != QCBOR_SUCCESS) {
271 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700272 }
273
274 if(pE->uNumCylinders > MAX_CYLINDERS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700275 return TooManyCylinders;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700276 }
277
278 QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700279 for(int64_t i = 0; i < pE->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700280 QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700281 }
282 QCBORDecode_ExitArray(&DecodeCtx);
283 QCBORDecode_ExitMap(&DecodeCtx);
284
Laurence Lundblade06c83042020-07-03 23:04:53 -0700285 /* Catch the remainder of errors here */
286 uErr = QCBORDecode_Finish(&DecodeCtx);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700287
Laurence Lundblade06c83042020-07-03 23:04:53 -0700288Done:
289 return ConvertError(uErr);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700290}
291
Laurence Lundblade06c83042020-07-03 23:04:53 -0700292
Laurence Lundbladeda319282020-07-06 23:04:58 -0700293/**
294 @brief Simplest engine decode using advanced decoe features.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700295
Laurence Lundbladeda319282020-07-06 23:04:58 -0700296 @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
297 @param[out] pE The structure filled in from the decoding.
298
299 @return The decode error or success.
300
Laurence Lundblade1818e632020-07-26 04:14:08 -0700301 This verssion of the decoder is still fairly simple and uses the
Laurence Lundbladeda319282020-07-06 23:04:58 -0700302 advanced decode features like DecodeEngine(), but is faster
303 and pulls in less library code. It is faster because all the items
304 except the array are pulled out of the map in one pass, rather
305 than multiple passes.
306
307 See also DecodeEngineAdvanced() and DecodeEngineBasic().
308*/
Laurence Lundblade67257dc2020-07-27 03:33:37 -0700309EngineDecodeErrors DecodeEngineSpiffyFaster(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700310{
311 QCBORError uErr;
312 QCBORDecodeContext DecodeCtx;
313
314 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
315 QCBORDecode_EnterMap(&DecodeCtx);
316
Laurence Lundbladeda319282020-07-06 23:04:58 -0700317 QCBORItem EngineItems[7];
318 EngineItems[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
319 EngineItems[0].label.string = UsefulBuf_FROM_SZ_LITERAL("Manufacturer");
320 EngineItems[0].uDataType = QCBOR_TYPE_TEXT_STRING;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700321
Laurence Lundbladeda319282020-07-06 23:04:58 -0700322 EngineItems[1].uLabelType = QCBOR_TYPE_TEXT_STRING;
323 EngineItems[1].label.string = UsefulBuf_FROM_SZ_LITERAL("Displacement");
324 EngineItems[1].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700325
Laurence Lundbladeda319282020-07-06 23:04:58 -0700326 EngineItems[2].uLabelType = QCBOR_TYPE_TEXT_STRING;
327 EngineItems[2].label.string = UsefulBuf_FROM_SZ_LITERAL("Horsepower");
328 EngineItems[2].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700329
Laurence Lundbladeda319282020-07-06 23:04:58 -0700330 EngineItems[3].uLabelType = QCBOR_TYPE_TEXT_STRING;
331 EngineItems[3].label.string = UsefulBuf_FROM_SZ_LITERAL("DesignedCompression");
332 EngineItems[3].uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700333
Laurence Lundbladeda319282020-07-06 23:04:58 -0700334 EngineItems[4].uLabelType = QCBOR_TYPE_TEXT_STRING;
335 EngineItems[4].label.string = UsefulBuf_FROM_SZ_LITERAL("Turbo");
336 EngineItems[4].uDataType = QCBOR_TYPE_ANY;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700337
Laurence Lundbladeda319282020-07-06 23:04:58 -0700338 EngineItems[5].uLabelType = QCBOR_TYPE_TEXT_STRING;
339 EngineItems[5].label.string = UsefulBuf_FROM_SZ_LITERAL("NumCylinders");
340 EngineItems[5].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700341
Laurence Lundbladeda319282020-07-06 23:04:58 -0700342 EngineItems[6].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700343
Laurence Lundbladeda319282020-07-06 23:04:58 -0700344 uErr = QCBORDecode_GetItemsInMap(&DecodeCtx, EngineItems);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700345 if(uErr != QCBOR_SUCCESS) {
346 goto Done;
347 }
348
Laurence Lundbladeda319282020-07-06 23:04:58 -0700349 pE->Manufacturer = EngineItems[0].val.string;
350 pE->uDisplacement = EngineItems[1].val.int64;
351 pE->uHorsePower = EngineItems[2].val.int64;
352 pE->dDesignedCompresion = EngineItems[3].val.dfnum;
353 pE->uNumCylinders = EngineItems[5].val.int64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700354
Laurence Lundbladeda319282020-07-06 23:04:58 -0700355 if(EngineItems[4].uDataType == QCBOR_TYPE_TRUE) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700356 pE->bTurboCharged = true;
Laurence Lundbladeda319282020-07-06 23:04:58 -0700357 } else if(EngineItems[4].uDataType == QCBOR_TYPE_FALSE) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700358 pE->bTurboCharged = false;
359 } else {
360 return EngineProtocolerror;
361 }
362
363
364 /* Must check error before referencing pE->uNumCylinders to be sure it
365 is valid. If any of the above errored, it won't be valid. */
366 uErr = QCBORDecode_GetError(&DecodeCtx);
367 if(uErr != QCBOR_SUCCESS) {
368 goto Done;
369 }
370
371 if(pE->uNumCylinders > MAX_CYLINDERS) {
372 return TooManyCylinders;
373 }
374
375 QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
376 for(int64_t i = 0; i < pE->uNumCylinders; i++) {
377 QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
378 }
379 QCBORDecode_ExitArray(&DecodeCtx);
380 QCBORDecode_ExitMap(&DecodeCtx);
381
382 /* Catch the remainder of errors here */
383 uErr = QCBORDecode_Finish(&DecodeCtx);
384
385Done:
386 return ConvertError(uErr);
387}
388
389
390
391
Laurence Lundblade06c83042020-07-03 23:04:53 -0700392
Laurence Lundblade1818e632020-07-26 04:14:08 -0700393/**
394 @brief Check the type and lable of an item.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700395
Laurence Lundblade1818e632020-07-26 04:14:08 -0700396 @param[in] szLabel The expected string label.
397 @param[in] uQCBORType The expected type or @c QCBOR_TYPE_ANY
398 @param[in] pItem The item to check.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700399
Laurence Lundblade1818e632020-07-26 04:14:08 -0700400 @retval QCBOR_ERR_NOT_FOUND The label doesn't match.
401 @retval QCBOR_ERR_UNEXPECTED_TYPE The label matches, but the type is not as expected.
402 @retval QCBOR_SUCCESS Both label and type match.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700403 */
Laurence Lundblade1818e632020-07-26 04:14:08 -0700404QCBORError CheckLabelAndType(const char *szLabel, uint8_t uQCBORType, const QCBORItem *pItem)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700405{
406 if(pItem->uLabelType != QCBOR_TYPE_TEXT_STRING) {
407 return QCBOR_ERR_NOT_FOUND;
408 }
409
410 UsefulBufC Label = UsefulBuf_FromSZ(szLabel);
411
Laurence Lundblade06c83042020-07-03 23:04:53 -0700412 if(UsefulBuf_Compare(Label, pItem->label.string)) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700413 return QCBOR_ERR_NOT_FOUND;
414 }
415
Laurence Lundblade06c83042020-07-03 23:04:53 -0700416 if(pItem->uDataType != uQCBORType && uQCBORType != QCBOR_TYPE_ANY) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700417 return QCBOR_ERR_UNEXPECTED_TYPE;
418 }
419
420 return QCBOR_SUCCESS;
421}
422
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700423
Laurence Lundblade1818e632020-07-26 04:14:08 -0700424/**
425 @brief Decode the array of engine cylinders.
426
427 @param[in] pDecodeCtx The decode context from which to get items.
428 @param[out] pE The structure filled in from the decoding.
429 @param[in] pItem The data item that is the start of the array.
430
431 @return Either @ref EngineSuccess or an error.
432
433 This always consumes the whole array. If it has the wrong number of
434 items in it, an error is returned.
435 */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700436EngineDecodeErrors DecodeCylinders(QCBORDecodeContext *pDecodeCtx,
Laurence Lundbladeda319282020-07-06 23:04:58 -0700437 CarEngine *pE,
Laurence Lundblade06c83042020-07-03 23:04:53 -0700438 const QCBORItem *pItem)
439{
440 int i = 0;
441 QCBORItem Item;
442
Laurence Lundblade1818e632020-07-26 04:14:08 -0700443 /* Loop getting all the items in the array. This uses
444 nesting level to detect the end so it works for both
445 definite and indefinite length arrays. */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700446 do {
447 QCBORError uErr;
448
449 uErr = QCBORDecode_GetNext(pDecodeCtx, &Item);
450 if(uErr != QCBOR_SUCCESS) {
451 return CBORNotWellFormed;
452 }
453 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
454 return CBORNotWellFormed;
455 }
456
457 if(i < MAX_CYLINDERS) {
458 pE->cylinders[i].uMeasuredCompression = Item.val.dfnum;
459 i++;
460 }
461
462 } while (Item.uNextNestLevel == pItem->uNextNestLevel);
463
464 if(i != pE->uNumCylinders) {
465 return WrongNumberOfCylinders;
466 } else {
467 return EngineSuccess;
468 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700469}
470
Laurence Lundblade06c83042020-07-03 23:04:53 -0700471
Laurence Lundbladeda319282020-07-06 23:04:58 -0700472/**
Laurence Lundblade1818e632020-07-26 04:14:08 -0700473 @brief Engine decode without advanced decode features.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700474
Laurence Lundblade1818e632020-07-26 04:14:08 -0700475 @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
476 @param[out] pE The structure filled in from the decoding.
Laurence Lundbladeda319282020-07-06 23:04:58 -0700477
Laurence Lundblade1818e632020-07-26 04:14:08 -0700478 @return The decode error or success.
Laurence Lundbladeda319282020-07-06 23:04:58 -0700479
Laurence Lundblade1818e632020-07-26 04:14:08 -0700480 This version of the deocde is the most complex, but uses
Laurence Lundbladeda319282020-07-06 23:04:58 -0700481 significantly less code from the QCBOR library. It is also
482 the most CPU-efficient since it does only one pass
483 through the CBOR.
484
Laurence Lundblade1818e632020-07-26 04:14:08 -0700485 Code size is yet to be measured, but this is probably the smallest total
Laurence Lundbladeda319282020-07-06 23:04:58 -0700486 code size of all three, if just one CBOR protocol is being decoded. If
487 multiple protocols are being decoded the other options.
488
489 See also DecodeEngineAdvanced() and DecodeEngineAdvancedFaster().
490*/
491EngineDecodeErrors DecodeEngineBasic(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700492{
493 QCBORDecodeContext DecodeCtx;
494
495 QCBORDecode_Init(&DecodeCtx, EncodedEngine, 0);// TODO: fill in mode;
496
497 QCBORItem Item;
498 QCBORError uErr;
Laurence Lundblade06c83042020-07-03 23:04:53 -0700499 EngineDecodeErrors uReturn;
500
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700501
502 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
503 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700504 uReturn = CBORNotWellFormed;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700505 goto Done;
506 }
507 if(Item.uDataType != QCBOR_TYPE_MAP) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700508 uReturn = CBORNotWellFormed;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700509 goto Done;
510 }
511
512 while(1) {
513 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
514 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700515 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
516 break; /* Non-error exit from the loop */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700517 } else {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700518 uReturn = CBORNotWellFormed;
519 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700520 }
Laurence Lundblade06c83042020-07-03 23:04:53 -0700521 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700522
Laurence Lundblade06c83042020-07-03 23:04:53 -0700523 uErr = CheckLabelAndType("Manufacturer", QCBOR_TYPE_TEXT_STRING, &Item);
524 if(uErr == QCBOR_SUCCESS) {
525 pE->Manufacturer = Item.val.string;
526 continue;
527 } else if(uErr != QCBOR_ERR_NOT_FOUND){
528 /* Maunfacturer field missing or badly formed */
529 return EngineProtocolerror;
530 } /* continue on and try for another match */
531
Laurence Lundblade06c83042020-07-03 23:04:53 -0700532 uErr = CheckLabelAndType("NumCylinders", QCBOR_TYPE_INT64, &Item);
533 if(uErr == QCBOR_SUCCESS) {
534 if(Item.val.int64 > MAX_CYLINDERS) {
535 return TooManyCylinders;
536 } else {
537 pE->uNumCylinders = (uint8_t)Item.val.int64;
538 continue;
539 }
540 } else if(uErr != QCBOR_ERR_NOT_FOUND){
Laurence Lundblade1818e632020-07-26 04:14:08 -0700541 /* NumCylinders field missing or badly formed */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700542 return EngineProtocolerror;
Laurence Lundblade1818e632020-07-26 04:14:08 -0700543 } /* continue on and try for another match */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700544
545 uErr = CheckLabelAndType("Cylinders", QCBOR_TYPE_ARRAY, &Item);
546 if(uErr == QCBOR_SUCCESS) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700547 DecodeCylinders(&DecodeCtx, pE, &Item);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700548 continue;
549 } else if(uErr != QCBOR_ERR_NOT_FOUND){
550 return EngineProtocolerror;
551 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700552
Laurence Lundblade06c83042020-07-03 23:04:53 -0700553 uErr = CheckLabelAndType("Displacement", QCBOR_TYPE_INT64, &Item);
554 if(uErr == QCBOR_SUCCESS) {
555 pE->uDisplacement = Item.val.int64;
556 continue;
557 } else if(uErr != QCBOR_ERR_NOT_FOUND){
558 return EngineProtocolerror;
559 }
560
561 uErr = CheckLabelAndType("Horsepower", QCBOR_TYPE_INT64, &Item);
562 if(uErr == QCBOR_SUCCESS) {
563 pE->uHorsePower = Item.val.int64;
564 continue;
565 } else if(uErr != QCBOR_ERR_NOT_FOUND){
566 return EngineProtocolerror;
567 }
568
569 uErr = CheckLabelAndType("DesignedCompression", QCBOR_TYPE_DOUBLE, &Item);
570 if(uErr == QCBOR_SUCCESS) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700571 pE->dDesignedCompresion = Item.val.dfnum;
Laurence Lundblade06c83042020-07-03 23:04:53 -0700572 continue;
573 } else if(uErr != QCBOR_ERR_NOT_FOUND){
574 return EngineProtocolerror;
575 }
576
Laurence Lundbladeda319282020-07-06 23:04:58 -0700577 uErr = CheckLabelAndType("Turbo", QCBOR_TYPE_ANY, &Item);
Laurence Lundblade1818e632020-07-26 04:14:08 -0700578 if(uErr == QCBOR_SUCCESS) {
579 if(Item.uDataType == QCBOR_TYPE_TRUE) {
580 pE->bTurboCharged = true;
581 } else if(Item.uDataType == QCBOR_TYPE_FALSE) {
582 pE->bTurboCharged = false;
583 } else {
584 return EngineProtocolerror;
585 }
586 continue;
587 } else if(uErr != QCBOR_ERR_NOT_FOUND){
588 return EngineProtocolerror;
589 }
Laurence Lundblade06c83042020-07-03 23:04:53 -0700590
591 /* Some label data item that is not known
592 (could just ignore extras data items) */
593 return EngineProtocolerror;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700594 }
Laurence Lundblade06c83042020-07-03 23:04:53 -0700595 uReturn = EngineSuccess;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700596
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700597Done:
Laurence Lundblade06c83042020-07-03 23:04:53 -0700598 return uReturn;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700599}
600
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700601
602
603
604
Laurence Lundblade1818e632020-07-26 04:14:08 -0700605int32_t RunQCborExample()
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700606{
Laurence Lundbladeda319282020-07-06 23:04:58 -0700607 CarEngine E, DecodedEngine;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700608 MakeUsefulBufOnStack( EngineBuffer, 300);
609 UsefulBufC EncodedEngine;
610
611 MakeUsefulBufOnStack( InDefEngineBuffer, 300);
612 UsefulBufC InDefEncodedEngine;
613
Laurence Lundblade1818e632020-07-26 04:14:08 -0700614 // TODO: error codes and other clean up
615
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700616 EngineInit(&E);
617
618 EncodedEngine = EncodeEngine(&E, EngineBuffer);
619
620 printf("Engine Encoded in %zu bytes\n", EncodedEngine.len);
621
Laurence Lundblade67257dc2020-07-27 03:33:37 -0700622 int x = (int)DecodeEngineSpiffy(EncodedEngine, &DecodedEngine);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700623 printf("Engine Decode Result: %d\n", x);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700624
625
626 InDefEncodedEngine = EncodeEngineIndefinteLen(&E, InDefEngineBuffer);
627
628 printf("Indef Engine Encoded in %zu bytes\n", InDefEncodedEngine.len);
629
Laurence Lundblade67257dc2020-07-27 03:33:37 -0700630 x = (int)DecodeEngineSpiffy(InDefEncodedEngine, &DecodedEngine);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700631 printf("Indef Engine Decode Result: %d\n", x);
632
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700633 if(!EngineCompare(&E, &DecodedEngine)) {
634 printf("decode comparison fail\n");
635 }
636
Laurence Lundblade06c83042020-07-03 23:04:53 -0700637
638 x = (int)DecodeEngineBasic(EncodedEngine, &DecodedEngine);
639 printf("Engine Basic Decode Result: %d\n", x);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700640
641 if(!EngineCompare(&E, &DecodedEngine)) {
642 printf("decode comparison fail\n");
643 }
644
645
646 x = (int)DecodeEngineBasic(InDefEncodedEngine, &DecodedEngine);
647 printf("Indef Engine Basic Decode Result: %d\n", x);
648
649 if(!EngineCompare(&E, &DecodedEngine)) {
650 printf("indef decode comparison fail\n");
651 }
652
Laurence Lundblade67257dc2020-07-27 03:33:37 -0700653 x = (int)DecodeEngineSpiffyFaster(EncodedEngine, &DecodedEngine);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700654 printf("Efficient Engine Basic Decode Result: %d\n", x);
655
656 if(!EngineCompare(&E, &DecodedEngine)) {
657 printf("effcieit decode comparison fail\n");
658 }
Laurence Lundblade1818e632020-07-26 04:14:08 -0700659
660 return 0;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700661}