Add support for indeterminate length Arrays and Maps.
Change-Id: I15c64278b3eb9c697cd927bb4191dd7ca7c5ac21
diff --git a/README.md b/README.md
index b23cc0f..6463766 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,8 @@
CBOR, nor (yet) support validation against CDDL schemata, though both
are planned. CBOR features that aren't supported include:
-* Indefinite length values
+* Parsing Indefinite length values for major types 2 (byte string) and 3 (text string)
+* Writing Indefinite length values
* Semantic tagging
* Floating point
diff --git a/include/cppbor/cppbor.h b/include/cppbor/cppbor.h
index 2362e3c..0589e0c 100644
--- a/include/cppbor/cppbor.h
+++ b/include/cppbor/cppbor.h
@@ -68,6 +68,7 @@
TWO_BYTE_LENGTH = 25,
FOUR_BYTE_LENGTH = 26,
EIGHT_BYTE_LENGTH = 27,
+ INDEFINITE_LENGTH = 31,
};
class Item;
diff --git a/src/cppbor_parse.cpp b/src/cppbor_parse.cpp
index c3fa070..fdfd7bf 100644
--- a/src/cppbor_parse.cpp
+++ b/src/cppbor_parse.cpp
@@ -127,8 +127,10 @@
public:
explicit IncompleteArray(size_t size) : mSize(size) {}
- // We return the "complete" size, rather than the actual size.
- size_t size() const override { return mSize; }
+ // If the "complete" size is known, return it, otherwise return the current size.
+ size_t size() const override {
+ return mSize == SIZE_MAX ? Array::size() : mSize;
+ }
void add(std::unique_ptr<Item> item) override {
mEntries.push_back(std::move(item));
@@ -148,8 +150,10 @@
public:
explicit IncompleteMap(size_t size) : mSize(size) {}
- // We return the "complete" size, rather than the actual size.
- size_t size() const override { return mSize; }
+ // If the "complete" size is known, return it, otherwise return the current size.
+ size_t size() const override {
+ return mSize == SIZE_MAX ? Map::size() : mSize;
+ }
void add(std::unique_ptr<Item> item) override {
if (mKeyHeldForAdding) {
@@ -216,6 +220,11 @@
parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
return {hdrBegin, nullptr /* end parsing */};
}
+ if (*pos == 0xFF) {
+ // Next character is the "break" Stop Code
+ ++pos;
+ break;
+ }
std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient, depth + 1);
if (!parseClient) return {hdrBegin, nullptr};
}
@@ -265,7 +274,9 @@
bool success = true;
uint64_t addlData;
- if (tagInt < ONE_BYTE_LENGTH) {
+ if ((type == ARRAY || type == MAP) && tagInt == INDEFINITE_LENGTH) {
+ addlData = SIZE_MAX;
+ } else if (tagInt < ONE_BYTE_LENGTH) {
addlData = tagInt;
} else if (tagInt > EIGHT_BYTE_LENGTH) {
parseClient->error(
diff --git a/tests/cppbor_test.cpp b/tests/cppbor_test.cpp
index fadcaa9..62fd5db 100644
--- a/tests/cppbor_test.cpp
+++ b/tests/cppbor_test.cpp
@@ -1862,14 +1862,55 @@
message);
}
-TEST(FullParserTest, IndefiniteArray) {
- vector<uint8_t> indefiniteArray = {0x7F};
+TEST(FullParserTest, IndefiniteArrayEmpty) {
+ Bstr encoding("\x9F\xFF");
+ string expected = Array().toString();
- auto [item, pos, message] = parse(indefiniteArray);
- EXPECT_THAT(item, IsNull());
- EXPECT_EQ(pos, indefiniteArray.data());
- EXPECT_EQ("Reserved additional information value or unsupported indefinite length item.",
- message);
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
+}
+
+TEST(FullParserTest, IndefiniteArrayWithOneNumber) {
+ Bstr encoding("\x9F\x01\xFF");
+ string expected = Array(Uint(1)).toString();
+
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
+}
+
+TEST(FullParserTest, IndefiniteArrayOfArray) {
+ Bstr encoding("\x9F\x9F\x01\xFF\xFF");
+
+ Array nested;
+ nested.add(Array(Uint(1)));
+ string expected = nested.toString();
+
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
+}
+
+TEST(FullParserTest, IndefiniteMapEmpty) {
+ Bstr encoding("\xBF\xFF");
+ string expected = Map().toString();
+
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
+}
+
+TEST(FullParserTest, IndefiniteMapsNested) {
+ Bstr encoding("\xBF\x01\xBF\xFF\xFF");
+ string expected = Map(Uint(1), Map()).toString();
+
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
+}
+
+TEST(FullParserTest, IndefiniteMapWithOneEntry) {
+ Bstr encoding("\xBF\x01\x05\xFF");
+ string expected = Map(Uint(1), Uint(5)).toString();
+
+ auto [item, pos, message] = parse(&encoding);
+ EXPECT_EQ(expected, item->toString());
}
TEST(FullParserTest, UnassignedSimpleValue) {