24 |
24 |
25 namespace relpipe { |
25 namespace relpipe { |
26 namespace in { |
26 namespace in { |
27 namespace asn1 { |
27 namespace asn1 { |
28 |
28 |
|
29 /** |
|
30 * Converts arbitrary ASN.1 stream of events to a relation |
|
31 * i.e. does not require any specific structures/schema. |
|
32 * |
|
33 * Useful especially for testing and debugging and sometimes instead of relpipe-in-asn1table, |
|
34 * because this handler supports streaming and does not depend on any third-party library (no XML dependency). |
|
35 */ |
29 class FreeformASN1ContentHandler : public lib::ASN1ContentHandler { |
36 class FreeformASN1ContentHandler : public lib::ASN1ContentHandler { |
30 private: |
37 private: |
|
38 wstring_convert < codecvt_utf8<wchar_t>> convertor; // ASN.1 parser works with UTF-8 |
31 std::shared_ptr<relpipe::writer::RelationalWriter> writer; |
39 std::shared_ptr<relpipe::writer::RelationalWriter> writer; |
32 Configuration configuration; |
40 Configuration configuration; |
33 std::vector<relpipe::common::type::Integer> position; |
41 std::vector<relpipe::common::type::Integer> position; |
34 |
42 |
35 class Record { |
43 class Record { |
36 public: |
44 public: |
37 const Header* header; |
45 const Header* header; |
38 const std::vector<relpipe::common::type::Integer>& position; |
46 const std::vector<relpipe::common::type::Integer>& position; |
39 relpipe::common::type::Integer level = 0; |
47 relpipe::common::type::Integer level = 0; |
40 relpipe::common::type::StringX event; |
48 relpipe::common::type::StringX event; |
|
49 relpipe::common::type::StringX valueText; |
|
50 relpipe::common::type::StringX valueBinary; |
41 |
51 |
42 Record(const Header* header, std::vector<relpipe::common::type::Integer>& position, relpipe::common::type::StringX event) : header(header), position(position), event(event) { |
52 Record(const Header* header, std::vector<relpipe::common::type::Integer>& position, relpipe::common::type::StringX event) : header(header), position(position), event(event) { |
43 } |
53 } |
44 |
54 |
45 virtual ~Record() { |
55 virtual ~Record() { |
72 writer->writeAttribute(&level, typeid (level)); |
82 writer->writeAttribute(&level, typeid (level)); |
73 writer->writeAttribute(&r.event, typeid (r.event)); |
83 writer->writeAttribute(&r.event, typeid (r.event)); |
74 // writer->writeAttribute(&pc, typeid (pc)); |
84 // writer->writeAttribute(&pc, typeid (pc)); |
75 writer->writeAttribute(&tagClass, typeid (tagClass)); |
85 writer->writeAttribute(&tagClass, typeid (tagClass)); |
76 writer->writeAttribute(&tag, typeid (tag)); |
86 writer->writeAttribute(&tag, typeid (tag)); |
|
87 writer->writeAttribute(&r.valueText, typeid (r.valueText)); |
|
88 writer->writeAttribute(&r.valueBinary, typeid (r.valueBinary)); |
|
89 } |
|
90 |
|
91 /** |
|
92 * @param header |
|
93 * @param value an octet string |
|
94 * @return original value if octet string was a text string; otherwise an empty string |
|
95 */ |
|
96 const std::string getText(const Header& header, const std::string& value) { |
|
97 // TODO: support also UTF-8 |
|
98 for (uint8_t b : value) if (b < 32 || b >= 127) return ""; |
|
99 return value; |
77 } |
100 } |
78 |
101 |
79 public: |
102 public: |
80 |
103 |
81 FreeformASN1ContentHandler(std::shared_ptr<relpipe::writer::RelationalWriter> writer, Configuration configuration) : writer(writer), configuration(configuration) { |
104 FreeformASN1ContentHandler(std::shared_ptr<relpipe::writer::RelationalWriter> writer, Configuration configuration) : writer(writer), configuration(configuration) { |
92 {L"level", relpipe::writer::TypeId::INTEGER}, |
115 {L"level", relpipe::writer::TypeId::INTEGER}, |
93 {L"event", relpipe::writer::TypeId::STRING}, |
116 {L"event", relpipe::writer::TypeId::STRING}, |
94 // {L"pc", relpipe::writer::TypeId::STRING}, |
117 // {L"pc", relpipe::writer::TypeId::STRING}, |
95 {L"tag_class", relpipe::writer::TypeId::STRING}, |
118 {L"tag_class", relpipe::writer::TypeId::STRING}, |
96 {L"tag", relpipe::writer::TypeId::INTEGER}, |
119 {L"tag", relpipe::writer::TypeId::INTEGER}, |
|
120 {L"value_text", relpipe::writer::TypeId::STRING}, |
|
121 {L"value_binary", relpipe::writer::TypeId::STRING}, // TODO: OctetString data type (when available) instead of text |
97 }, true); |
122 }, true); |
98 |
123 |
99 position.push_back(-1); // TODO: null |
124 position.push_back(-1); // TODO: null |
100 position.push_back(1); |
125 position.push_back(1); |
101 Record r(nullptr, position, L"stream-start"); |
126 Record r(nullptr, position, L"stream-start"); |
120 |
146 |
121 void writeCollectionEnd() override { |
147 void writeCollectionEnd() override { |
122 auto id = position.back() + 1; |
148 auto id = position.back() + 1; |
123 position.pop_back(); |
149 position.pop_back(); |
124 position.back() = id; |
150 position.back() = id; |
|
151 // TODO: put end event under the start parent? |
125 Record r(nullptr, position, L"collection-end"); |
152 Record r(nullptr, position, L"collection-end"); |
126 write(r); |
153 write(r); |
127 } |
154 } |
128 |
155 |
129 void writeBitString(const Header& header, std::vector<bool> value) override { |
156 void writeBitString(const Header& header, std::vector<bool> value) override { |
|
157 std::stringstream bits; |
|
158 for (bool b : value) bits << (int) b; |
|
159 // for (bool b : value) bits << (b ? ':' : '.'); // TODO: configurable true/false symbols? |
|
160 |
130 position.back()++; |
161 position.back()++; |
131 Record r(&header, position, L"bit-string"); |
162 Record r(&header, position, L"bit-string"); |
|
163 r.valueText = convertor.from_bytes(bits.str()); |
132 write(r); |
164 write(r); |
133 } |
165 } |
134 |
166 |
135 void writeBoolean(const Header& header, bool value) override { |
167 void writeBoolean(const Header& header, bool value) override { |
136 position.back()++; |
168 position.back()++; |
137 Record r(&header, position, L"boolean"); |
169 Record r(&header, position, L"boolean"); |
|
170 r.valueText = value ? L"true" : L"false"; |
|
171 r.valueBinary = value ? L"FF" : L"00"; |
138 write(r); |
172 write(r); |
139 } |
173 } |
140 |
174 |
141 void writeDateTime(const Header& header, DateTime value) override { |
175 void writeDateTime(const Header& header, DateTime value) override { |
142 position.back()++; |
176 position.back()++; |
143 Record r(&header, position, L"date-time"); |
177 Record r(&header, position, L"date-time"); |
|
178 r.valueText = convertor.from_bytes(value.toString()); |
144 write(r); |
179 write(r); |
145 } |
180 } |
146 |
181 |
147 void writeInteger(const Header& header, Integer value) override { |
182 void writeInteger(const Header& header, Integer value) override { |
148 position.back()++; |
183 position.back()++; |
149 Record r(&header, position, L"integer"); |
184 Record r(&header, position, L"integer"); |
|
185 r.valueText = convertor.from_bytes(value.toString()); |
|
186 r.valueBinary = convertor.from_bytes(value.toHex()); |
150 write(r); |
187 write(r); |
151 } |
188 } |
152 |
189 |
153 void writeNull(const Header& header) override { |
190 void writeNull(const Header& header) override { |
154 position.back()++; |
191 position.back()++; |
155 Record r(&header, position, L"null"); |
192 Record r(&header, position, L"null"); |
|
193 r.valueText = L"null"; |
156 write(r); |
194 write(r); |
157 } |
195 } |
158 |
196 |
159 void writeOID(const Header& header, ObjectIdentifier value) override { |
197 void writeOID(const Header& header, ObjectIdentifier value) override { |
160 position.back()++; |
198 position.back()++; |
161 Record r(&header, position, L"oid"); |
199 Record r(&header, position, L"oid"); |
|
200 r.valueText = convertor.from_bytes(value.toString()); |
162 write(r); |
201 write(r); |
163 } |
202 } |
164 |
203 |
165 void writeOctetString(const Header& header, std::string value) override { |
204 void writeOctetString(const Header& header, std::string value) override { |
|
205 std::string text = getText(header, value); |
|
206 std::stringstream hex; |
|
207 hex << std::hex << std::setfill('0'); |
|
208 for (uint8_t b : value) hex << std::setw(2) << (int) b; |
|
209 |
166 position.back()++; |
210 position.back()++; |
167 Record r(&header, position, L"octet-string"); |
211 Record r(&header, position, L"octet-string"); |
|
212 r.valueText = convertor.from_bytes(text); |
|
213 r.valueBinary = convertor.from_bytes(hex.str()); |
168 write(r); |
214 write(r); |
169 } |
215 } |
170 |
216 |
171 void writeTextString(const Header& header, std::string value) override { |
217 void writeTextString(const Header& header, std::string value) override { |
172 position.back()++; |
218 position.back()++; |
173 Record r(&header, position, L"text-string"); |
219 Record r(&header, position, L"text-string"); |
|
220 r.valueText = convertor.from_bytes(value); |
174 write(r); |
221 write(r); |
175 } |
222 } |
176 |
223 |
177 void writeSpecific(const Header& header, std::string value) override { |
224 void writeSpecific(const Header& header, std::string value) override { |
|
225 std::stringstream hex; |
|
226 hex << std::hex << std::setfill('0'); |
|
227 for (uint8_t b : value) hex << std::setw(2) << (int) b; |
|
228 |
|
229 std::stringstream ascii; |
|
230 for (uint8_t b : value) ascii << (b >= 32 && b < 127 ? (char) b : '.'); // TODO: configurable unsupported symbol? |
|
231 |
178 position.back()++; |
232 position.back()++; |
179 Record r(&header, position, L"specific"); |
233 Record r(&header, position, L"specific"); |
|
234 r.valueText = convertor.from_bytes(ascii.str()); |
|
235 r.valueBinary = convertor.from_bytes(hex.str()); |
180 write(r); |
236 write(r); |
181 } |
237 } |
182 |
238 |
183 |
239 |
184 |
240 |