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