--- a/src/XMLDocumentConstructor.h Tue Jun 01 19:25:12 2021 +0200
+++ b/src/XMLDocumentConstructor.h Sat Jun 05 20:03:13 2021 +0200
@@ -40,14 +40,23 @@
enum class Mode {
ROOT,
- SEQUENCE,
- MAPPING,
- MAP_KEY
+ ARRAY,
+ MAP_KEY,
+ MAP_VALUE,
+ CHAR_STRING,
+ BYTE_STRING
};
- std::string rootName = "cbor";
+
+ Glib::ustring rootName = "cbor";
+ Glib::ustring itemName;
xmlpp::Element* current;
std::vector<Mode> mode;
+ /**
+ * number of remainin items in the fixed-size container (map or array) at current tree-level
+ */
+ std::vector<ssize_t> remainingItems;
+#define INDEFINITE -1
cbor_callbacks callbacks = cbor_empty_callbacks;
@@ -66,11 +75,71 @@
return current->get_parent() == nullptr ? current : current->get_parent();
}
+ void checkRemainingItems() {
+ if (mode.back() == Mode::ARRAY || mode.back() == Mode::MAP_KEY) {
+ if (remainingItems.back() != INDEFINITE) {
+ remainingItems.back()--;
+ if (remainingItems.back() < 1) containerEnd();
+ }
+ }
+ }
+
void appendScalarValue(Glib::ustring value, Glib::ustring cborType, bool isNull = false) {
- // TODO: different behavior depending on mode
- xmlpp::Element* element = current->add_child("scalar");
- element->add_child_text(value);
- element->set_attribute("type", cborType);
+ // TODO: null
+ if (mode.back() == Mode::ARRAY) {
+ current->add_child(itemName)->add_child_text(value);
+ } else if (mode.back() == Mode::MAP_KEY) {
+ current = current->add_child(value);
+ mode.push_back(Mode::MAP_VALUE);
+ } else if (mode.back() == Mode::MAP_VALUE) {
+ current->add_child_text(value);
+ current = parentOrSelf(current);
+ mode.pop_back();
+ } else if (mode.back() == Mode::ROOT) {
+ current->add_child_text(value);
+ } else {
+ // TODO: process YAML_SCALAR_EVENT
+ }
+
+ checkRemainingItems();
+ }
+
+ void arrayStart(ssize_t size) {
+ xmlpp::Element* parent = current->get_parent();
+ if (parent) {
+ itemName = current->get_name();
+ parent->remove_child(current);
+ current = parent;
+ } else {
+ itemName = "item";
+ }
+
+ if (mode.back() == Mode::MAP_KEY) mode.pop_back();
+ mode.push_back(Mode::ARRAY);
+ remainingItems.push_back(size);
+ }
+
+ void mapStart(ssize_t size) {
+ if (mode.back() == Mode::ROOT) {
+ } else if (mode.back() == Mode::ARRAY) {
+ current = current->add_child(itemName);
+ } else if (mode.back() == Mode::MAP_VALUE) {
+ mode.pop_back();
+ // TODO: remainingItems
+ } else {
+ // TODO: map might be a key of another map → wrap/nest
+ // …probably not
+ }
+
+ mode.push_back(Mode::MAP_KEY);
+ remainingItems.push_back(size);
+ }
+
+ void containerEnd() {
+ current->add_child_comment(Glib::ustring::compose("end of a container: mode = %1", (int) mode.back())); // FIXME: remove
+ remainingItems.pop_back();
+ if (mode.back() == Mode::MAP_KEY || mode.back() == Mode::MAP_VALUE) current = parentOrSelf(current);
+ mode.pop_back(); // TODO: assert map/array
}
public:
@@ -82,9 +151,7 @@
callbacks.array_start = [](void* context, size_t size) {
CBOR_CALLBACK_START
- // TODO: implement
- xmlpp::Element* element = instance->current->add_child("array-start");
- element->set_attribute("size", std::to_string(size));
+ instance->arrayStart(size);
CBOR_CALLBACK_END
};
@@ -105,6 +172,8 @@
callbacks.byte_string_start = [](void* context) {
CBOR_CALLBACK_START
+ instance->mode.push_back(Mode::BYTE_STRING);
+ instance->remainingItems.push_back(INDEFINITE);
// TODO: implement
xmlpp::Element* element = instance->current->add_child("byte-string-start");
CBOR_CALLBACK_END
@@ -130,30 +199,25 @@
callbacks.indef_array_start = [](void* context) {
CBOR_CALLBACK_START
- // TODO: implement
- xmlpp::Element* element = instance->current->add_child("array-start");
+ instance->arrayStart(INDEFINITE);
CBOR_CALLBACK_END
};
callbacks.indef_map_start = [](void* context) {
CBOR_CALLBACK_START
- // TODO: implement
- xmlpp::Element* element = instance->current->add_child("map-start");
+ instance->mapStart(INDEFINITE);
CBOR_CALLBACK_END
};
callbacks.indef_break = [](void* context) {
CBOR_CALLBACK_START
- // TODO: implement
- xmlpp::Element* element = instance->current->add_child("indef-break");
+ instance->containerEnd();
CBOR_CALLBACK_END
};
callbacks.map_start = [](void* context, size_t size) {
CBOR_CALLBACK_START
- // TODO: implement
- xmlpp::Element* element = instance->current->add_child("map-start");
- element->set_attribute("size", std::to_string(size));
+ instance->mapStart(size);
CBOR_CALLBACK_END
};
@@ -195,6 +259,8 @@
callbacks.string_start = [](void* context) {
CBOR_CALLBACK_START
+ instance->mode.push_back(Mode::CHAR_STRING);
+ instance->remainingItems.push_back(INDEFINITE);
// TODO: implement
xmlpp::Element* element = instance->current->add_child("string-start");
CBOR_CALLBACK_END
@@ -250,7 +316,9 @@
void process() {
current = parser->get_document()->create_root_node(rootName);
+ mode.push_back(Mode::ROOT);
+ // TODO: better streaming/buffering? (however, we still have to hold whole document in memory and „infinite“ stream processing is impossible)
std::stringstream bufferStream;
for (char ch = input->get(); input->good(); ch = input->get()) bufferStream.put(ch);
std::string buffer = bufferStream.str();
@@ -262,6 +330,8 @@
if (result.status != cbor_decoder_status::CBOR_DECODER_FINISHED) throw relpipe::writer::RelpipeWriterException(L"CBOR parsing failed: status = " + std::to_wstring(result.status));
}
+ checkRemainingItems();
+
parser->get_document()->get_root_node()->set_attribute("bytes-read", std::to_string(bytesRead));
}
};