DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
xml.cpp
Go to the documentation of this file.
1#include "oks/xml.hpp"
2#include "oks/defs.hpp"
3#include "oks/exceptions.hpp"
4#include "oks/kernel.hpp"
5#include "oks/object.hpp"
6#include "oks/cstring.hpp"
7
8#include <iostream>
9#include <sstream>
10
11#include <boost/spirit/include/karma.hpp>
12
13#include <errno.h>
14#include <stdlib.h>
15
16#include "ers/ers.hpp"
17#include "logging/Logging.hpp"
18
19namespace dunedaq {
20namespace oks {
22
23
24 namespace xml {
25
26 const char left_angle_bracket[] = "&lt;";
27 const char right_angle_bracket[] = "&gt;";
28 const char ampersand[] = "&amp;";
29 const char carriage_return[] = "&#xD;";
30 const char new_line[] = "&#xA;";
31 const char tabulation[] = "&#x9;";
32 const char single_quote[] = "&apos;";
33 const char double_quote[] = "&quot;";
34
35 }
36
37 exception::exception(const std::string& what_arg, int level_arg) noexcept : p_level (level_arg)
38 {
39 std::ostringstream s;
40 s << "oks[" << p_level << "] ***: " << what_arg << std::ends;
41 p_what = s.str();
42 }
43
44 void throw_validate_not_empty(const char * name)
45 {
46 std::string text(name);
47 text += " is not set";
48 throw std::runtime_error(text.c_str());
49 }
50
51 std::string
52 BadFileData::fill(const std::string& item, unsigned long line_no, unsigned long line_pos) noexcept
53 {
54 std::ostringstream s;
55 s << item << " (line " << line_no << ", char " << line_pos << ')';
56 return s.str();
57 }
58
59 std::string
60 FailedRead::fill(const std::string& item, const std::string& reason) noexcept
61 {
62 return (std::string("Failed to read \'") + item + "\'\n" + reason);
63 }
64
65 std::string
66 FailedSave::fill(const std::string& item, const std::string& name, const std::string& reason) noexcept
67 {
68 return (std::string("Failed to save ") + item + " \'" + name + "\'\n" + reason);
69 }
70
71 std::string
72 EndOfXmlStream::fill(const std::string& tag)
73 {
74 return (std::string("Read end-of-stream tag \'") + tag + '\'');
75 }
76
77
78static std::string
79report_unexpected(const char * what, const char expected, const char read)
80{
81 std::string s;
82
83 if(what) {
84 s += "Failed to read ";
85 s += what;
86 s += ": ";
87 }
88
89 s += "symbol \'";
90 s += expected;
91 s += "\' is expected instead of \'";
92 s += read;
93 s += '\'';
94
95 return s;
96}
97
98
99static void
100__throw_runtime_error_unexpected_symbol(const char expected, const char read)
101{
102 throw std::runtime_error(report_unexpected(0, expected, read));
103}
104
105static void
106__throw_bad_file_data_unexpected_symbol(const char * what, const char expected, const char read, unsigned long l, unsigned long p)
107{
108 throw oks::BadFileData(report_unexpected(what, expected, read), l, p);
109}
110
111void
113{
114 throw std::runtime_error("write to file failed");
115}
116
117
118 //
119 // Save char to xml output stream
120 // Throw std::exception if failed
121 //
122
123void
125{
128 else if(c == '&') put_raw(oks::xml::ampersand, sizeof(oks::xml::ampersand)-1);
129 else if(c == '\'') put_raw(oks::xml::single_quote, sizeof(oks::xml::single_quote)-1);
130 else if(c == '\"') put_raw(oks::xml::double_quote, sizeof(oks::xml::double_quote)-1);
131 else if(c == '\r') put_raw(oks::xml::carriage_return, sizeof(oks::xml::carriage_return)-1);
132 else if(c == '\n') put_raw(oks::xml::new_line, sizeof(oks::xml::new_line)-1);
133 else if(c == '\t') put_raw(oks::xml::tabulation, sizeof(oks::xml::tabulation)-1);
134 else put_raw(c);
135
136}
137
138
139 //
140 // Save string to xml output stream
141 // Throw std::exception if failed
142 //
143
144void
145OksXmlOutputStream::put(const char * str)
146{
147 while(*str) put(*str++);
148}
149
150
151 //
152 // Save quoted string to xml output stream
153 // Throw std::exception if failed
154 //
155
156void
158{
159 put_raw('\"');
160 put(str);
161 put_raw('\"');
162}
163
164
165 //
166 // Save xml start tag and element name, i.e. '<element-name'
167 // Throw std::exception if failed
168 //
169
170void
171OksXmlOutputStream::put_start_tag(const char *name, size_t len)
172{
173 put_raw('<');
174 put_raw(name, len);
175}
176
177
178
179 //
180 // Save xml end tag, i.e. '/>\n'
181 // Throw std::exception if failed
182 //
183
184void
186{
187 static const char __end_tag[] = "/>\n";
188 put_raw(__end_tag, sizeof(__end_tag)-1);
189}
190
191void
193{
194 static const char __eol_tag[] = ">\n";
195 put_raw(__eol_tag, sizeof(__eol_tag)-1);
196}
197
198 //
199 // Save xml last tag, i.e. '</tag-name>\n'
200 // Throw std::exception if failed
201 //
202
203void
204OksXmlOutputStream::put_last_tag(const char * name, size_t len)
205{
206 put_raw('<');
207 put_raw('/');
208 put_raw(name, len);
209 put_raw('>');
210 put_raw('\n');
211}
212
213
214 //
215 // Save xml element attribute with value, i.e. ' name="value"'
216 // Throw std::exception if failed
217 //
218
219void
220OksXmlOutputStream::put_attribute(const char * name, size_t len, const char *value)
221{
222 put_raw(' ');
223 put_raw(name, len);
224 put_raw('=');
225 put_raw('\"');
226 put(value);
227 put_raw('\"');
228}
229
230void
231OksXmlOutputStream::put_attribute(const char * name, size_t len, uint32_t value)
232{
233 put_raw(' ');
234 put_raw(name, len);
235 put_raw('=');
236 put_raw('\"');
237 if(value == 0) {
238 put_raw('0');
239 }
240 else {
241 char buf[12];
242 char * ptr = buf;
243 boost::spirit::karma::generate(ptr, boost::spirit::uint_, (unsigned int)value);
244 put_raw(buf, ptr - buf);
245 }
246 put_raw('\"');
247}
248
249void
250OksXmlOutputStream::put_attribute(const char * name, size_t len, const OksData& value)
251{
252 put_raw(' ');
253 put_raw(name, len);
254 put_raw('=');
255 put_raw('\"');
256 value.WriteTo(*this);
257 put_raw('\"');
258}
259
260void
261OksXmlInputStream::throw_unexpected_tag(const char * what, const char * expected)
262{
263 std::ostringstream s;
264
265 if(!*what) {
266 if(expected) {
267 s << "expected tag \'" << expected << '\'';
268 }
269 else {
270 s << "empty tag";
271 }
272 }
273 else {
274 s << "unexpected tag \'" << what << '\'' ;
275 if(expected) {
276 s << " instead of \'" << expected << '\'' ;
277 }
278 }
279
280 throw oks::BadFileData(s.str(), line_no, line_pos);
281}
282
283void
285{
286 throw oks::BadFileData(std::string("Value \'") + what + "\' is not a valid attribute name", line_no, line_pos);
287}
288
289size_t
291{
292 size_t pos(0);
293
294 try {
295 char c = get_first_non_empty();
296
297 if( __builtin_expect((c != '\"'), 0) ) {
299 }
300
301 while(true) {
302 c = get();
303
304 if( __builtin_expect((c == '\"'), 0) ) {
305 m_v1->m_buf[pos] = 0;
306 return pos;
307 }
308 else if( __builtin_expect((c == '&'), 0) ) {
309 c = cvt_char();
310 }
311
312 m_v1->realloc(pos);
313 m_v1->m_buf[pos++] = c;
314 }
315
316 throw std::runtime_error("cannot find closing quote character");
317 }
318 catch (std::exception & ex) {
319 m_v1->m_buf[pos] = 0;
320 throw oks::BadFileData(std::string("Failed to read quoted string: ") + ex.what(), line_no, line_pos);
321 }
322}
323
324
325 // check for start of comment
326
327inline bool __is_comment(const char * s) {
328 return oks::cmp_str4n(s, "<!--");
329}
330
331
332 //
333 // Read xml tag while number of closing angles (i.e. '>') will not be equal
334 // number of opening ones (i.e. '<')
335 //
336
337const char *
339{
340 m_v1->m_buf[0] = 0;
341
342 unsigned long start_line_no = line_no;
343 unsigned long start_line_pos = line_pos;
344
345 size_t pos(0);
346
347 try {
348 while(true) {
349 char c(get_first_non_empty());
350
351 if( __builtin_expect((c != '<'), 0) ) {
353 }
354
355 start_line_no = line_no;
356 start_line_pos = line_pos;
357
358 m_v1->m_buf[0] = c;
359 pos = 1;
360
361 int count(1);
362
363 while(true) {
364 char c2 = get();
365
366 if(c2 == '<') count++;
367 else if(c2 == '>') count--;
368
369 m_v1->realloc(pos);
370 m_v1->m_buf[pos++] = c2;
371
372 if(pos > 3) {
373 if(__is_comment(m_v1->m_buf + pos - 4)) {
374 char buf[3] = {0, 0, 0};
375 unsigned long start_comment_line_no = line_no;
376 try {
377 while(true) {
378 buf[0] = buf[1];
379 buf[1] = buf[2];
380 buf[2] = get();
381
382 if(oks::cmp_str3n(buf, "-->")) {
383 break; // end of comment = '-->'
384 }
385 }
386 }
387 catch(std::exception& failure) {
388 std::ostringstream what;
389 what << "Cannot find end of comment started on line " << start_comment_line_no << ": " << failure.what();
390 throw oks::BadFileData(what.str(), line_no, line_pos);
391 }
392
393 pos -= 4;
394 count--;
395 }
396 }
397
398 if(count == 0) {
399 m_v1->m_buf[pos] = '\0';
400 break;
401 }
402 }
403
404 if(pos > 0) {
405 if(count != 0) { throw std::runtime_error("unbalanced tags"); }
406 else { return m_v1->m_buf; }
407 }
408 }
409 }
410 catch(std::exception& ex) {
411 m_v1->m_buf[pos] = '\0';
412 throw oks::BadFileData(std::string(ex.what()) + " when read xml tag started at", start_line_no, start_line_pos);
413 }
414}
415
416
417 //
418 // Reads token from stream until any symbol from 'separator' will be found.
419 // If 'first_symbol' is not 0, if will be first symbol of token.
420 //
421
422inline size_t
424{
425 size_t pos(0);
426
427 while(true) {
428 last_read_c = get();
429
430 if(last_read_c == __s1) { token.m_buf[pos] = '\0'; return pos; }
431 else if( __builtin_expect((last_read_c == '&'), 0) ) last_read_c = cvt_char();
432
433 token.realloc(pos);
434 token.m_buf[pos++] = last_read_c;
435 }
436
437 token.m_buf[pos] = 0;
438
439 throw std::runtime_error("cannot find closing separator while read token");
440}
441
442inline size_t
443OksXmlInputStream::get_token2(char __fs, const char __s1, const char __s2, OksXmlToken& token)
444{
445 size_t pos(1);
446 token.m_buf[0] = __fs;
447 if(__fs == __s1 || __fs == __s2) { token.m_buf[1] = '\0'; return 1; }
448
449 while(true) {
450 last_read_c = get();
451
452 if(last_read_c == __s1 || last_read_c == __s2) { token.m_buf[pos] = '\0'; return pos; }
453 else if( __builtin_expect((last_read_c == '&'), 0) ) last_read_c = cvt_char();
454
455 token.realloc(pos);
456 token.m_buf[pos++] = last_read_c;
457 }
458
459 token.m_buf[pos] = 0;
460
461 throw std::runtime_error("cannot find closing separator while read token");
462}
463
464inline void
465OksXmlInputStream::get_token5(const char __s1, const char __s2, const char __s3, const char __s4, const char __s5, OksXmlToken& token)
466{
467 size_t pos(0);
468
469 while(true) {
470 last_read_c = get();
471
472 if(last_read_c == __s1 || last_read_c == __s2 || last_read_c == __s3 || last_read_c == __s4 || last_read_c == __s5) { token.m_buf[pos] = '\0'; return; }
473 else if( __builtin_expect((last_read_c == '&'), 0) ) last_read_c = cvt_char();
474
475 token.realloc(pos);
476 token.m_buf[pos++] = last_read_c;
477 }
478
479 token.m_buf[pos] = 0;
480
481 throw std::runtime_error("cannot find closing separator while read token");
482}
483
484const char *
486{
487 try {
488 while(true) {
489 char c = get_first_non_empty();
490
491 if( __builtin_expect((c != '<'), 0) ) {
493 }
494
495 get_token5(' ', '>', '\t', '\n', '\r', *m_v1);
496 TLOG_DEBUG(8) << "read tag \'" << m_v1->m_buf << '\'';
497
498 if( __builtin_expect((oks::cmp_str3n(m_v1->m_buf, "!--")), 0) ) {
499 char buf[3] = {0, 0, 0};
500 unsigned long start_comment_line_no = line_no;
501 auto tag_len = strlen(m_v1->m_buf);
502 if(tag_len < 5 || !oks::cmp_str2n(m_v1->m_buf + tag_len- 2, "--")) // special case for comments without empty symbols like <!--foo-->
503 try {
504 while(true) {
505 buf[0] = buf[1];
506 buf[1] = buf[2];
507 c = buf[2] = get();
508 if(oks::cmp_str3n(buf, "-->")) {
509 break; // end of comment = '-->'
510 }
511 }
512 }
513 catch(std::exception& failure) {
514 std::ostringstream what;
515 what << "Cannot find end of comment started on line " << start_comment_line_no << ": " << failure.what();
516 throw oks::BadFileData(what.str(), line_no, line_pos);
517 }
518 }
519
520 if( __builtin_expect((c != '>'), 1) ) return m_v1->m_buf;
521 }
522 }
523 catch(std::exception& ex) {
524 throw oks::BadFileData(std::string("Failed to read start-of-tag: ") + ex.what(), line_no, line_pos);
525 }
526
527 return 0; // never reach this line
528}
529
530
531OksXmlAttribute::OksXmlAttribute(OksXmlInputStream& s) : p_name(*s.m_v1), p_value(*s.m_v2)
532{
533 unsigned long start_line_no = s.line_no;
534 unsigned long start_line_pos = s.line_pos;
535
536 try {
537 char c = s.get_first_non_empty();
538
539 start_line_no = s.line_no;
540 start_line_pos = s.line_pos;
541
542 size_t pos = s.get_token2(c, '=', '>', p_name);
543
544 char * m_buf_ptr(p_name.m_buf);
545
546 // skip empty symbols
547
548 for(char * str(m_buf_ptr + pos - 1); str >= m_buf_ptr; --str) {
549 if(*str == ' ' || *str == '\n' || *str == '\r' || *str == '\t') {
550 *str = 0;
551 }
552 else {
553 break;
554 }
555 }
556
557 if(c == '>' || c == '/' || c == '?') return; // end of attribute
558
559 c = s.get_first_non_empty();
560
561 if( __builtin_expect((c != '\"'), 0) ) {
562 __throw_bad_file_data_unexpected_symbol("start-of-attribute-value", '\"', c, s.line_no, s.line_pos);
563 }
564
565 p_value_len = s.get_token('\"', p_value);
566
567 TLOG_DEBUG(8) << "read attribute \'" << m_buf_ptr << "\' and value \'" << p_value.m_buf << '\'';
568 }
569 catch(std::exception& ex) {
570 throw oks::BadFileData(std::string(ex.what()) + " when read xml attribute started at", start_line_no, start_line_pos);
571 }
572}
573
574
575 //
576 // This method is used to convert special xml symbols:
577 // "&lt;" -> <
578 // "&gt;" -> >
579 // "&amp;" -> &
580 // "&apos;" -> '
581 // "&quot;" -> "
582 //
583
584char
586{
587 get_token(';', *m_cvt_char);
588
591 else if(oks::cmp_str3n(m_cvt_char->m_buf, oks::xml::ampersand + 1)) return '&';
592 else if(oks::cmp_str3n(m_cvt_char->m_buf, oks::xml::carriage_return + 1)) return '\r';
593 else if(oks::cmp_str3n(m_cvt_char->m_buf, oks::xml::new_line + 1)) return '\n';
594 else if(oks::cmp_str3n(m_cvt_char->m_buf, oks::xml::tabulation + 1)) return '\t';
595 else if(oks::cmp_str4n(m_cvt_char->m_buf, oks::xml::single_quote + 1)) return '\'';
596 else if(oks::cmp_str4n(m_cvt_char->m_buf, oks::xml::double_quote + 1)) return '\"';
597 else {
598 std::string text("bad symbol \'&");
599 text += m_cvt_char->m_buf;
600 text += '\'';
601 throw std::runtime_error(text.c_str());
602 }
603}
604
605
606std::ostream&
608{
609 return Oks::error_msg(msg)
610 << "(line " << line_no << ", char " << line_pos << ")\n";
611}
612
613void
615{
616 throw std::runtime_error("unexpected end of file");
617}
618
619void
620OksXmlInputStream::__throw_strto(const char * f, const char * where, const char * what, unsigned long line_no, unsigned long line_pos)
621{
622 std::ostringstream text;
623 text << "function " << f << "(\'" << what << "\') has failed";
624 if(*where) text << " on unrecognized characters \'" << where << "\'";
625 if(errno) text << " with code " << errno << ", reason = \'" << oks::strerror(errno) << '\'';
626 throw oks::BadFileData(text.str(), line_no, line_pos);
627}
628
629
630} // namespace oks
631} // namespace dunedaq
static std::string fill(const std::string &what, unsigned long line_no, unsigned long line_pos) noexcept
Definition xml.cpp:52
static std::string fill(const std::string &tag)
Definition xml.cpp:72
static std::string fill(const std::string &what, const std::string &reason) noexcept
Definition xml.cpp:60
static std::string fill(const std::string &what, const std::string &name, const std::string &reason) noexcept
Definition xml.cpp:66
void throw_unexpected_attribute(const char *what)
Definition xml.cpp:284
std::ostream & error_msg(const char *)
Definition xml.cpp:607
size_t get_token(const char s1, OksXmlToken &token)
Definition xml.cpp:423
size_t get_token2(char, const char s1, const char s2, OksXmlToken &token)
Definition xml.cpp:443
void throw_unexpected_tag(const char *what, const char *expected=0)
Definition xml.cpp:261
void get_token5(const char s1, const char s2, const char s3, const char s4, const char s5, OksXmlToken &token)
Definition xml.cpp:465
static void __throw_strto(const char *f, const char *where, const char *what, unsigned long line_no, unsigned long line_pos)
Definition xml.cpp:620
std::shared_ptr< std::istream > f
Definition xml.hpp:429
const char * get_tag_start()
Definition xml.cpp:485
std::istream::pos_type pos
Definition xml.hpp:436
static OksXmlTokenPool s_tokens_pool
Definition xml.hpp:441
void put_last_tag(const char *, size_t len)
Definition xml.cpp:204
void put_attribute(const char *, size_t len, const char *)
Definition xml.cpp:220
void put_start_tag(const char *, size_t len)
Definition xml.cpp:171
static void __throw_write_failed()
Definition xml.cpp:112
void put_quoted(const char *)
Definition xml.cpp:157
static std::ostream & error_msg(const char *)
Definition kernel.cpp:556
exception(const std::string &what_arg, int level_arg) noexcept
Definition xml.cpp:37
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
const char left_angle_bracket[]
Definition xml.cpp:26
const char new_line[]
Definition xml.cpp:30
const char tabulation[]
Definition xml.cpp:31
const char single_quote[]
Definition xml.cpp:32
const char ampersand[]
Definition xml.cpp:28
const char right_angle_bracket[]
Definition xml.cpp:27
const char carriage_return[]
Definition xml.cpp:29
const char double_quote[]
Definition xml.cpp:33
bool cmp_str2n(const char *s1, const char s2[2])
Definition cstring.hpp:17
const std::string strerror(int error)
Convert C error number to string.
Definition kernel.cpp:114
static void __throw_bad_file_data_unexpected_symbol(const char *what, const char expected, const char read, unsigned long l, unsigned long p)
Definition xml.cpp:106
bool __is_comment(const char *s)
Definition xml.cpp:327
bool cmp_str3n(const char *s1, const char s2[3])
Definition cstring.hpp:25
static std::string report_unexpected(const char *what, const char expected, const char read)
Definition xml.cpp:79
void throw_validate_not_empty(const char *name)
Definition xml.cpp:44
static void __throw_runtime_error_unexpected_symbol(const char expected, const char read)
Definition xml.cpp:100
bool cmp_str4n(const char *s1, const char s2[4])
Definition cstring.hpp:33
Including Qt Headers.
Definition __init__.py:1
the structure to pass common parameters to various read() methods of OksData and OksObject class
Definition object.hpp:449
void WriteTo(OksXmlOutputStream &, bool) const
OksXmlAttribute(OksXmlInputStream &s)
Definition xml.cpp:531
void realloc(unsigned long pos)
Definition xml.hpp:208