LCOV - code coverage report
Current view: top level - oks/src - data.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 25.8 % 1176 303
Test Date: 2026-07-12 15:23:06 Functions: 34.4 % 64 22

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

Generated by: LCOV version 2.0-1