30 |
30 |
31 class XMLDocumentConstructor { |
31 class XMLDocumentConstructor { |
32 private: |
32 private: |
33 std::istream* input = nullptr; |
33 std::istream* input = nullptr; |
34 xmlpp::DomParser* parser = nullptr; |
34 xmlpp::DomParser* parser = nullptr; |
35 yaml_parser_t yamlParser; |
|
36 XMLNameCodec nameCodec; |
35 XMLNameCodec nameCodec; |
37 |
36 |
38 enum class Mode { |
37 std::string rootName = "cbor"; |
39 ROOT, |
|
40 SEQUENCE, |
|
41 MAPPING, |
|
42 MAP_KEY |
|
43 }; |
|
44 |
|
45 std::string rootName = "yaml"; |
|
46 xmlpp::Element* current; |
38 xmlpp::Element* current; |
47 std::vector<Mode> mode; |
|
48 |
|
49 static int readFromInput(void* instance, unsigned char* buffer, size_t size, size_t* length) { |
|
50 std::istream* input = ((XMLDocumentConstructor*) instance)->input; |
|
51 input->read((char*) buffer, size); |
|
52 *length = input->gcount(); |
|
53 return (input->good() || input->eof()) ? 1 : 0; |
|
54 } |
|
55 |
39 |
56 /** |
40 /** |
57 * Both YAML and XML strings are in UTF-8. |
41 * Both CBOR and XML strings are in UTF-8. |
58 */ |
42 */ |
59 const char* y2x(yaml_char_t* value) { |
43 const char* c2x(char* value) { // FIXME: cbor type |
60 return value ? (const char*) value : ""; |
44 return value ? (const char*) value : ""; |
61 } |
45 } |
62 |
46 |
63 const Glib::ustring y2xname(yaml_char_t* value) { |
47 const Glib::ustring c2xname(char* value) { // FIXME: cbor type |
64 return nameCodec.encode(y2x(value)); |
48 return nameCodec.encode(c2x(value)); |
65 } |
49 } |
66 |
50 |
67 xmlpp::Element* parentOrSelf(xmlpp::Element* current) { |
51 xmlpp::Element* parentOrSelf(xmlpp::Element* current) { |
68 return current->get_parent() == nullptr ? current : current->get_parent(); |
52 return current->get_parent() == nullptr ? current : current->get_parent(); |
69 } |
53 } |
70 |
54 |
71 public: |
55 public: |
72 |
56 |
73 XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) { |
57 XMLDocumentConstructor(std::istream* input, xmlpp::DomParser* parser) : input(input), parser(parser) { |
74 yaml_parser_initialize(&yamlParser); |
58 // cbor_item_t * root = cbor_new_definite_map(2); |
75 yaml_parser_set_input(&yamlParser, readFromInput, (void*) this); |
59 // FIXME: initialize CBOR parser |
76 } |
60 } |
77 |
61 |
78 virtual ~XMLDocumentConstructor() { |
62 virtual ~XMLDocumentConstructor() { |
79 yaml_parser_delete(&yamlParser); |
63 // FIXME: destroy CBOR parser |
80 } |
64 } |
81 |
65 |
82 void setOption(const std::string& uri, const std::string& value) { |
66 void setOption(const std::string& uri, const std::string& value) { |
83 if (uri == "root-name") rootName = value; |
67 if (uri == "root-name") rootName = value; |
84 else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“"); |
68 else throw std::invalid_argument(std::string("Invalid parser option: „") + uri + "“ with value: „" + value + "“"); |
85 } |
69 } |
86 |
70 |
87 void process() { |
71 void process() { |
88 current = parser->get_document()->create_root_node(rootName); |
72 current = parser->get_document()->create_root_node(rootName); |
89 mode.push_back(Mode::ROOT); |
|
90 std::string itemName; |
|
91 |
|
92 while (true) { |
|
93 yaml_event_t event; |
|
94 |
|
95 if (!yaml_parser_parse(&yamlParser, &event)) { |
|
96 // FIXME: throw exception |
|
97 return; |
|
98 } |
|
99 |
|
100 |
|
101 if (event.type == YAML_STREAM_END_EVENT) { |
|
102 yaml_event_delete(&event); |
|
103 break; |
|
104 } else if (event.type == YAML_STREAM_START_EVENT) { |
|
105 } else if (event.type == YAML_NO_EVENT) { |
|
106 current->add_child("null"); // TODO: null? |
|
107 } else if (event.type == YAML_DOCUMENT_START_EVENT) { |
|
108 } else if (event.type == YAML_DOCUMENT_END_EVENT) { |
|
109 } else if (event.type == YAML_ALIAS_EVENT) { |
|
110 // TODO: alias? |
|
111 } else if (event.type == YAML_SCALAR_EVENT) { |
|
112 if (mode.back() == Mode::SEQUENCE) { |
|
113 current->add_child(itemName)->add_child_text(y2x(event.data.scalar.value)); |
|
114 } else if (mode.back() == Mode::MAPPING) { |
|
115 current = current->add_child(y2xname(event.data.scalar.value)); |
|
116 mode.push_back(Mode::MAP_KEY); |
|
117 } else if (mode.back() == Mode::MAP_KEY) { |
|
118 current->add_child_text(y2x(event.data.scalar.value)); |
|
119 current = parentOrSelf(current); |
|
120 mode.pop_back(); |
|
121 } else if (mode.back() == Mode::ROOT) { |
|
122 current->add_child_text(y2x(event.data.scalar.value)); |
|
123 } else { |
|
124 // TODO: process YAML_SCALAR_EVENT |
|
125 } |
|
126 |
|
127 } else if (event.type == YAML_SEQUENCE_START_EVENT) { |
|
128 xmlpp::Element* parent = current->get_parent(); |
|
129 if (parent) { |
|
130 itemName = current->get_name(); |
|
131 parent->remove_child(current); |
|
132 current = parent; |
|
133 } else { |
|
134 itemName = "item"; |
|
135 } |
|
136 if (mode.back() == Mode::MAP_KEY) mode.pop_back(); |
|
137 mode.push_back(Mode::SEQUENCE); |
|
138 } else if (event.type == YAML_SEQUENCE_END_EVENT) { |
|
139 mode.pop_back(); // TODO: assert sequence? |
|
140 } else if (event.type == YAML_MAPPING_START_EVENT) { |
|
141 |
|
142 if (mode.back() == Mode::ROOT) { |
|
143 } else if (mode.back() == Mode::SEQUENCE) { |
|
144 current = current->add_child(itemName); |
|
145 } else if (mode.back() == Mode::MAP_KEY) { |
|
146 mode.pop_back(); |
|
147 } else { |
|
148 // TODO: map might be a key of another map → wrap/nest |
|
149 } |
|
150 |
|
151 mode.push_back(Mode::MAPPING); |
|
152 } else if (event.type == YAML_MAPPING_END_EVENT) { |
|
153 current = parentOrSelf(current); |
|
154 mode.pop_back(); // TODO: assert map? |
|
155 } else { |
|
156 // TODO: unsupported type? |
|
157 } |
|
158 |
|
159 yaml_event_delete(&event); |
|
160 } |
|
161 |
|
162 |
|
163 } |
73 } |
164 }; |
74 }; |
165 |
75 |
166 } |
76 } |
167 } |
77 } |