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