homogenous arrays starting to work
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index b3301c7..223cc7f 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -5919,3 +5919,209 @@
}
#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+
+
+
+/* The one that matches the endianness should return without copying
+ The other either has to copy or has to swap by violating const-ness.
+ If copying, the caller has to know. If violating const-ness, then
+the caller only knows that const-ness is violated. */
+
+void QCBORDecode_GetUint32ArrayBE(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ uint32_t *pInts,
+ size_t *pSize)
+{
+ QCBORItem item;
+ QCBORDecode_VGetNext(pMe, &item);
+
+ if(item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+ !QCBORDecode_IsTagged(pMe, &item, 99)) { // TODO: correct tag number
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ return;
+ }
+
+ if(item.val.string.len % 4 != 0) {
+ pMe->uLastError = 99; // TODO: figure out error
+ return;
+ }
+
+ *pSize = item.val.string.len / 4;
+
+ /* may have to swap if endianness doesn't match */
+ pInts = (uint32_t *) &(item.val.string.ptr);
+}
+
+
+void QCBORDecode_GetUint32ArrayLE(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ uint32_t *pInts,
+ size_t *pSize)
+{
+ QCBORItem item;
+ QCBORDecode_GetNext(pMe, &item);
+
+ // TODO: check type
+ // TODO: check size is a multiple of 4
+
+ *pSize = item.val.string.len / 4;
+
+ // TODO: must swap all the ints
+
+ pInts = (uint32_t *) &(item.val.string.ptr);
+
+
+}
+
+
+
+
+
+static QCBORError
+CheckTagList(uint64_t uTag, const uint64_t *puTagList)
+{
+ for(size_t i = 0; puTagList[i] != CBOR_TAG_INVALID64; i++) {
+ if(uTag == puTagList[i]) {
+ return QCBOR_SUCCESS;
+ }
+ }
+ return QCBOR_ERR_UNEXPECTED_TYPE;
+}
+
+
+QCBORError CheckTagRequirement2(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ const uint64_t *puTagNumbers,
+ const uint8_t *puContentTypes,
+ const QCBORItem *pItem)
+{
+ /* In this checker, the tags of interest are never mapped
+ to QCBOR_TYPEs. */
+
+ /* Check the content type first. If that is wrong, then this fails
+ no matter what. */
+ QCBORError uReturn = CheckTypeList(pItem->uDataType, puContentTypes);
+ if(uReturn != QCBOR_SUCCESS) {
+ return uReturn;
+ }
+
+ uReturn = CheckTagList(QCBORDecode_GetNthTag(pMe, pItem, 0), puTagNumbers);
+
+ const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
+ switch(nTagReq) {
+ case QCBOR_TAG_REQUIREMENT_TAG:
+ if(uReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ break;
+
+ case QCBOR_TAG_REQUIREMENT_NOT_A_TAG:
+ if(uReturn == QCBOR_SUCCESS) {
+ uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+ break;
+
+ case QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG:
+ break;
+ }
+
+ if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
+ /* Additional tags are prohibited. */
+ int nAdditionalIndex = 0;
+ if(uReturn == QCBOR_SUCCESS) {
+ nAdditionalIndex++;
+ }
+ if(pItem->uTags[0] != CBOR_TAG_INVALID16) {
+ uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
+ }
+ }
+ uReturn = QCBOR_SUCCESS;
+
+Done:
+ return uReturn;
+}
+
+
+
+
+void QCBORDecode_GetHomogenousArray(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ uint8_t uType,
+ size_t nInArrayCount,
+ union QCBORHomogenousArray array,
+ size_t *pnOutArrayCount)
+{
+ QCBORItem item;
+ QCBORDecode_GetNext(pMe, &item);
+
+ const uint64_t puAllowedTags[] = {CBOR_TAG_HOMOGENEOUS_ARRAY, CBOR_TAG_INVALID64};
+
+ const uint8_t puAllowedContents[] = {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE};
+
+
+ QCBORError uError = CheckTagRequirement2(pMe,
+ uTagRequirement,
+ puAllowedTags,
+ puAllowedContents,
+ &item);
+ if(uError) {
+ pMe->uLastError = (uint8_t)uError;
+ goto Done;
+ }
+
+ const uint8_t uIntNestLevel = item.uNextNestLevel;
+
+ size_t uIntCount = 0;
+ do {
+ QCBORDecode_GetNext(pMe, &item);
+ if(item.uDataType != uType) {
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+
+ /* A good compiler should not generate much code here since
+ since it is just a copy of either 8 or 16 bytes for the
+ cases. */
+ switch (uType) {
+ case QCBOR_TYPE_INT64:
+ if(array.pnInt64s) {
+ array.pnInt64s[uIntCount] = item.val.int64;
+ }
+ break;
+
+ case QCBOR_TYPE_UINT64:
+ if(array.puUInt64s) {
+ array.puUInt64s[uIntCount] = item.val.int64;
+ }
+ break;
+
+ case QCBOR_TYPE_DOUBLE:
+ if(array.pDoubles) {
+ array.pDoubles[uIntCount] = item.val.dfnum;
+ }
+ break;
+
+ case QCBOR_TYPE_TEXT_STRING:
+ case QCBOR_TYPE_BYTE_STRING:
+ if(array.pStrings) {
+ array.pStrings[uIntCount] = item.val.string;
+ }
+ break;
+ }
+ uIntCount++;
+
+ if(uIntCount >= nInArrayCount) {
+ pMe->uLastError = QCBOR_ERR_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ } while(item.uNextNestLevel >= uIntNestLevel);
+
+
+ *pnOutArrayCount = uIntCount;
+
+Done:
+ return;
+}
+
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 59c420b..55d51f6 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -950,3 +950,195 @@
return nReturn;
}
+
+
+
+static inline void UsefulOutBuf_InsertUint32LE(UsefulOutBuf *pMe,
+ uint32_t uInteger32,
+ size_t uPos)
+{
+ /* See UsefulOutBuf_InsertUint64() for comments on this code */
+
+ /* htonl is not used (but it is used for outputting BE)
+
+ htonl will swap if CPU is little endian and do nothing if it is big endian
+
+ The opposite is needed.
+
+ Could use htonl and then always swap the result, but
+ that doesn't seem any better than the default
+ shift and swap that always works.
+
+
+ */
+
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
+ pBytes = &uInteger32;
+
+#elif defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ uint32_t uTmp = __builtin_bswap32(uInteger32);
+
+ pBytes = &uTmp;
+
+#else
+ uint8_t aTmp[4];
+
+ aTmp[0] = (uint8_t)((uInteger32 & 0xff) >> 24);
+ aTmp[1] = (uint8_t)((uInteger32 & 0xff00) >> 16);
+ aTmp[2] = (uint8_t)((uInteger32 & 0xff0000) >> 8);
+ aTmp[3] = (uint8_t)(uInteger32 & 0xff000000);
+
+ pBytes = aTmp;
+#endif
+
+ UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
+}
+
+void
+QCBOREncode_AddUint32ArrayLittleEndian(QCBOREncodeContext *pMe,
+ const uint32_t array[],
+ size_t uArrayLen)
+{
+ QCBOREncode_AddTag(pMe, 84); // TODO: the correct tag
+
+ const size_t uNumBytes = uArrayLen * sizeof(uint32_t);
+
+ AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uNumBytes, 0);
+
+ for(size_t n = 0; n < uArrayLen; n++) {
+ UsefulOutBuf_InsertUint32LE(&(pMe->OutBuf), array[n], 99); // TODO: correct position
+ }
+}
+
+void
+QCBOREncode_AddUint32ArrayBigEndian(QCBOREncodeContext *pMe,
+ const uint32_t array[],
+ size_t uArrayLen)
+{
+ QCBOREncode_AddTag(pMe, 84); // TODO: the correct tag
+
+ const size_t uNumBytes = uArrayLen * sizeof(uint32_t);
+
+ AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uNumBytes, 0);
+
+ for(size_t n = 0; n < uArrayLen; n++) {
+ UsefulOutBuf_AppendUint32(&(pMe->OutBuf), array[n]);
+ }
+}
+
+
+// Note that this will produce an array of major type 0 and 1,
+// but that is what is necessary to have an array of positive
+// and negative integers. The types allowed for a homogeneous
+// array are caller-defined, not strictly by CBOR major type
+// or such, so this is just fine.
+void
+QCBOREncode_AddArrayOfInts(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const int64_t *puInts,
+ size_t uNumInts)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumInts; i++) {
+ QCBOREncode_AddInt64(pMe, puInts[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+
+void
+QCBOREncode_AddArrayOfUInts(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const uint64_t *puInts,
+ size_t uNumInts)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumInts; i++) {
+ QCBOREncode_AddUInt64(pMe, puInts[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+
+void
+QCBOREncode_AddArrayOfDoubles(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const double *pdDoubles,
+ size_t uNumDoubles)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumDoubles; i++) {
+ QCBOREncode_AddDouble(pMe, pdDoubles[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+
+void
+QCBOREncode_AddArrayOfByteStrings(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const UsefulBufC *pStrings,
+ size_t uNumStrings)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumStrings; i++) {
+ QCBOREncode_AddBytes(pMe, pStrings[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+void
+QCBOREncode_AddArrayOfTextStrings(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const UsefulBufC *pStrings,
+ size_t uNumStrings)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumStrings; i++) {
+ QCBOREncode_AddText(pMe, pStrings[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+
+void
+QCBOREncode_AddArrayOSZStrings(QCBOREncodeContext *pMe,
+ uint8_t uTagRequirement,
+ const char **pStrings,
+ size_t uNumStrings)
+{
+ if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
+ QCBOREncode_AddTag(pMe, CBOR_TAG_HOMOGENEOUS_ARRAY);
+ }
+ QCBOREncode_OpenArray(pMe);
+
+ for(size_t i = 0; i < uNumStrings; i++) {
+ QCBOREncode_AddSZString(pMe, pStrings[i]);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+
+
+