Improve documentation for encode size calculation mode (#123)
This adds the constant SizeCalculateUsefulBuf which can be passed to QCBOR Encode and to UsefulOutBuf to indicate only size calculation should be performed, that no encoded CBOR is to be output.
The documentation for this mode is improved, an example is added and test cases are added.
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 8b41af3..d3ada13 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -512,200 +512,222 @@
--XXXXboundary text--";
+static void AddAll(QCBOREncodeContext *pECtx)
+{
+ QCBOREncode_OpenArray(pECtx);
+
+ /* Some ints that are tagged and have strings preceeding them
+ * (not labels becase it is not a map) */
+ QCBOREncode_AddSZString(pECtx, "UINT62");
+ QCBOREncode_AddTag(pECtx, 100);
+ QCBOREncode_AddUInt64(pECtx, 89989909);
+ QCBOREncode_AddSZString(pECtx, "INT64");
+ QCBOREncode_AddTag(pECtx, 76);
+ QCBOREncode_AddInt64(pECtx, 77689989909);
+ QCBOREncode_AddUInt64(pECtx,0);
+ QCBOREncode_AddInt64(pECtx, -44);
+
+ /* ints that go in maps */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddUInt64ToMap(pECtx, "LBL", 77);
+ QCBOREncode_AddUInt64ToMapN(pECtx, -4, 88);
+ QCBOREncode_AddInt64ToMap(pECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238);
+ QCBOREncode_AddInt64ToMapN(pECtx, -100000000, -800000000);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Epoch Date */
+ QCBOREncode_AddDateEpoch(pECtx, 2383748234);
+
+ /* Epoch date with labels */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddDateEpochToMap(pECtx, "LongLiveDenisRitchie", 1400000000);
+ QCBOREncode_AddDateEpochToMap(pECtx, "time()", 1477263730);
+ QCBOREncode_AddDateEpochToMapN(pECtx, -1969, 1477263222);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Binary blobs */
+ QCBOREncode_AddBytes(pECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2}));
+
+ /* binary blobs in maps */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddSZString(pECtx, "binbin");
+ QCBOREncode_AddTag(pECtx, 100000);
+ QCBOREncode_AddBytes(pECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1}));
+ QCBOREncode_AddBytesToMap(pECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
+ QCBOREncode_AddBytesToMapN(pECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4}));
+ QCBOREncode_CloseMap(pECtx);
+
+ /* text blobs */
+ QCBOREncode_AddText(pECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar"));
+ QCBOREncode_AddSZString(pECtx, "oof\n");
+ const char *szURL =
+ "http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8";
+ QCBOREncode_AddURI(pECtx, UsefulBuf_FromSZ(szURL));
+ QCBOREncode_AddB64Text(pECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
+ QCBOREncode_AddRegex(pECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+"));
+ QCBOREncode_AddMIMEData(pECtx, UsefulBuf_FromSZ(szMIME));
+
+ /* text blobs in maps */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddTextToMap(pECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo"));
+ QCBOREncode_AddTextToMap(pECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar"));
+ QCBOREncode_AddSZString(pECtx, "()()()");
+ QCBOREncode_AddTag(pECtx, 1000);
+ QCBOREncode_AddSZString(pECtx, "rab rab oof");
+ QCBOREncode_AddTextToMapN(pECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo"));
+ QCBOREncode_AddSZStringToMap(pECtx, "^^", "oooooooof");
+ QCBOREncode_AddSZStringToMapN(pECtx, 99, "ffffoooooooof");
+ QCBOREncode_AddURIToMap(pECtx,
+ "RFC",
+ UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5"));
+ QCBOREncode_AddURIToMapN(pECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/"));
+ QCBOREncode_AddB64TextToMap(pECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu"));
+ QCBOREncode_AddB64TextToMapN(pECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4="));
+ QCBOREncode_AddRegexToMap(pECtx, "popo", UsefulBuf_FROM_SZ_LITERAL("100\\s*mk")); // x code string literal bug
+ QCBOREncode_AddRegexToMapN(pECtx, -51, UsefulBuf_FROM_SZ_LITERAL("perl\\B")); // x code string literal bug
+ QCBOREncode_AddMIMEDataToMap(pECtx, "Ned", UsefulBuf_FromSZ(szMIME));
+ QCBOREncode_AddMIMEDataToMapN(pECtx, 10, UsefulBuf_FromSZ(szMIME));
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Date strings */
+ QCBOREncode_AddDateString(pECtx, "2003-12-13T18:30:02Z");
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddDateStringToMap(pECtx, "Bed time", "2003-12-13T18:30:02.25+01:00");
+ QCBOREncode_AddDateStringToMapN(pECtx, 88, "2003-12-13T18:30:02.25+01:00");
+ QCBOREncode_CloseMap(pECtx);
+
+ /* true / false ... */
+ QCBOREncode_AddSimple(pECtx, CBOR_SIMPLEV_UNDEF);
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddSZString(pECtx, "dare");
+ QCBOREncode_AddTag(pECtx, 66);
+ QCBOREncode_AddBool(pECtx, true);
+ QCBOREncode_AddBoolToMap(pECtx, "uu", false);
+ QCBOREncode_AddSimpleToMapN(pECtx, 737634, CBOR_SIMPLEV_NULL);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* opening an array */
+ QCBOREncode_OpenArray(pECtx);
+ QCBOREncode_CloseArray(pECtx);
+
+ /* opening arrays in a map */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddSZString(pECtx, "label and tagged empty array");
+ QCBOREncode_AddTag(pECtx, 1093);
+ QCBOREncode_OpenArray(pECtx);
+ QCBOREncode_CloseArray(pECtx);
+ QCBOREncode_OpenArrayInMap(pECtx, "alabl");
+ QCBOREncode_CloseArray(pECtx);
+ QCBOREncode_OpenArrayInMapN(pECtx, 42);
+ QCBOREncode_CloseArray(pECtx);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* opening maps with labels and tagging */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_OpenMapInMap(pECtx, "in a map");
+ QCBOREncode_OpenMapInMapN(pECtx, 5556);
+ QCBOREncode_AddSZString(pECtx, "in a in a in a");
+ QCBOREncode_AddTag(pECtx, 9087);
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_CloseMap(pECtx);
+ QCBOREncode_CloseMap(pECtx);
+ QCBOREncode_CloseMap(pECtx);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Extended simple values (these are not standard...) */
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddSZString(pECtx, "s1");
+ QCBOREncode_AddTag(pECtx, 88);
+ QCBOREncode_AddSimple(pECtx, 255);
+ QCBOREncode_AddSimpleToMap(pECtx, "s2", 0);
+ QCBOREncode_AddSZString(pECtx, "s3");
+ QCBOREncode_AddTag(pECtx, 88);
+ QCBOREncode_AddSimple(pECtx, 33);
+ QCBOREncode_AddInt64(pECtx, 88378374); // label before tag
+ QCBOREncode_AddTag(pECtx, 88);
+ QCBOREncode_AddSimple(pECtx, 255);
+ QCBOREncode_AddInt64(pECtx, 89); // label before tag
+ QCBOREncode_AddTag(pECtx, 88);
+ QCBOREncode_AddSimple(pECtx, 19);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* UUIDs */
+ static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43,
+ 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46,
+ 0x49, 0x43, 0x41, 0x32};
+ const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
+ QCBOREncode_AddBinaryUUID(pECtx, XXUUID);
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddBinaryUUIDToMap(pECtx, "UUUU", XXUUID);
+ QCBOREncode_AddBinaryUUIDToMapN(pECtx, 99, XXUUID);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Bool */
+ QCBOREncode_AddBool(pECtx, true);
+ QCBOREncode_AddBool(pECtx, false);
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddBoolToMap(pECtx, "George is the man", true);
+ QCBOREncode_AddBoolToMapN(pECtx, 010101, true);
+ QCBOREncode_CloseMap(pECtx);
+
+ /* Big numbers */
+ static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
+ QCBOREncode_AddPositiveBignum(pECtx, BIGNUM);
+ QCBOREncode_AddNegativeBignum(pECtx, BIGNUM);
+ QCBOREncode_OpenMap(pECtx);
+ QCBOREncode_AddPositiveBignumToMap(pECtx, "BN+", BIGNUM);
+ QCBOREncode_AddPositiveBignumToMapN(pECtx, 64, BIGNUM);
+ QCBOREncode_AddNegativeBignumToMap(pECtx, "BN-", BIGNUM);
+ QCBOREncode_AddNegativeBignumToMapN(pECtx, -64, BIGNUM);
+ QCBOREncode_CloseMap(pECtx);
+
+ QCBOREncode_CloseArray(pECtx);
+}
+
+
int32_t AllAddMethodsTest()
{
- // Improvement: this test should be broken down into several so it is more
- // managable. Tags and labels could be more sensible
+ /* Improvement: this test should be broken down into several so it is more
+ * managable. Tags and labels could be more sensible */
QCBOREncodeContext ECtx;
int nReturn = 0;
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
- QCBOREncode_OpenArray(&ECtx);
-
- // Some ints that are tagged and have strings preceeding them
- // (not labels becase it is not a map)
- QCBOREncode_AddSZString(&ECtx, "UINT62");
- QCBOREncode_AddTag(&ECtx, 100);
- QCBOREncode_AddUInt64(&ECtx, 89989909);
- QCBOREncode_AddSZString(&ECtx, "INT64");
- QCBOREncode_AddTag(&ECtx, 76);
- QCBOREncode_AddInt64(&ECtx, 77689989909);
- QCBOREncode_AddUInt64(&ECtx,0);
- QCBOREncode_AddInt64(&ECtx, -44);
-
- // ints that go in maps
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddUInt64ToMap(&ECtx, "LBL", 77);
- QCBOREncode_AddUInt64ToMapN(&ECtx, -4, 88);
- QCBOREncode_AddInt64ToMap(&ECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238);
- QCBOREncode_AddInt64ToMapN(&ECtx, -100000000, -800000000);
- QCBOREncode_CloseMap(&ECtx);
-
- // Epoch Date
- QCBOREncode_AddDateEpoch(&ECtx, 2383748234);
-
- // Epoch date with labels
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddDateEpochToMap(&ECtx, "LongLiveDenisRitchie", 1400000000);
- QCBOREncode_AddDateEpochToMap(&ECtx, "time()", 1477263730);
- QCBOREncode_AddDateEpochToMapN(&ECtx, -1969, 1477263222);
- QCBOREncode_CloseMap(&ECtx);
-
- // Binary blobs
- QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2}));
-
- // binary blobs in maps
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddSZString(&ECtx, "binbin");
- QCBOREncode_AddTag(&ECtx, 100000);
- QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0x00}, 1}));
- QCBOREncode_AddBytesToMap(&ECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
- QCBOREncode_AddBytesToMapN(&ECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4}));
- QCBOREncode_CloseMap(&ECtx);
-
- // text blobs
- QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar"));
- QCBOREncode_AddSZString(&ECtx, "oof\n");
- const char *szURL =
- "http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8";
- QCBOREncode_AddURI(&ECtx, UsefulBuf_FromSZ(szURL));
- QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
- QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+"));
- QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME));
-
- // text blobs in maps
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddTextToMap(&ECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo"));
- QCBOREncode_AddTextToMap(&ECtx, "____", UsefulBuf_FROM_SZ_LITERAL("foo bar"));
- QCBOREncode_AddSZString(&ECtx, "()()()");
- QCBOREncode_AddTag(&ECtx, 1000);
- QCBOREncode_AddSZString(&ECtx, "rab rab oof");
- QCBOREncode_AddTextToMapN(&ECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo"));
- QCBOREncode_AddSZStringToMap(&ECtx, "^^", "oooooooof");
- QCBOREncode_AddSZStringToMapN(&ECtx, 99, "ffffoooooooof");
- QCBOREncode_AddURIToMap(&ECtx,
- "RFC",
- UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5"));
- QCBOREncode_AddURIToMapN(&ECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/"));
- QCBOREncode_AddB64TextToMap(&ECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu"));
- QCBOREncode_AddB64TextToMapN(&ECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4="));
- QCBOREncode_AddRegexToMap(&ECtx, "popo", UsefulBuf_FROM_SZ_LITERAL("100\\s*mk")); // x code string literal bug
- QCBOREncode_AddRegexToMapN(&ECtx, -51, UsefulBuf_FROM_SZ_LITERAL("perl\\B")); // x code string literal bug
- QCBOREncode_AddMIMEDataToMap(&ECtx, "Ned", UsefulBuf_FromSZ(szMIME));
- QCBOREncode_AddMIMEDataToMapN(&ECtx, 10, UsefulBuf_FromSZ(szMIME));
- QCBOREncode_CloseMap(&ECtx);
-
- // Date strings
- QCBOREncode_AddDateString(&ECtx, "2003-12-13T18:30:02Z");
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddDateStringToMap(&ECtx, "Bed time", "2003-12-13T18:30:02.25+01:00");
- QCBOREncode_AddDateStringToMapN(&ECtx, 88, "2003-12-13T18:30:02.25+01:00");
- QCBOREncode_CloseMap(&ECtx);
-
- // true / false ...
- QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddSZString(&ECtx, "dare");
- QCBOREncode_AddTag(&ECtx, 66);
- QCBOREncode_AddBool(&ECtx, true);
- QCBOREncode_AddBoolToMap(&ECtx, "uu", false);
- QCBOREncode_AddSimpleToMapN(&ECtx, 737634, CBOR_SIMPLEV_NULL);
- QCBOREncode_CloseMap(&ECtx);
-
- // opening an array
- QCBOREncode_OpenArray(&ECtx);
- QCBOREncode_CloseArray(&ECtx);
-
- // opening arrays in a map
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddSZString(&ECtx, "label and tagged empty array");
- QCBOREncode_AddTag(&ECtx, 1093);
- QCBOREncode_OpenArray(&ECtx);
- QCBOREncode_CloseArray(&ECtx);
- QCBOREncode_OpenArrayInMap(&ECtx, "alabl");
- QCBOREncode_CloseArray(&ECtx);
- QCBOREncode_OpenArrayInMapN(&ECtx, 42);
- QCBOREncode_CloseArray(&ECtx);
- QCBOREncode_CloseMap(&ECtx);
-
- // opening maps with labels and tagging
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_OpenMapInMap(&ECtx, "in a map");
- QCBOREncode_OpenMapInMapN(&ECtx, 5556);
- QCBOREncode_AddSZString(&ECtx, "in a in a in a");
- QCBOREncode_AddTag(&ECtx, 9087);
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_CloseMap(&ECtx);
- QCBOREncode_CloseMap(&ECtx);
- QCBOREncode_CloseMap(&ECtx);
- QCBOREncode_CloseMap(&ECtx);
-
-
- // Extended simple values (these are not standard...)
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddSZString(&ECtx, "s1");
- QCBOREncode_AddTag(&ECtx, 88);
- QCBOREncode_AddSimple(&ECtx, 255);
- QCBOREncode_AddSimpleToMap(&ECtx, "s2", 0);
- QCBOREncode_AddSZString(&ECtx, "s3");
- QCBOREncode_AddTag(&ECtx, 88);
- QCBOREncode_AddSimple(&ECtx, 33);
- QCBOREncode_AddInt64(&ECtx, 88378374); // label before tag
- QCBOREncode_AddTag(&ECtx, 88);
- QCBOREncode_AddSimple(&ECtx, 255);
- QCBOREncode_AddInt64(&ECtx, 89); // label before tag
- QCBOREncode_AddTag(&ECtx, 88);
- QCBOREncode_AddSimple(&ECtx, 19);
- QCBOREncode_CloseMap(&ECtx);
-
- // UUIDs
- static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43,
- 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46,
- 0x49, 0x43, 0x41, 0x32};
- const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
- QCBOREncode_AddBinaryUUID(&ECtx, XXUUID);
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddBinaryUUIDToMap(&ECtx, "UUUU", XXUUID);
- QCBOREncode_AddBinaryUUIDToMapN(&ECtx, 99, XXUUID);
- QCBOREncode_CloseMap(&ECtx);
-
- // Bool
- QCBOREncode_AddBool(&ECtx, true);
- QCBOREncode_AddBool(&ECtx, false);
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddBoolToMap(&ECtx, "George is the man", true);
- QCBOREncode_AddBoolToMapN(&ECtx, 010101, true);
- QCBOREncode_CloseMap(&ECtx);
-
-
- static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
- QCBOREncode_AddPositiveBignum(&ECtx, BIGNUM);
- QCBOREncode_AddNegativeBignum(&ECtx, BIGNUM);
- QCBOREncode_OpenMap(&ECtx);
- QCBOREncode_AddPositiveBignumToMap(&ECtx, "BN+", BIGNUM);
- QCBOREncode_AddPositiveBignumToMapN(&ECtx, 64, BIGNUM);
- QCBOREncode_AddNegativeBignumToMap(&ECtx, "BN-", BIGNUM);
- QCBOREncode_AddNegativeBignumToMapN(&ECtx, -64, BIGNUM);
- QCBOREncode_CloseMap(&ECtx);
-
- QCBOREncode_CloseArray(&ECtx);
+ AddAll (&ECtx);
UsefulBufC Enc;
-
if(QCBOREncode_Finish(&ECtx, &Enc)) {
nReturn = -1;
goto Done;
}
- if(CheckResults(Enc, spExpectedEncodedAll))
+ if(CheckResults(Enc, spExpectedEncodedAll)) {
nReturn = -2;
+ }
+
+
+ /* Also test size calculation */
+ QCBOREncode_Init(&ECtx, SizeCalculateUsefulBuf);
+
+ AddAll (&ECtx);
+
+ size_t size;
+ if(QCBOREncode_FinishGetSize(&ECtx, &size)) {
+ nReturn = -10;
+ goto Done;
+ }
+
+ if(size != sizeof(spExpectedEncodedAll)) {
+ nReturn = -11;
+ }
Done:
return nReturn;
}
+
/*
98 30 # array(48)
3B 7FFFFFFFFFFFFFFF # negative(9223372036854775807)