DABC (Data Acquisition Backbone Core)  2.9.9
Record.cxx
Go to the documentation of this file.
1 // $Id: Record.cxx 4725 2021-03-13 18:02:57Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/Record.h"
17 
18 #include <cstring>
19 #include <fnmatch.h>
20 
21 #include "dabc/Manager.h"
22 
24 {
25  if (!is_input()) return false;
26  uint32_t storesz(0);
27  read_uint32(storesz);
28 
29  return shift(((uint64_t) storesz)*8-4);
30 }
31 
32 
33 bool dabc::iostream::verify_size(uint64_t pos, uint64_t sz)
34 {
35  uint64_t actualsz = size() - pos;
36 
37  if (actualsz==sz) return true;
38 
39  if (pos % 8 != 0) { EOUT("start position not 8-byte aligned!!!"); return false; }
40 
41  if (!is_real()) {
42  // special case for size stream, we just shift until 8-byte alignment
43  uint64_t rest = size() % 8;
44  if (rest > 0) shift(8 - rest);
45  return true;
46  }
47 
48  if (sz % 8 != 0) { EOUT("size is not 8-byte aligned!!!"); return false; }
49 
50  if (actualsz > sz) {
51  EOUT("Too many bytes %lu was accessed in stream compared to provided %lu", (long unsigned) actualsz, (long unsigned) sz);
52  return false;
53  }
54 
55  if (is_input()) return shift(sz-actualsz);
56 
57  while (actualsz < sz) {
58  uint64_t buf(0);
59  uint64_t portion = sz - actualsz;
60  if (portion>8) portion = 8;
61  write(&buf, portion);
62  actualsz += portion;
63  }
64  return true;
65 }
66 
67 
68 uint64_t dabc::iostream::str_storesize(const std::string &str)
69 {
70  uint64_t res = sizeof(int32_t);
71  res += str.length() + 1; // null-terminated string will be stored
72  while (res % 8 != 0) res++;
73  return res;
74 }
75 
76 bool dabc::iostream::write_str(const std::string &str)
77 {
78  uint64_t sz = str_storesize(str);
79  if (sz > maxstoresize()) {
80  EOUT("Cannot store string in the buffer sz %lu maxsize %lu pos %lu real %s",
81  (long unsigned) sz, (long unsigned) maxstoresize(), (long unsigned) size(), DBOOL(is_real()));
82  return 0;
83  }
84 
85  uint64_t pos = size();
86 
87  uint32_t storesz = sz / 8;
88  write_uint32(storesz);
89  write(str.c_str(), str.length()+1);
90 
91  return verify_size(pos, sz);
92 }
93 
94 bool dabc::iostream::read_str(std::string& str)
95 {
96  uint64_t pos = size();
97 
98  uint32_t storesz(0);
99  read_uint32(storesz);
100  uint64_t sz = ((uint64_t) storesz) * 8;
101 
102  if (sz > tmpbuf_size()) {
103  EOUT("Cannot read complete string!!!");
104  return false;
105  }
106 
107  str.clear();
108  str.append(tmpbuf()); // null-terminated string
109  return verify_size(pos, sz);
110 }
111 
112 // ===========================================================================
113 
114 bool dabc::memstream::shift(uint64_t len)
115 {
116  if (len > fRemains) return false;
117  fCurr+=len;
118  fRemains-=len;
119  return true;
120 }
121 
122 bool dabc::memstream::write(const void* src, uint64_t len)
123 {
124  if (len > fRemains) return false;
125  memcpy(fCurr, src, len);
126  fCurr+=len;
127  fRemains-=len;
128  return true;
129 }
130 
131 
132 bool dabc::memstream::read(void* tgt, uint64_t len)
133 {
134  if (len > fRemains) return false;
135  memcpy(tgt, fCurr, len);
136  fCurr+=len;
137  fRemains-=len;
138  return true;
139 }
140 
141 
142 // ===============================================================================
143 
144 
145 void dabc::HStore::CreateNode(const char *nodename)
146 {
147  // starts new json node, will be closed by CloseNode
148 
149  if (isxml()) {
150  // starts new xml node, will be closed by CloseNode
151  buf.append(dabc::format("%*s<item", compact() > 0 ? 0 : lvl * 2, ""));
152  if (first_node) { buf.append(" xmlns:dabc=\"http://dabc.gsi.de/xhtml\""); first_node = false; }
153  if (nodename!=0)
154  buf.append(dabc::format(" _name=\"%s\"", nodename));
155  numchilds.push_back(0);
156  numflds.push_back(0);
157  lvl++;
158  } else {
159  buf.append(dabc::format("%*s{", (compact() > 0) ? 0 : lvl * 4, ""));
160  lvl++;
161  numflds.push_back(0);
162  numchilds.push_back(0);
163  if (nodename!=0)
164  SetField("_name", dabc::format("\"%s\"",nodename).c_str());
165  }
166 
167  first_node = false;
168 }
169 
170 void dabc::HStore::SetField(const char *field, const char *value)
171 {
172  // set field (json field) in current node
173 
174  if (numflds.back() < 0) {
175  EOUT("Not allowed to set fields (here %s) after any child was created", field);
176  return;
177  }
178 
179  if (isxml()) {
180 
181  buf.append(dabc::format(" %s=", field));
182  int vlen = strlen(value);
183 
184  const char* v = value;
185  const char* stop = value+vlen;
186 
187  if ((vlen > 1) && (value[0] == '\"') && (value[vlen-1] == '\"')) {
188  v++; stop--;
189  }
190 
191  buf.append("\"");
192 
193  while (v!=stop) {
194  switch (*v) {
195  case '<' : buf.append("&lt;"); break;
196  case '>' : buf.append("&gt;"); break;
197  case '&' : buf.append("&amp;"); break;
198  case '\'' : buf.append("&apos;"); break;
199  case '\"' : buf.append("&quot;"); break;
200  default: buf.append(v, 1); break;
201  }
202  v++;
203  }
204  buf.append("\"");
205 
206  } else {
207 
208  if (numflds.back()++ > 0) buf.append(",");
209  NewLine();
210  buf.append(dabc::format("%*s\"%s\"", (compact() > 0) ? 0 : lvl * 4 - 2, "", field));
211  switch(compact()) {
212  case 2: buf.append(": "); break;
213  case 3: buf.append(":"); break;
214  default: buf.append(" : ");
215  }
216  buf.append(value);
217 
218  }
219 }
220 
221 void dabc::HStore::CloseNode(const char * nodename)
222 {
223  // called when node should be closed
224  // depending from number of childs different json format is applied
225 
226  if (isxml()) {
227  lvl--;
228  if (numchilds.back() > 0) {
229  buf.append(dabc::format("%*s</item>", compact() > 0 ? 0 : lvl * 2, ""));
230  NewLine();
231  } else {
232  buf.append(dabc::format("/>"));
233  NewLine();
234  }
235  numchilds.pop_back();
236  numflds.pop_back();
237  } else {
238  CloseChilds();
239  numchilds.pop_back();
240  numflds.pop_back();
241  lvl--;
242  NewLine();
243  buf.append(dabc::format("%*s}", (compact() > 0) ? 0 : lvl * 4, ""));
244  }
245 }
246 
247 void dabc::HStore::BeforeNextChild(const char* basename)
248 {
249  // called before next child node created
250 
251  if (isxml()) {
252  if (numchilds.back()++ == 0) { buf.append(">"); NewLine(); }
253  return;
254  }
255 
256  // first of all, close field and mark that we did it
257  if (numflds.back() > 0) buf.append(",");
258  numflds.back() = -1;
259 
260  if (numchilds.back()++ == 0) {
261  NewLine();
262 
263  if (basename==0) basename = "_childs";
264 
265  buf.append(dabc::format("%*s\"%s\"", (compact() > 0) ? 0 : lvl * 4 - 2, "", basename));
266  switch(compact()) {
267  case 2: buf.append(": ["); break;
268  case 3: buf.append(":["); break;
269  default: buf.append(" : [");
270  }
271  } else {
272  buf.append(",");
273  }
274  NewLine();
275 }
276 
278 {
279  if (isxml()) return;
280 
281  if (numchilds.back() > 0) {
282  NewLine();
283  buf.append(dabc::format("%*s]", (compact() > 0) ? 0 : lvl * 4 - 2, ""));
284  numchilds.back() = 0;
285  numflds.back() = 1; // artificially mark that something was written
286  }
287 }
288 
289 
290 // ===========================================================================
291 
292 
294  fKind(kind_none),
295  fModified(false),
296  fTouched(false),
297  fProtected(false)
298 {
299  valueStr = nullptr; // reset all pointers if any
300 }
301 
303 {
304  if (isreadonly()) return true;
305  return false;
306 }
307 
309 {
310  fKind = kind_none;
311  fModified = false;
312  fTouched = false;
313 
314  switch (src.fKind) {
315  case kind_none: break;
316  case kind_bool: SetBool(src.valueInt!=0); break;
317  case kind_int: SetInt(src.valueInt); break;
318  case kind_datime: SetDatime(src.valueUInt); break;
319  case kind_uint: SetUInt(src.valueUInt); break;
320  case kind_double: SetDouble(src.valueDouble); break;
321  case kind_arrint: SetArrInt(src.valueInt, (int64_t*) src.arrInt); break;
322  case kind_arruint: SetArrUInt(src.valueInt, (uint64_t*) src.arrUInt); break;
323  case kind_arrdouble: SetArrDouble(src.valueInt, (double*) src.arrDouble); break;
324  case kind_string: SetStr(src.valueStr); break;
325  case kind_arrstr: SetArrStrDirect(src.valueInt, src.valueStr); break;
326  case kind_buffer: SetBuffer(*src.valueBuf); break;
327  case kind_reference: SetReference(*src.valueRef); break;
328  }
329 }
330 
332 {
333  release();
334 }
335 
337 {
338  sizestream s;
339  Stream(s);
340  return s.size();
341 }
342 
344 {
345  uint64_t pos = s.size();
346  uint64_t sz = 0;
347 
348  uint32_t storesz(0), storekind(0), storeversion(0);
349 
350  if (s.is_output()) {
351  sz = s.is_real() ? StoreSize() : 0;
352  storesz = sz / 8;
353  storekind = ((uint32_t)fKind & 0xffffff) | (storeversion << 24);
354  s.write_uint32(storesz);
355  s.write_uint32(storekind);
356  switch (fKind) {
357  case kind_none: break;
358  case kind_bool:
359  case kind_int: s.write_int64(valueInt); break;
360  case kind_datime:
361  case kind_uint: s.write_uint64(valueUInt); break;
362  case kind_double: s.write_double(valueDouble); break;
363  case kind_arrint:
364  s.write_int64(valueInt);
365  s.write(arrInt, valueInt*sizeof(int64_t));
366  break;
367  case kind_arruint:
368  s.write_int64(valueInt);
369  s.write(arrUInt, valueInt*sizeof(uint64_t));
370  break;
371  case kind_arrdouble:
372  s.write_int64(valueInt);
373  s.write(arrDouble, valueInt*sizeof(double));
374  break;
375  case kind_string:
376  s.write(valueStr, strlen(valueStr)+1);
377  break;
378  case kind_arrstr: {
379  int64_t fulllen = 0;
380  char* ps = valueStr;
381  for (int64_t n=0;n<valueInt;n++) {
382  int len = strlen(ps) + 1;
383  fulllen += len; ps += len;
384  }
385  s.write_int64(valueInt);
386  s.write(valueStr, fulllen);
387  break;
388  }
389  case kind_buffer:
390  s.write_uint64(valueBuf->SegmentSize());
391  s.write(valueBuf->SegmentPtr(), valueBuf->SegmentSize());
392  break;
393  case kind_reference:
394  // we do not write reference at all
395  break;
396  }
397  } else {
398  release();
399  s.read_uint32(storesz);
400  s.read_uint32(storekind);
401  sz = ((uint64_t) storesz) * 8;
402  // storeversion = storekind >> 24;
403 
404  fKind = (ValueKind) (storekind & 0xffffff);
405  switch (fKind) {
406  case kind_none: break;
407  case kind_bool:
408  case kind_int: s.read_int64(valueInt); break;
409  case kind_datime:
410  case kind_uint: s.read_uint64(valueUInt); break;
411  case kind_double: s.read_double(valueDouble); break;
412  case kind_arrint:
413  s.read_int64(valueInt);
414  arrInt = new int64_t[valueInt];
415  s.read(arrInt, valueInt*sizeof(int64_t));
416  break;
417  case kind_arruint:
418  s.read_int64(valueInt);
419  arrUInt = new uint64_t[valueInt];
420  s.read(arrUInt, valueInt*sizeof(uint64_t));
421  break;
422  case kind_arrdouble:
423  s.read_int64(valueInt);
424  arrDouble = new double[valueInt];
425  s.read(arrDouble, valueInt*sizeof(double));
426  break;
427  case kind_string:
428  valueStr = (char*) malloc((storesz-1)*8);
429  s.read(valueStr, (storesz-1)*8);
430  break;
431  case kind_arrstr: {
432  s.read_int64(valueInt);
433  valueStr = (char*) malloc((storesz-2)*8);
434  s.read(valueStr, (storesz-2)*8);
435  break;
436  }
437  case kind_buffer: {
438  uint64_t sz(0);
439  s.read_uint64(sz);
440  valueBuf = new Buffer;
441  *valueBuf = Buffer::CreateBuffer((storesz-1)*8);
442  s.read(valueBuf->SegmentPtr(), (storesz-1)*8);
443  if (sz != (storesz-1)*8) valueBuf->SetTotalSize(sz);
444  break;
445  }
446  case kind_reference:
447  // also do not read reference
448  valueRef = new Reference;
449  break;
450  }
451  }
452 
453  return s.verify_size(pos, sz);
454 }
455 
457 {
458  switch (fKind) {
459  case kind_none: break;
460  case kind_bool: break;
461  case kind_int: break;
462  case kind_datime: break;
463  case kind_uint: break;
464  case kind_double: break;
465  case kind_arrint: delete [] arrInt; arrInt = nullptr; break;
466  case kind_arruint: delete [] arrUInt; arrUInt = nullptr; break;
467  case kind_arrdouble: delete [] arrDouble; arrDouble = nullptr; break;
468  case kind_string:
469  case kind_arrstr: free(valueStr); valueStr = nullptr; break;
470  case kind_buffer: delete valueBuf; valueBuf = nullptr; break;
471  case kind_reference: delete valueRef; valueRef = nullptr; break;
472  }
473 
474  fKind = kind_none;
475 }
476 
477 bool dabc::RecordField::AsBool(bool dflt) const
478 {
479  switch (fKind) {
480  case kind_none: return dflt;
481  case kind_bool:
482  case kind_int: return valueInt!=0;
483  case kind_datime:
484  case kind_uint: return valueUInt!=0;
485  case kind_double: return valueDouble!=0.;
486  case kind_arrint: if (valueInt>0) return arrInt[0]!=0; break;
487  case kind_arruint: if (valueInt>0) return arrUInt[0]!=0; break;
488  case kind_arrdouble: if (valueInt>0) return arrDouble[0]!=0; break;
489  case kind_string:
490  case kind_arrstr: {
491  if (strcmp(valueStr,xmlTrueValue)==0) return true;
492  if (strcmp(valueStr,xmlFalseValue)==0) return false;
493  break;
494  }
495  case kind_buffer: if (valueBuf!=0) return valueBuf->SegmentSize()!=0; break;
496  case kind_reference: if (valueRef!=0) return !valueRef->null(); break;
497  }
498  return dflt;
499 }
500 
501 int64_t dabc::RecordField::AsInt(int64_t dflt) const
502 {
503  switch (fKind) {
504  case kind_none: return dflt;
505  case kind_bool:
506  case kind_int: return valueInt;
507  case kind_datime:
508  case kind_uint: return (int64_t) valueUInt;
509  case kind_double: return (int64_t) valueDouble;
510  case kind_arrint: if (valueInt>0) return arrInt[0]; break;
511  case kind_arruint: if (valueInt>0) return (int64_t) arrUInt[0]; break;
512  case kind_arrdouble: if (valueInt>0) return (int64_t) arrDouble[0]; break;
513  case kind_string:
514  case kind_arrstr: {
515  long res;
516  if (str_to_lint(valueStr, &res)) return res;
517  break;
518  }
519  case kind_buffer: return dflt;
520  case kind_reference: return dflt;
521  }
522  return dflt;
523 }
524 
525 uint64_t dabc::RecordField::AsUInt(uint64_t dflt) const
526 {
527  switch (fKind) {
528  case kind_none: return dflt;
529  case kind_bool:
530  case kind_int: return (uint64_t) valueInt;
531  case kind_datime:
532  case kind_uint: return valueUInt;
533  case kind_double: return (uint64_t) valueDouble;
534  case kind_arrint: if (valueInt>0) return (uint64_t) arrInt[0]; break;
535  case kind_arruint: if (valueInt>0) return arrUInt[0]; break;
536  case kind_arrdouble: if (valueInt>0) return (uint64_t) arrDouble[0]; break;
537  case kind_string:
538  case kind_arrstr: {
539  long unsigned res;
540  if (str_to_luint(valueStr, &res)) return res;
541  break;
542  }
543  case kind_buffer: return dflt;
544  case kind_reference: return dflt;
545  }
546  return dflt;
547 }
548 
549 double dabc::RecordField::AsDouble(double dflt) const
550 {
551  switch (fKind) {
552  case kind_none: return dflt;
553  case kind_bool:
554  case kind_int: return (double) valueInt;
555  case kind_datime:
556  case kind_uint: return (double) valueUInt;
557  case kind_double: return valueDouble;
558  case kind_arrint: if (valueInt>0) return (double) arrInt[0]; break;
559  case kind_arruint: if (valueInt>0) return (double) arrUInt[0]; break;
560  case kind_arrdouble: if (valueInt>0) return arrDouble[0]; break;
561  case kind_string:
562  case kind_arrstr: {
563  double res;
564  if (str_to_double(valueStr, &res)) return res;
565  break;
566  }
567  case kind_buffer: return dflt;
568  case kind_reference: return dflt;
569  }
570  return dflt;
571 }
572 
573 std::vector<int64_t> dabc::RecordField::AsIntVect() const
574 {
575  std::vector<int64_t> res;
576 
577  switch (fKind) {
578  case kind_none: break;
579  case kind_bool:
580  case kind_int: res.push_back(valueInt); break;
581  case kind_datime:
582  case kind_uint: res.push_back((int64_t) valueUInt); break;
583  case kind_double: res.push_back((int64_t) valueDouble); break;
584  case kind_arrint:
585  res.reserve(valueInt);
586  for (int64_t n=0;n<valueInt;n++)
587  res.push_back(arrInt[n]);
588  break;
589  case kind_arruint:
590  res.reserve(valueInt);
591  for (int64_t n=0;n<valueInt;n++)
592  res.push_back((int64_t) arrUInt[n]);
593  break;
594  case kind_arrdouble:
595  res.reserve(valueInt);
596  for (int64_t n=0;n<valueInt;n++)
597  res.push_back((int64_t) arrDouble[n]);
598  break;
599  case kind_string: {
600  std::vector<std::string> svect;
601  long res0;
602  // try to convert string in vector
603  if (StrToStrVect(valueStr, svect, false)) {
604  for (unsigned n=0;n<svect.size();n++)
605  if (str_to_lint(svect[n].c_str(), &res0))
606  res.push_back(res0);
607  break;
608  }
609  if (str_to_lint(valueStr, &res0)) res.push_back(res0);
610  break;
611  }
612  case kind_arrstr: {
613  res.reserve(valueInt);
614  long res0;
615  char* p = valueStr;
616 
617  for (int64_t n=0;n<valueInt;n++) {
618  if (!str_to_lint(p, &res0)) res0 = 0;
619  res.push_back(res0);
620  p += strlen(p)+1;
621  }
622  break;
623  }
624  case kind_buffer: break;
625  case kind_reference: break;
626  }
627 
628  return res;
629 }
630 
631 std::vector<uint64_t> dabc::RecordField::AsUIntVect() const
632 {
633  std::vector<uint64_t> res;
634 
635  switch (fKind) {
636  case kind_none: break;
637  case kind_bool:
638  case kind_int: res.push_back((uint64_t) valueInt); break;
639  case kind_datime:
640  case kind_uint: res.push_back(valueUInt); break;
641  case kind_double: res.push_back((uint64_t) valueDouble); break;
642  case kind_arrint:
643  res.reserve(valueInt);
644  for (int64_t n=0;n<valueInt;n++)
645  res.push_back((uint64_t) arrInt[n]);
646  break;
647  case kind_arruint:
648  res.reserve(valueInt);
649  for (int64_t n=0;n<valueInt;n++)
650  res.push_back(arrUInt[n]);
651  break;
652  case kind_arrdouble:
653  res.reserve(valueInt);
654  for (int64_t n=0;n<valueInt;n++)
655  res.push_back((uint64_t) arrDouble[n]);
656  break;
657  case kind_string: {
658  std::vector<std::string> svect;
659  long unsigned res0;
660  // try to convert string in vector
661  if (StrToStrVect(valueStr, svect, false)) {
662  for (unsigned n=0;n<svect.size();n++)
663  if (str_to_luint(svect[n].c_str(), &res0))
664  res.push_back(res0);
665  break;
666  }
667 
668  if (str_to_luint(valueStr, &res0)) res.push_back(res0);
669  break;
670  }
671  case kind_arrstr: {
672  res.reserve(valueInt);
673  long unsigned res0;
674  char* p = valueStr;
675 
676  for (int64_t n=0;n<valueInt;n++) {
677  if (!str_to_luint(p, &res0)) res0 = 0;
678  res.push_back(res0);
679  p += strlen(p)+1;
680  }
681  break;
682  }
683  case kind_buffer: break;
684  case kind_reference: break;
685  }
686 
687  return res;
688 }
689 
690 
691 std::vector<double> dabc::RecordField::AsDoubleVect() const
692 {
693  std::vector<double> res;
694 
695  switch (fKind) {
696  case kind_none: break;
697  case kind_bool:
698  case kind_int: res.push_back((double) valueInt); break;
699  case kind_datime:
700  case kind_uint: res.push_back((double) valueUInt); break;
701  case kind_double: res.push_back(valueDouble); break;
702  case kind_arrint:
703  res.reserve(valueInt);
704  for (int64_t n=0;n<valueInt;n++)
705  res.push_back((double) arrInt[n]);
706  break;
707  case kind_arruint:
708  res.reserve(valueInt);
709  for (int64_t n=0;n<valueInt;n++)
710  res.push_back((double) arrUInt[n]);
711  break;
712  case kind_arrdouble:
713  res.reserve(valueInt);
714  for (int64_t n=0;n<valueInt;n++)
715  res.push_back(arrDouble[n]);
716  break;
717  case kind_string: {
718  std::vector<std::string> svect;
719  double res0;
720  // try to convert string in vector
721  if (StrToStrVect(valueStr, svect, false)) {
722  for (unsigned n=0;n<svect.size();n++)
723  if (str_to_double(svect[n].c_str(), &res0))
724  res.push_back(res0);
725  break;
726  }
727  if (str_to_double(valueStr, &res0)) res.push_back(res0);
728  break;
729  }
730  case kind_arrstr: {
731  res.reserve(valueInt);
732  double res0;
733  char* p = valueStr;
734 
735  for (int64_t n=0;n<valueInt;n++) {
736  if (!str_to_double(p, &res0)) res0 = 0.;
737  res.push_back(res0);
738  p += strlen(p)+1;
739  }
740  break;
741  }
742  case kind_buffer: break;
743  case kind_reference: break;
744  }
745 
746  return res;
747 }
748 
749 std::string dabc::RecordField::AsStr(const std::string &dflt) const
750 {
751  switch (fKind) {
752  case kind_none: return dflt;
753  case kind_bool: return valueInt!=0 ? xmlTrueValue : xmlFalseValue;
754  case kind_int: return dabc::format("%ld", (long) valueInt);
755  case kind_datime: {
756  std::string res = dabc::DateTime(valueUInt).AsJSString(3);
757  return res.empty() ? dflt : res;
758  }
759  case kind_uint: return dabc::format("%lu", (long unsigned) valueUInt);
760  case kind_double: return dabc::format("%g", valueDouble);
761  case kind_arrint:
762  case kind_arruint:
763  case kind_arrdouble:
764  case kind_arrstr: {
765 
766  std::vector<std::string> vect = AsStrVect();
767  if (vect.size()==0) return dflt;
768 
769  std::string res("[");
770  for (unsigned n=0; n<vect.size();n++) {
771  if (n>0) res.append(",");
772  res.append("\"");
773  if (NeedJsonReformat(vect[n]))
774  res.append(JsonReformat(vect[n]));
775  else
776  res.append(vect[n]);
777  res.append("\"");
778  }
779  res.append("]");
780  return res;
781  }
782  case kind_string: {
783  if (valueStr!=0) return valueStr;
784  break;
785  }
786  case kind_buffer: return dflt;
787  case kind_reference: return dflt;
788  }
789  return dflt;
790 }
791 
792 bool dabc::RecordField::NeedJsonReformat(const std::string &str)
793 {
794  // here we have situation that both single and double quotes present
795  // first try to define which kind quotes preceding with escape character
796 
797  for (unsigned n=0;n<str.length();n++)
798  switch (str[n]) {
799  case '\n':
800  case '\t':
801  case '\"':
802  case '\\':
803  case '\b':
804  case '\f':
805  case '\r':
806  case '/': return true;
807  default: if ((str[n] < 32) || (str[n]>126)) return true;
808  }
809 
810  return false;
811 }
812 
813 std::string dabc::RecordField::JsonReformat(const std::string &str)
814 {
815  std::string res;
816 
817  for (unsigned n = 0; n<str.length(); n++)
818  switch(str[n]) {
819  case '\n': res.append("\\n"); break;
820  case '\t': res.append("\\t"); break;
821  case '\"': res.append("\\\""); break;
822  case '\\': res.append("\\\\"); break;
823  case '\b': res.append("\\b"); break;
824  case '\f': res.append("\\f"); break;
825  case '\r': res.append("\\r"); break;
826  case '/': res.append("\\/"); break;
827  default:
828  if ((str[n] > 31) && (str[n]<127)) res.append(1, str[n]);
829  else res.append(dabc::format("\\u%04x", (unsigned) str[n]));
830  }
831 
832  return res;
833 }
834 
835 std::string dabc::RecordField::AsJson() const
836 {
837  switch (fKind) {
838  case kind_none: return "null";
839  case kind_bool: return valueInt!=0 ? "true" : "false";
840  case kind_int: return dabc::format("%ld", (long) valueInt);
841  case kind_datime: {
842  std::string res = dabc::DateTime(valueUInt).AsJSString(3);
843  if (res.length()>0)
844  return dabc::format("\"%s\"", res.c_str());
845  break;
846  }
847  case kind_uint: return dabc::format("%lu", (long unsigned) valueUInt);
848  case kind_double: return dabc::format("%g", valueDouble);
849  case kind_arrint: {
850  std::string res("[");
851  for (int64_t n=0; n<valueInt;n++) {
852  if (n>0) res.append(",");
853  res.append(dabc::format("%ld", (long) arrInt[n]));
854  }
855  res.append("]");
856  return res;
857  }
858  case kind_arruint: {
859  std::string res("[");
860  for (int64_t n=0; n<valueInt;n++) {
861  if (n>0) res.append(",");
862  res.append(dabc::format("%lu", (long unsigned) arrUInt[n]));
863  }
864  res.append("]");
865  return res;
866  }
867  case kind_arrdouble: {
868  std::string res("[");
869  for (int64_t n=0; n<valueInt;n++) {
870  if (n>0) res.append(",");
871  res.append(dabc::format("%g", arrDouble[n]));
872  }
873  res.append("]");
874  return res;
875  }
876  case kind_arrstr: {
877 
878  std::vector<std::string> vect = AsStrVect();
879 
880  std::string res("[");
881  for (unsigned n=0; n<vect.size();n++) {
882  if (n>0) res.append(",");
883  res.append("\"");
884  if (NeedJsonReformat(vect[n]))
885  res.append(JsonReformat(vect[n]));
886  else
887  res.append(vect[n]);
888  res.append("\"");
889  }
890  res.append("]");
891  return res;
892  }
893  case kind_string: {
894  if (valueStr==0) return "\"\"";
895  std::string res("\"");
896  if (NeedJsonReformat(valueStr))
897  res.append(JsonReformat(valueStr));
898  else
899  res.append(valueStr);
900  res.append("\"");
901  return res;
902  }
903  case kind_buffer: {
904  if (valueBuf==0) return "null";
905  std::string res("[");
906  uint8_t* ptr = (uint8_t*) valueBuf->SegmentPtr();
907  for (unsigned n=0;n<valueBuf->SegmentSize();n++) {
908  if (n>0) res.append(",");
909  res.append(dabc::format("0x%02x", (unsigned) ptr[n]));
910  }
911  res.append("]");
912  return res;
913  }
914  case kind_reference: {
915  if (valueRef==0) return "null";
916  // no idea how to store reference
917  return "\"<Refernce>\"";
918  }
919  }
920  return "null";
921 }
922 
923 std::vector<std::string> dabc::RecordField::AsStrVect() const
924 {
925  std::vector<std::string> res;
926 
927  switch (fKind) {
928  case kind_none: break;
929  case kind_bool:
930  case kind_int:
931  case kind_datime:
932  case kind_uint:
933  case kind_double: res.push_back(AsStr()); break;
934  case kind_arrint: {
935  for (int64_t n=0; n<valueInt;n++)
936  res.push_back(dabc::format("%ld", (long) arrInt[n]));
937  break;
938  }
939  case kind_arruint: {
940  for (int64_t n=0; n<valueInt;n++)
941  res.push_back(dabc::format("%lu", (long unsigned) arrUInt[n]));
942  break;
943  }
944  case kind_arrdouble: {
945  for (int64_t n=0; n<valueInt;n++)
946  res.push_back(dabc::format("%g", arrDouble[n]));
947  break;
948  }
949  case kind_string: {
950  if (!StrToStrVect(valueStr, res))
951  res.push_back(valueStr);
952  break;
953  }
954  case kind_arrstr: {
955  char* p = valueStr;
956  for (int64_t n=0;n<valueInt;n++) {
957  res.push_back(p);
958  p += strlen(p)+1;
959  }
960  break;
961  }
962  case kind_buffer: break;
963  case kind_reference: break;
964  }
965 
966  return res;
967 }
968 
970 {
971  if (fKind != kind_buffer) return dabc::Buffer();
972 
973  return *valueBuf;
974 }
975 
977 {
978  if (fKind != kind_reference) return dabc::Reference();
979 
980  return *valueRef;
981 }
982 
983 bool dabc::RecordField::StrToStrVect(const char* str, std::vector<std::string>& vect, bool verbose)
984 {
985  int len = strlen(str);
986 
987  if ((len<2) || (str[0]!='[') || (str[len-1]!=']')) return false;
988 
989  const char* pos = str + 1;
990 
991  while (*pos != 0) {
992  while (*pos==' ') pos++; // exclude possible spaces in the begin
993  if ((*pos=='\'') || (*pos == '\"')) {
994  const char* p1 = strchr(pos+1, *pos);
995  if (p1==0) {
996  if (verbose) EOUT("Error syntax in array %s after char:%u - closing quote not found ", str, (unsigned) (pos - str));
997  vect.clear();
998  return false;
999  }
1000  vect.push_back(std::string(pos+1, p1 - pos - 1));
1001  pos = p1 + 1;
1002  } else {
1003  const char* p1 = strpbrk(pos+1, ",]");
1004  if (p1==0) {
1005  if (verbose) EOUT("Error syntax in array %s after char:%u - ',' or ']' not found ", str, (unsigned) (pos - str));
1006  vect.clear();
1007  return false;
1008  }
1009  int spaces = 0;
1010  while ((p1 - spaces > pos + 1) && (*(p1-spaces-1)==' ')) spaces++;
1011  vect.push_back(std::string(pos, p1 - pos - spaces));
1012  pos = p1;
1013  }
1014  while (*pos==' ') pos++; // exclude possible spaces at the end
1015 
1016  // this is end of the array
1017  if (*pos==']') break;
1018 
1019  if (*pos != ',') {
1020  if (verbose) EOUT("Error syntax in array %s char:%u - expected ',' ", str, (unsigned) (pos - str));
1021  break;
1022  }
1023  pos++;
1024  }
1025 
1026  return true;
1027 }
1028 
1029 
1031 {
1032  switch (src.fKind) {
1033  case kind_none: return SetNull();
1034  case kind_bool: return SetBool(src.valueInt!=0);
1035  case kind_int: return SetInt(src.valueInt);
1036  case kind_datime: return SetDatime(src.valueUInt);
1037  case kind_uint: return SetUInt(src.valueUInt);
1038  case kind_double: return SetDouble(src.valueDouble);
1039  case kind_arrint: return SetArrInt(src.valueInt, (int64_t*) src.arrInt);
1040  case kind_arruint: return SetArrUInt(src.valueInt, (uint64_t*) src.arrUInt);
1041  case kind_arrdouble: return SetArrDouble(src.valueInt, (double*) src.arrDouble);
1042  case kind_string: return SetStr(src.valueStr);
1043  case kind_arrstr: return SetArrStr(src.valueInt, src.valueStr);
1044  case kind_buffer: return SetBuffer(*src.valueBuf);
1045  case kind_reference: return SetReference(*src.valueRef);
1046  }
1047  return false;
1048 }
1049 
1050 
1052 {
1053  if (cannot_modify()) return false;
1054  if (fKind == kind_none) return modified(false);
1055  release();
1056  return modified();
1057 }
1058 
1059 
1061 {
1062  if (cannot_modify()) return false;
1063 
1064  if ((fKind == kind_bool) && (valueInt == (v ? 1 : 0))) return modified(false);
1065 
1066  release();
1067  fKind = kind_bool;
1068  valueInt = v ? 1 : 0;
1069 
1070  return modified();
1071 }
1072 
1074 {
1075  if (cannot_modify()) return false;
1076  if ((fKind == kind_int) && (valueInt == v)) return modified(false);
1077  release();
1078  fKind = kind_int;
1079  valueInt = v;
1080  return modified();
1081 }
1082 
1084 {
1085  if (cannot_modify()) return false;
1086  if ((fKind == kind_datime) && (valueUInt == v)) return modified(false);
1087 
1088  release();
1089  fKind = kind_datime;
1090  valueUInt = v;
1091 
1092  return modified();
1093 }
1094 
1096 {
1097  return SetDatime(v.AsJSDate());
1098 }
1099 
1100 
1102 {
1103  if (cannot_modify()) return false;
1104 
1105  if ((fKind == kind_uint) && (valueUInt == v)) return modified(false);
1106 
1107  release();
1108  fKind = kind_uint;
1109  valueUInt = v;
1110 
1111  return modified();
1112 }
1113 
1115 {
1116  if (cannot_modify()) return false;
1117 
1118  if ((fKind == kind_double) && (valueDouble == v)) return modified(false);
1119 
1120  release();
1121  fKind = kind_double;
1122  valueDouble = v;
1123 
1124  return modified();
1125 }
1126 
1127 bool dabc::RecordField::SetStr(const std::string &v)
1128 {
1129  if (cannot_modify()) return false;
1130 
1131  if ((fKind == kind_string) && (v==valueStr)) return modified(false);
1132 
1133  release();
1134  size_t len = v.length();
1135  valueStr = (char*) malloc(len+1);
1136  if (!valueStr) return false;
1137 
1138  fKind = kind_string;
1139  strncpy(valueStr, v.c_str(), len+1);
1140 
1141  return modified();
1142 }
1143 
1144 bool dabc::RecordField::SetStr(const char* v)
1145 {
1146  if (cannot_modify()) return false;
1147 
1148  if ((fKind == kind_string) && v && (strcmp(v,valueStr)==0)) return modified(false);
1149 
1150  release();
1151  size_t len = !v ? 0 : strlen(v);
1152  valueStr = (char*) malloc(len+1);
1153  if (!valueStr) return false;
1154 
1155  fKind = kind_string;
1156  if (v) strncpy(valueStr, v, len+1);
1157  else *valueStr = 0;
1158 
1159  return modified();
1160 }
1161 
1162 bool dabc::RecordField::SetStrVect(const std::vector<std::string> &vect)
1163 {
1164  if (cannot_modify()) return false;
1165 
1166  if ((fKind == kind_arrstr) && (valueInt == (int64_t) vect.size())) {
1167  std::vector<std::string> vect0 = AsStrVect();
1168  if (vect0.size() == vect.size()) {
1169  bool diff = false;
1170  for (unsigned n=0;n<vect.size();n++)
1171  if (vect[n]!=vect0[n]) diff = true;
1172  if (!diff) return modified(false);
1173  }
1174  }
1175 
1176  release();
1177 
1178  size_t len = 0;
1179  for (unsigned n=0;n<vect.size();n++)
1180  len += vect[n].length()+1;
1181  valueStr = (char *) malloc(len);
1182  if (!valueStr) return false;
1183 
1184  fKind = kind_arrstr;
1185  valueInt = (int64_t) vect.size();
1186 
1187  char *p = valueStr;
1188 
1189  for (unsigned n=0;n<vect.size();n++) {
1190  strncpy(p, vect[n].c_str(), vect[n].length()+1);
1191  p += vect[n].length()+1;
1192  }
1193 
1194  return modified();
1195 }
1196 
1198 {
1199  if (cannot_modify()) return false;
1200 
1201  release();
1202 
1203  fKind = kind_buffer;
1204  valueBuf = new Buffer;
1205  *valueBuf = buf;
1206 
1207  return modified();
1208 }
1209 
1211 {
1212  if (cannot_modify()) return false;
1213 
1214  release();
1215 
1216  fKind = kind_reference;
1217  valueRef = new Reference;
1218  *valueRef = ref;
1219 
1220  return modified();
1221 }
1222 
1223 
1224 bool dabc::RecordField::SetArrInt(int64_t size, int64_t* arr, bool owner)
1225 {
1226  if (cannot_modify() || (size<=0)) {
1227  if (owner) delete[] arr;
1228  return false;
1229  }
1230 
1231  if ((fKind == kind_arrint) && (size==valueInt))
1232  if (memcmp(arrInt, arr, size*sizeof(int64_t))==0)
1233  {
1234  if (owner) delete[] arr;
1235  return modified(false);
1236  }
1237 
1238  release();
1239  fKind = kind_arrint;
1240  valueInt = size;
1241  if (owner) {
1242  arrInt = arr;
1243  } else {
1244  arrInt = new int64_t[size];
1245  memcpy(arrInt, arr, size*sizeof(int64_t));
1246  }
1247 
1248  return modified();
1249 }
1250 
1251 bool dabc::RecordField::SetVectInt(const std::vector<int64_t>& v)
1252 {
1253  int64_t* arr = 0;
1254  if (v.size()>0) {
1255  arr = new int64_t[v.size()];
1256  for (unsigned n=0;n<v.size();n++)
1257  arr[n] = v[n];
1258  }
1259  return SetArrInt(v.size(), arr, true);
1260 }
1261 
1262 
1263 bool dabc::RecordField::SetArrUInt(int64_t size, uint64_t* arr, bool owner)
1264 {
1265  if (cannot_modify()) return false;
1266  if (size<=0) return false;
1267 
1268  if ((fKind == kind_arruint) && (valueInt == size))
1269  if (memcmp(arrUInt, arr, size*sizeof(uint64_t))==0) {
1270  if (owner) delete [] arr;
1271  return modified(false);
1272  }
1273 
1274  release();
1275  fKind = kind_arruint;
1276  valueInt = size;
1277  if (owner) {
1278  arrUInt = arr;
1279  } else {
1280  arrUInt = new uint64_t[size];
1281  memcpy(arrUInt, arr, size*sizeof(uint64_t));
1282  }
1283 
1284  return modified();
1285 }
1286 
1287 bool dabc::RecordField::SetVectUInt(const std::vector<uint64_t>& v)
1288 {
1289  uint64_t* arr = 0;
1290  if (v.size()>0) {
1291  arr = new uint64_t[v.size()];
1292  for (unsigned n=0;n<v.size();n++)
1293  arr[n] = v[n];
1294  }
1295  return SetArrUInt(v.size(), arr, true);
1296 }
1297 
1298 
1299 bool dabc::RecordField::SetVectDouble(const std::vector<double>& v)
1300 {
1301  double* arr = 0;
1302  if (v.size()>0) {
1303  arr = new double[v.size()];
1304  for (unsigned n=0;n<v.size();n++)
1305  arr[n] = v[n];
1306  }
1307 
1308  return SetArrDouble(v.size(), arr, true);
1309 }
1310 
1311 
1312 bool dabc::RecordField::SetArrDouble(int64_t size, double* arr, bool owner)
1313 {
1314  if (cannot_modify()) return false;
1315  if (size<=0) return false;
1316 
1317  if ((fKind == kind_arrdouble) && (valueInt == size))
1318  if (memcmp(arrDouble, arr, size*sizeof(double))==0) {
1319  if (owner) delete[] arr;
1320  return modified(false);
1321  }
1322 
1323  release();
1324  fKind = kind_arrdouble;
1325  valueInt = size;
1326  if (owner) {
1327  arrDouble = arr;
1328  } else {
1329  arrDouble = new double[size];
1330  memcpy(arrDouble, arr, size*sizeof(double));
1331  }
1332 
1333  return modified();
1334 }
1335 
1336 bool dabc::RecordField::SetArrStr(int64_t size, char* arr, bool owner)
1337 {
1338  if (cannot_modify()) return false;
1339  if (size<0) return false;
1340  // TODO: check if content was not changed
1341  release();
1342  SetArrStrDirect(size, arr, owner);
1343  return modified();
1344 }
1345 
1346 
1347 void dabc::RecordField::SetArrStrDirect(int64_t size, char* arr, bool owner)
1348 {
1349  fKind = kind_arrstr;
1350  valueInt = size;
1351  if (owner) {
1352  valueStr = arr;
1353  } else {
1354  int fullsize = 0;
1355  const char* p = arr;
1356  for (unsigned n=0;n<size;n++) {
1357  int len = strlen(p);
1358  fullsize += len+1;
1359  p+=len+1;
1360  }
1361  valueStr = (char*) malloc(fullsize);
1362  if (valueStr)
1363  memcpy(valueStr, arr, fullsize);
1364  else
1365  fKind = kind_none;
1366  }
1367 }
1368 
1369 
1370 // =========================================================================
1371 
1373  fMap(),
1374  fChanged(false)
1375 {
1376 }
1377 
1379 {
1380 }
1381 
1382 bool dabc::RecordFieldsMap::HasField(const std::string &name) const
1383 {
1384  return fMap.find(name) != fMap.end();
1385 }
1386 
1387 bool dabc::RecordFieldsMap::RemoveField(const std::string &name)
1388 {
1389  FieldsMap::iterator iter = fMap.find(name);
1390  if (iter==fMap.end()) return false;
1391  fMap.erase(iter);
1392  fChanged = true;
1393  return true;
1394 }
1395 
1396 
1397 std::string dabc::RecordFieldsMap::FieldName(unsigned n) const
1398 {
1399  if (n>=fMap.size()) return "";
1400 
1401  for (FieldsMap::const_iterator iter = fMap.begin(); iter!=fMap.end(); iter++) {
1402  if (n==0) return iter->first;
1403  n--;
1404  }
1405 
1406  return "";
1407 }
1408 
1410 {
1411  if (fChanged) return true;
1412 
1413  for (FieldsMap::const_iterator iter = fMap.begin(); iter!=fMap.end(); iter++)
1414  if (iter->second.IsModified()) return true;
1415 
1416  return false;
1417 }
1418 
1419 
1420 bool dabc::RecordFieldsMap::WasChangedWith(const std::string &prefix)
1421 {
1422  // returns true when field with specified prefix was modified
1423 
1424  for (auto &&fld: fMap) {
1425  if (fld.second.IsModified())
1426  if (fld.first.find(prefix)==0) return true;
1427  }
1428 
1429  return false;
1430 }
1431 
1432 
1434 {
1435  fChanged = false;
1436  for (auto &&fld: fMap)
1437  fld.second.SetModified(false);
1438 }
1439 
1441 {
1443 
1444  for (FieldsMap::iterator iter = fMap.begin(); iter!=fMap.end(); iter++)
1445  res->Field(iter->first).SetValue(iter->second);
1446 
1447  return res;
1448 }
1449 
1450 uint64_t dabc::RecordFieldsMap::StoreSize(const std::string &nameprefix)
1451 {
1452  sizestream s;
1453  Stream(s, nameprefix);
1454  return s.size();
1455 }
1456 
1457 bool dabc::RecordFieldsMap::match_prefix(const std::string &name, const std::string &prefix)
1458 {
1459  if (name.empty()) return false;
1460  // all fields started with # are invisible for I/O
1461  if (name[0]=='#') return false;
1462 
1463  return prefix.empty() || (name.find(prefix) == 0);
1464 }
1465 
1466 
1467 bool dabc::RecordFieldsMap::Stream(iostream& s, const std::string &nameprefix)
1468 {
1469  uint32_t storesz(0), storenum(0), storevers(0);
1470  uint64_t sz(0);
1471 
1472  uint64_t pos = s.size();
1473 
1474  if (s.is_output()) {
1475  sz = s.is_real() ? StoreSize(nameprefix) : 0;
1476  storesz = sz/8;
1477  storenum = 0;
1478  for (FieldsMap::iterator iter = fMap.begin(); iter!=fMap.end(); iter++) {
1479  if (match_prefix(iter->first, nameprefix)) storenum++;
1480  }
1481 
1482  s.write_uint32(storesz);
1483  s.write_uint32(storenum | (storevers<<24));
1484 
1485  for (FieldsMap::iterator iter = fMap.begin(); iter!=fMap.end(); iter++) {
1486  if (!match_prefix(iter->first, nameprefix)) continue;
1487  s.write_str(iter->first);
1488  iter->second.Stream(s);
1489  }
1490 
1491  } else {
1492  // depending on nameprefix argument, two strategy are followed
1493  // if nameprefix.empty(), we need to detect changed, removed or new fields
1494  // at the end full list should be exactly to that we try to read from the stream
1495  // if not nameprefix.empty(), we need just to detect if fields with provided prefix are changed,
1496  // all other fields can remain as is
1497 
1498  s.read_uint32(storesz);
1499  sz = ((uint64_t) storesz)*8;
1500  s.read_uint32(storenum);
1501  // storevers = storenum >> 24;
1502  storenum = storenum & 0xffffff;
1503 
1504  // first clear touch flags
1505  for (FieldsMap::iterator iter = fMap.begin(); iter!=fMap.end(); iter++)
1506  iter->second.fTouched = false;
1507 
1508  for (uint32_t n=0;n<storenum;n++) {
1509  std::string name;
1510  s.read_str(name);
1511  RecordField& fld = fMap[name];
1512  fld.Stream(s);
1513  fld.fTouched = true;
1514  }
1515 
1516  FieldsMap::iterator iter = fMap.begin();
1517  // now we should remove all fields, which were not touched
1518  while (iter!=fMap.end()) {
1519  if (iter->second.fTouched) { iter++; continue; }
1520  if (!match_prefix(iter->first, nameprefix)) { iter++; continue; }
1521  fMap.erase(iter++);
1522  }
1523 
1524  }
1525 
1526  return s.verify_size(pos, sz);
1527 }
1528 
1530 {
1531  for (FieldsMap::const_iterator iter = fMap.begin(); iter!=fMap.end(); iter++) {
1532 
1533  if (iter->first.empty() || (iter->first[0]=='#')) continue;
1534 
1535  // discard attributes, which using quotes or any special symbols in the names
1536  if (iter->first.find_first_of(" #&\"\'!@%^*()=-\\/|~.,") != std::string::npos) continue;
1537 
1538  res.SetField(iter->first.c_str(), iter->second.AsJson().c_str());
1539  }
1540  return true;
1541 }
1542 
1543 void dabc::RecordFieldsMap::CopyFrom(const RecordFieldsMap& src, bool overwrite)
1544 {
1545  for (FieldsMap::const_iterator iter = src.fMap.begin(); iter!=src.fMap.end(); iter++)
1546  if (overwrite || !HasField(iter->first))
1547  fMap[iter->first] = iter->second;
1548 }
1549 
1551 {
1552  std::vector<std::string> delfields;
1553 
1554  for (FieldsMap::iterator iter = fMap.begin(); iter!=fMap.end(); iter++) {
1555  if (iter->second.IsProtected()) continue;
1556  if (!src.HasField(iter->first)) delfields.push_back(iter->first);
1557  }
1558 
1559  for (unsigned n=0;n<delfields.size();n++)
1560  RemoveField(delfields[n]);
1561 
1562  for (FieldsMap::iterator iter = src.fMap.begin(); iter!=src.fMap.end(); iter++) {
1563  // should we completely preserve protected fields???
1564  // if (iter->second.IsProtected()) continue;
1565 
1566  fMap[iter->first].SetValue(iter->second);
1567  }
1568 }
1569 
1571 {
1572  std::vector<std::string> delfields;
1573 
1574  for (auto &&fld : current.fMap) {
1575  if (!HasField(fld.first))
1576  delfields.push_back(fld.first);
1577  else
1578  if (!fld.second.fModified) RemoveField(fld.first);
1579  }
1580 
1581  // we remember fields, which should be delete when we start to reconstruct history
1582  if (delfields.size() > 0)
1583  Field("dabc:del").SetStrVect(delfields);
1584 }
1585 
1587 {
1588  for (FieldsMap::const_iterator iter = diff.fMap.begin(); iter!=diff.fMap.end(); iter++) {
1589  if (iter->first != "dabc:del") {
1590  fMap[iter->first] = iter->second;
1591  fMap[iter->first].fModified = true;
1592  } else {
1593  std::vector<std::string> delfields = iter->second.AsStrVect();
1594  for (unsigned n=0;n<delfields.size();n++)
1595  RemoveField(delfields[n]);
1596  }
1597  }
1598 }
1599 
1600 // ===============================================================================
1601 
1602 
1603 dabc::RecordContainer::RecordContainer(const std::string &name, unsigned flags) :
1604  Object(0, name, flags | flAutoDestroy),
1605  fFields(new RecordFieldsMap)
1606 {
1607 }
1608 
1609 dabc::RecordContainer::RecordContainer(Reference parent, const std::string &name, unsigned flags) :
1610  Object(MakePair(parent, name), flags | flAutoDestroy),
1611  fFields(new RecordFieldsMap)
1612 {
1613 }
1614 
1616 {
1617  delete fFields; fFields = 0;
1618 }
1619 
1621 {
1622  dabc::RecordFieldsMap* res = fFields;
1623  fFields = new RecordFieldsMap;
1624  return res;
1625 }
1626 
1628 {
1629  delete fFields;
1630  fFields = newmap;
1631  if (fFields==0) fFields = new RecordFieldsMap;
1632 }
1633 
1635 {
1636  DOUT1("%s : %s", ClassName(), GetName());
1637 
1638  for (unsigned n=0;n<fFields->NumFields();n++) {
1639  std::string name = fFields->FieldName(n);
1640  std::string value = fFields->Field(name).AsStr();
1641  DOUT1(" %s = %s", name.c_str(), value.c_str());
1642  }
1643 }
1644 
1645 bool dabc::RecordContainer::SaveTo(HStore& store, bool create_node)
1646 {
1647  if (create_node)
1648  store.CreateNode(GetName());
1649  bool res = fFields->SaveTo(store);
1650  if (create_node)
1651  store.CloseNode(GetName());
1652  return res;
1653 }
1654 
1655 // ===========================================================================================
1656 
1657 
1658 std::string dabc::Record::SaveToJson(unsigned mask)
1659 {
1660  dabc::NumericLocale loc;
1661  dabc::HStore store(mask);
1662  if (SaveTo(store)) return store.GetResult();
1663  return "";
1664 }
1665 
1666 std::string dabc::Record::SaveToXml(unsigned mask)
1667 {
1668  dabc::NumericLocale loc;
1669  dabc::HStore store(mask | dabc::storemask_AsXML);
1670  if (SaveTo(store)) return store.GetResult();
1671  return "";
1672 }
1673 
1674 void dabc::Record::CreateRecord(const std::string &name)
1675 {
1676  Release();
1677  SetObject(new RecordContainer(name));
1678 }
1679 
1681 {
1682  uint64_t pos = s.size();
1683  uint64_t sz = 0;
1684 
1685  if (s.is_output()) {
1686  if (s.is_real()) {
1687  sizestream sizes;
1688  Stream(sizes);
1689  sz = sizes.size();
1690  }
1691  s.write_uint64(sz);
1692  s.write_str(GetName());
1693  GetObject()->Fields().Stream(s);
1694  } else {
1695 
1696  s.read_uint64(sz);
1697 
1698  std::string objname;
1699  s.read_str(objname);
1700 
1701  if (null())
1702  CreateRecord(objname);
1703  else
1704  GetObject()->SetName(objname.c_str());
1705 
1706  GetObject()->Fields().Stream(s);
1707  }
1708 
1709  return s.verify_size(pos, sz);
1710 }
1711 
1713 {
1714  if (null()) return dabc::Buffer();
1715 
1716  // first define size we need
1717  sizestream s;
1718  Stream(s);
1719 
1721  if (res.null()) return res;
1722 
1723  memstream outs(false, (char*) res.SegmentPtr(), res.SegmentSize());
1724 
1725  if (Stream(outs)) {
1726  if (s.size() != outs.size()) { EOUT("Stream sizes mismatch %u %u", (unsigned) s.size(), (unsigned) outs.size()); }
1727  res.SetTotalSize(s.size());
1728  } else {
1729  res.Release();
1730  }
1731 
1732  return res;
1733 }
1734 
1736 {
1737  if (buf.null()) return false;
1738 
1739  memstream inps(true, (char*) buf.SegmentPtr(), buf.SegmentSize());
1740 
1741  if (!Stream(inps)) {
1742  EOUT("Cannot reconstruct record from the binary data!");
1743  return false;
1744  }
1745 
1746  return true;
1747 }
Reference on memory from memory pool.
Definition: Buffer.h:135
unsigned SegmentSize(unsigned n=0) const
Returns size on the segment, no any boundary checks.
Definition: Buffer.h:174
void SetTotalSize(BufferSize_t len)
Set total length of the buffer to specified value Size cannot be bigger than original size of the buf...
Definition: Buffer.cxx:99
static Buffer CreateBuffer(BufferSize_t sz)
This static method create independent buffer for any other memory pools Therefore it can be used in s...
Definition: Buffer.cxx:419
void * SegmentPtr(unsigned n=0) const
Returns pointer on the segment, no any boundary checks.
Definition: Buffer.h:171
Class for holding GMT time with precision of nanoseconds.
Definition: timing.h:190
std::string AsJSString(int ndecimal=3) const
convert string into sec.frac format, can be interpret directly in JavaScript ISO 8601 standard is use...
Definition: timing.cxx:212
uint64_t AsJSDate() const
Return date and time in JS format - number of millisecond since 1.1.1970.
Definition: timing.cxx:158
class, used for direct store of records in JSON/XML form
Definition: Record.h:179
void CloseNode(const char *nodename)
Definition: Record.cxx:221
void SetField(const char *name, const char *value)
Definition: Record.cxx:170
void CloseChilds()
Definition: Record.cxx:277
void BeforeNextChild(const char *basename=0)
Definition: Record.cxx:247
std::string GetResult()
Definition: Record.h:212
void CreateNode(const char *nodename)
Definition: Record.cxx:145
Base class for most of the DABC classes.
Definition: Object.h:116
Container for records fields.
Definition: Record.h:440
virtual ~RecordContainer()
Definition: Record.cxx:1615
RecordFieldsMap * TakeFieldsMap()
Remove map and returns to the user.
Definition: Record.cxx:1620
RecordContainer(const std::string &name, unsigned flags=flIsOwner)
Definition: Record.cxx:1603
void SetFieldsMap(RecordFieldsMap *newmap)
Replaces existing fields map.
Definition: Record.cxx:1627
virtual bool SaveTo(HStore &store, bool create_node=true)
Definition: Record.cxx:1645
virtual void Print(int lvl=0)
Print object content on debug output.
Definition: Record.cxx:1634
bool SetUInt(uint64_t v)
Definition: Record.cxx:1101
bool SetArrUInt(int64_t size, uint64_t *arr, bool owner=false)
Set as array, if owner flag specified, one get ownership over array and do not need to create copy.
Definition: Record.cxx:1263
bool fTouched
! when true, field was modified at least once
Definition: Record.h:261
bool Stream(iostream &s)
Definition: Record.cxx:343
bool SetArrInt(int64_t size, int64_t *arr, bool owner=false)
Set as array, if owner flag specified, one get ownership over array and do not need to create copy.
Definition: Record.cxx:1224
void SetArrStrDirect(int64_t size, char *arr, bool owner=false)
Definition: Record.cxx:1347
virtual ~RecordField()
Definition: Record.cxx:331
bool SetVectInt(const std::vector< int64_t > &v)
Definition: Record.cxx:1251
Reference * valueRef
! buffer object
Definition: Record.h:257
bool SetStr(const std::string &v)
Definition: Record.cxx:1127
bool SetDatime(uint64_t v)
Definition: Record.cxx:1083
uint64_t * arrUInt
! int array, size in valueInt
Definition: Record.h:253
std::vector< uint64_t > AsUIntVect() const
Definition: Record.cxx:631
static std::string JsonReformat(const std::string &str)
Definition: Record.cxx:813
bool cannot_modify()
Definition: Record.cxx:302
std::vector< std::string > AsStrVect() const
Definition: Record.cxx:923
ValueKind fKind
Definition: Record.h:243
uint64_t valueUInt
scalar int type
Definition: Record.h:247
uint64_t AsUInt(uint64_t dflt=0) const
Definition: Record.cxx:525
bool SetBool(bool v)
Definition: Record.cxx:1060
dabc::Reference AsReference() const
Definition: Record.cxx:976
double * arrDouble
! uint array, size in valueInt
Definition: Record.h:254
std::vector< int64_t > AsIntVect() const
Definition: Record.cxx:573
bool SetVectUInt(const std::vector< uint64_t > &v)
Definition: Record.cxx:1287
bool SetDouble(double v)
Definition: Record.cxx:1114
dabc::Buffer AsBuffer() const
Definition: Record.cxx:969
bool SetArrDouble(int64_t size, double *arr, bool owner=false)
Set as array, if owner flag specified, one get ownership over array and do not need to create copy.
Definition: Record.cxx:1312
int64_t * arrInt
Definition: Record.h:252
double valueDouble
scalar unsigned int type
Definition: Record.h:248
std::string AsJson() const
Returns field value in JSON format.
Definition: Record.cxx:835
bool SetReference(const Reference &ref)
Definition: Record.cxx:1210
bool SetStrVect(const std::vector< std::string > &vect)
Definition: Record.cxx:1162
bool AsBool(bool dflt=false) const
Definition: Record.cxx:477
std::string AsStr(const std::string &dflt="") const
Definition: Record.cxx:749
bool SetVectDouble(const std::vector< double > &v)
Definition: Record.cxx:1299
static bool NeedJsonReformat(const std::string &str)
Definition: Record.cxx:792
int64_t AsInt(int64_t dflt=0) const
Definition: Record.cxx:501
double AsDouble(double dflt=0.) const
Definition: Record.cxx:549
bool SetArrStr(int64_t size, char *arr, bool owner=false)
Sets as array of string, placed one after another in memory.
Definition: Record.cxx:1336
std::vector< double > AsDoubleVect() const
Definition: Record.cxx:691
bool SetValue(const RecordField &src)
Definition: Record.cxx:1030
char * valueStr
! double array, size in valueInt
Definition: Record.h:255
int64_t valueInt
Definition: Record.h:246
bool SetBuffer(const Buffer &buf)
Definition: Record.cxx:1197
Buffer * valueBuf
! string or array of strings
Definition: Record.h:256
bool SetInt(int64_t v)
Definition: Record.cxx:1073
static bool StrToStrVect(const char *str, std::vector< std::string > &vect, bool verbose=true)
Definition: Record.cxx:983
uint64_t StoreSize()
Definition: Record.cxx:336
void release()
! when true, field will not be automatically deleted when full list updated from other hierarchy
Definition: Record.cxx:456
RecordFieldsMap * Clone()
Create complete copy of fields map.
Definition: Record.cxx:1440
virtual ~RecordFieldsMap()
Definition: Record.cxx:1378
std::string FieldName(unsigned n) const
Definition: Record.cxx:1397
uint64_t StoreSize(const std::string &nameprefix="")
Definition: Record.cxx:1450
void ApplyDiff(const RecordFieldsMap &diff)
Apply diff map One should use fields, generated with MakeAsDiffTo call.
Definition: Record.cxx:1586
bool WasChanged() const
Return true if any field was changed or map was modified (removed filed)
Definition: Record.cxx:1409
void CopyFrom(const RecordFieldsMap &src, bool overwrite=true)
Copy fields from source map.
Definition: Record.cxx:1543
bool HasField(const std::string &name) const
Definition: Record.cxx:1382
void MakeAsDiffTo(const RecordFieldsMap &src)
In the map only modified fields are remained Also dabc:delete field can appear which marks all remove...
Definition: Record.cxx:1570
void MoveFrom(RecordFieldsMap &src)
Move fields from source map, delete no longer existing (except protected)
Definition: Record.cxx:1550
RecordField & Field(const std::string &name)
Direct access to the fields.
Definition: Record.h:401
void ClearChangeFlags()
Clear all change flags.
Definition: Record.cxx:1433
FieldsMap fMap
Definition: Record.h:378
bool WasChangedWith(const std::string &prefix)
Returns true when fields with specified prefix were changed.
Definition: Record.cxx:1420
static bool match_prefix(const std::string &name, const std::string &prefix)
Definition: Record.cxx:1457
bool RemoveField(const std::string &name)
Definition: Record.cxx:1387
bool Stream(iostream &s, const std::string &nameprefix="")
Definition: Record.cxx:1467
bool SaveTo(HStore &res)
Save all field in json format.
Definition: Record.cxx:1529
dabc::Buffer SaveToBuffer()
Definition: Record.cxx:1712
bool Stream(iostream &s)
Definition: Record.cxx:1680
bool ReadFromBuffer(const dabc::Buffer &buf)
Definition: Record.cxx:1735
std::string SaveToJson(unsigned mask=0)
Store record in JSON form.
Definition: Record.cxx:1658
std::string SaveToXml(unsigned mask=0)
Store record in XML form.
Definition: Record.cxx:1666
virtual void CreateRecord(const std::string &name)
Definition: Record.cxx:1674
Reference on the arbitrary object
Definition: Reference.h:73
void Release()
Releases reference on the object.
Definition: Reference.cxx:138
bool null() const
Returns true if reference contains nullptr.
Definition: Reference.h:151
class to stream binary data
Definition: Record.h:41
virtual bool write(const void *src, uint64_t len)
Definition: Record.h:67
bool write_uint32(uint32_t v)
Definition: Record.h:77
bool write_int64(int64_t v)
Definition: Record.h:78
virtual bool is_real() const
Definition: Record.h:58
bool read_uint64(uint64_t &v)
Definition: Record.h:85
bool read_double(double &v)
Definition: Record.h:86
virtual bool read(void *tgt, uint64_t len)
Definition: Record.h:68
bool read_uint32(uint32_t &v)
Definition: Record.h:83
static uint64_t str_storesize(const std::string &str)
Returns bytes count, required to store string.
Definition: Record.cxx:68
bool is_output() const
Definition: Record.h:57
virtual uint64_t size() const
return number of bytes, written or read from the stream
Definition: Record.h:71
bool is_input() const
Definition: Record.h:56
bool skip_object()
Insted of reading object we read size and shift on that size Only can be done where size stored as 32...
Definition: Record.cxx:23
bool write_uint64(uint64_t v)
Definition: Record.h:79
bool read_int64(int64_t &v)
Definition: Record.h:84
bool read_str(std::string &str)
Restore string from the stream.
Definition: Record.cxx:94
bool write_double(double v)
Definition: Record.h:80
virtual bool shift(uint64_t len)
Definition: Record.h:69
bool write_str(const std::string &str)
Store string in the stream.
Definition: Record.cxx:76
bool verify_size(uint64_t pos, uint64_t sz)
Definition: Record.cxx:33
iostream class, which write and read data from memory
Definition: Record.h:133
virtual bool write(const void *src, uint64_t len)
Definition: Record.cxx:122
virtual bool shift(uint64_t len)
Definition: Record.cxx:114
virtual bool read(void *tgt, uint64_t len)
Definition: Record.cxx:132
virtual uint64_t size() const
return number of bytes, written or read from the stream
Definition: Record.h:145
special class only to define how many data will be written to the stream
Definition: Record.h:102
virtual uint64_t size() const
return number of bytes, written or read from the stream
Definition: Record.h:116
#define EOUT(args ...)
Definition: logging.h:150
#define DOUT1(args ...)
Definition: logging.h:162
#define DBOOL(arg)
Definition: logging.h:191
@ storemask_AsXML
Definition: Record.h:173
bool str_to_double(const char *val, double *res)
Convert string to double value.
Definition: string.cxx:216
std::string format(const char *fmt,...)
Definition: string.cxx:49
const char * xmlTrueValue
Definition: ConfigBase.cxx:90
bool str_to_lint(const char *val, long *res)
Convert string to long integer value.
Definition: string.cxx:162
bool str_to_luint(const char *val, long unsigned *res)
Convert string to long unsigned integer value One could use hexadecimal (in form 0xabc100) or decimal...
Definition: string.cxx:200
const char * xmlFalseValue
Definition: ConfigBase.cxx:91