blob: a12c148a5e543b23af3afef26274104edbac0148 [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"
18
19#define MAX_CYLINDERS 16
20
Laurence Lundbladeda319282020-07-06 23:04:58 -070021
22/**
23 The data structure representing a car engine that is encoded and decoded in this examples.
24 */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070025typedef struct
26{
27 UsefulBufC Manufacturer;
Laurence Lundblade06c83042020-07-03 23:04:53 -070028 int64_t uDisplacement;
29 int64_t uHorsePower;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -070030 double dDesignedCompresion;
Laurence Lundbladeda319282020-07-06 23:04:58 -070031 int64_t uNumCylinders;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070032 struct {
33 double uMeasuredCompression;
34 } cylinders[MAX_CYLINDERS];
35 bool bTurboCharged;
Laurence Lundbladeda319282020-07-06 23:04:58 -070036} CarEngine;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070037
38
Laurence Lundbladeda319282020-07-06 23:04:58 -070039/**
40 Initialize the Engine data structure with some values to encode/decode.
41 */
42void EngineInit(CarEngine *pE)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070043{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070044 pE->Manufacturer = UsefulBuf_FROM_SZ_LITERAL("Porsche");
45 pE->uDisplacement = 3296;
46 pE->uHorsePower = 210;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -070047 pE->dDesignedCompresion = 9.1;
Laurence Lundbladeda319282020-07-06 23:04:58 -070048 pE->uNumCylinders = 6;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070049 pE->cylinders[0].uMeasuredCompression = 9.0;
50 pE->cylinders[1].uMeasuredCompression = 9.2;
51 pE->cylinders[2].uMeasuredCompression = 8.9;
52 pE->cylinders[3].uMeasuredCompression = 8.9;
53 pE->cylinders[4].uMeasuredCompression = 9.1;
54 pE->cylinders[5].uMeasuredCompression = 9.0;
Laurence Lundbladeda319282020-07-06 23:04:58 -070055 pE->bTurboCharged = false;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -070056}
57
58
Laurence Lundbladeda319282020-07-06 23:04:58 -070059/**
60 Return @c true if the two Engined data structures are exactly the same.
61 */
62bool EngineCompare(CarEngine *pE1, CarEngine *pE2)
Laurence Lundbladee6bbf552020-07-05 22:57:57 -070063{
64 if(pE1->uNumCylinders != pE2->uNumCylinders) {
65 return false;
66 }
67 if(pE1->bTurboCharged != pE2->bTurboCharged) {
68 return false;
69 }
70 if(pE1->uDisplacement != pE2->uDisplacement) {
71 return false;
72 }
73 if(pE1->uHorsePower != pE2->uHorsePower) {
74 return false;
75 }
76 if(pE1->dDesignedCompresion != pE2->dDesignedCompresion) {
77 return false;
78 }
79 for(int64_t i = 0; i < pE2->uNumCylinders; i++) {
80 if(pE1->cylinders[i].uMeasuredCompression !=
81 pE2->cylinders[i].uMeasuredCompression) {
82 return false;
83 }
84 }
85
86 if(UsefulBuf_Compare(pE1->Manufacturer, pE2->Manufacturer)) {
87 return false;
88 }
89
90 return true;
91}
92
93
Laurence Lundbladeda319282020-07-06 23:04:58 -070094/**
95 @brief Encode an initialized Engine data structure in CBOR.
96
97 @param[in] pEngine The data structure to encode.
98 @param[in] Buffer Pointer and length of buffer to output to.
99
100 @return The pointer and length of the encoded CBOR or @ref NULLUsefulBufC on error.
101
102 @c Buffer must be big enough to hold the output. If it is not @ref NULLUsefulBufC
103 will be returned. @ref @ref NULLUsefulBufC will be returned for any other encoding
104 errors.
105
106 This encoding will use definite CBOR lengths.
107 */
108UsefulBufC EncodeEngine(const CarEngine *pEngine, UsefulBuf Buffer)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700109{
Laurence Lundblade06c83042020-07-03 23:04:53 -0700110 /* Initialize th encoder with the buffer big enough to hold the expected output.
111 If it is too small, QCBOREncode_Finish() will return an error. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700112 QCBOREncodeContext EncodeCtx;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700113 QCBOREncode_Init(&EncodeCtx, Buffer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700114
115 /* Proceed output all the items, letting the internal error
116 tracking do its work. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700117 QCBOREncode_OpenMap(&EncodeCtx);
118 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700119 QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
120 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
121 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700122 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700123 QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders");
Laurence Lundblade06c83042020-07-03 23:04:53 -0700124 for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700125 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
126 }
127 QCBOREncode_CloseArray(&EncodeCtx);
Laurence Lundbladeda319282020-07-06 23:04:58 -0700128 QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700129 QCBOREncode_CloseMap(&EncodeCtx);
130
Laurence Lundblade06c83042020-07-03 23:04:53 -0700131 /* Get the pointer and length of the encoded output. If there was
132 anny error it will be returned here. */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700133 UsefulBufC EncodedCBOR;
134 QCBORError uErr;
135 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
136 if(uErr != QCBOR_SUCCESS) {
137 return NULLUsefulBufC;
138 } else {
139 return EncodedCBOR;
140 }
141}
142
143
Laurence Lundbladeda319282020-07-06 23:04:58 -0700144/**
145 @brief Encode an initialized Engine data structure in CBOR using indefinite lengths..
146
147 @param[in] pEngine The data structure to encode.
148 @param[in] Buffer Pointer and length of buffer to output to.
149
150 @return The pointer and length of the encoded CBOR or @ref NULLUsefulBufC on error.
151
152 This is virtually the same as EncodeEngine(). The encoded CBOR is slightly different as the
153 map and array use indefinite lengths, rather than definite lengths.
154
155 There is little practical use for this function as definite lengths are generally preferred for
156 CBOR and QCBOR always easily encodes definite lengths. (The advantage of indefinite
157 lengths are that they are simpler to encode, but that doesn't come into effect here).
158 */
159UsefulBufC EncodeEngineIndefinteLen(const CarEngine *pEngine, UsefulBuf Buffer)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700160{
161 QCBOREncodeContext EncodeCtx;
162
163 QCBOREncode_Init(&EncodeCtx, Buffer);
164 QCBOREncode_OpenMapIndefiniteLength(&EncodeCtx);
165 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700166 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
167 QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700168 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700169 QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700170 QCBOREncode_OpenArrayIndefiniteLengthInMap(&EncodeCtx, "Cylinders");
Laurence Lundblade06c83042020-07-03 23:04:53 -0700171 for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700172 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
173 }
174 QCBOREncode_CloseArrayIndefiniteLength(&EncodeCtx);
Laurence Lundbladeda319282020-07-06 23:04:58 -0700175 QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700176 QCBOREncode_CloseMapIndefiniteLength(&EncodeCtx);
177
178 UsefulBufC EncodedCBOR;
179 QCBORError uErr;
180 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
181 if(uErr != QCBOR_SUCCESS) {
182 return NULLUsefulBufC;
183 } else {
184 return EncodedCBOR;
185 }
186}
187
188
Laurence Lundbladeda319282020-07-06 23:04:58 -0700189/**
190 Error results when decoding an Engine data structure.
191 */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700192typedef enum {
193 EngineSuccess,
194 CBORNotWellFormed,
195 TooManyCylinders,
196 EngineProtocolerror,
197 WrongNumberOfCylinders
198} EngineDecodeErrors;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700199
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700200
Laurence Lundbladeda319282020-07-06 23:04:58 -0700201/**
202 Convert \ref QCBORError to \ref EngineDecodeErrors.
203 */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700204EngineDecodeErrors ConvertError(QCBORError uErr)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700205{
Laurence Lundblade06c83042020-07-03 23:04:53 -0700206 EngineDecodeErrors uReturn;
207
208 switch(uErr)
209 {
210 case QCBOR_SUCCESS:
211 uReturn = EngineSuccess;
212 break;
213
214 case QCBOR_ERR_HIT_END:
215 uReturn = CBORNotWellFormed;
216 break;
217
218 default:
219 uReturn = EngineProtocolerror;
220 break;
221 }
222
223 return uReturn;
224}
225
226
Laurence Lundbladeda319282020-07-06 23:04:58 -0700227/**
228 @brief Simplest engine decode using advanced decoe features.
229
230 @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
231 @param[out] pE The structure filled in from the decoding.
232
233 @return The decode error or success.
234
235 This verssion of the decoder has the simplest implementation, but
236 pulls in more code from the QCBOR library. This version uses
237 the most CPU because it scanns the all the CBOR each time
238 a data item is decoded. The CPU used for a data structure as small
239 as this is probably insignificant. CPU use for this style of decode is
240 probably only a factor on slow CPUs with big CBOR inputs.
241
242 Code size is yet to be measured, but this is probably the smallest total
243 code size if multiple protocols are being decoded in one application because
244 the complex parsing of a map and array is done be shared code from the
245 CBOR library rather than by individual protocol-specific chunks of code.
246 Similarly, this may be the smallest for complex CBOR with multiple
247 maps that need to be processed..
248
249 See also DecodeEngineAdvancedFaster() and DecodeEngineBasic().
Laurence Lundblade06c83042020-07-03 23:04:53 -0700250 */
Laurence Lundbladeda319282020-07-06 23:04:58 -0700251EngineDecodeErrors DecodeEngineAdvanced(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundblade06c83042020-07-03 23:04:53 -0700252{
253 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700254 QCBORDecodeContext DecodeCtx;
255
256 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
257 QCBORDecode_EnterMap(&DecodeCtx);
258 QCBORDecode_GetTextInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer));
Laurence Lundblade06c83042020-07-03 23:04:53 -0700259 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement));
260 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "Horsepower", &(pE->uHorsePower));
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700261 QCBORDecode_GetDoubleInMapSZ(&DecodeCtx, "DesignedCompression", &(pE->dDesignedCompresion));
Laurence Lundbladeda319282020-07-06 23:04:58 -0700262 QCBORDecode_GetBoolInMapSZ(&DecodeCtx, "Turbo", &(pE->bTurboCharged));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700263
Laurence Lundblade06c83042020-07-03 23:04:53 -0700264 QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "NumCylinders", &(pE->uNumCylinders));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700265
266 /* Must check error before referencing pE->uNumCylinders to be sure it
267 is valid. If any of the above errored, it won't be valid. */
Laurence Lundblade06c83042020-07-03 23:04:53 -0700268 uErr = QCBORDecode_GetError(&DecodeCtx);
269 if(uErr != QCBOR_SUCCESS) {
270 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700271 }
272
273 if(pE->uNumCylinders > MAX_CYLINDERS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700274 return TooManyCylinders;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700275 }
276
277 QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700278 for(int64_t i = 0; i < pE->uNumCylinders; i++) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700279 QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700280 }
281 QCBORDecode_ExitArray(&DecodeCtx);
282 QCBORDecode_ExitMap(&DecodeCtx);
283
Laurence Lundblade06c83042020-07-03 23:04:53 -0700284 /* Catch the remainder of errors here */
285 uErr = QCBORDecode_Finish(&DecodeCtx);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700286
Laurence Lundblade06c83042020-07-03 23:04:53 -0700287Done:
288 return ConvertError(uErr);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700289}
290
Laurence Lundblade06c83042020-07-03 23:04:53 -0700291
Laurence Lundbladeda319282020-07-06 23:04:58 -0700292/**
293 @brief Simplest engine decode using advanced decoe features.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700294
Laurence Lundbladeda319282020-07-06 23:04:58 -0700295 @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
296 @param[out] pE The structure filled in from the decoding.
297
298 @return The decode error or success.
299
300This verssion of the decoder is still fairly simple and uses the
301 advanced decode features like DecodeEngine(), but is faster
302 and pulls in less library code. It is faster because all the items
303 except the array are pulled out of the map in one pass, rather
304 than multiple passes.
305
306 See also DecodeEngineAdvanced() and DecodeEngineBasic().
307*/
308EngineDecodeErrors DecodeEngineAdvancedFaster(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700309{
310 QCBORError uErr;
311 QCBORDecodeContext DecodeCtx;
312
313 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
314 QCBORDecode_EnterMap(&DecodeCtx);
315
Laurence Lundbladeda319282020-07-06 23:04:58 -0700316 QCBORItem EngineItems[7];
317 EngineItems[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
318 EngineItems[0].label.string = UsefulBuf_FROM_SZ_LITERAL("Manufacturer");
319 EngineItems[0].uDataType = QCBOR_TYPE_TEXT_STRING;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700320
Laurence Lundbladeda319282020-07-06 23:04:58 -0700321 EngineItems[1].uLabelType = QCBOR_TYPE_TEXT_STRING;
322 EngineItems[1].label.string = UsefulBuf_FROM_SZ_LITERAL("Displacement");
323 EngineItems[1].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700324
Laurence Lundbladeda319282020-07-06 23:04:58 -0700325 EngineItems[2].uLabelType = QCBOR_TYPE_TEXT_STRING;
326 EngineItems[2].label.string = UsefulBuf_FROM_SZ_LITERAL("Horsepower");
327 EngineItems[2].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700328
Laurence Lundbladeda319282020-07-06 23:04:58 -0700329 EngineItems[3].uLabelType = QCBOR_TYPE_TEXT_STRING;
330 EngineItems[3].label.string = UsefulBuf_FROM_SZ_LITERAL("DesignedCompression");
331 EngineItems[3].uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700332
Laurence Lundbladeda319282020-07-06 23:04:58 -0700333 EngineItems[4].uLabelType = QCBOR_TYPE_TEXT_STRING;
334 EngineItems[4].label.string = UsefulBuf_FROM_SZ_LITERAL("Turbo");
335 EngineItems[4].uDataType = QCBOR_TYPE_ANY;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700336
Laurence Lundbladeda319282020-07-06 23:04:58 -0700337 EngineItems[5].uLabelType = QCBOR_TYPE_TEXT_STRING;
338 EngineItems[5].label.string = UsefulBuf_FROM_SZ_LITERAL("NumCylinders");
339 EngineItems[5].uDataType = QCBOR_TYPE_INT64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700340
Laurence Lundbladeda319282020-07-06 23:04:58 -0700341 EngineItems[6].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700342
Laurence Lundbladeda319282020-07-06 23:04:58 -0700343 uErr = QCBORDecode_GetItemsInMap(&DecodeCtx, EngineItems);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700344 if(uErr != QCBOR_SUCCESS) {
345 goto Done;
346 }
347
Laurence Lundbladeda319282020-07-06 23:04:58 -0700348 pE->Manufacturer = EngineItems[0].val.string;
349 pE->uDisplacement = EngineItems[1].val.int64;
350 pE->uHorsePower = EngineItems[2].val.int64;
351 pE->dDesignedCompresion = EngineItems[3].val.dfnum;
352 pE->uNumCylinders = EngineItems[5].val.int64;
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700353
Laurence Lundbladeda319282020-07-06 23:04:58 -0700354 if(EngineItems[4].uDataType == QCBOR_TYPE_TRUE) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700355 pE->bTurboCharged = true;
Laurence Lundbladeda319282020-07-06 23:04:58 -0700356 } else if(EngineItems[4].uDataType == QCBOR_TYPE_FALSE) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700357 pE->bTurboCharged = false;
358 } else {
359 return EngineProtocolerror;
360 }
361
362
363 /* Must check error before referencing pE->uNumCylinders to be sure it
364 is valid. If any of the above errored, it won't be valid. */
365 uErr = QCBORDecode_GetError(&DecodeCtx);
366 if(uErr != QCBOR_SUCCESS) {
367 goto Done;
368 }
369
370 if(pE->uNumCylinders > MAX_CYLINDERS) {
371 return TooManyCylinders;
372 }
373
374 QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
375 for(int64_t i = 0; i < pE->uNumCylinders; i++) {
376 QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
377 }
378 QCBORDecode_ExitArray(&DecodeCtx);
379 QCBORDecode_ExitMap(&DecodeCtx);
380
381 /* Catch the remainder of errors here */
382 uErr = QCBORDecode_Finish(&DecodeCtx);
383
384Done:
385 return ConvertError(uErr);
386}
387
388
389
390
Laurence Lundblade06c83042020-07-03 23:04:53 -0700391
392/*
393
394 - Match
395 - Error
396 - No match
397
398 */
399
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700400QCBORError CheckLabelAndType(const char *szLabel, uint8_t uQCBORType, QCBORItem *pItem)
401{
402 if(pItem->uLabelType != QCBOR_TYPE_TEXT_STRING) {
403 return QCBOR_ERR_NOT_FOUND;
404 }
405
406 UsefulBufC Label = UsefulBuf_FromSZ(szLabel);
407
Laurence Lundblade06c83042020-07-03 23:04:53 -0700408 if(UsefulBuf_Compare(Label, pItem->label.string)) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700409 return QCBOR_ERR_NOT_FOUND;
410 }
411
Laurence Lundblade06c83042020-07-03 23:04:53 -0700412 if(pItem->uDataType != uQCBORType && uQCBORType != QCBOR_TYPE_ANY) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700413 return QCBOR_ERR_UNEXPECTED_TYPE;
414 }
415
416 return QCBOR_SUCCESS;
417}
418
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700419
Laurence Lundblade06c83042020-07-03 23:04:53 -0700420EngineDecodeErrors DecodeCylinders(QCBORDecodeContext *pDecodeCtx,
Laurence Lundbladeda319282020-07-06 23:04:58 -0700421 CarEngine *pE,
Laurence Lundblade06c83042020-07-03 23:04:53 -0700422 const QCBORItem *pItem)
423{
424 int i = 0;
425 QCBORItem Item;
426
427 /* Loop getting all the items in the array */
428 do {
429 QCBORError uErr;
430
431 uErr = QCBORDecode_GetNext(pDecodeCtx, &Item);
432 if(uErr != QCBOR_SUCCESS) {
433 return CBORNotWellFormed;
434 }
435 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
436 return CBORNotWellFormed;
437 }
438
439 if(i < MAX_CYLINDERS) {
440 pE->cylinders[i].uMeasuredCompression = Item.val.dfnum;
441 i++;
442 }
443
444 } while (Item.uNextNestLevel == pItem->uNextNestLevel);
445
446 if(i != pE->uNumCylinders) {
447 return WrongNumberOfCylinders;
448 } else {
449 return EngineSuccess;
450 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700451}
452
Laurence Lundblade06c83042020-07-03 23:04:53 -0700453
Laurence Lundbladeda319282020-07-06 23:04:58 -0700454/**
455@brief Engine decode without advanced decode features.
Laurence Lundblade06c83042020-07-03 23:04:53 -0700456
Laurence Lundbladeda319282020-07-06 23:04:58 -0700457@param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
458@param[out] pE The structure filled in from the decoding.
459
460@return The decode error or success.
461
462This version of the deocde is the most complex, but uses
463 significantly less code from the QCBOR library. It is also
464 the most CPU-efficient since it does only one pass
465 through the CBOR.
466
467 Code size is yet to be measured, but this is probably the smallest total
468 code size of all three, if just one CBOR protocol is being decoded. If
469 multiple protocols are being decoded the other options.
470
471 See also DecodeEngineAdvanced() and DecodeEngineAdvancedFaster().
472*/
473EngineDecodeErrors DecodeEngineBasic(UsefulBufC EncodedEngine, CarEngine *pE)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700474{
475 QCBORDecodeContext DecodeCtx;
476
477 QCBORDecode_Init(&DecodeCtx, EncodedEngine, 0);// TODO: fill in mode;
478
479 QCBORItem Item;
480 QCBORError uErr;
Laurence Lundblade06c83042020-07-03 23:04:53 -0700481 EngineDecodeErrors uReturn;
482
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700483
484 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
485 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700486 uReturn = CBORNotWellFormed;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700487 goto Done;
488 }
489 if(Item.uDataType != QCBOR_TYPE_MAP) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700490 uReturn = CBORNotWellFormed;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700491 goto Done;
492 }
493
494 while(1) {
495 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
496 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700497 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
498 break; /* Non-error exit from the loop */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700499 } else {
Laurence Lundblade06c83042020-07-03 23:04:53 -0700500 uReturn = CBORNotWellFormed;
501 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700502 }
Laurence Lundblade06c83042020-07-03 23:04:53 -0700503 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700504
Laurence Lundblade06c83042020-07-03 23:04:53 -0700505 uErr = CheckLabelAndType("Manufacturer", QCBOR_TYPE_TEXT_STRING, &Item);
506 if(uErr == QCBOR_SUCCESS) {
507 pE->Manufacturer = Item.val.string;
508 continue;
509 } else if(uErr != QCBOR_ERR_NOT_FOUND){
510 /* Maunfacturer field missing or badly formed */
511 return EngineProtocolerror;
512 } /* continue on and try for another match */
513
514
Laurence Lundblade06c83042020-07-03 23:04:53 -0700515 uErr = CheckLabelAndType("NumCylinders", QCBOR_TYPE_INT64, &Item);
516 if(uErr == QCBOR_SUCCESS) {
517 if(Item.val.int64 > MAX_CYLINDERS) {
518 return TooManyCylinders;
519 } else {
520 pE->uNumCylinders = (uint8_t)Item.val.int64;
521 continue;
522 }
523 } else if(uErr != QCBOR_ERR_NOT_FOUND){
524 /* Maunfacturer field missing or badly formed */
525 return EngineProtocolerror;
526 }
527
528 uErr = CheckLabelAndType("Cylinders", QCBOR_TYPE_ARRAY, &Item);
529 if(uErr == QCBOR_SUCCESS) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700530 DecodeCylinders(&DecodeCtx, pE, &Item);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700531 continue;
532 } else if(uErr != QCBOR_ERR_NOT_FOUND){
533 return EngineProtocolerror;
534 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700535
Laurence Lundblade06c83042020-07-03 23:04:53 -0700536 uErr = CheckLabelAndType("Displacement", QCBOR_TYPE_INT64, &Item);
537 if(uErr == QCBOR_SUCCESS) {
538 pE->uDisplacement = Item.val.int64;
539 continue;
540 } else if(uErr != QCBOR_ERR_NOT_FOUND){
541 return EngineProtocolerror;
542 }
543
544 uErr = CheckLabelAndType("Horsepower", QCBOR_TYPE_INT64, &Item);
545 if(uErr == QCBOR_SUCCESS) {
546 pE->uHorsePower = Item.val.int64;
547 continue;
548 } else if(uErr != QCBOR_ERR_NOT_FOUND){
549 return EngineProtocolerror;
550 }
551
552 uErr = CheckLabelAndType("DesignedCompression", QCBOR_TYPE_DOUBLE, &Item);
553 if(uErr == QCBOR_SUCCESS) {
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700554 pE->dDesignedCompresion = Item.val.dfnum;
Laurence Lundblade06c83042020-07-03 23:04:53 -0700555 continue;
556 } else if(uErr != QCBOR_ERR_NOT_FOUND){
557 return EngineProtocolerror;
558 }
559
Laurence Lundbladeda319282020-07-06 23:04:58 -0700560 uErr = CheckLabelAndType("Turbo", QCBOR_TYPE_ANY, &Item);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700561 if(uErr == QCBOR_SUCCESS) {
562 if(Item.uDataType == QCBOR_TYPE_TRUE) {
563 pE->bTurboCharged = true;
564 } else if(Item.uDataType == QCBOR_TYPE_FALSE) {
565 pE->bTurboCharged = false;
566 } else {
567 return EngineProtocolerror;
568 }
569 continue;
570 } else if(uErr != QCBOR_ERR_NOT_FOUND){
571 return EngineProtocolerror;
572 }
573
574
575 /* Some label data item that is not known
576 (could just ignore extras data items) */
577 return EngineProtocolerror;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700578 }
Laurence Lundblade06c83042020-07-03 23:04:53 -0700579 uReturn = EngineSuccess;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700580
581
582Done:
Laurence Lundblade06c83042020-07-03 23:04:53 -0700583 return uReturn;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700584}
585
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700586
587
588
589
590void RunQCborExample()
591{
Laurence Lundbladeda319282020-07-06 23:04:58 -0700592 CarEngine E, DecodedEngine;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700593 MakeUsefulBufOnStack( EngineBuffer, 300);
594 UsefulBufC EncodedEngine;
595
596 MakeUsefulBufOnStack( InDefEngineBuffer, 300);
597 UsefulBufC InDefEncodedEngine;
598
599 EngineInit(&E);
600
601 EncodedEngine = EncodeEngine(&E, EngineBuffer);
602
603 printf("Engine Encoded in %zu bytes\n", EncodedEngine.len);
604
Laurence Lundbladeda319282020-07-06 23:04:58 -0700605 int x = (int)DecodeEngineAdvanced(EncodedEngine, &DecodedEngine);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700606 printf("Engine Decode Result: %d\n", x);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700607
608
609 InDefEncodedEngine = EncodeEngineIndefinteLen(&E, InDefEngineBuffer);
610
611 printf("Indef Engine Encoded in %zu bytes\n", InDefEncodedEngine.len);
612
Laurence Lundbladeda319282020-07-06 23:04:58 -0700613 x = (int)DecodeEngineAdvanced(InDefEncodedEngine, &DecodedEngine);
Laurence Lundblade06c83042020-07-03 23:04:53 -0700614 printf("Indef Engine Decode Result: %d\n", x);
615
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700616 if(!EngineCompare(&E, &DecodedEngine)) {
617 printf("decode comparison fail\n");
618 }
619
Laurence Lundblade06c83042020-07-03 23:04:53 -0700620
621 x = (int)DecodeEngineBasic(EncodedEngine, &DecodedEngine);
622 printf("Engine Basic Decode Result: %d\n", x);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700623
624 if(!EngineCompare(&E, &DecodedEngine)) {
625 printf("decode comparison fail\n");
626 }
627
628
629 x = (int)DecodeEngineBasic(InDefEncodedEngine, &DecodedEngine);
630 printf("Indef Engine Basic Decode Result: %d\n", x);
631
632 if(!EngineCompare(&E, &DecodedEngine)) {
633 printf("indef decode comparison fail\n");
634 }
635
Laurence Lundbladeda319282020-07-06 23:04:58 -0700636 x = (int)DecodeEngineAdvancedFaster(EncodedEngine, &DecodedEngine);
Laurence Lundbladee6bbf552020-07-05 22:57:57 -0700637 printf("Efficient Engine Basic Decode Result: %d\n", x);
638
639 if(!EngineCompare(&E, &DecodedEngine)) {
640 printf("effcieit decode comparison fail\n");
641 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -0700642}