blob: b07a76c42ee5797ebb0abdedda7de2f9dccae4b2 [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
21typedef struct
22{
23 UsefulBufC Manufacturer;
24 uint64_t uNumCylinders;
25 uint64_t uDisplacement;
26 uint64_t uHorsePower;
27 double uDesignedCompresion;
28 struct {
29 double uMeasuredCompression;
30 } cylinders[MAX_CYLINDERS];
31 bool bTurboCharged;
32} Engine;
33
34
35void EngineInit(Engine *pE)
36{
37 pE->uNumCylinders = 6;
38 pE->bTurboCharged = false;
39 pE->Manufacturer = UsefulBuf_FROM_SZ_LITERAL("Porsche");
40 pE->uDisplacement = 3296;
41 pE->uHorsePower = 210;
42 pE->uDesignedCompresion = 9.1;
43 pE->cylinders[0].uMeasuredCompression = 9.0;
44 pE->cylinders[1].uMeasuredCompression = 9.2;
45 pE->cylinders[2].uMeasuredCompression = 8.9;
46 pE->cylinders[3].uMeasuredCompression = 8.9;
47 pE->cylinders[4].uMeasuredCompression = 9.1;
48 pE->cylinders[5].uMeasuredCompression = 9.0;
49}
50
51
52UsefulBufC EncodeEngine(const Engine *pEngine, UsefulBuf Buffer)
53{
54 QCBOREncodeContext EncodeCtx;
55
56 QCBOREncode_Init(&EncodeCtx, Buffer);
57 QCBOREncode_OpenMap(&EncodeCtx);
58 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
59 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
60 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
61 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "HorsePower", pEngine->uHorsePower);
62 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->uDesignedCompresion);
63 QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders");
64 for(uint64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
65 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
66 }
67 QCBOREncode_CloseArray(&EncodeCtx);
68 QCBOREncode_AddBoolToMap(&EncodeCtx, "turbo", pEngine->bTurboCharged);
69 QCBOREncode_CloseMap(&EncodeCtx);
70
71 UsefulBufC EncodedCBOR;
72 QCBORError uErr;
73 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
74 if(uErr != QCBOR_SUCCESS) {
75 return NULLUsefulBufC;
76 } else {
77 return EncodedCBOR;
78 }
79}
80
81
82UsefulBufC EncodeEngineIndefinteLen(const Engine *pEngine, UsefulBuf Buffer)
83{
84 QCBOREncodeContext EncodeCtx;
85
86 QCBOREncode_Init(&EncodeCtx, Buffer);
87 QCBOREncode_OpenMapIndefiniteLength(&EncodeCtx);
88 QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
89 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
90 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "HorsePower", pEngine->uHorsePower);
91 QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->uDesignedCompresion);
92 QCBOREncode_AddUInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
93 QCBOREncode_OpenArrayIndefiniteLengthInMap(&EncodeCtx, "Cylinders");
94 for(uint64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
95 QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
96 }
97 QCBOREncode_CloseArrayIndefiniteLength(&EncodeCtx);
98 QCBOREncode_AddBoolToMap(&EncodeCtx, "turbo", pEngine->bTurboCharged);
99 QCBOREncode_CloseMapIndefiniteLength(&EncodeCtx);
100
101 UsefulBufC EncodedCBOR;
102 QCBORError uErr;
103 uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
104 if(uErr != QCBOR_SUCCESS) {
105 return NULLUsefulBufC;
106 } else {
107 return EncodedCBOR;
108 }
109}
110
111
112/*
113A -- require all fields ; easiest code
114B -- all are optional; messiest code; should this be accommodate better?
115C -- some are optional; not too hard
116
117It is a protocol error to have the wrong type for a label.
118
119 */
120
121QCBORError DecodeEngine(UsefulBufC EncodedEngine, Engine *pE)
122{
123 QCBORDecodeContext DecodeCtx;
124
125 QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
126 QCBORDecode_EnterMap(&DecodeCtx);
127 QCBORDecode_GetTextInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer));
128 QCBORDecode_GetUInt64InMapSZ(&DecodeCtx, "Displacement", &(pE->uDisplacement));
129 QCBORDecode_GetUInt64InMapSZ(&DecodeCtx, "HorsePower", &(pE->uHorsePower));
130 QCBORDecode_GetDoubleInMapSZ(&DecodeCtx, "DesignedCompression", &(pE->uDesignedCompresion));
131 QCBORDecode_GetBoolInMapSZ(&DecodeCtx, "turbo", &(pE->bTurboCharged));
132
133 QCBORDecode_GetUInt64InMapSZ(&DecodeCtx, "NumCylinders", &(pE->uNumCylinders));
134
135 /* Must check error before referencing pE->uNumCylinders to be sure it
136 is valid. If any of the above errored, it won't be valid. */
137 if(QCBORDecode_GetError(&DecodeCtx)) {
138 return 100; // TODO: more error processing
139 }
140
141 if(pE->uNumCylinders > MAX_CYLINDERS) {
142 return 900;
143 }
144
145 QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
146 uint64_t i = 0;
147 while(1) {
148 QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
149 i++;
150 if(i >= pE->uNumCylinders ) {
151 break;
152 }
153 }
154 QCBORDecode_ExitArray(&DecodeCtx);
155 QCBORDecode_ExitMap(&DecodeCtx);
156
157 QCBORError uErr = QCBORDecode_Finish(&DecodeCtx);
158
159 return uErr;
160}
161
162#if 0
163QCBORError CheckLabelAndType(const char *szLabel, uint8_t uQCBORType, QCBORItem *pItem)
164{
165 if(pItem->uLabelType != QCBOR_TYPE_TEXT_STRING) {
166 return QCBOR_ERR_NOT_FOUND;
167 }
168
169 UsefulBufC Label = UsefulBuf_FromSZ(szLabel);
170
171 if(UsefulBuf_Compare(Label, pItem->val.string)) {
172 return QCBOR_ERR_NOT_FOUND;
173 }
174
175 if(pItem->uDataType != uQCBORType) {
176 return QCBOR_ERR_UNEXPECTED_TYPE;
177 }
178
179 return QCBOR_SUCCESS;
180}
181
182void DecodeCylinders(QCBORDecodeContext *pDctx, Engine *pE, const QCBORItem *pItem)
183{
184
185}
186
187QCBORError DecodeEngineBasic(UsefulBufC EncodedEngine, Engine *pE)
188{
189 QCBORDecodeContext DecodeCtx;
190
191 QCBORDecode_Init(&DecodeCtx, EncodedEngine, 0);// TODO: fill in mode;
192
193 QCBORItem Item;
194 QCBORError uErr;
195
196 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
197 if(uErr != QCBOR_SUCCESS) {
198 goto Done;
199 }
200 if(Item.uDataType != QCBOR_TYPE_MAP) {
201 uErr = 100;
202 goto Done;
203 }
204
205 while(1) {
206 uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
207 if(uErr != QCBOR_SUCCESS) {
208 goto Done;
209 }
210 if(Item.uDataType != QCBOR_TYPE_MAP) {
211 uErr = 100;
212 goto Done;
213 }
214
215 if(CheckLabelAndType("Manufacturer", QCBOR_TYPE_TEXT_STRING, &Item )) {
216 if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
217 return 99; // TODO: what to do on wrong type?
218 } else {
219 // TODO: copy string or change data type
220 }
221
222 } else if(CheckLabel("NumCylinders", &Item)) {
223 if(Item.uDataType != QCBOR_TYPE_INT64) {
224 return 99; // TODO: what to do on wrong type?
225 } else {
226 // TODO: what about overflow
227 pE->uNumCylinders = (uint8_t)Item.val.int64;
228 // TODO: copy string or change data type
229 }
230 } else if(CheckLabel("Cylinders", &Item)) {
231 DecodeCylinders(&DecodeCtx, pE, &Item);
232 }
233
234 }
235
236
237Done:
238 return uErr;
239}
240
241#endif
242
243
244
245
246
247void RunQCborExample()
248{
249 Engine E, DecodedEngine;
250 MakeUsefulBufOnStack( EngineBuffer, 300);
251 UsefulBufC EncodedEngine;
252
253 MakeUsefulBufOnStack( InDefEngineBuffer, 300);
254 UsefulBufC InDefEncodedEngine;
255
256 EngineInit(&E);
257
258 EncodedEngine = EncodeEngine(&E, EngineBuffer);
259
260 printf("Engine Encoded in %zu bytes\n", EncodedEngine.len);
261
262 DecodeEngine(EncodedEngine, &DecodedEngine);
263
264
265 InDefEncodedEngine = EncodeEngineIndefinteLen(&E, InDefEngineBuffer);
266
267 printf("Indef Engine Encoded in %zu bytes\n", InDefEncodedEngine.len);
268
269}