Athena IO Library
DNAYaml.hpp
1 #ifndef DNAYAML_HPP
2 #define DNAYAML_HPP
3 
4 /* BIG FAT WARNING!!!
5  *
6  * The type-structure of this file is expected to remain consistent for 'atdna'
7  * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp'
8  */
9 
10 #include <string.h>
11 #include <yaml.h>
12 #include <utf8proc.h>
13 #include "DNA.hpp"
14 #include "FileReader.hpp"
15 
16 namespace athena
17 {
18 namespace io
19 {
20 
21 std::string base64_encode(const atUint8* bytes_to_encode, size_t in_len);
22 std::unique_ptr<atUint8[]> base64_decode(const std::string& encoded_string);
23 
24 void HandleYAMLParserError(yaml_parser_t* parser);
25 void HandleYAMLEmitterError(yaml_emitter_t* emitter);
26 
28 {
29  std::string::const_iterator begin;
30  std::string::const_iterator end;
31  YAMLStdStringReaderState(const std::string& str)
32  {
33  begin = str.begin();
34  end = str.end();
35  }
36 };
37 int YAMLStdStringReader(YAMLStdStringReaderState* str,
38  unsigned char* buffer, size_t size, size_t* size_read);
39 int YAMLStdStringWriter(std::string* str, unsigned char* buffer, size_t size);
40 
41 struct YAMLNode
42 {
43  yaml_node_type_t m_type;
44  std::string m_scalarString;
45  std::vector<std::unique_ptr<YAMLNode>> m_seqChildren;
46  std::vector<std::pair<std::string, std::unique_ptr<YAMLNode>>> m_mapChildren;
47  YAMLNode(yaml_node_type_t type) : m_type(type) {}
48  inline const YAMLNode* findMapChild(const char* key) const
49  {
50  for (const auto& item : m_mapChildren)
51  if (!item.first.compare(key))
52  return item.second.get();
53  return nullptr;
54  }
55 };
56 
57 template <typename RETURNTYPE>
58 RETURNTYPE NodeToVal(const YAMLNode* node);
59 
60 template <typename INTYPE>
61 std::unique_ptr<YAMLNode> ValToNode(const INTYPE& val);
62 template <typename INTYPE>
63 std::unique_ptr<YAMLNode> ValToNode(const INTYPE* val);
64 template <typename INTYPE>
65 std::unique_ptr<YAMLNode> ValToNode(const INTYPE& val, size_t byteCount);
66 
67 template <>
68 inline bool NodeToVal(const YAMLNode* node)
69 {
70  char firstCh = tolower(node->m_scalarString[0]);
71  if (firstCh == 't')
72  return true;
73  else if (firstCh == 'f')
74  return false;
75  else if (isdigit(firstCh) && firstCh != 0)
76  return true;
77  return false;
78 }
79 
80 template <>
81 inline std::unique_ptr<YAMLNode> ValToNode(const bool& val)
82 {
83  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
84  ret->m_scalarString = val?"True":"False";
85  return std::unique_ptr<YAMLNode>(ret);
86 }
87 
88 template <>
89 inline atInt8 NodeToVal(const YAMLNode* node)
90 {
91  return strtol(node->m_scalarString.c_str(), NULL, 0);
92 }
93 
94 template <>
95 inline std::unique_ptr<YAMLNode> ValToNode(const atInt8& val)
96 {
97  char str[32];
98  snprintf(str, 32, "0x%02X", val);
99  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
100  ret->m_scalarString = str;
101  return std::unique_ptr<YAMLNode>(ret);
102 }
103 
104 template <>
105 inline atUint8 NodeToVal(const YAMLNode* node)
106 {
107  return strtoul(node->m_scalarString.c_str(), NULL, 0);
108 }
109 
110 template <>
111 inline std::unique_ptr<YAMLNode> ValToNode(const atUint8& val)
112 {
113  char str[32];
114  snprintf(str, 32, "0x%02X", val);
115  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
116  ret->m_scalarString = str;
117  return std::unique_ptr<YAMLNode>(ret);
118 }
119 
120 template <>
121 inline atInt16 NodeToVal(const YAMLNode* node)
122 {
123  return strtol(node->m_scalarString.c_str(), NULL, 0);
124 }
125 
126 template <>
127 inline std::unique_ptr<YAMLNode> ValToNode(const atInt16& val)
128 {
129  char str[32];
130  snprintf(str, 32, "0x%04X", val);
131  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
132  ret->m_scalarString = str;
133  return std::unique_ptr<YAMLNode>(ret);
134 }
135 
136 template <>
137 inline atUint16 NodeToVal(const YAMLNode* node)
138 {
139  return strtoul(node->m_scalarString.c_str(), NULL, 0);
140 }
141 
142 template <>
143 inline std::unique_ptr<YAMLNode> ValToNode(const atUint16& val)
144 {
145  char str[32];
146  snprintf(str, 32, "0x%04X", val);
147  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
148  ret->m_scalarString = str;
149  return std::unique_ptr<YAMLNode>(ret);
150 }
151 
152 template <>
153 inline atInt32 NodeToVal(const YAMLNode* node)
154 {
155  return strtol(node->m_scalarString.c_str(), NULL, 0);
156 }
157 
158 template <>
159 inline std::unique_ptr<YAMLNode> ValToNode(const atInt32& val)
160 {
161  char str[32];
162  snprintf(str, 32, "0x%08X", val);
163  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
164  ret->m_scalarString = str;
165  return std::unique_ptr<YAMLNode>(ret);
166 }
167 
168 template <>
169 inline atUint32 NodeToVal(const YAMLNode* node)
170 {
171  return strtoul(node->m_scalarString.c_str(), NULL, 0);
172 }
173 
174 template <>
175 inline std::unique_ptr<YAMLNode> ValToNode(const atUint32& val)
176 {
177  char str[32];
178  snprintf(str, 32, "0x%08X", val);
179  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
180  ret->m_scalarString = str;
181  return std::unique_ptr<YAMLNode>(ret);
182 }
183 
184 template <>
185 inline atInt64 NodeToVal(const YAMLNode* node)
186 {
187 #if _WIN32
188  return _strtoi64(node->m_scalarString.c_str(), NULL, 0);
189 #else
190  return strtoq(node->m_scalarString.c_str(), NULL, 0);
191 #endif
192 }
193 
194 template <>
195 inline std::unique_ptr<YAMLNode> ValToNode(const atInt64& val)
196 {
197  char str[32];
198  snprintf(str, 32, "0x%016" PRIX64, val);
199  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
200  ret->m_scalarString = str;
201  return std::unique_ptr<YAMLNode>(ret);
202 }
203 
204 template <>
205 inline atUint64 NodeToVal(const YAMLNode* node)
206 {
207 #if _WIN32
208  return _strtoui64(node->m_scalarString.c_str(), NULL, 0);
209 #else
210  return strtouq(node->m_scalarString.c_str(), NULL, 0);
211 #endif
212 }
213 
214 template <>
215 inline std::unique_ptr<YAMLNode> ValToNode(const atUint64& val)
216 {
217  char str[32];
218  snprintf(str, 32, "0x%016" PRIX64, val);
219  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
220  ret->m_scalarString = str;
221  return std::unique_ptr<YAMLNode>(ret);
222 }
223 
224 template <>
225 inline float NodeToVal(const YAMLNode* node)
226 {
227  return strtof(node->m_scalarString.c_str(), NULL);
228 }
229 
230 template <>
231 inline std::unique_ptr<YAMLNode> ValToNode(const float& val)
232 {
233  char str[64];
234  snprintf(str, 64, "%f", val);
235  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
236  ret->m_scalarString = str;
237  return std::unique_ptr<YAMLNode>(ret);
238 }
239 
240 template <>
241 inline double NodeToVal(const YAMLNode* node)
242 {
243  return strtod(node->m_scalarString.c_str(), NULL);
244 }
245 
246 template <>
247 inline std::unique_ptr<YAMLNode> ValToNode(const double& val)
248 {
249  char str[64];
250  snprintf(str, 64, "%f", val);
251  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
252  ret->m_scalarString = str;
253  return std::unique_ptr<YAMLNode>(ret);
254 }
255 
256 template <typename RETURNTYPE>
257 inline RETURNTYPE NodeToVec(const YAMLNode* node)
258 {
259  RETURNTYPE retval = {};
260  auto it = node->m_seqChildren.begin();
261  for (size_t i=0;
262  i<4 && it != node->m_seqChildren.end();
263  ++i, ++it)
264  {
265  YAMLNode* snode = it->get();
266  if (snode->m_type == YAML_SCALAR_NODE)
267  {
268  if (std::is_same<RETURNTYPE, atVec2d>::value ||
269  std::is_same<RETURNTYPE, atVec3d>::value ||
270  std::is_same<RETURNTYPE, atVec4d>::value)
271  retval.vec[i] = NodeToVal<double>(snode);
272  else
273  retval.vec[i] = NodeToVal<float>(snode);
274  }
275  else
276  retval.vec[i] = 0.0;
277  }
278  return retval;
279 }
280 
281 template <>
282 inline atVec2f NodeToVal(const YAMLNode* node)
283 {
284  return NodeToVec<atVec2f>(node);
285 }
286 
287 template <>
288 inline std::unique_ptr<YAMLNode> ValToNode(const atVec2f& val)
289 {
290  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
291  ret->m_seqChildren.reserve(2);
292  for (size_t i=0 ; i<2 ; ++i)
293  {
294  char str[64];
295  snprintf(str, 64, "%f", val.vec[i]);
296  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
297  comp->m_scalarString = str;
298  ret->m_seqChildren.emplace_back(comp);
299  }
300  return std::unique_ptr<YAMLNode>(ret);
301 }
302 
303 template <>
304 inline atVec3f NodeToVal(const YAMLNode* node)
305 {
306  return NodeToVec<atVec3f>(node);
307 }
308 
309 template <>
310 inline std::unique_ptr<YAMLNode> ValToNode(const atVec3f& val)
311 {
312  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
313  ret->m_seqChildren.reserve(3);
314  for (size_t i=0 ; i<3 ; ++i)
315  {
316  char str[64];
317  snprintf(str, 64, "%f", val.vec[i]);
318  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
319  comp->m_scalarString = str;
320  ret->m_seqChildren.emplace_back(comp);
321  }
322  return std::unique_ptr<YAMLNode>(ret);
323 }
324 
325 template <>
326 inline atVec4f NodeToVal(const YAMLNode* node)
327 {
328  return NodeToVec<atVec4f>(node);
329 }
330 
331 template <>
332 inline std::unique_ptr<YAMLNode> ValToNode(const atVec4f& val)
333 {
334  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
335  ret->m_seqChildren.reserve(4);
336  for (size_t i=0 ; i<4 ; ++i)
337  {
338  char str[64];
339  snprintf(str, 64, "%f", val.vec[i]);
340  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
341  comp->m_scalarString = str;
342  ret->m_seqChildren.emplace_back(comp);
343  }
344  return std::unique_ptr<YAMLNode>(ret);
345 }
346 
347 template <>
348 inline atVec2d NodeToVal(const YAMLNode* node)
349 {
350  return NodeToVec<atVec2d>(node);
351 }
352 
353 template <>
354 inline std::unique_ptr<YAMLNode> ValToNode(const atVec2d& val)
355 {
356  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
357  ret->m_seqChildren.reserve(2);
358  for (size_t i=0 ; i<2 ; ++i)
359  {
360  char str[64];
361  snprintf(str, 64, "%f", val.vec[i]);
362  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
363  comp->m_scalarString = str;
364  ret->m_seqChildren.emplace_back(comp);
365  }
366  return std::unique_ptr<YAMLNode>(ret);
367 }
368 
369 template <>
370 inline atVec3d NodeToVal(const YAMLNode* node)
371 {
372  return NodeToVec<atVec3d>(node);
373 }
374 
375 template <>
376 inline std::unique_ptr<YAMLNode> ValToNode(const atVec3d& val)
377 {
378  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
379  ret->m_seqChildren.reserve(3);
380  for (size_t i=0 ; i<3 ; ++i)
381  {
382  char str[64];
383  snprintf(str, 64, "%f", val.vec[i]);
384  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
385  comp->m_scalarString = str;
386  ret->m_seqChildren.emplace_back(comp);
387  }
388  return std::unique_ptr<YAMLNode>(ret);
389 }
390 
391 template <>
392 inline atVec4d NodeToVal(const YAMLNode* node)
393 {
394  return NodeToVec<atVec4d>(node);
395 }
396 
397 template <>
398 inline std::unique_ptr<YAMLNode> ValToNode(const atVec4d& val)
399 {
400  YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE);
401  ret->m_seqChildren.reserve(4);
402  for (size_t i=0 ; i<4 ; ++i)
403  {
404  char str[64];
405  snprintf(str, 64, "%f", val.vec[i]);
406  YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE);
407  comp->m_scalarString = str;
408  ret->m_seqChildren.emplace_back(comp);
409  }
410  return std::unique_ptr<YAMLNode>(ret);
411 }
412 
413 template <>
414 inline std::unique_ptr<atUint8[]> NodeToVal(const YAMLNode* node)
415 {
416  return base64_decode(node->m_scalarString);
417 }
418 
419 template <>
420 inline std::unique_ptr<YAMLNode> ValToNode(const std::unique_ptr<atUint8[]>& val, size_t byteCount)
421 {
422  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
423  ret->m_scalarString = base64_encode(val.get(), byteCount);
424  return std::unique_ptr<YAMLNode>(ret);
425 }
426 
427 template <>
428 inline std::string NodeToVal(const YAMLNode* node)
429 {
430  return node->m_scalarString;
431 }
432 
433 template <>
434 inline std::unique_ptr<YAMLNode> ValToNode(const std::string& val)
435 {
436  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
437  ret->m_scalarString = val;
438  return std::unique_ptr<YAMLNode>(ret);
439 }
440 
441 template <>
442 inline std::unique_ptr<YAMLNode> ValToNode(const char* val)
443 {
444  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
445  ret->m_scalarString = val;
446  return std::unique_ptr<YAMLNode>(ret);
447 }
448 
449 template <>
450 inline std::wstring NodeToVal(const YAMLNode* node)
451 {
452  std::wstring retval;
453  retval.reserve(node->m_scalarString.length());
454  const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(node->m_scalarString.c_str());
455  while (*buf)
456  {
457  utf8proc_int32_t wc;
458  utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
459  if (len < 0)
460  {
461  atWarning("invalid UTF-8 character while decoding");
462  return retval;
463  }
464  buf += len;
465  retval += wchar_t(wc);
466  }
467  return retval;
468 }
469 
470 template <>
471 inline std::unique_ptr<YAMLNode> ValToNode(const std::wstring& val)
472 {
473  YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE);
474  ret->m_scalarString.reserve(val.length());
475  for (wchar_t ch : val)
476  {
477  utf8proc_uint8_t mb[4];
478  utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
479  if (c < 0)
480  {
481  atWarning("invalid UTF-8 character while encoding");
482  return std::unique_ptr<YAMLNode>(ret);
483  }
484  ret->m_scalarString.append(reinterpret_cast<char*>(mb), c);
485  }
486  return std::unique_ptr<YAMLNode>(ret);
487 }
488 
489 template <>
490 inline std::unique_ptr<YAMLNode> ValToNode(const wchar_t* val)
491 {
492  std::wstring wstr(val);
493  return ValToNode<const std::wstring&>(wstr);
494 }
495 
497 {
498  std::unique_ptr<YAMLNode> m_rootNode;
499  std::vector<YAMLNode*> m_subStack;
500  std::vector<int> m_seqTrackerStack;
501  yaml_parser_t m_parser;
502  std::unique_ptr<YAMLNode> ParseEvents(athena::io::IStreamReader* reader);
503 
504 public:
505  YAMLDocReader()
506  {
507  if (!yaml_parser_initialize(&m_parser))
508  {
509  HandleYAMLParserError(&m_parser);
510  return;
511  }
512  }
513  ~YAMLDocReader()
514  {
515  yaml_parser_delete(&m_parser);
516  }
517 
518  void reset()
519  {
520  yaml_parser_delete(&m_parser);
521  if (!yaml_parser_initialize(&m_parser))
522  HandleYAMLParserError(&m_parser);
523  }
524 
525  yaml_parser_t* getParser() {return &m_parser;}
526  bool parse(athena::io::IStreamReader* reader)
527  {
528  std::unique_ptr<YAMLNode> newRoot = ParseEvents(reader);
529  if (!newRoot)
530  return false;
531  m_rootNode = std::move(newRoot);
532  m_subStack.clear();
533  m_subStack.push_back(m_rootNode.get());
534  m_seqTrackerStack.clear();
535  return true;
536  }
537 
538  bool ClassTypeOperation(std::function<bool(const char* dnaType)> func);
539  bool ValidateClassType(const char* expectedType);
540 
541  inline const YAMLNode* getRootNode() const {return m_rootNode.get();}
542  inline const YAMLNode* getCurNode() const {return m_subStack.empty() ? nullptr : m_subStack.back();}
543  std::unique_ptr<YAMLNode> releaseRootNode() {return std::move(m_rootNode);}
544 
545  bool enterSubRecord(const char* name)
546  {
547  YAMLNode* curSub = m_subStack.back();
548  if (curSub->m_type == YAML_SEQUENCE_NODE)
549  {
550  int& seqIdx = m_seqTrackerStack.back();
551  m_subStack.push_back(curSub->m_seqChildren[seqIdx++].get());
552  if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
553  m_seqTrackerStack.push_back(0);
554  return true;
555  }
556  for (const auto& item : curSub->m_mapChildren)
557  {
558  if (!item.first.compare(name))
559  {
560  m_subStack.push_back(item.second.get());
561  if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
562  m_seqTrackerStack.push_back(0);
563  return true;
564  }
565  }
566  return false;
567  }
568 
569  void leaveSubRecord()
570  {
571  if (m_subStack.size() > 1)
572  {
573  if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE)
574  m_seqTrackerStack.pop_back();
575  m_subStack.pop_back();
576  }
577  }
578 
579  template <class T>
580  void enumerate(const char* name, T& record)
581  {
582  enterSubRecord(name);
583  record.read(*this);
584  leaveSubRecord();
585  }
586 
587  bool enterSubVector(const char* name, size_t& countOut)
588  {
589  YAMLNode* curSub = m_subStack.back();
590  if (!name && curSub->m_type == YAML_SEQUENCE_NODE)
591  {
592  m_subStack.push_back(curSub);
593  m_seqTrackerStack.push_back(0);
594  countOut = curSub->m_seqChildren.size();
595  return true;
596  }
597  else
598  {
599  for (const auto& item : curSub->m_mapChildren)
600  {
601  if (!item.first.compare(name))
602  {
603  YAMLNode* nextSub = item.second.get();
604  if (nextSub->m_type == YAML_SEQUENCE_NODE)
605  {
606  countOut = nextSub->m_seqChildren.size();
607  }
608  else
609  {
610  atError("'%s' is not a vector field", name);
611  countOut = 0;
612  }
613  m_subStack.push_back(nextSub);
614  m_seqTrackerStack.push_back(0);
615  return true;
616  }
617  }
618  }
619  countOut = 0;
620  return false;
621  }
622 
623  void leaveSubVector()
624  {
625  if (m_subStack.size() > 1)
626  {
627  m_subStack.pop_back();
628  m_seqTrackerStack.pop_back();
629  }
630  }
631  template <class T>
632  size_t enumerate(const char* name, std::vector<T>& vector,
633  typename std::enable_if<!std::is_arithmetic<T>::value &&
634  !std::is_same<T, atVec2f>::value &&
635  !std::is_same<T, atVec3f>::value &&
636  !std::is_same<T, atVec4f>::value>::type* = 0)
637  {
638  size_t countOut;
639  enterSubVector(name, countOut);
640  vector.clear();
641  vector.reserve(countOut);
642  for (size_t i=0 ; i<countOut ; ++i)
643  {
644  vector.emplace_back();
645  enterSubRecord(nullptr);
646  vector.back().read(*this);
647  leaveSubRecord();
648  }
649  leaveSubVector();
650  return countOut;
651  }
652 
653  template <class T>
654  size_t enumerate(const char* name, std::vector<T>& vector,
655  typename std::enable_if<std::is_arithmetic<T>::value ||
656  std::is_same<T, atVec2f>::value ||
657  std::is_same<T, atVec3f>::value ||
658  std::is_same<T, atVec4f>::value>::type* = 0)
659  {
660  size_t countOut;
661  enterSubVector(name, countOut);
662  vector.clear();
663  vector.reserve(countOut);
664  for (size_t i=0 ; i<countOut ; ++i)
665  vector.push_back(readVal<T>(name));
666  leaveSubVector();
667  return countOut;
668  }
669 
670  template <class T>
671  size_t enumerate(const char* name, std::vector<T>& vector,
672  std::function<void(YAMLDocReader&, T&)> readf)
673  {
674  size_t countOut;
675  enterSubVector(name, countOut);
676  vector.clear();
677  vector.reserve(countOut);
678  for (size_t i=0 ; i<countOut ; ++i)
679  {
680  vector.emplace_back();
681  enterSubRecord(nullptr);
682  readf(*this, vector.back());
683  leaveSubRecord();
684  }
685  leaveSubVector();
686  return countOut;
687  }
688 
689  template <typename RETURNTYPE>
690  RETURNTYPE readVal(const char* name)
691  {
692  if (m_subStack.size())
693  {
694  const YAMLNode* mnode = m_subStack.back();
695  if (mnode->m_type == YAML_SCALAR_NODE)
696  {
697  return NodeToVal<RETURNTYPE>(mnode);
698  }
699  else if (mnode->m_type == YAML_SEQUENCE_NODE)
700  {
701  int& seqIdx = m_seqTrackerStack.back();
702  return NodeToVal<RETURNTYPE>(mnode->m_seqChildren[seqIdx++].get());
703  }
704  else if (mnode->m_type == YAML_MAPPING_NODE)
705  {
706  for (const auto& item : mnode->m_mapChildren)
707  {
708  if (!item.first.compare(name))
709  {
710  return NodeToVal<RETURNTYPE>(item.second.get());
711  }
712  }
713  }
714  }
715  if (name)
716  atWarning("Unable to find field '%s'; returning 0", name);
717  return RETURNTYPE();
718  }
719 
720  inline bool readBool(const char* name)
721  {
722  return readVal<bool>(name);
723  }
724 
725  inline atInt8 readByte(const char* name)
726  {
727  return readVal<atInt8>(name);
728  }
729 
730  inline atUint8 readUByte(const char* name)
731  {
732  return readVal<atUint8>(name);
733  }
734 
735  inline atInt16 readInt16(const char* name)
736  {
737  return readVal<atInt16>(name);
738  }
739 
740  inline atUint16 readUint16(const char* name)
741  {
742  return readVal<atUint16>(name);
743  }
744 
745  inline atInt32 readInt32(const char* name)
746  {
747  return readVal<atInt32>(name);
748  }
749 
750  inline atUint32 readUint32(const char* name)
751  {
752  return readVal<atUint32>(name);
753  }
754 
755  inline atInt64 readInt64(const char* name)
756  {
757  return readVal<atInt64>(name);
758  }
759 
760  inline atUint64 readUint64(const char* name)
761  {
762  return readVal<atUint64>(name);
763  }
764 
765  inline float readFloat(const char* name)
766  {
767  return readVal<float>(name);
768  }
769 
770  inline double readDouble(const char* name)
771  {
772  return readVal<double>(name);
773  }
774 
775  inline atVec2f readVec2f(const char* name)
776  {
777  return readVal<atVec2f>(name);
778  }
779 
780  inline atVec3f readVec3f(const char* name)
781  {
782  return readVal<atVec3f>(name);
783  }
784  inline atVec4f readVec4f(const char* name)
785  {
786  return readVal<atVec4f>(name);
787  }
788 
789  inline atVec2d readVec2d(const char* name)
790  {
791  return readVal<atVec2d>(name);
792  }
793 
794  inline atVec3d readVec3d(const char* name)
795  {
796  return readVal<atVec3d>(name);
797  }
798 
799  inline atVec4d readVec4d(const char* name)
800  {
801  return readVal<atVec4d>(name);
802  }
803 
804  inline std::unique_ptr<atUint8[]> readUBytes(const char* name)
805  {
806  return readVal<std::unique_ptr<atUint8[]>>(name);
807  }
808 
809  inline std::string readString(const char* name)
810  {
811  return readVal<std::string>(name);
812  }
813 
814  inline std::wstring readWString(const char* name)
815  {
816  return readVal<std::wstring>(name);
817  }
818 
819 };
820 
822 {
823  YAMLNode m_rootNode;
824  std::vector<YAMLNode*> m_subStack;
825  yaml_emitter_t m_emitter;
826  static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node);
827 public:
828  YAMLDocWriter(const char* classType) : m_rootNode(YAML_MAPPING_NODE)
829  {
830  if (!yaml_emitter_initialize(&m_emitter))
831  {
832  HandleYAMLEmitterError(&m_emitter);
833  return;
834  }
835  yaml_emitter_set_unicode(&m_emitter, true);
836  yaml_emitter_set_width(&m_emitter, -1);
837 
838  m_subStack.emplace_back(&m_rootNode);
839  if (classType)
840  {
841  YAMLNode* classVal = new YAMLNode(YAML_SCALAR_NODE);
842  classVal->m_scalarString.assign(classType);
843  m_rootNode.m_mapChildren.emplace_back("DNAType", std::unique_ptr<YAMLNode>(classVal));
844  }
845  }
846 
847  ~YAMLDocWriter()
848  {
849  yaml_emitter_delete(&m_emitter);
850  }
851 
852  yaml_emitter_t* getEmitter() {return &m_emitter;}
853 
854  bool finish(athena::io::IStreamWriter* fout);
855 
856  inline YAMLNode* getCurNode() const {return m_subStack.empty() ? nullptr : m_subStack.back();}
857 
858  void enterSubRecord(const char* name)
859  {
860  YAMLNode* curSub = m_subStack.back();
861  if (curSub->m_type != YAML_MAPPING_NODE &&
862  curSub->m_type != YAML_SEQUENCE_NODE)
863  return;
864  YAMLNode* newNode = new YAMLNode(YAML_MAPPING_NODE);
865  if (curSub->m_type == YAML_MAPPING_NODE)
866  curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
867  else if (curSub->m_type == YAML_SEQUENCE_NODE)
868  curSub->m_seqChildren.emplace_back(newNode);
869  m_subStack.push_back(newNode);
870  }
871 
872  void leaveSubRecord()
873  {
874  if (m_subStack.size() > 1)
875  {
876  YAMLNode* curSub = m_subStack.back();
877  /* Automatically lower to scalar or sequence if there's only one unnamed node */
878  if (curSub->m_mapChildren.size() == 1 &&
879  curSub->m_mapChildren[0].first.empty())
880  {
881  auto& item = curSub->m_mapChildren[0];
882  if (item.first.empty())
883  {
884  if (item.second->m_type == YAML_SCALAR_NODE)
885  {
886  curSub->m_type = YAML_SCALAR_NODE;
887  curSub->m_scalarString = std::move(item.second->m_scalarString);
888  curSub->m_mapChildren.clear();
889  }
890  else if (item.second->m_type == YAML_SEQUENCE_NODE)
891  {
892  curSub->m_type = YAML_SEQUENCE_NODE;
893  curSub->m_seqChildren = std::move(item.second->m_seqChildren);
894  curSub->m_mapChildren.clear();
895  }
896  }
897  }
898  m_subStack.pop_back();
899  }
900  }
901 
902  template <class T>
903  void enumerate(const char* name, T& record)
904  {
905  enterSubRecord(name);
906  record.write(*this);
907  leaveSubRecord();
908  }
909 
910  void enterSubVector(const char* name)
911  {
912  YAMLNode* curSub = m_subStack.back();
913  if (curSub->m_type != YAML_MAPPING_NODE &&
914  curSub->m_type != YAML_SEQUENCE_NODE)
915  return;
916  YAMLNode* newNode = new YAMLNode(YAML_SEQUENCE_NODE);
917  if (curSub->m_type == YAML_MAPPING_NODE)
918  curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr<YAMLNode>(newNode));
919  else if (curSub->m_type == YAML_SEQUENCE_NODE)
920  curSub->m_seqChildren.emplace_back(newNode);
921  m_subStack.push_back(newNode);
922  }
923 
924  void leaveSubVector()
925  {
926  if (m_subStack.size() > 1)
927  m_subStack.pop_back();
928  }
929 
930  template <class T>
931  void enumerate(const char* name, const std::vector<T>& vector,
932  typename std::enable_if<!std::is_arithmetic<T>::value &&
933  !std::is_same<T, atVec2f>::value &&
934  !std::is_same<T, atVec3f>::value &&
935  !std::is_same<T, atVec4f>::value &&
936  !std::is_same<T, atVec2d>::value &&
937  !std::is_same<T, atVec3d>::value &&
938  !std::is_same<T, atVec4d>::value>::type* = 0)
939  {
940  enterSubVector(name);
941  for (const T& item : vector)
942  {
943  enterSubRecord(nullptr);
944  item.write(*this);
945  leaveSubRecord();
946  }
947  leaveSubVector();
948  }
949 
950  template <class T>
951  void enumerate(const char* name, const std::vector<T>& vector,
952  typename std::enable_if<std::is_arithmetic<T>::value ||
953  std::is_same<T, atVec2f>::value ||
954  std::is_same<T, atVec3f>::value ||
955  std::is_same<T, atVec4f>::value ||
956  std::is_same<T, atVec2d>::value ||
957  std::is_same<T, atVec3d>::value ||
958  std::is_same<T, atVec4d>::value>::type* = 0)
959  {
960  enterSubVector(name);
961  for (T item : vector)
962  writeVal<T>(nullptr, item);
963  leaveSubVector();
964  }
965 
966  template <class T>
967  void enumerate(const char* name, const std::vector<T>& vector,
968  std::function<void(YAMLDocWriter&, const T&)> writef)
969  {
970  enterSubVector(name);
971  for (const T& item : vector)
972  {
973  enterSubRecord(nullptr);
974  writef(*this, item);
975  leaveSubRecord();
976  }
977  leaveSubVector();
978  }
979 
980  template <typename INTYPE>
981  void writeVal(const char* name, const INTYPE& val)
982  {
983  YAMLNode* curSub = m_subStack.back();
984  if (curSub->m_type == YAML_MAPPING_NODE)
985  curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val)));
986  else if (curSub->m_type == YAML_SEQUENCE_NODE)
987  curSub->m_seqChildren.emplace_back(std::move(ValToNode(val)));
988  }
989 
990  template <typename INTYPE>
991  void writeVal(const char* name, const INTYPE& val, size_t byteCount)
992  {
993  YAMLNode* curSub = m_subStack.back();
994  if (curSub->m_type == YAML_MAPPING_NODE)
995  curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val, byteCount)));
996  else if (curSub->m_type == YAML_SEQUENCE_NODE)
997  curSub->m_seqChildren.emplace_back(std::move(ValToNode(val, byteCount)));
998  }
999 
1000  inline void writeBool(const char* name, const bool& val)
1001  {
1002  writeVal<bool>(name, val);
1003  }
1004 
1005  inline void writeByte(const char* name, const atInt8& val)
1006  {
1007  writeVal<atInt8>(name, val);
1008  }
1009 
1010  inline void writeUByte(const char* name, const atUint8& val)
1011  {
1012  writeVal<atUint8>(name, val);
1013  }
1014 
1015  inline void writeInt16(const char* name, const atInt16& val)
1016  {
1017  writeVal<atInt16>(name, val);
1018  }
1019 
1020  inline void writeUint16(const char* name, const atUint16& val)
1021  {
1022  writeVal<atUint16>(name, val);
1023  }
1024 
1025  inline void writeInt32(const char* name, const atInt32& val)
1026  {
1027  writeVal<atInt32>(name, val);
1028  }
1029 
1030  inline void writeUint32(const char* name, const atUint32& val)
1031  {
1032  writeVal<atUint32>(name, val);
1033  }
1034 
1035  inline void writeInt64(const char* name, const atInt64& val)
1036  {
1037  writeVal<atInt64>(name, val);
1038  }
1039 
1040  inline void writeUint64(const char* name, const atUint64& val)
1041  {
1042  writeVal<atUint64>(name, val);
1043  }
1044 
1045  inline void writeFloat(const char* name, const float& val)
1046  {
1047  writeVal<float>(name, val);
1048  }
1049 
1050  inline void writeDouble(const char* name, const double& val)
1051  {
1052  writeVal<double>(name, val);
1053  }
1054 
1055  inline void writeVec2f(const char* name, const atVec2f& val)
1056  {
1057  writeVal<atVec2f>(name, val);
1058  }
1059 
1060  inline void writeVec3f(const char* name, const atVec3f& val)
1061  {
1062  writeVal<atVec3f>(name, val);
1063  }
1064 
1065  inline void writeVec4f(const char* name, const atVec4f& val)
1066  {
1067  writeVal<atVec4f>(name, val);
1068  }
1069 
1070  inline void writeVec2d(const char* name, const atVec2d& val)
1071  {
1072  writeVal<atVec2d>(name, val);
1073  }
1074 
1075  inline void writeVec3d(const char* name, const atVec3d& val)
1076  {
1077  writeVal<atVec3d>(name, val);
1078  }
1079 
1080  inline void writeVec4d(const char* name, const atVec4d& val)
1081  {
1082  writeVal<atVec4d>(name, val);
1083  }
1084 
1085  inline void writeUBytes(const char* name, const std::unique_ptr<atUint8[]>& val, size_t byteCount)
1086  {
1087  writeVal<const std::unique_ptr<atUint8[]>&>(name, val, byteCount);
1088  }
1089 
1090  inline void writeString(const char* name, const std::string& val)
1091  {
1092  writeVal<std::string>(name, val);
1093  }
1094 
1095  inline void writeString(const char* name, const char* val)
1096  {
1097  writeVal<const char*>(name, val);
1098  }
1099 
1100  inline void writeWString(const char* name, const std::wstring& val)
1101  {
1102  writeVal<std::wstring>(name, val);
1103  }
1104 
1105  inline void writeWString(const char* name, const wchar_t* val)
1106  {
1107  writeVal<const wchar_t*>(name, val);
1108  }
1109 };
1110 
1111 int YAMLAthenaReader(athena::io::IStreamReader* reader,
1112  unsigned char* buffer, size_t size, size_t* size_read);
1113 
1114 int YAMLAthenaWriter(athena::io::IStreamWriter* writer,
1115  unsigned char *buffer, size_t size);
1116 
1117 /* forward-declaration dance for recursively-derived types */
1118 
1119 template <size_t sizeVar, Endian VE>
1120 struct BufferYaml;
1121 
1122 template <atInt32 sizeVar, Endian VE>
1123 struct StringYaml;
1124 
1125 template <atInt32 sizeVar, Endian VE>
1127 
1128 template <atInt32 sizeVar, Endian VE>
1130 
1131 template <Endian DNAE>
1132 struct DNAYaml : DNA<DNAE>
1133 {
1134  virtual ~DNAYaml() {}
1135 
1136  using DNA<DNAE>::read;
1137  using DNA<DNAE>::write;
1138  virtual void read(YAMLDocReader& in)=0;
1139  virtual void write(YAMLDocWriter& out) const=0;
1140  static const char* DNAType() {return nullptr;}
1141  virtual const char* DNATypeV() const {return nullptr;}
1142 
1143  template <size_t sizeVar>
1144  using Buffer = struct athena::io::BufferYaml<sizeVar, DNAE>;
1145 
1146  template <atInt32 sizeVar = -1>
1147  using String = struct athena::io::StringYaml<sizeVar, DNAE>;
1148 
1149  template <atInt32 sizeVar = -1, Endian VE = DNAE>
1150  using WString = struct athena::io::WStringYaml<sizeVar, VE>;
1151 
1152  template <atInt32 sizeVar = -1>
1153  using WStringAsString = struct athena::io::WStringAsStringYaml<sizeVar, DNAE>;
1154 
1155  std::string toYAMLString() const
1156  {
1157  YAMLDocWriter docWriter(DNATypeV());
1158 
1159  std::string res;
1160  yaml_emitter_set_output(docWriter.getEmitter(), (yaml_write_handler_t*)YAMLStdStringWriter, &res);
1161  yaml_emitter_set_unicode(docWriter.getEmitter(), true);
1162  yaml_emitter_set_width(docWriter.getEmitter(), -1);
1163 
1164  write(docWriter);
1165  if (!docWriter.finish(nullptr))
1166  return std::string();
1167 
1168  return res;
1169  }
1170 
1171  bool fromYAMLString(const std::string& str)
1172  {
1173  YAMLStdStringReaderState reader(str);
1174  YAMLDocReader docReader;
1175  yaml_parser_set_input(docReader.getParser(), (yaml_read_handler_t*)YAMLStdStringReader, &reader);
1176  if (!docReader.parse(nullptr))
1177  return false;
1178  read(docReader);
1179  return true;
1180  }
1181 
1182  template<class DNASubtype>
1183  static bool ValidateFromYAMLString(const std::string& str)
1184  {
1185  YAMLStdStringReaderState reader(str);
1186  YAMLDocReader docReader;
1187  yaml_parser_set_input(docReader.getParser(), (yaml_read_handler_t*)YAMLStdStringReader, &reader);
1188  bool retval = docReader.ValidateClassType(DNASubtype::DNAType());
1189  return retval;
1190  }
1191 
1192  bool toYAMLStream(athena::io::IStreamWriter& fout) const
1193  {
1194  YAMLDocWriter docWriter(DNATypeV());
1195 
1196  yaml_emitter_set_unicode(docWriter.getEmitter(), true);
1197  yaml_emitter_set_width(docWriter.getEmitter(), -1);
1198 
1199  write(docWriter);
1200  if (!docWriter.finish(&fout))
1201  return false;
1202 
1203  return true;
1204  }
1205 
1206  bool fromYAMLStream(athena::io::IStreamReader& fin)
1207  {
1208  YAMLDocReader docReader;
1209  if (!docReader.parse(&fin))
1210  return false;
1211  read(docReader);
1212  return true;
1213  }
1214 
1215  template<class DNASubtype>
1216  static bool ValidateFromYAMLStream(athena::io::IStreamReader& fin)
1217  {
1218  YAMLDocReader reader;
1219  atUint64 pos = fin.position();
1220  yaml_parser_set_input(reader.getParser(), (yaml_read_handler_t*)YAMLAthenaReader, &fin);
1221  bool retval = reader.ValidateClassType(DNASubtype::DNAType());
1222  fin.seek(pos, athena::Begin);
1223  return retval;
1224  }
1225 };
1226 
1227 template <size_t sizeVar, Endian VE>
1228 struct BufferYaml : public DNAYaml<VE>, public std::unique_ptr<atUint8[]>
1229 {
1230  typename DNA<VE>::Delete expl;
1231  void read(IStreamReader& reader)
1232  {
1233  reset(new atUint8[sizeVar]);
1234  reader.readUBytesToBuf(get(), sizeVar);
1235  }
1236  void write(IStreamWriter& writer) const
1237  {
1238  writer.writeUBytes(get(), sizeVar);
1239  }
1240  size_t binarySize(size_t __isz) const
1241  {
1242  return __isz + sizeVar;
1243  }
1244  void read(athena::io::YAMLDocReader& reader)
1245  {*this = reader.readUBytes(nullptr);}
1246  void write(athena::io::YAMLDocWriter& writer) const
1247  {writer.writeUBytes(nullptr, *this, sizeVar);}
1248 };
1249 
1250 template <atInt32 sizeVar, Endian VE>
1251 struct StringYaml : public DNAYaml<VE>, public std::string
1252 {
1253  typename DNA<VE>::Delete expl;
1254  void read(IStreamReader& reader)
1255  {this->assign(std::move(reader.readString(sizeVar)));}
1256  void write(IStreamWriter& writer) const
1257  {writer.writeString(*this, sizeVar);}
1258  size_t binarySize(size_t __isz) const
1259  {return __isz + ((sizeVar<0)?(this->size()+1):sizeVar);}
1260  void read(athena::io::YAMLDocReader& reader)
1261  {this->assign(std::move(reader.readString(nullptr)));}
1262  void write(athena::io::YAMLDocWriter& writer) const
1263  {writer.writeString(nullptr, *this);}
1264  std::string& operator=(const std::string& __str)
1265  {return this->assign(__str);}
1266  std::string& operator=(std::string&& __str)
1267  {this->swap(__str); return *this;}
1268 };
1269 
1270 template <atInt32 sizeVar, Endian VE>
1271 struct WStringYaml : public DNAYaml<VE>, public std::wstring
1272 {
1273  typename DNA<VE>::Delete expl;
1274  void read(IStreamReader& reader)
1275  {
1276  reader.setEndian(VE);
1277  this->assign(std::move(reader.readWString(sizeVar)));
1278  }
1279  void write(IStreamWriter& writer) const
1280  {
1281  writer.setEndian(VE);
1282  writer.writeWString(*this, sizeVar);
1283  }
1284  size_t binarySize(size_t __isz) const
1285  {return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
1286  void read(athena::io::YAMLDocReader& reader)
1287  {this->assign(std::move(reader.readWString(nullptr)));}
1288  void write(athena::io::YAMLDocWriter& writer) const
1289  {writer.writeWString(nullptr, *this);}
1290  std::wstring& operator=(const std::wstring& __str)
1291  {return this->assign(__str);}
1292  std::wstring& operator=(std::wstring&& __str)
1293  {this->swap(__str); return *this;}
1294 };
1295 
1296 template <atInt32 sizeVar, Endian VE>
1297 struct WStringAsStringYaml : public DNAYaml<VE>, public std::string
1298 {
1299  typename DNA<VE>::Delete expl;
1300  void read(IStreamReader& reader)
1301  {*this = reader.readWStringAsString(sizeVar);}
1302  void write(IStreamWriter& writer) const
1303  {writer.writeStringAsWString(*this, sizeVar);}
1304  size_t binarySize(size_t __isz) const
1305  {return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);}
1306  void read(athena::io::YAMLDocReader& reader)
1307  {this->assign(std::move(reader.readString(nullptr)));}
1308  void write(athena::io::YAMLDocWriter& writer) const
1309  {writer.writeString(nullptr, *this);}
1310  std::string& operator=(const std::string& __str)
1311  {return this->assign(__str);}
1312  std::string& operator=(std::string&& __str)
1313  {this->swap(__str); return *this;}
1314 };
1315 
1317 #define DECL_YAML \
1318  DECL_DNA \
1319  void read(athena::io::YAMLDocReader&); \
1320  void write(athena::io::YAMLDocWriter&) const; \
1321  static const char* DNAType(); \
1322  const char* DNATypeV() const {return DNAType();} \
1323 
1324 
1325 #define DECL_EXPLICIT_YAML \
1326  void read(athena::io::YAMLDocReader&); \
1327  void write(athena::io::YAMLDocWriter&) const; \
1328  static const char* DNAType(); \
1329  const char* DNATypeV() const {return DNAType();} \
1330 
1331 }
1332 }
1333 
1334 #endif // DNAYAML_HPP
void read(IStreamReader &reader)
Common virtual read function for all DNA types.
Definition: DNAYaml.hpp:1254
void read(IStreamReader &reader)
Common virtual read function for all DNA types.
Definition: DNAYaml.hpp:1274
std::string readWStringAsString(atInt32 fixedLen=-1)
Reads a wide-char string (using endianness from setEndian), converts to UTF8 and advances the positio...
std::wstring readWString(atInt32 fixedLen=-1)
Reads a wstring and advances the position in the file.
void writeWString(const std::wstring &str, atInt32 fixedLen=-1)
Writes an wstring to the buffer and advances the buffer.
Base DNA class used against &#39;atdna&#39;.
Definition: DNA.hpp:45
virtual void writeUBytes(const atUint8 *data, atUint64 len)=0
Writes the given buffer with the specified length, buffers can be bigger than the length however it&#39;s...
Concrete converting-wstring type used by DNA::WStringAsString.
Definition: DNA.hpp:33
The IStreamReader class defines a basic API for reading from streams, Implementors are provided with ...
Concrete buffer type used by DNA::Buffer.
Definition: DNA.hpp:24
void write(IStreamWriter &writer) const
Common virtual write function for all DNA types.
Definition: DNAYaml.hpp:1302
void write(IStreamWriter &writer) const
Common virtual write function for all DNA types.
Definition: DNAYaml.hpp:1256
void writeStringAsWString(const std::string &str, atInt32 fixedLen=-1)
Converts a UTF8 string to a wide-char string in the buffer and advances the buffer. It also swaps the bytes depending on the platform and Stream settings.
size_t binarySize(size_t __isz) const
Common virtual binary size computation for all DNA types.
Definition: DNAYaml.hpp:1304
Concrete wstring type used by DNA::WString.
Definition: DNA.hpp:30
void read(IStreamReader &reader)
Common virtual read function for all DNA types.
Definition: DNAYaml.hpp:1300
std::string readString(atInt32 fixedLen=-1)
Reads a string and advances the position in the file.
virtual atUint64 position() const =0
Returns the current position in the stream.
virtual void seek(atInt64 pos, SeekOrigin origin=SeekOrigin::Current)=0
Sets the buffers position relative to the specified position. It seeks relative to the current posit...
void read(IStreamReader &reader)
Common virtual read function for all DNA types.
Definition: DNAYaml.hpp:1231
size_t binarySize(size_t __isz) const
Common virtual binary size computation for all DNA types.
Definition: DNAYaml.hpp:1240
size_t binarySize(size_t __isz) const
Common virtual binary size computation for all DNA types.
Definition: DNAYaml.hpp:1284
void write(IStreamWriter &writer) const
Common virtual write function for all DNA types.
Definition: DNAYaml.hpp:1279
void writeString(const std::string &str, atInt32 fixedLen=-1)
Writes an string to the buffer and advances the buffer.
Concrete string type used by DNA::String.
Definition: DNA.hpp:27
virtual atUint64 readUBytesToBuf(void *buf, atUint64 len)=0
Attempts to read a fixed length of data into a pre-allocated buffer, this function is client defined ...
size_t binarySize(size_t __isz) const
Common virtual binary size computation for all DNA types.
Definition: DNAYaml.hpp:1258
void write(IStreamWriter &writer) const
Common virtual write function for all DNA types.
Definition: DNAYaml.hpp:1236