DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
data.cpp
Go to the documentation of this file.
1#define _OksBuildDll_
2
3#include "oks/object.hpp"
4#include "oks/xml.hpp"
5#include "oks/attribute.hpp"
7#include "oks/class.hpp"
8#include "oks/kernel.hpp"
9#include "oks/cstring.hpp"
10
11#include "oks_utils.hpp"
12
13#include "logging/Logging.hpp"
14
15#include <string.h>
16#include <stdlib.h>
17
18#include <string>
19#include <sstream>
20#include <stdexcept>
21#include <limits>
22
23#include <boost/date_time/posix_time/time_formatters.hpp>
24#include <boost/date_time/posix_time/time_parsers.hpp>
25#include <boost/date_time/gregorian/gregorian.hpp>
26
27
28namespace dunedaq {
30 oks,
31 DeprecatedFormat,
32 "the file " << file << " contains OKS time data stored in deprecated format \'" << data << "\'. Please refresh it using an oks application. Support for such format will be removed in a future release.",
33 ((const char *)file)
34 ((const char *)data)
35)
36
37namespace oks {
38 // ugly reinterpret staff to convert date and time to integers
39
40void OksData::SetFast(boost::gregorian::date d)
41{
42 data.DATE = d.day_number();
43}
44
45void OksData::SetFast(boost::posix_time::ptime t)
46{
47 data.TIME = *reinterpret_cast<uint64_t*>(&t);
48}
49
50boost::gregorian::date OksData::date() const noexcept
51{
52 return boost::gregorian::date(boost::gregorian::gregorian_calendar::from_day_number(data.DATE));
53}
54
55boost::posix_time::ptime OksData::time() const noexcept
56{
57 return *reinterpret_cast<boost::posix_time::ptime*>(const_cast<uint64_t*>(&data.TIME));
58}
59
60
61inline void free_list(OksData::List& dlist)
62{
63 for(OksData::List::const_iterator i = dlist.begin(); i != dlist.end(); ++i) {
64 delete *i;
65 }
66 dlist.clear();
67}
68
69
70static bool
71operator==(const OksData::List & l1, const OksData::List & l2)
72{
73 if(&l1 == &l2) return true;
74
75 size_t l1Lenght = l1.size();
76 size_t l2Lenght = l2.size();
77
78 if(!l1Lenght && !l2Lenght) return true;
79 if(l1Lenght != l2Lenght) return false;
80
81 size_t pos = 0;
82
83 auto i1 = l1.begin();
84 auto i2 = l2.begin();
85
86 for(;i1 != l1.end(); ++i1, ++i2) {
87 OksData * d1 = *i1;
88 OksData * d2 = *i2;
89
90 if( !d1 && !d2 ) return true;
91 if( !d1 || !d2 ) return false;
92
93 if(
94 (
95 (d1->type == d2->type) &&
96 (d1->type == OksData::object_type) &&
97 (
98 (!d1->data.OBJECT && !d2->data.OBJECT) ||
99 (
100 (d1->data.OBJECT && d2->data.OBJECT) &&
101 (d1->data.OBJECT->GetClass()->get_name() == d2->data.OBJECT->GetClass()->get_name()) &&
102 (d1->data.OBJECT->GetId() == d2->data.OBJECT->GetId())
103 )
104 )
105 ) ||
106 (
107 (*d1 == *d2)
108 )
109 ) {
110 pos++;
111 continue;
112 }
113
114 return false;
115 }
116
117 return true;
118}
119
120
121bool
122OksData::operator==(const OksData& d) const {
123 return (
124 (d.type == type) &&
125 (
126 ( (type == string_type) && (*d.data.STRING == *data.STRING) ) ||
127 ( (type == u32_int_type) && (d.data.U32_INT == data.U32_INT) ) ||
128 ( (type == s32_int_type) && (d.data.S32_INT == data.S32_INT) ) ||
129 ( (type == u16_int_type) && (d.data.U16_INT == data.U16_INT) ) ||
130 ( (type == s16_int_type) && (d.data.S16_INT == data.S16_INT) ) ||
131 ( (type == s8_int_type) && (d.data.S8_INT == data.S8_INT) ) ||
132 ( (type == u8_int_type) && (d.data.U8_INT == data.U8_INT) ) ||
133 ( (type == s64_int_type) && (d.data.S64_INT == data.S64_INT) ) ||
134 ( (type == u64_int_type) && (d.data.U64_INT == data.U64_INT) ) ||
135 ( (type == float_type) && (d.data.FLOAT == data.FLOAT) ) ||
136 ( (type == double_type) && (d.data.DOUBLE == data.DOUBLE) ) ||
137 ( (type == bool_type) && (d.data.BOOL == data.BOOL) ) ||
138 ( (type == date_type) && (d.data.DATE == data.DATE) ) ||
139 ( (type == time_type) && (d.data.TIME == data.TIME) ) ||
140 ( (type == object_type) && OksObject::are_equal_fast(d.data.OBJECT, data.OBJECT) ) ||
141 ( (type == list_type) && (*d.data.LIST == *data.LIST) ) ||
142 ( (type == uid_type) && (d.data.UID.class_id->get_name() == data.UID.class_id->get_name() && *d.data.UID.object_id == *data.UID.object_id) ) ||
143 ( (type == uid2_type) && (*d.data.UID2.class_id == *data.UID2.class_id && *d.data.UID2.object_id == *data.UID2.object_id) ) ||
144 ( (type == enum_type) && (*d.data.ENUMERATION == *data.ENUMERATION) ) ||
145 ( (type == class_type) && (d.data.CLASS->get_name() == data.CLASS->get_name()) )
146 )
147 );
148}
149
150bool
151OksData::operator!=(const OksData& d) const {
152 return ( (d == *this) ? false : true );
153}
154
155
156static bool
157test_comparable(OksData::Type type1, OksData::Type type2)
158{
159 const char * fname = "OksData::operator[<|<=|>|>=](const OksData&) const";
160 const char * h3 = "Can't compare ";
161
162 if(type1 != type2 && !(OksData::is_object(type1) && OksData::is_object(type2))) {
163 Oks::error_msg(fname) << h3 << "OKS data of different types\n";
164 return false;
165 }
166 else if(type1 == OksData::list_type) {
167 Oks::error_msg(fname) << h3 << "lists\n";
168 return false;
169 }
170
171 return true;
172}
173
174const std::string&
175OksData::__oid() const
176{
177 if(type == object_type)
178 return data.OBJECT->uid.object_id;
179 else if(type == uid_type)
180 return *data.UID.object_id;
181 else
182 return *data.UID2.object_id;
183}
184
185const std::string&
186OksData::__cn() const
187{
188 if(type == object_type)
189 return data.OBJECT->uid.class_id->get_name();
190 else if(type == uid_type)
191 return data.UID.class_id->get_name();
192 else
193 return *data.UID2.class_id;
194}
195
196#define CMP_OBJ( OP, c1, c2, id1, id2 ) (c1 OP c2) || (!(c2 OP c1) && id1 OP id2)
197
198#define CMP_DATA( OP ) \
199 switch(type) { \
200 case string_type: return (*data.STRING OP *d.data.STRING); \
201 case u32_int_type: return (data.U32_INT OP d.data.U32_INT); \
202 case s32_int_type: return (data.S32_INT OP d.data.S32_INT); \
203 case u16_int_type: return (data.U16_INT OP d.data.U16_INT); \
204 case s16_int_type: return (data.S16_INT OP d.data.S16_INT); \
205 case s8_int_type: return (data.S8_INT OP d.data.S8_INT); \
206 case u8_int_type: return (data.U8_INT OP d.data.U8_INT); \
207 case s64_int_type: return (data.S64_INT OP d.data.S64_INT); \
208 case u64_int_type: return (data.U64_INT OP d.data.U64_INT); \
209 case float_type: return (data.FLOAT OP d.data.FLOAT); \
210 case double_type: return (data.DOUBLE OP d.data.DOUBLE); \
211 case bool_type: return (data.BOOL OP d.data.BOOL); \
212 case date_type: return (data.DATE OP d.data.DATE); \
213 case time_type: return (data.TIME OP d.data.TIME); \
214 case enum_type: return (*data.ENUMERATION OP *d.data.ENUMERATION); \
215 case class_type: return (data.CLASS->get_name() OP d.data.CLASS->get_name()); \
216 case object_type: \
217 case uid_type: \
218 case uid2_type: \
219 return CMP_OBJ ( OP, __cn(), d.__cn(), __oid(), d.__oid() ); \
220 default: return false; \
221 }
222
223
224bool OksData::is_le(const OksData &d) const noexcept
225{
226 CMP_DATA( <= )
227}
228
229bool OksData::is_ge(const OksData &d) const noexcept
230{
231 CMP_DATA( >= )
232}
233
234bool OksData::is_l(const OksData &d) const noexcept
235{
236 CMP_DATA( < )
237}
238
239bool OksData::is_g(const OksData &d) const noexcept
240{
241 CMP_DATA( > )
242}
243
244
245bool
246OksData::operator<=(const OksData& d) const {
247 if(test_comparable(type, d.type) == false) return false;
248 return is_le(d);
249}
250
251
252bool
253OksData::operator>=(const OksData& d) const {
254 if(test_comparable(type, d.type) == false) return false;
255 return is_ge(d);
256}
257
258
259bool
260OksData::operator>(const OksData& d) const {
261 if(test_comparable(type, d.type) == false) return false;
262 return is_g(d);
263}
264
265
266bool
267OksData::operator<(const OksData& d) const {
268 if(test_comparable(type, d.type) == false) return false;
269 return is_l(d);
270}
271
272
273void
274OksData::copy(const OksData & d)
275{
276 type = d.type;
277
278 if(type == list_type) {
279 data.LIST = new List();
280
281 for(List::iterator i = d.data.LIST->begin(); i != d.data.LIST->end(); ++i) {
282 OksData *d2 = new OksData();
283 *d2 = *(*i);
284 data.LIST->push_back(d2);
285 }
286 }
287 else if(type == string_type) data.STRING = new OksString(*d.data.STRING);
288 else if(type == object_type) data.OBJECT = d.data.OBJECT; // Don't allow deep copy for objects
289 else if(type == u32_int_type) data.U32_INT = d.data.U32_INT;
290 else if(type == s32_int_type) data.S32_INT = d.data.S32_INT;
291 else if(type == u16_int_type) data.U16_INT = d.data.U16_INT;
292 else if(type == s16_int_type) data.S16_INT = d.data.S16_INT;
293 else if(type == double_type) data.DOUBLE = d.data.DOUBLE;
294 else if(type == float_type) data.FLOAT = d.data.FLOAT;
295 else if(type == s8_int_type) data.S8_INT = d.data.S8_INT;
296 else if(type == u8_int_type) data.U8_INT = d.data.U8_INT;
297 else if(type == s64_int_type) data.S64_INT = d.data.S64_INT;
298 else if(type == u64_int_type) data.U64_INT = d.data.U64_INT;
299 else if(type == class_type) data.CLASS = d.data.CLASS;
300 else if(type == uid2_type) {
301 data.UID2.class_id = new OksString(*d.data.UID2.class_id);
302 data.UID2.object_id = new OksString(*d.data.UID2.object_id);
303 }
304 else if(type == uid_type) {
305 data.UID.class_id = d.data.UID.class_id;
306 data.UID.object_id = new OksString(*d.data.UID.object_id);
307 }
308 else if(type == bool_type) data.BOOL = d.data.BOOL;
309 else if(type == date_type) data.DATE = d.data.DATE;
310 else if(type == time_type) data.TIME = d.data.TIME;
311 else if(type == enum_type) data.ENUMERATION = d.data.ENUMERATION;
312}
313
314
315std::ostream&
316operator<<(std::ostream& s, const OksData & d)
317{
318 switch (d.type) {
319 case OksData::list_type: {
320 s << '(';
321 for(OksData::List::iterator i = d.data.LIST->begin(); i != d.data.LIST->end(); ++i) {
322 s << *(*i);
323 if((*i) != d.data.LIST->back()) s << ", ";
324 }
325 s << ')';
326 break; }
327
329 s << '\"' << *(d.data.STRING) << '\"';
330 break;
331
333 if(d.data.OBJECT)
334 s << '[' << d.data.OBJECT->GetId() << '@' << d.data.OBJECT->GetClass()->get_name() << ']';
335 else
336 s << "[NIL]";
337
338 break;
339
341 s << '#' << '[' << *d.data.UID2.object_id << '@' << *d.data.UID2.class_id << ']';
342 break;
343
345 s << '#' << '[' << *d.data.UID.object_id << '@' << d.data.UID.class_id->get_name() << ']';
346 break;
347
349 s << d.data.S32_INT;
350 break;
351
353 s << d.data.U32_INT;
354 break;
355
357 s << d.data.S16_INT;
358 break;
359
361 s << d.data.U16_INT;
362 break;
363
364 case OksData::float_type: {
365 std::streamsize p = s.precision();
366 s.precision(std::numeric_limits< float >::digits10);
367 s << d.data.FLOAT;
368 s.precision(p);
369 break; }
370
372 std::streamsize p = s.precision();
373 s.precision(std::numeric_limits< double >::digits10);
374 s << d.data.DOUBLE;
375 s.precision(p);
376 break; }
377
379 s << static_cast<int16_t>(d.data.S8_INT);
380 break;
381
383 s << static_cast<uint16_t>(d.data.U8_INT);
384 break;
385
387 s << d.data.S64_INT;
388 break;
389
391 s << d.data.U64_INT;
392 break;
393
395 s << ( (d.data.BOOL == true) ? "true" : "false" );
396 break;
397
399 s << boost::gregorian::to_simple_string(d.date());
400 break;
401
403 s << boost::posix_time::to_simple_string(d.time());
404 break;
405
407 s << '\"' << *(d.data.ENUMERATION) << '\"';
408 break;
409
411 s << '[' << d.data.CLASS->get_name() << ']';
412 break;
413
415 Oks::error_msg("operator<<(ostream&, const OksData&)")
416 << "Can't put to stream \'OksData::unknown_type\'";
417 break;
418 }
419
420 return s;
421}
422
423
424void
426{
427 if(type >= string_type) {
428 switch(type) {
429 case list_type:
430 if(List * dlist = data.LIST) {
431 if(!dlist->empty()) {
432 free_list(*dlist);
433 }
434 delete dlist;
435 }
436 break;
437
438 case string_type:
439 if(data.STRING) { delete data.STRING; }
440 break;
441
442 case uid2_type:
443 if(data.UID2.object_id) { delete data.UID2.object_id; }
444 if(data.UID2.class_id) { delete data.UID2.class_id; }
445 break;
446
447 case uid_type:
448 if(data.UID.object_id) { delete data.UID.object_id; }
449 break;
450
451 default:
452 /* Make compiler happy */
453 break;
454 }
455 }
456
457 type = unknown_type;
458}
459
460 std::string
461 AttributeRangeError::fill(const OksData * d, const std::string& range)
462 {
463 std::ostringstream s;
464 s << "value ";
465 if (d->type == OksData::string_type || d->type == OksData::enum_type)
466 s << *d;
467 else
468 s << '\'' << *d << '\'';
469 s << " is out of range \'" << range << '\'';
470 return s.str();
471 }
472
473 std::string
474 AttributeReadError::fill(const char * value, const char * type, const std::string& reason)
475 {
476 std::ostringstream s;
477
478 if(value) { s << "string \'" << value << '\''; }
479 else { s << "empty string"; }
480
481 s << " is not a valid value for \'" << type << "\' type";
482
483 if(!reason.empty()) s << ":\n" << reason;
484
485 return s.str();
486 }
487
488 std::string
489 AttributeReadError::fill(const char * type, const std::string& reason)
490 {
491 std::ostringstream s;
492
493 s << "the string is not a valid value for \'" << type << "\' type";
494
495 if(!reason.empty()) s << ":\n" << reason;
496
497 return s.str();
498 }
499
500
501void
502OksData::check_range(const OksAttribute * a) const
503{
504 if (a->p_range_obj == nullptr)
505 return;
506
507 if (type == list_type)
508 {
509 if (data.LIST)
510 {
511 for (const auto& i : *data.LIST)
512 {
513 i->check_range(a);
514 }
515 }
516 }
517 else
518 {
519 if (a->p_range_obj->validate(*this) == false)
520 {
521 throw AttributeRangeError(this, a->get_range());
522 }
523 }
524}
525
526void
527OksData::SetNullValue(const OksAttribute * a)
528{
529 switch(type) {
530 case s8_int_type: data.S8_INT = 0; return;
531 case u8_int_type: data.U8_INT = 0; return;
532 case bool_type: data.BOOL = false; return;
533 case u32_int_type: data.U32_INT = 0L; return;
534 case s32_int_type: data.S32_INT = 0L; return;
535 case s16_int_type: data.S16_INT = 0; return;
536 case u16_int_type: data.U16_INT = 0; return;
537 case s64_int_type: data.S64_INT = (int64_t)(0); return;
538 case u64_int_type: data.U64_INT = (uint64_t)(0); return;
539 case float_type: data.FLOAT = (float)(.0); return;
540 case double_type: data.DOUBLE = (double)(.0); return;
541 case string_type: data.STRING = new OksString(); return;
542 case enum_type: data.ENUMERATION = &((*(a->p_enumerators))[0]); return; // first value
543 case class_type: data.CLASS = a->p_class; return; // some class
544 case date_type: SetFast(boost::gregorian::day_clock::universal_day()); return;
545 case time_type: SetFast(boost::posix_time::second_clock::universal_time()); return;
546 default: Clear2(); throw AttributeReadError("", "non-attribute-type", "internal OKS error");
547 }
548}
549
550
551void
552OksData::SetValue(const char * s, const OksAttribute * a)
553{
554 if(*s == '\0') {
555 SetNullValue(a);
556 }
557 else {
558 switch(type) {
559 case s8_int_type: data.S8_INT = static_cast<int8_t>(strtol(s, 0, 0)); return;
560 case u8_int_type: data.U8_INT = static_cast<uint8_t>(strtoul(s, 0, 0)); return;
561 case bool_type: switch(strlen(s)) {
562 case 4: data.BOOL = (cmp_str4n(s, "true") || cmp_str4n(s, "TRUE") || cmp_str4n(s, "True")); return;
563 case 1: data.BOOL = (*s == 't' || *s == 'T' || *s == '1'); return;
564 default: data.BOOL = false; return;
565 }
566 case u32_int_type: data.U32_INT = static_cast<uint32_t>(strtoul(s, 0, 0)); return;
567 case s32_int_type: data.S32_INT = static_cast<int32_t>(strtol(s, 0, 0)); return;
568 case s16_int_type: data.S16_INT = static_cast<int16_t>(strtol(s, 0, 0)); return;
569 case u16_int_type: data.U16_INT = static_cast<uint16_t>(strtoul(s, 0, 0)); return;
570 case s64_int_type: data.S64_INT = static_cast<int64_t>(strtoll(s, 0, 0)); return;
571 case u64_int_type: data.U64_INT = static_cast<uint64_t>(strtoull(s, 0, 0)); return;
572 case float_type: data.FLOAT = strtof(s, 0); return;
573 case double_type: data.DOUBLE = strtod(s, 0); return;
574
575 case string_type: data.STRING = new OksString(s); return;
576 case enum_type: try {
577 data.ENUMERATION = a->get_enum_value(s, strlen(s)); return;
578 }
579 catch(std::exception& ex) {
580 throw AttributeReadError(s, "enum", ex.what());
581 }
582 case date_type: try {
583 if(strchr(s, '-') || strchr(s, '/')) {
584 SetFast(boost::gregorian::from_simple_string(s)); return;
585 }
586 else {
587 SetFast(boost::gregorian::from_undelimited_string(s)); return;
588 }
589 }
590 catch(std::exception& ex) {
591 throw AttributeReadError(s, "date", ex.what());
592 }
593 case time_type: try {
594 if(strlen(s) == 15 && s[8] == 'T') {
595 SetFast(boost::posix_time::from_iso_string(s)); return;
596 }
597 else {
598 SetFast(boost::posix_time::time_from_string(s)); return;
599 }
600 }
601 catch(std::exception& ex) {
602 throw AttributeReadError(s, "time", ex.what());
603 }
604 case class_type: if(OksClass * c = a->p_class->get_kernel()->find_class(s)) {
605 data.CLASS = c; return;
606 }
607 else {
608 Clear2(); throw AttributeReadError(s, "class", "the value is not a name of valid OKS class");
609 }
610 default: Clear2(); throw AttributeReadError(s, "non-attribute-type", "internal OKS error");
611 }
612 }
613
614}
615
616
617std::list<std::string>
619{
620 std::list<std::string> val;
621
622 // check, if the attribute is multi-value
623 if(get_is_multi_values() == true) {
624 OksData d;
625 d.SetValues(get_init_value().c_str(), this);
626
627 for(OksData::List::const_iterator i = d.data.LIST->begin(); i != d.data.LIST->end(); ++i) {
628 val.push_back((*i)->str());
629 }
630 }
631
632 return val;
633}
634
635
636void
637OksData::SetValues(const char *s, const OksAttribute *a)
638{
639 if( !a->get_is_multi_values() ) {
640 ReadFrom(s, a->get_data_type(), a);
641 return;
642 }
643
644 if(type != list_type) {
645 Set(new List());
646 }
647 else if(!data.LIST->empty()) {
648 free_list(*data.LIST);
649 }
650
651 if( !s ) return;
652 while( *s == ' ' ) s++;
653 if( *s == '\0' ) return;
654
655 std::string str(s);
656
657 while( str.length() ) {
658 while( str.length() && str[0] == ' ') str.erase(0, 1);
659 if( !str.length() ) return;
660 char delimeter = (
661 str[0] == '\"' ? '\"' :
662 str[0] == '\'' ? '\'' :
663 str[0] == '`' ? '`' :
664 ','
665 );
666
667 if(delimeter != ',') str.erase(0, 1);
668 std::string::size_type p = str.find(delimeter);
669
670 OksData *d = new OksData();
671 d->type = a->get_data_type();
672
673 if(d->type == OksData::string_type) {
674 d->data.STRING = new OksString(str, p);
675 }
676 else if(d->type == OksData::enum_type) {
677 std::string token(str, 0, p);
678 d->data.ENUMERATION = a->get_enum_value(token); // FIXME, create more efficient using compare(idx, len ,str)
679 }
680 else {
681 std::string token(str, 0, p);
682 d->SetValue(token.c_str(), a);
683 }
684
685 data.LIST->push_back(d);
686
687 str.erase(0, p);
688 if(str.length()) {
689 if(delimeter != ',') {
690 p = str.find(',');
691 if( p == std::string::npos )
692 p = str.length();
693 else
694 p++;
695 str.erase(0, p);
696 }
697 else
698 str.erase(0, 1);
699 }
700 }
701}
702
703
704void
705OksData::ReadFrom(const OksRelationship *r) noexcept
706{
707 if(r->get_high_cardinality_constraint() != OksRelationship::Many) {
708 Set((OksObject *)0);
709 }
710 else {
711 Set(new List());
712 }
713}
714
715
716void
718{
719 size_t pos(1);
720
721 try {
722 char c = get_first_non_empty();
723
724 if(c == __last) {
725 m_cvt_char->m_buf[0] = 0;
726 throw std::runtime_error("empty numeric value");
727 }
728
729 m_cvt_char->m_buf[0] = c;
730
731 while(true) {
732 c = get();
733
734 if(c == __last) {
735 m_cvt_char->m_buf[pos] = '\0';
736 f->unget();
737 return;
738 }
739 else if(c == ' ' || c == '\n' || c == '\r' || c == '\t') {
740 m_cvt_char->m_buf[pos] = '\0';
741 return;
742 }
743
745 m_cvt_char->m_buf[pos++] = c;
746 }
747 }
748 catch(std::exception& ex) {
749 m_cvt_char->m_buf[pos] = '\0';
750 throw BadFileData(std::string("failed to read numeric value: ") + ex.what(), line_no, line_pos);
751 }
752}
753
754void
755OksData::read(const ReadFileParams& read_params, const OksAttribute * a, /*atype,*/ int32_t num)
756{
757 if(type != list_type) {
758 Set(new List());
759 }
760 else if(!data.LIST->empty()) {
761 free_list(*data.LIST);
762 }
763
764 while(num-- > 0) {
765 data.LIST->push_back(new OksData(read_params, a));
766 }
767}
768
769
770void
771OksData::read(const ReadFileParams& read_params, const OksAttribute *a)
772{
773 const char * read_value=""; // is used for report in case of exception
774 char * __sanity;
775 OksXmlInputStream& fxs(read_params.s);
776
777 try {
778 switch(a->get_data_type()) {
779 case string_type:
780 read_value = "quoted string";
781 {
782 size_t len = fxs.get_quoted();
783 if(type == string_type && data.STRING) {
784 data.STRING->assign(fxs.get_xml_token().m_buf, len);
785 }
786 else {
787 Clear();
788 type = string_type;
789 data.STRING = new OksString(fxs.get_xml_token().m_buf, len);
790 }
791 }
792 break;
793
794 case s32_int_type:
795 read_value = "signed 32 bits integer";
796 fxs.get_num_token('<');
797 Set(static_cast<int32_t>(strtol(fxs.m_cvt_char->m_buf, &__sanity, 0)));
798 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
799 break;
800
801 case u32_int_type:
802 read_value = "unsigned 32 bits integer";
803 fxs.get_num_token('<');
804 Set(static_cast<uint32_t>(strtoul(fxs.m_cvt_char->m_buf, &__sanity, 0)));
805 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
806 break;
807
808 case s16_int_type:
809 read_value = "signed 16 bits integer";
810 fxs.get_num_token('<');
811 Set(static_cast<int16_t>(strtol(fxs.m_cvt_char->m_buf, &__sanity, 0)));
812 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
813 break;
814
815 case u16_int_type:
816 read_value = "unsigned 16 bits integer";
817 fxs.get_num_token('<');
818 Set(static_cast<uint16_t>(strtoul(fxs.m_cvt_char->m_buf, &__sanity, 0)));
819 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
820 break;
821
822 case s8_int_type:
823 read_value = "signed 8 bits integer";
824 fxs.get_num_token('<');
825 Set(static_cast<int8_t>(strtol(fxs.m_cvt_char->m_buf, &__sanity, 0)));
826 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
827 break;
828
829 case u8_int_type:
830 read_value = "unsigned 8 bits integer";
831 fxs.get_num_token('<');
832 Set(static_cast<uint8_t>(strtoul(fxs.m_cvt_char->m_buf, &__sanity, 0)));
833 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
834 break;
835
836 case s64_int_type:
837 read_value = "signed 64 bits integer";
838 fxs.get_num_token('<');
839 Set(static_cast<int64_t>(strtoll(fxs.m_cvt_char->m_buf, &__sanity, 0)));
840 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoll", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
841 break;
842
843 case u64_int_type:
844 read_value = "unsigned 64 bits integer";
845 fxs.get_num_token('<');
846 Set(static_cast<uint64_t>(strtoull(fxs.m_cvt_char->m_buf, &__sanity, 0)));
847 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoull", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
848 break;
849
850 case float_type:
851 read_value = "float";
852 fxs.get_num_token('<');
853 Set(strtof(fxs.m_cvt_char->m_buf, &__sanity));
854 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtof", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
855 break;
856
857 case double_type:
858 read_value = "double";
859 fxs.get_num_token('<');
860 Set(strtod(fxs.m_cvt_char->m_buf, &__sanity));
861 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtod", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
862 break;
863
864 case bool_type:
865 read_value = "boolean";
866 fxs.get_num_token('<');
867 Set(static_cast<bool>(strtol(fxs.m_cvt_char->m_buf, &__sanity, 0)));
868 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, fxs.m_cvt_char->m_buf, fxs.line_no, fxs.line_pos);
869 break;
870
871 case date_type:
872 read_value = "quoted date string";
873 {
874 size_t len = fxs.get_quoted();
875 Set(str2date(fxs.get_xml_token().m_buf, len));
876 }
877 break;
878
879 case time_type:
880 read_value = "quoted time string";
881 {
882 size_t len = fxs.get_quoted();
883 Set(str2time(fxs.get_xml_token().m_buf, len));
884 }
885 break;
886
887 case enum_type:
888 read_value = "quoted enum string";
889 {
890 size_t len = fxs.get_quoted();
891 SetE(fxs.get_xml_token().m_buf, len, a);
892 }
893 break;
894
895 case uid2_type:
896 read_value = "two quoted class-name / object-id strings";
897 Set(new OksString(), new OksString());
898 {
899 size_t len = fxs.get_quoted();
900 data.UID2.class_id->assign(fxs.get_xml_token().m_buf, len);
901 len = fxs.get_quoted();
902 data.UID2.object_id->assign(fxs.get_xml_token().m_buf, len);
903 }
904 break;
905
906 case class_type:
907 read_value = "quoted class-type string";
908 type = class_type;
909 fxs.get_quoted();
910 SetValue(fxs.get_xml_token().m_buf, a);
911 break;
912
913 default:
914 type = unknown_type;
915 {
916 std::ostringstream s;
917 s << "Unknown attribute type \"" << (int)a->get_data_type() << "\" (line " << fxs.get_line_no() << ", char " << fxs.get_line_pos() << ')';
918 throw std::runtime_error( s.str().c_str() );
919 }
920 }
921 }
922 catch (exception & e) {
923 throw FailedRead(read_value, e);
924 }
925 catch (std::exception & e) {
926 throw FailedRead(read_value, e.what());
927 }
928}
929
930
931void
932OksData::read(const OksAttribute *a, const OksXmlValue& value)
933{
934 const char * read_value=""; // is used for report in case of exception
935 char * __sanity;
936
937 try {
938 switch(a->get_data_type()) {
939 case string_type:
940 {
941 if(type == string_type && data.STRING) {
942 data.STRING->assign(value.buf(), value.len());
943 }
944 else {
945 Clear();
946 type = string_type;
947 data.STRING = new OksString(value.buf(), value.len());
948 }
949 }
950 break;
951
952 case s32_int_type:
953 read_value = "signed 32 bits integer";
954 Set(static_cast<int32_t>(strtol(value.buf(), &__sanity, 0)));
955 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, value.buf(), value.line_no(), value.line_pos());
956 break;
957
958 case u32_int_type:
959 read_value = "unsigned 32 bits integer";
960 Set(static_cast<uint32_t>(strtoul(value.buf(), &__sanity, 0)));
961 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, value.buf(), value.line_no(), value.line_pos());
962 break;
963
964 case s16_int_type:
965 read_value = "signed 16 bits integer";
966 Set(static_cast<int16_t>(strtol(value.buf(), &__sanity, 0)));
967 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, value.buf(), value.line_no(), value.line_pos());
968 break;
969
970 case u16_int_type:
971 read_value = "unsigned 16 bits integer";
972 Set(static_cast<uint16_t>(strtoul(value.buf(), &__sanity, 0)));
973 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, value.buf(), value.line_no(), value.line_pos());
974 break;
975
976 case s8_int_type:
977 read_value = "signed 8 bits integer";
978 Set(static_cast<int8_t>(strtol(value.buf(), &__sanity, 0)));
979 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, value.buf(), value.line_no(), value.line_pos());
980 break;
981
982 case u8_int_type:
983 read_value = "unsigned 8 bits integer";
984 Set(static_cast<uint8_t>(strtoul(value.buf(), &__sanity, 0)));
985 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoul", __sanity, value.buf(), value.line_no(), value.line_pos());
986 break;
987
988 case s64_int_type:
989 read_value = "signed 64 bits integer";
990 Set(static_cast<int64_t>(strtoll(value.buf(), &__sanity, 0)));
991 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoll", __sanity, value.buf(), value.line_no(), value.line_pos());
992 break;
993
994 case u64_int_type:
995 read_value = "unsigned 64 bits integer";
996 Set(static_cast<uint64_t>(strtoull(value.buf(), &__sanity, 0)));
997 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtoull", __sanity, value.buf(), value.line_no(), value.line_pos());
998 break;
999
1000 case float_type:
1001 read_value = "float";
1002 Set(strtof(value.buf(), &__sanity));
1003 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtof", __sanity, value.buf(), value.line_no(), value.line_pos());
1004 break;
1005
1006 case double_type:
1007 read_value = "double";
1008 Set(strtod(value.buf(), &__sanity));
1009 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtod", __sanity, value.buf(), value.line_no(), value.line_pos());
1010 break;
1011
1012 case bool_type:
1013 read_value = "boolean";
1014 Set(static_cast<bool>(strtol(value.buf(), &__sanity, 0)));
1015 if( __builtin_expect((*__sanity != 0 || errno == ERANGE), 0) ) OksXmlInputStream::__throw_strto("strtol", __sanity, value.buf(), value.line_no(), value.line_pos());
1016 break;
1017
1018 case date_type:
1019 read_value = "quoted date string";
1020 Set(str2date(value.buf(), value.len()));
1021 break;
1022
1023 case time_type:
1024 read_value = "quoted time string";
1025 Set(str2time(value.buf(), value.len()));
1026 break;
1027
1028 case enum_type:
1029 read_value = "quoted enum string";
1030 SetE(value.buf(), value.len(), a);
1031 break;
1032
1033 case uid2_type:
1034 read_value = "two quoted class-name / object-id strings";
1035 {
1036 std::ostringstream s;
1037 s << "Unexpected uid2 type at (line " << value.line_no() << ", char " << value.line_pos() << ')';
1038 throw std::runtime_error( s.str().c_str() );
1039 }
1040 break;
1041
1042 case class_type:
1043 read_value = "quoted class-type string";
1044 type = class_type;
1045 SetValue(value.buf(), a);
1046 break;
1047
1048 default:
1049 type = unknown_type;
1050 {
1051 std::ostringstream s;
1052 s << "Unknown attribute type \"" << (int)a->get_data_type() << "\" (line " << value.line_no() << ", char " << value.line_pos() << ')';
1053 throw std::runtime_error( s.str().c_str() );
1054 }
1055 }
1056 }
1057 catch (exception & e) {
1058 throw FailedRead(read_value, e);
1059 }
1060 catch (std::exception & e) {
1061 throw FailedRead(read_value, e.what());
1062 }
1063}
1064
1065void
1066OksData::read(const OksAttribute *a, const ReadFileParams& read_params)
1067{
1068 if (type != list_type)
1069 Set(new List());
1070 else if (!data.LIST->empty())
1071 free_list(*data.LIST);
1072
1073 while (true)
1074 try
1075 {
1076 const char * tag_start = read_params.s.get_tag_start();
1077
1078 // check for closing tag
1079 if (*tag_start == '/' && cmp_str5n(tag_start+1, OksObject::attribute_xml_tag))
1080 break;
1081
1082 if (cmp_str4(tag_start, OksObject::data_xml_tag))
1083 {
1084 {
1085 OksXmlAttribute attr(read_params.s);
1086
1087 if (cmp_str3(attr.name(), OksObject::value_xml_attribute))
1088 {
1089 OksXmlValue value(read_params.s.get_value(attr.p_value_len));
1090 data.LIST->push_back(new OksData(a, value));
1091 }
1092 else
1093 {
1094 std::ostringstream s;
1095 s << "Unexpected attribute \"" << attr.name() << "\" instead of \"" << OksObject::value_xml_attribute << "\" (line " << read_params.s.get_line_no() << ", char " << read_params.s.get_line_pos() << ')';
1096 throw std::runtime_error(s.str().c_str());
1097 }
1098 }
1099 {
1100 OksXmlAttribute attr(read_params.s);
1101
1102 if (cmp_str1(attr.name(), "/") == false)
1103 {
1104 std::ostringstream s;
1105 s << "Unexpected tag \"" << attr.name() << "\" instead of close tag (line " << read_params.s.get_line_no() << ", char " << read_params.s.get_line_pos() << ')';
1106 throw std::runtime_error(s.str().c_str());
1107 }
1108 }
1109 }
1110 else
1111 {
1112 std::ostringstream s;
1113 s << "Unexpected tag \"" << tag_start << "\" (line " << read_params.s.get_line_no() << ", char " << read_params.s.get_line_pos() << ')';
1114 throw std::runtime_error(s.str().c_str());
1115 }
1116 }
1117 catch (exception & e)
1118 {
1119 throw FailedRead("multi-value", e);
1120 }
1121 catch (std::exception & e)
1122 {
1123 throw FailedRead("multi-value", e.what());
1124 }
1125}
1126
1127void
1128OksData::read(const ReadFileParams& read_params, const OksRelationship * r, int32_t num)
1129{
1130 if( __builtin_expect((type != list_type), 0) ) {
1131 Set(new List());
1132 }
1133 else if( __builtin_expect((!data.LIST->empty()), 0) ) {
1134 free_list(*data.LIST);
1135 }
1136
1137 while(num-- > 0) {
1138 OksData * d = new OksData(read_params, r);
1139
1140 // ignore dangling objects saved previously
1141 if( __builtin_expect((d->type == OksData::uid2_type && d->data.UID2.class_id->empty()), 0) ) continue;
1142
1143 // add real object
1144 data.LIST->push_back(d);
1145 }
1146}
1147
1148void
1149OksData::read(const ReadFileParams& read_params, const OksRelationship * r)
1150{
1151 const OksClass * rel_class(r->p_class_type); // class of relationship
1152 OksString * class_id(0); // class-name of read object
1153 const OksClass * c(0); // class of read object
1154 OksXmlInputStream& fxs(read_params.s);
1155
1156 try {
1157
1158 // read class name from stream and store it either on 'c' (pointer-to-class) or new OksString
1159
1160 size_t len = fxs.get_quoted();
1161
1162 if( __builtin_expect((len > 0), 1) ) {
1163 if( __builtin_expect((!read_params.alias_table), 1) ) {
1164 if( __builtin_expect((rel_class != 0), 1) ) {
1165 c = rel_class->get_kernel()->find_class(fxs.get_xml_token().m_buf);
1166 }
1167
1168 if( __builtin_expect((c == 0), 0) ) {
1169 class_id = new OksString(fxs.get_xml_token().m_buf, len);
1170 }
1171 }
1172 else {
1173 const char * class_name_str(fxs.get_xml_token().m_buf);
1174
1175 if(class_name_str[0] == '@') {
1176 class_name_str++;
1177 len--;
1178
1179 c = ( rel_class ? rel_class->get_kernel()->find_class(class_name_str) : 0 );
1180
1181 if(c) {
1182 read_params.alias_table->add_value(0, c);
1183 }
1184 else {
1185 read_params.alias_table->add_value(new OksString(class_name_str, len), 0);
1186 }
1187 }
1188 else {
1189 if(rel_class) {
1190 if(const OksAliasTable::Value * value = read_params.alias_table->get(class_name_str)) {
1191 c = (
1192 value->class_ptr
1193 ? value->class_ptr
1194 : rel_class->get_kernel()->find_class(*value->class_name)
1195 );
1196 }
1197 else {
1198 Oks::warning_msg("OksData::read(const ReadFileParams&, const OksRelationship*")
1199 << " Can't find alias for class \'" << class_name_str << "\'\n"
1200 " Possibly data file has been saved in old format\n";
1201
1202 c = rel_class->get_kernel()->find_class(class_name_str);
1203 }
1204 }
1205 }
1206
1207 if(!c) {
1208 class_id = new OksString(class_name_str, len);
1209 }
1210 }
1211 }
1212
1213
1214 // read object id from stream and try to find OksObject
1215
1216 len = fxs.get_quoted();
1217
1218 if( __builtin_expect((c == 0), 0) ) {
1219 if(class_id) {
1220 Set(class_id, new OksString(fxs.get_xml_token().m_buf, len));
1221 class_id = 0;
1222 }
1223 else {
1224 Set((OksObject *)0);
1225 }
1226
1227 goto final;
1228 }
1229
1230
1231 std::string& obj_id((const_cast<ReadFileParams&>(read_params)).tmp); // use temporal string for fast assignment
1232 obj_id.assign(fxs.get_xml_token().m_buf, len);
1233 OksObject * obj = c->get_object(obj_id);
1234
1235 if(!obj) {
1236 Set(c, new OksString(obj_id));
1237 goto final;
1238 }
1239
1240
1241 // final checks
1242
1243 read_params.owner->OksObject::check_class_type(r, c);
1244 Set(obj);
1245 obj->add_RCR(read_params.owner, r);
1246 }
1247 catch(exception& ex) {
1248 if(class_id) delete class_id;
1249 throw FailedRead("relationship value", ex);
1250 }
1251 catch (std::exception & ex) {
1252 if(class_id) delete class_id;
1253 throw FailedRead("relationship value", ex.what());
1254 }
1255
1256final:
1257
1258 IsConsistent(r, read_params.owner, "WARNING");
1259
1260}
1261
1262
1263void
1264OksData::read(const OksRelationship * r, const OksXmlRelValue& value)
1265{
1266 try
1267 {
1268 if (__builtin_expect((value.m_class == nullptr), 0))
1269 {
1270 if (value.m_class_id)
1271 {
1272 Set(value.m_class_id, new OksString(value.m_value.buf(), value.m_value.len()));
1273 value.m_class_id = nullptr;
1274 }
1275 else
1276 {
1277 Set((OksObject *) nullptr);
1278 }
1279
1280 goto final;
1281 }
1282
1283 OksObject * obj = value.m_class->get_object(value.m_value.buf());
1284
1285 if (!obj)
1286 {
1287 Set(value.m_class, new OksString(value.m_value.buf(), value.m_value.len()));
1288 goto final;
1289 }
1290
1291 // final checks
1292
1293 value.m_file_params.owner->OksObject::check_class_type(r, value.m_class);
1294 Set(obj);
1295 obj->add_RCR(value.m_file_params.owner, r);
1296 }
1297 catch (exception& ex)
1298 {
1299 if (value.m_class_id)
1300 delete value.m_class_id;
1301 throw FailedRead("relationship value", ex);
1302 }
1303 catch (std::exception & ex)
1304 {
1305 if (value.m_class_id)
1306 delete value.m_class_id;
1307 throw FailedRead("relationship value", ex.what());
1308 }
1309
1310 final:
1311
1312 IsConsistent(r, value.m_file_params.owner, "WARNING");
1313}
1314
1315void
1316OksData::read(const OksRelationship *r, const ReadFileParams& read_params)
1317{
1318 if (type != list_type)
1319 Set(new List());
1320 else if (!data.LIST->empty())
1321 free_list(*data.LIST);
1322
1323 while (true)
1324 try
1325 {
1326 const char * tag_start = read_params.s.get_tag_start();
1327
1328 // check for closing tag
1329 if (*tag_start == '/' && cmp_str4n(tag_start+1, OksObject::relationship_xml_tag))
1330 break;
1331
1332 if (cmp_str3(tag_start, OksObject::ref_xml_tag))
1333 {
1334 OksXmlRelValue value(read_params);
1335
1336 try {
1337 while(true) {
1338 OksXmlAttribute attr(read_params.s);
1339
1340 // check for close of tag
1341
1342 if(cmp_str1(attr.name(), ">") || cmp_str1(attr.name(), "/")) { break; }
1343
1344 // check for known oks-relationship' attributes
1345
1346 else if(cmp_str5(attr.name(), OksObject::class_xml_attribute)) {
1347 value.m_class = read_params.owner->uid.class_id->get_kernel()->find_class(attr.value());
1348 if( __builtin_expect((value.m_class == nullptr && attr.value_len() > 0), 0) ) {
1349 value.m_class_id = new OksString(attr.value(), attr.value_len());
1350 }
1351 }
1352 else if(cmp_str2(attr.name(), OksObject::id_xml_attribute)) {
1353 value.m_value = read_params.s.get_value(attr.p_value_len);
1354 }
1355 else
1356 read_params.s.throw_unexpected_attribute(attr.name());
1357 }
1358
1359 if(value.is_empty() == false)
1360 {
1361 OksData * d = new OksData(r, value);
1362
1363 // ignore dangling objects saved previously
1364 if( __builtin_expect((d->type == OksData::uid2_type && d->data.UID2.class_id->empty()), 0) ) continue;
1365
1366 // add real object
1367 data.LIST->push_back(d);
1368 }
1369 }
1370 catch(exception & e) {
1371 throw FailedRead("multi-value relationship", e);
1372 }
1373 catch (std::exception & e) {
1374 throw FailedRead("multi-value relationship", e.what());
1375 }
1376 }
1377 else
1378 {
1379 std::ostringstream s;
1380 s << "Unexpected tag \"" << tag_start << "\" (line " << read_params.s.get_line_no() << ", char " << read_params.s.get_line_pos() << ')';
1381 throw std::runtime_error(s.str().c_str());
1382 }
1383 }
1384 catch (exception & e)
1385 {
1386 throw FailedRead("multi-value", e);
1387 }
1388 catch (std::exception & e)
1389 {
1390 throw FailedRead("multi-value", e.what());
1391 }
1392}
1393
1394
1395 //
1396 // Writes to stream any OKS data except relationship types
1397 // (i.e. object, uid, uid2)
1398 //
1399
1400void
1401OksData::WriteTo(OksXmlOutputStream& xmls, bool put_number) const
1402{
1403 switch (type) {
1404 case list_type: {
1405 if(!data.LIST->empty()) {
1406 if(put_number) xmls.put_value((unsigned long)data.LIST->size());
1407 for(List::iterator i = data.LIST->begin(); i != data.LIST->end(); ++i) {
1408 if(!put_number) {
1409 xmls.put_raw('\n');
1410 xmls.put_raw(' ');
1411 }
1412
1413 xmls.put_raw(' ');
1414
1415 (*i)->WriteTo(xmls, put_number);
1416 }
1417
1418 if(!put_number)
1419 {
1420 xmls.put_raw('\n');
1421 xmls.put_raw(' ');
1422 }
1423 }
1424 else {
1425 if(put_number) xmls.put_raw('0');
1426 }
1427
1428 break; }
1429
1430 case string_type:
1431 xmls.put_quoted(data.STRING->c_str());
1432 break;
1433
1434 case s32_int_type:
1435 xmls.put_value(data.S32_INT);
1436 break;
1437
1438 case u32_int_type:
1439 xmls.put_value(data.U32_INT);
1440 break;
1441
1442 case s16_int_type:
1443 xmls.put_value(data.S16_INT);
1444 break;
1445
1446 case u16_int_type:
1447 xmls.put_value(data.U16_INT);
1448 break;
1449
1450 case float_type: {
1451 std::ostream& s = xmls.get_stream();
1452 std::streamsize p = s.precision();
1453 s.precision(std::numeric_limits< float >::digits10);
1454 xmls.put_value(data.FLOAT);
1455 s.precision(p);
1456 break; }
1457
1458 case double_type: {
1459 std::ostream& s = xmls.get_stream();
1460 std::streamsize p = s.precision();
1461 s.precision(std::numeric_limits< double >::digits10);
1462 xmls.put_value(data.DOUBLE);
1463 s.precision(p);
1464 break; }
1465
1466 case s8_int_type:
1467 xmls.put_value(static_cast<int16_t>(data.S8_INT));
1468 break;
1469
1470 case u8_int_type:
1471 xmls.put_value(static_cast<uint16_t>(data.U8_INT));
1472 break;
1473
1474 case s64_int_type:
1475 xmls.put_value(data.S64_INT);
1476 break;
1477
1478 case u64_int_type:
1479 xmls.put_value(data.U64_INT);
1480 break;
1481
1482 case bool_type:
1483 xmls.put_value((short)(data.BOOL));
1484 break;
1485
1486 case date_type:
1487 xmls.put_quoted(boost::gregorian::to_iso_string(date()).c_str());
1488 break;
1489
1490 case time_type:
1491 xmls.put_quoted(boost::posix_time::to_iso_string(time()).c_str());
1492 break;
1493
1494 case enum_type:
1495 xmls.put_quoted(data.ENUMERATION->c_str());
1496 break;
1497
1498 case class_type:
1499 xmls.put_quoted(data.CLASS->get_name().c_str());
1500 break;
1501
1502 case uid2_type:
1503 case uid_type:
1504 case object_type:
1505 case unknown_type:
1506 Oks::error_msg("OksData::WriteTo(OksXmlOutputStream&, bool)")
1507 << "Can't write \'" << (type == unknown_type ? "unknown" : "relationship") << "_type\'\n";
1508 break;
1509 }
1510}
1511
1512
1513void
1514OksData::WriteTo(OksXmlOutputStream& xmls) const
1515{
1516 switch (type) {
1517 case string_type:
1518 xmls.put(data.STRING->c_str());
1519 break;
1520
1521 case s32_int_type:
1522 xmls.put_value(data.S32_INT);
1523 break;
1524
1525 case u32_int_type:
1526 xmls.put_value(data.U32_INT);
1527 break;
1528
1529 case s16_int_type:
1530 xmls.put_value(data.S16_INT);
1531 break;
1532
1533 case u16_int_type:
1534 xmls.put_value(data.U16_INT);
1535 break;
1536
1537 case float_type: {
1538 std::ostream& s = xmls.get_stream();
1539 std::streamsize p = s.precision();
1540 s.precision(std::numeric_limits< float >::digits10);
1541 xmls.put_value(data.FLOAT);
1542 s.precision(p);
1543 break; }
1544
1545 case double_type: {
1546 std::ostream& s = xmls.get_stream();
1547 std::streamsize p = s.precision();
1548 s.precision(std::numeric_limits< double >::digits10);
1549 xmls.put_value(data.DOUBLE);
1550 s.precision(p);
1551 break; }
1552
1553 case s8_int_type:
1554 xmls.put_value(static_cast<int16_t>(data.S8_INT));
1555 break;
1556
1557 case u8_int_type:
1558 xmls.put_value(static_cast<uint16_t>(data.U8_INT));
1559 break;
1560
1561 case s64_int_type:
1562 xmls.put_value(data.S64_INT);
1563 break;
1564
1565 case u64_int_type:
1566 xmls.put_value(data.U64_INT);
1567 break;
1568
1569 case bool_type:
1570 xmls.put_value((short)(data.BOOL));
1571 break;
1572
1573 case date_type:
1574 xmls.put(boost::gregorian::to_iso_string(date()).c_str());
1575 break;
1576
1577 case time_type:
1578 xmls.put(boost::posix_time::to_iso_string(time()).c_str());
1579 break;
1580
1581 case enum_type:
1582 xmls.put(data.ENUMERATION->c_str());
1583 break;
1584
1585 case class_type:
1586 xmls.put(data.CLASS->get_name().c_str());
1587 break;
1588
1589 case list_type:
1590 throw std::runtime_error("internal error: call OksData::WriteTo() on list");
1591
1592 case uid2_type:
1593 case uid_type:
1594 case object_type:
1595 case unknown_type:
1596 Oks::error_msg("OksData::WriteTo(OksXmlOutputStream&, bool)")
1597 << "Can't write \'" << (type == unknown_type ? "unknown" : "relationship") << "_type\'\n";
1598 break;
1599 }
1600}
1601
1602
1603
1604 //
1605 // Writes to XML stream OKS data relationship types
1606 //
1607
1608void
1609OksData::WriteTo(OksXmlOutputStream& xmls, OksKernel *k, OksAliasTable *alias_table, bool /*test_existance*/, bool put_number) const
1610{
1611 const char * fname = "WriteTo(OksXmlOutputStream&, ...)";
1612
1613 static std::string emptyName(""); // to save NIL name
1614
1615 const std::string * class_name = 0;
1616 const std::string * object_id = 0;
1617
1618 switch (type) {
1619 case object_type:
1620 if(data.OBJECT) {
1621 class_name = &data.OBJECT->GetClass()->get_name();
1622 object_id = &data.OBJECT->GetId();
1623 }
1624 else
1625 class_name = object_id = &emptyName;
1626
1627 break;
1628
1629 case list_type: {
1630 if(!data.LIST->empty()) {
1631 if(put_number) xmls.put_value((unsigned long)data.LIST->size());
1632
1633 for(List::iterator i = data.LIST->begin(); i != data.LIST->end(); ++i) {
1634 if(!put_number) {
1635 xmls.put_raw('\n');
1636 xmls.put_raw(' ');
1637 }
1638
1639 xmls.put_raw(' ');
1640
1641 (*i)->WriteTo(xmls, k, alias_table, false, put_number);
1642 }
1643
1644 if(!put_number) {
1645 xmls.put_raw('\n');
1646 xmls.put_raw(' ');
1647 }
1648 }
1649 else {
1650 if(put_number) xmls.put_raw('0');
1651 }
1652
1653 return; }
1654
1655 case uid2_type:
1656 class_name = data.UID2.class_id;
1657 object_id = data.UID2.object_id;
1658 break;
1659
1660 case uid_type:
1661 class_name = &data.UID.class_id->get_name();
1662 object_id = data.UID.object_id;
1663 break;
1664
1665 default:
1666 Oks::error_msg(fname)
1667 << "Can't write \'" << (type == unknown_type ? "unknown" : "attribute") << "_type\'\n";
1668 return;
1669 }
1670
1671
1672 if(!class_name->empty()) {
1673
1674 // if alias table is not defined, store object in extended format
1675
1676 if(!alias_table) {
1677 xmls.put_quoted(class_name->c_str());
1678 }
1679
1680
1681 // otherwise store object in compact format
1682
1683 else {
1684 const OksAliasTable::Value *value = alias_table->get(static_cast<const OksString *>(class_name));
1685
1686 // class' alias was already defined
1687 if(value)
1688 xmls.put_quoted(value->class_name->c_str());
1689
1690 //makes new class' alias
1691 else {
1692 alias_table->add_key(static_cast<OksString *>(const_cast<std::string *>(class_name)));
1693
1694 std::string s(*class_name);
1695 s.insert(0, "@"); // add '@' to distinguish alias from class name when load
1696 xmls.put_quoted(s.c_str());
1697 }
1698 }
1699
1700 }
1701 else {
1702 xmls.put_quoted("");
1703 }
1704
1705 xmls.put_raw(' ');
1706 xmls.put_quoted(object_id->c_str());
1707}
1708
1709void
1710OksData::ConvertTo(OksData *to, const OksRelationship *r) const
1711{
1712 if(r->get_high_cardinality_constraint() == OksRelationship::Many) {
1713 to->Set(new List());
1714
1715 if(type != list_type) {
1716 OksData *item = new OksData();
1717
1718 if(type == OksData::object_type) item->Set(data.OBJECT);
1719 else if(type == OksData::uid_type) item->Set(data.UID.class_id, *data.UID.object_id);
1720 else if(type == OksData::uid2_type) item->Set(*data.UID2.class_id, *data.UID2.object_id);
1721
1722 to->data.LIST->push_back(item);
1723
1724 return;
1725 }
1726 else if(data.LIST && !data.LIST->empty()){
1727 for(List::iterator i = data.LIST->begin(); i != data.LIST->end(); ++i) {
1728 OksData *item = new OksData();
1729 OksData *dd = *i;
1730
1731 if(dd->type == OksData::object_type) item->Set(dd->data.OBJECT);
1732 else if(dd->type == OksData::uid_type) item->Set(dd->data.UID.class_id, *dd->data.UID.object_id);
1733 else if(dd->type == OksData::uid2_type) item->Set(*dd->data.UID2.class_id, *dd->data.UID2.object_id);
1734
1735 to->data.LIST->push_back(item);
1736 }
1737
1738 return;
1739 }
1740
1741 }
1742 else {
1743 const OksData * from = ((type == list_type) ? data.LIST->front() : this);
1744
1745 if(from->type == OksData::object_type) to->Set(from->data.OBJECT);
1746 else if(from->type == OksData::uid_type) to->Set(from->data.UID.class_id, *from->data.UID.object_id);
1747 else if(from->type == OksData::uid2_type) to->Set(*from->data.UID2.class_id, *from->data.UID2.object_id);
1748 }
1749}
1750
1751
1752void
1753OksData::cvt(OksData *to, const OksAttribute *a) const
1754{
1755 if(a->get_is_multi_values()) {
1756 to->Set(new List());
1757
1758 if(type != list_type) {
1759 OksData *item = new OksData();
1760
1761 std::string cvts = str();
1762 item->ReadFrom(cvts.c_str(), a->get_data_type(), a);
1763
1764 to->data.LIST->push_back(item);
1765
1766 return;
1767 }
1768 else if(data.LIST && !data.LIST->empty()) {
1769 for(List::iterator i = data.LIST->begin(); i != data.LIST->end(); ++i) {
1770 OksData *item = new OksData();
1771 OksData *dd = *i;
1772
1773 std::string cvts = dd->str();
1774 item->ReadFrom(cvts.c_str(), a->get_data_type(), a);
1775
1776 to->data.LIST->push_back(item);
1777 }
1778
1779 return;
1780 }
1781 }
1782 else {
1783 const OksData * from = ((type == list_type) ? (data.LIST->empty() ? 0 : data.LIST->front() ) : this);
1784 std::string cvts;
1785 if(from) cvts = from->str();
1786 to->ReadFrom(cvts.c_str(), a->get_data_type(), a);
1787 }
1788}
1789
1790
1791static std::string
1792list2str(const OksData::List * l, const OksKernel * k, int base)
1793{
1794 std::ostringstream s;
1795
1796 s << '(';
1797
1798 if(l) {
1799 bool is_first = true;
1800
1801 for(OksData::List::const_iterator i = l->begin(); i != l->end(); ++i) {
1802 std::string s2 = (k ? (*i)->str(k) : (*i)->str(base));
1803
1804 if(!s2.empty()) {
1805 if(is_first == false) { s << ", "; }
1806 else { is_first = false; }
1807 s << s2;
1808 }
1809 }
1810 }
1811
1812 s << ')';
1813
1814 return s.str();
1815}
1816
1817
1818
1819 // only is used for OksData pointing to objects
1820
1821std::string
1822OksData::str(const OksKernel * kernel) const
1823{
1824 if(type == list_type) {
1825 return list2str(data.LIST, kernel, 0);
1826 }
1827
1828 std::ostringstream s;
1829
1830 switch (type) {
1831 case uid2_type:
1832 s << "#[" << *data.UID2.object_id << '@' << *data.UID2.class_id << ']';
1833 break;
1834
1835 case uid_type:
1836 s << "#[" << *data.UID.object_id << '@' << data.UID.class_id->get_name() << ']';
1837 break;
1838
1839 case object_type:
1840 if(data.OBJECT && !kernel->is_dangling(data.OBJECT) && data.OBJECT->GetClass()->get_name().length()) {
1841 s << '[' << data.OBJECT->GetId() << '@' << data.OBJECT->GetClass()->get_name() << ']';
1842 }
1843 break;
1844
1845 default:
1846 std::cerr << "ERROR [OksData::str(const OksKernel *)]: wrong use for such data: " << *this << std::endl;
1847 return "";
1848 }
1849
1850 return s.str();
1851}
1852
1853
1854 // is only used for primitive data types
1855
1856std::string
1857OksData::str(int base) const
1858{
1859 if(type == string_type) { return *data.STRING; }
1860 else if(type == enum_type) { return *data.ENUMERATION; }
1861 else if(type == bool_type) { return (data.BOOL ? "true" : "false"); }
1862 else if(type == list_type) { return list2str(data.LIST, 0, base); }
1863 else if(type == date_type) { return boost::gregorian::to_simple_string(date()); }
1864 else if(type == time_type) { return boost::posix_time::to_simple_string(time()); }
1865 else if(type == class_type) { return data.CLASS->get_name(); }
1866
1867
1868 std::ostringstream s;
1869
1870 if(base) {
1871 s.setf((base == 10 ? std::ios::dec : base == 16 ? std::ios::hex : std::ios::oct), std::ios::basefield );
1872 s.setf(std::ios::showbase);
1873 }
1874
1875 switch (type) {
1876 case s8_int_type:
1877 s << static_cast<int16_t>(data.S8_INT);
1878 break;
1879
1880 case u8_int_type:
1881 s << static_cast<uint16_t>(data.U8_INT);
1882 break;
1883
1884 case s16_int_type:
1885 s << data.S16_INT;
1886 break;
1887
1888 case u16_int_type:
1889 s << data.U16_INT;
1890 break;
1891
1892 case s32_int_type:
1893 s << data.S32_INT;
1894 break;
1895
1896 case u32_int_type:
1897 s << data.U32_INT;
1898 break;
1899
1900 case s64_int_type:
1901 s << data.S64_INT;
1902 break;
1903
1904 case u64_int_type:
1905 s << data.U64_INT;
1906 break;
1907
1908 case float_type:
1909 s.precision(std::numeric_limits< float >::digits10);
1910 s << data.FLOAT;
1911 break;
1912
1913 case double_type:
1914 s.precision(std::numeric_limits< double >::digits10);
1915 s << data.DOUBLE;
1916 break;
1917
1918 default:
1919 std::cerr << "ERROR [OksData::str(int)]: wrong use for such data: " << *this << std::endl;
1920 return "";
1921 }
1922
1923 return s.str();
1924}
1925
1926
1927bool
1928OksData::IsConsistent(const OksRelationship *r, const OksObject *o, const char *msg)
1929{
1930 if(r->get_low_cardinality_constraint() != OksRelationship::Zero) {
1931 if(
1932 ( type == OksData::object_type && data.OBJECT == 0 ) ||
1933 ( type == OksData::uid_type && (!data.UID.object_id || data.UID.object_id->empty() || !data.UID.class_id) ) ||
1934 ( type == OksData::uid2_type && (!data.UID2.object_id || !data.UID2.class_id || data.UID2.object_id->empty() || data.UID2.class_id->empty()) )
1935 ) {
1936 if(o->GetClass()->get_kernel()->get_silence_mode() != true) {
1937 std::cerr << msg << ": value of \"" << r->get_name() << "\" relationship in object " << o << " must be non-null\n";
1938 }
1939 return false;
1940 }
1941 else if(type == OksData::list_type && data.LIST->empty()) {
1942 if(o->GetClass()->get_kernel()->get_silence_mode() != true) {
1943 std::cerr << msg << ": \"" << r->get_name() << "\" relationship in object " << o << " must contain at least one object\n";
1944 }
1945 return false;
1946 }
1947 }
1948
1949 return true;
1950}
1951
1952
1953
1954void
1955OksData::sort(bool ascending)
1956{
1957 if (type != list_type || data.LIST->size() < 2)
1958 return;
1959
1960 if (ascending)
1961 data.LIST->sort( []( const OksData* a, const OksData* b ) { return *a < *b; } );
1962 else
1963 data.LIST->sort( []( const OksData* a, const OksData* b ) { return *a > *b; } );
1964}
1965
1966 boost::posix_time::ptime str2time(const char * value, size_t len, const char * file_name)
1967 {
1968 if(len == 15 && value[8] == 'T') {
1969 try {
1970 return boost::posix_time::from_iso_string(value);
1971 }
1972 catch (std::exception& ex) {
1973 //throw TimeCvtFailed(value, ex.what());
1974 throw AttributeReadError(value, "time", ex.what());
1975 }
1976 }
1977 else {
1978 try {
1979 Time t(value);
1980 std::ostringstream text;
1981 text << std::setfill('0')
1982 << std::setw(4) << t.year()
1983 << std::setw(2) << (t.month() + 1)
1984 << std::setw(2) << t.day()
1985 << 'T'
1986 << std::setw(2) << t.hour()
1987 << std::setw(2) << t.min()
1988 << std::setw(2) << t.sec();
1989 TLOG_DEBUG( 1 ) << "parse OKS time: " << t << " => " << text.str() ;
1990
1991 if(file_name)
1992 ers::warning(DeprecatedFormat(ERS_HERE, file_name, value));
1993 else
1994 Oks::warning_msg("oks str2time") << "The file is using deprecated OKS time format \"" << value << "\"\nPlease refresh it using an oks application\nSupport for such format will be removed in a future release.\n";
1995
1996 return boost::posix_time::from_iso_string(text.str());
1997 }
1998 catch (exception& ex) {
1999 //throw TimeCvtFailed(value, ex);
2000 throw AttributeReadError(value, "time", ex);
2001 }
2002 catch (std::exception& ex) {
2003 //throw TimeCvtFailed(value, ex.what());
2004 throw AttributeReadError(value, "time", ex.what());
2005 }
2006 }
2007 }
2008
2009 boost::gregorian::date str2date(const char * value, size_t len)
2010 {
2011 if(len == 8 && value[2] != '/' && value[3] != '/') {
2012 try {
2013 return boost::gregorian::from_undelimited_string(value);
2014 }
2015 catch (std::exception& ex) {
2016 throw AttributeReadError(value, "date", ex.what());
2017 }
2018 }
2019 else {
2020 try {
2021 Date t(value);
2022 std::ostringstream text;
2023 text << std::setfill('0')
2024 << std::setw(4) << t.year()
2025 << std::setw(2) << (t.month() + 1)
2026 << std::setw(2) << t.day();
2027 TLOG_DEBUG( 1 ) << "parse OKS date: " << t << " => " << text.str() ;
2028
2029 Oks::warning_msg("oks str2date") << "The file is using deprecated OKS date format \"" << value << "\"\nPlease refresh it using an oks application.\nSupport for such format will be removed in a future release.\n";
2030
2031 return boost::gregorian::from_undelimited_string(text.str());
2032 }
2033 catch (exception& ex) {
2034 throw AttributeReadError(value, "date", ex);
2035 }
2036 catch (std::exception& ex) {
2037 throw AttributeReadError(value, "date", ex.what());
2038 }
2039 }
2040 }
2041
2042} // namespace oks
2043} // namespace dunedaq
#define ERS_DECLARE_ISSUE(namespace_name, class_name, message, attributes)
#define ERS_HERE
static std::string fill(const OksData *d, const std::string &range)
static std::string fill(const char *value, const char *type, const std::string &reason)
bool get_is_multi_values() const noexcept
const std::string & get_init_value() const noexcept
std::list< std::string > get_init_values() const
Return list of initial values for mv-attribute.
const std::string & get_name() const noexcept
Definition class.hpp:363
struct dunedaq::oks::OksObject::OksUid uid
static const char relationship_xml_tag[]
Definition object.hpp:1516
static const char attribute_xml_tag[]
Definition object.hpp:1515
static const char value_xml_attribute[]
Definition object.hpp:1525
static const char id_xml_attribute[]
Definition object.hpp:1519
const OksClass * GetClass() const
Definition object.hpp:990
static bool are_equal_fast(const OksObject *o1, const OksObject *o2)
The fast equal method.
Definition object.cpp:1600
static const char class_xml_attribute[]
Definition object.hpp:1517
static const char data_xml_tag[]
Definition object.hpp:1526
static const char ref_xml_tag[]
Definition object.hpp:1527
const std::string & GetId() const
Definition object.hpp:995
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
std::istream::pos_type pos
Definition xml.hpp:436
static std::ostream & warning_msg(const char *)
Definition kernel.cpp:563
static std::ostream & error_msg(const char *)
Definition kernel.cpp:556
caught dunedaq::conffwk::Exception exception
#define CMP_DATA(OP)
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
bool cmp_str1(const char *s1, const char s2[2])
Definition cstring.hpp:9
bool cmp_str4(const char *s1, const char s2[5])
Definition cstring.hpp:29
bool cmp_str5n(const char *s1, const char s2[5])
Definition cstring.hpp:41
bool operator==(const OksString &s1, const OksString &s2)
Implementation of OksString logical equality operator.
Definition object.hpp:388
boost::posix_time::ptime str2time(const char *value, size_t len, const char *file_name=nullptr)
std::ostream & operator<<(std::ostream &s, const oks::exception &ex)
boost::gregorian::date str2date(const char *value, size_t len)
bool cmp_str2(const char *s1, const char s2[3])
Definition cstring.hpp:13
bool cmp_str5(const char *s1, const char s2[6])
Definition cstring.hpp:37
bool cmp_str3(const char *s1, const char s2[4])
Definition cstring.hpp:21
bool cmp_str4n(const char *s1, const char s2[4])
Definition cstring.hpp:33
Including Qt Headers.
DAC value out of range
Message.
Definition DACNode.hpp:32
void warning(const Issue &issue)
Definition ers.hpp:115
Definition __init__.py:1
void Set(int8_t c)
Definition object.hpp:543
void sort(bool ascending=true)
void SetNullValue(const OksAttribute *a)
std::string str(int base=0) const
void cvt(OksData *to, const OksAttribute *attr) const
Convert data to new type.
union dunedaq::oks::OksData::Data data
boost::gregorian::date date() const noexcept
boost::posix_time::ptime time() const noexcept
void copy(const OksData &)
std::list< OksData *, boost::fast_pool_allocator< OksData * > > List
Definition object.hpp:455
bool operator>=(const OksData &) const
void SetE(OksString *s, const OksAttribute *a)
void SetValue(const char *s, const OksAttribute *a)
void read(const oks::ReadFileParams &, const OksAttribute *, int32_t)
private methods which can be used by OksObject class only
void WriteTo(OksXmlOutputStream &, bool) const
const std::string & __oid() const
bool is_g(const OksData &) const noexcept
bool operator>(const OksData &) const
const std::string & __cn() const
void SetValues(const char *, const OksAttribute *a)
void ConvertTo(OksData *, const OksRelationship *) const
static bool is_object(Type t)
Definition object.hpp:701
void check_range(const OksAttribute *a) const
Check range of data.
void SetFast(boost::gregorian::date d)
bool operator!=(const OksData &) const
friend class OksObject
Definition object.hpp:450
bool operator==(const OksData &) const
bool is_le(const OksData &) const noexcept
bool IsConsistent(const OksRelationship *r, const OksObject *o, const char *msg)
void ReadFrom(const char *, Type, const OksAttribute *)
Definition object.hpp:747
bool is_l(const OksData &) const noexcept
bool is_ge(const OksData &) const noexcept
bool operator<=(const OksData &) const
bool operator<(const OksData &) const
void realloc(unsigned long pos)
Definition xml.hpp:208
const OksClass * CLASS
Definition object.hpp:493
struct dunedaq::oks::OksData::Data::@165 UID
struct dunedaq::oks::OksData::Data::@166 UID2
const std::string * ENUMERATION
Definition object.hpp:507