Visualization Library 2.0.0-b3

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
VLXParserVLT.hpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2017, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #ifndef VLXParserVLT_INCLUDE_ONCE
33 #define VLXParserVLT_INCLUDE_ONCE
34 
35 #include <vlCore/VLXParser.hpp>
36 #include <vlCore/VLTTokenizer.hpp>
37 #include <cstdlib>
38 
39 #ifdef _MSC_VER
40  #define atoll _atoi64
41 #endif
42 
43 namespace vl
44 {
46  class VLXParserVLT: public VLXParser
47  {
49 
50  public:
52  {
53  mTokenizer = new VLTTokenizer;
54  mVersion = 0;
55  }
56 
57  bool getToken(VLTToken& token) { return mTokenizer->getToken(token); }
58 
59  bool parseHeader()
60  {
61  mVersion = 0;
62  mEncoding.clear();
63 
64  // VLX
65  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "VLX")
66  {
67  Log::error("'VLX' header not found!\n");
68  return false;
69  }
70 
71  // version
72  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "version")
73  return false;
74 
75  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
76  return false;
77 
78  if (!getToken(mToken) || mToken.mType != VLTToken::Integer || mToken.mString != "100")
79  return false;
80  else
81  mVersion = (unsigned short)atoi( mToken.mString.c_str() );
82 
83  // encoding
84  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "encoding")
85  return false;
86 
87  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
88  return false;
89 
90  if (!getToken(mToken) || mToken.mType != VLTToken::Identifier || mToken.mString != "ascii")
91  return false;
92  else
93  mEncoding = mToken.mString;
94 
95  return true;
96  }
97 
98  bool parse()
99  {
100  class CloseFileClass
101  {
102  public:
103  CloseFileClass(VirtualFile* f): mFile(f) {}
104  ~CloseFileClass()
105  {
106  if (mFile)
107  mFile->close();
108  }
109  private:
110  ref<VirtualFile> mFile;
111  } CloseFile(tokenizer()->inputFile());
112 
113  // clear metadata
114  mMetadata.clear();
115 
116  // read version and encoding
117  if (!parseHeader())
118  {
119  Log::error( Say("Line %n : error parsing VLT header at '%s'.\n") << tokenizer()->lineNumber() << mToken.mString );
120  return false;
121  }
122 
123  if (mVersion != 100)
124  {
125  Log::error("VLX version not supported.\n");
126  return false;
127  }
128 
129  if (mEncoding != "ascii")
130  {
131  Log::error("Encoding not supported.\n");
132  return false;
133  }
134 
135  while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
136  {
137  if(mToken.mType == VLTToken::TagHeader)
138  {
139  mLastTag = mToken.mString;
140 
141  if(getToken(mToken) && mToken.mType == VLTToken::LeftCurlyBracket)
142  {
144  st->setLineNumber( tokenizer()->lineNumber() );
145 
146  if (!parseStructure(st.get()))
147  {
148  if (mToken.mString.length())
149  Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
150  else
151  Log::error( Say("Line %n : parse error.\n") << mTokenizer->lineNumber() );
152  return false;
153  }
154 
155  mStructures.push_back(st);
156  }
157  else
158  {
159  Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
160  return false;
161  }
162  }
163  else
164  {
165  Log::error( Say("Line %n : parse error at '%s'.\n") << mTokenizer->lineNumber() << mToken.mString.c_str() );
166  return false;
167  }
168  }
169 
170  parseMetadata();
171 
172  VL_CHECK(mToken.mType == VLTToken::TOKEN_EOF)
173  return mToken.mType == VLTToken::TOKEN_EOF;
174  }
175 
177  {
178  // consume last tag if there was one
179  if (!mLastTag.empty())
180  {
181  object->setTag(mLastTag.c_str());
182  mLastTag.clear();
183  }
184 
185  while(getToken(mToken))
186  {
187  if (mToken.mType == VLTToken::RightCurlyBracket)
188  {
189  return true;
190  }
191  else
192  if (mToken.mType == VLTToken::Identifier)
193  {
194  // ID field requires a proper #identifier
195  if (mToken.mString.length() == 2)
196  {
197  if (mToken.mString == "ID")
198  {
199  // Check if ID has already been set
200  if (!object->uid().empty() && object->uid() != "#NULL")
201  {
202  Log::error("ID already set.\n");
203  return false;
204  }
205 
206  // Equals
207  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
208  return false;
209 
210  // #identifier
211  if (getToken(mToken) && mToken.mType == VLTToken::ID)
212  {
213  object->setID(mToken.mString.c_str());
214  continue;
215  }
216  else
217  return false;
218  }
219  else
220  // ID is a reserved keyword: all the other case combinations are illegal
221  if (mToken.mString == "Id" || mToken.mString == "iD" || mToken.mString == "id")
222  return false;
223  }
224 
225  // non-ID key-values
226  object->value().push_back( VLXStructure::Value() );
227  VLXStructure::Value& name_value = object->value().back();
228 
229  // Key
230  name_value.setKey( mToken.mString.c_str() );
231 
232  // Equals
233  if (!getToken(mToken) || mToken.mType != VLTToken::Equals)
234  return false;
235 
236  // Member value
237  if (getToken(mToken))
238  {
239  name_value.value().setLineNumber( tokenizer()->lineNumber() );
240 
241  // A new <Tag>
242  if (mToken.mType == VLTToken::TagHeader)
243  {
244  if (mLastTag.empty())
245  {
246  mLastTag = mToken.mString;
247  if (!getToken(mToken))
248  return false;
249  }
250  else
251  return false;
252  }
253 
254  // A new { Structure }
255  if (mToken.mType == VLTToken::LeftCurlyBracket)
256  {
257  ref<VLXStructure> object = new VLXStructure;
258  object->setLineNumber( tokenizer()->lineNumber() );
259  name_value.value().setStructure(object.get());
260  if (!parseStructure( object.get() ) )
261  return false;
262  }
263  else
264  // An [ list ]
265  if (mToken.mType == VLTToken::LeftSquareBracket)
266  {
267  ref<VLXList> list = new VLXList;
268  list->setLineNumber( tokenizer()->lineNumber() );
269  name_value.value().setList(list.get());
270  if ( !parseList( list.get() ) )
271  return false;
272  }
273  else
274  // An ( array )
275  if (mToken.mType == VLTToken::LeftRoundBracket)
276  {
277  ref<VLXArray> arr;
278  if ( parseArray( arr ) )
279  name_value.value().setArray(arr.get());
280  else
281  return false;
282  }
283  else
284  // A {< rawtext block >}
285  if (mToken.mType == VLTToken::LeftFancyBracket)
286  {
287  if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
288  return false;
289  name_value.value().setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
290  name_value.value().getRawtextBlock()->setValue( mToken.mString.c_str() );
291  // consume the tag
292  mLastTag.clear();
293  if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
294  return false;
295  }
296  else
297  // A "string"
298  if (mToken.mType == VLTToken::String)
299  {
300  if (!mLastTag.empty())
301  return false;
302  name_value.value().setString(mToken.mString.c_str());
303  }
304  else
305  // An Identifier
306  if (mToken.mType == VLTToken::Identifier)
307  {
308  if (!mLastTag.empty())
309  return false;
310  name_value.value().setIdentifier(mToken.mString.c_str());
311  }
312  else
313  // An #id
314  if (mToken.mType == VLTToken::ID)
315  {
316  if (!mLastTag.empty())
317  return false;
318  name_value.value().setID(mToken.mString.c_str());
319  }
320  else
321  // A boolean true/false
322  if (mToken.mType == VLTToken::Boolean)
323  {
324  if (!mLastTag.empty())
325  return false;
326  name_value.value().setBool(mToken.mString == "true");
327  }
328  else
329  // An integer
330  if (mToken.mType == VLTToken::Integer)
331  {
332  if (!mLastTag.empty())
333  return false;
334  name_value.value().setInteger( atoll(mToken.mString.c_str()) );
335  }
336  else
337  // A float
338  if (mToken.mType == VLTToken::real)
339  {
340  if (!mLastTag.empty())
341  return false;
342  name_value.value().setReal( atof(mToken.mString.c_str()) );
343  }
344  else
345  return false;
346  }
347  }
348  else
349  return false;
350  }
351  return false;
352  }
353 
354  bool parseList(VLXList* list)
355  {
356  // consume last tag if there was one
357  if (!mLastTag.empty())
358  {
359  list->setTag(mLastTag.c_str());
360  mLastTag.clear();
361  }
362 
363  while(getToken(mToken))
364  {
365  if (mToken.mType == VLTToken::RightSquareBracket)
366  return true;
367  else
368  {
369  VLXValue value;
370  value.setLineNumber( tokenizer()->lineNumber() );
371  switch( mToken.mType )
372  {
373  // <tag>
374  case VLTToken::TagHeader:
375  {
376  if (mLastTag.empty())
377  mLastTag = mToken.mString;
378  else
379  return false;
380  break;
381  }
382 
383  // object
385  {
386  ref<VLXStructure> object = new VLXStructure;
387  object->setLineNumber( tokenizer()->lineNumber() );
388  if ( parseStructure( object.get() ) )
389  {
390  value.setStructure(object.get());
391  list->value().push_back( value );
392  }
393  else
394  return false;
395  break;
396  }
397 
398  // list
400  {
401  ref<VLXList> sub_list = new VLXList;
402  sub_list->setLineNumber( tokenizer()->lineNumber() );
403  if ( parseList( sub_list.get() ) )
404  {
405  value.setList( sub_list.get() );
406  list->value().push_back( value );
407  }
408  else
409  return false;
410  break;
411  }
412 
413  // array
415  {
416  ref<VLXArray> arr;
417  if (parseArray(arr))
418  {
419  value.setArray(arr.get());
420  list->value().push_back(value);
421  }
422  else
423  return false;
424  break;
425  }
426 
427  // string
428  case VLTToken::String:
429  if (!mLastTag.empty())
430  return false;
431  value.setString( mToken.mString.c_str() ); list->value().push_back( value );
432  break;
433 
434  // identifier
436  if (!mLastTag.empty())
437  return false;
438  value.setIdentifier( mToken.mString.c_str() ); list->value().push_back( value );
439  break;
440 
441  // A {< rawtext block >}
443  {
444  if(!getToken(mToken) || mToken.mType != VLTToken::RawtextBlock)
445  return false;
446 
447  value.setRawtextBlock( new VLXRawtextBlock(mLastTag.c_str()) );
448  value.getRawtextBlock()->setValue( mToken.mString.c_str() );
449  list->value().push_back( value );
450  // consume the tag
451  mLastTag.clear();
452 
453  if(!getToken(mToken) || mToken.mType != VLTToken::RightFancyBracket)
454  return false;
455  break;
456  }
457 
458  // ID
459  case VLTToken::ID:
460  if (!mLastTag.empty())
461  return false;
462  value.setID( mToken.mString.c_str() ); list->value().push_back( value );
463  break;
464 
465  // boolean
466  case VLTToken::Boolean:
467  if (!mLastTag.empty())
468  return false;
469  value.setBool( mToken.mString == "true" ); list->value().push_back( value );
470  break;
471 
472  // int
473  case VLTToken::Integer:
474  if (!mLastTag.empty())
475  return false;
476  value.setInteger( atoll(mToken.mString.c_str()) ); list->value().push_back( value );
477  break;
478 
479  // float
480  case VLTToken::real:
481  if (!mLastTag.empty())
482  return false;
483  value.setReal( atof(mToken.mString.c_str()) ); list->value().push_back( value );
484  break;
485 
486  default:
487  return false;
488  }
489  }
490  }
491  return false;
492  }
493 
495  {
496  // consume last tag if there was one
497  struct struct_consume_tag
498  {
499  struct_consume_tag(ref<VLXArray>* p1, std::string* p2): p_arr(p1), p_tag(p2) {}
500 
501  ~struct_consume_tag()
502  {
503  if ((*p_arr).get() && !p_tag->empty())
504  {
505  (*p_arr)->setTag(p_tag->c_str());
506  p_tag->clear();
507  }
508  }
509 
510  ref<VLXArray>* p_arr;
511  std::string* p_tag;
512  } consume_tag(&arr, &mLastTag);
513 
514  if(getToken(mToken))
515  {
516  // (1) from the fist token we decide what kind of array it is going to be
517  // (2) empty arrays default to empty VLXArrayInteger
518 
519  if (mToken.mType == VLTToken::RightRoundBracket)
520  {
521  arr = new VLXArrayInteger;
522  return true;
523  }
524  /*
525  else
526  if (mToken.mType == VLTToken::String)
527  {
528  ref<VLXArrayString> arr_string;
529  arr = arr_string = new VLXArrayString;
530  do
531  arr_string->mValue.push_back(mToken.mString);
532  while(getToken(mToken) && mToken.mType == VLTToken::String);
533  return mToken.mType == VLTToken::RightRoundBracket;
534  }
535  else
536  if (mToken.mType == VLTToken::Identifier)
537  {
538  ref<VLXArrayIdentifier> arr_identifier;
539  arr = arr_identifier = new VLXArrayIdentifier;
540  do
541  arr_identifier->mValue.push_back(mToken.mString);
542  while(getToken(mToken) && mToken.mType == VLTToken::Identifier);
543  return mToken.mType == VLTToken::RightRoundBracket;
544  }
545  else
546  if (mToken.mType == VLTToken::ID)
547  {
548  ref<VLXArrayID> arr_uid;
549  arr = arr_uid = new VLXArrayID;
550  do
551  arr_uid->mValue.push_back(mToken.mString.c_str());
552  while(getToken(mToken) && mToken.mType == VLTToken::ID);
553  return mToken.mType == VLTToken::RightRoundBracket;
554  }
555  */
556  else
557  if (mToken.mType == VLTToken::Integer)
558  {
559  ref<VLXArrayInteger> arr_integer;
560  arr = arr_integer = new VLXArrayInteger;
561  do
562  {
563  switch(mToken.mType)
564  {
565  case VLTToken::Integer: arr_integer->value().push_back( atoll( mToken.mString.c_str() ) ); break;
566  case VLTToken::RightRoundBracket: return true;
567  default:
568  return false;
569  }
570  }
571  while(getToken(mToken));
572  return false;
573  }
574  else
575  if (mToken.mType == VLTToken::real)
576  {
577  ref<VLXArrayReal> arr_floating;
578  arr = arr_floating = new VLXArrayReal;
579  arr_floating->value().reserve(1024);
580  // mic fixme:
581  // READING ARRAYS OF NUMBERS IS THE MAIN HOT SPOT FOR THE VLT PARSER
582  // - we could speed things up by quickly tokenizing and aotf-ing all the numbers here
583  // - we could also use a quicker atof() that works for numbers of the type +1234.1234 using the tokenizer to determine the sub-type
584  // - ideally we should mix the following:
585  // - read big chunks of bytes instead of one by one like now
586  // - merge the quick atof with the tokenizer in one single operation, fall back to standard atof() when complex numbers are detected
587  // - proceed until we find ")"
588  // - we could disallow comments in Arrays to speedup the parsing
589  do
590  {
591  switch(mToken.mType)
592  {
593  case VLTToken::Integer:
594  case VLTToken::real: arr_floating->value().push_back( atof( mToken.mString.c_str() ) ); break;
595  case VLTToken::RightRoundBracket: return true;
596  default:
597  return false;
598  }
599  }
600  while(getToken(mToken));
601  return false;
602  }
603  else
604  return false;
605  }
606 
607  return false;
608  }
609 
610  // for debug only
611  void listTokens()
612  {
613  while(getToken(mToken) && mToken.mType != VLTToken::TOKEN_EOF)
614  {
615  switch(mToken.mType)
616  {
617  case VLTToken::LeftRoundBracket: printf("LeftSquareBracket (\n"); break;
618  case VLTToken::RightRoundBracket: printf("RightSquareBracket )\n"); break;
619  case VLTToken::LeftSquareBracket: printf("LeftSquareBracket [\n"); break;
620  case VLTToken::RightSquareBracket: printf("RightSquareBracket ]\n"); break;
621  case VLTToken::LeftCurlyBracket: printf("LeftCurlyBracket {\n"); break;
622  case VLTToken::RightCurlyBracket: printf("RightCurlyBracket } \n"); break;
623  case VLTToken::LeftFancyBracket: printf("LeftFancyBracket >}\n"); break;
624  case VLTToken::RightFancyBracket: printf("RightFancyBracket {< \n"); break;
625  case VLTToken::Equals: printf("Equals =\n"); break;
626  case VLTToken::String: printf("String = %s\n", mToken.mString.c_str()); break;
627  case VLTToken::ID: printf("ID = %s\n", mToken.mString.c_str()); break;
628  case VLTToken::Identifier: printf("Identifier = %s\n", mToken.mString.c_str()); break;
629  case VLTToken::RawtextBlock: printf("RawtextBlock = %s\n", mToken.mString.c_str()); break;
630  case VLTToken::real: printf("real = %s\n", mToken.mString.c_str()); break;
631  case VLTToken::Integer: printf("Integer = %s\n", mToken.mString.c_str()); break;
632  case VLTToken::TagHeader: printf("TagHeader = %s\n", mToken.mString.c_str()); break;
633  default:
634  break;
635  }
636  }
637  if (mToken.mType != VLTToken::TOKEN_EOF)
638  {
639  printf("Line %d: syntax error : '%s'.\n", mTokenizer->lineNumber(), mToken.mString.c_str());
640  }
641  }
642 
643  VLTTokenizer* tokenizer() { return mTokenizer.get(); }
644 
645  const VLTTokenizer* tokenizer() const { return mTokenizer.get(); }
646 
647  private:
648  std::string mLastTag;
649  ref<VLTTokenizer> mTokenizer;
650  VLTToken mToken;
651  };
652 }
653 
654 #ifdef _MSC_VER
655  #undef atoll
656 #endif
657 
658 #endif
VLXRawtextBlock * getRawtextBlock()
Definition: VLXValue.hpp:417
double setReal(double val)
Definition: VLXValue.hpp:498
long long setInteger(long long val)
Definition: VLXValue.hpp:487
void setKey(const char *key)
Definition: VLXValue.hpp:591
std::vector< ref< VLXStructure > > mStructures
Definition: VLXParser.hpp:99
void setTag(const char *tag)
Definition: VLXValue.hpp:60
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
Base class for VLX parsers.
Definition: VLXParser.hpp:41
std::string mString
void setValue(const char *value)
Definition: VLXValue.hpp:87
A simple String formatting class.
Definition: Say.hpp:124
const VLTTokenizer * tokenizer() const
Parses a VLT file translating it into a VLX hierarchy.
VLCORE_EXPORT VLXStructure * setStructure(VLXStructure *)
Definition: VLXValue.cpp:133
std::map< std::string, VLXValue > mMetadata
Definition: VLXParser.hpp:100
bool parseArray(ref< VLXArray > &arr)
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:164
VLCORE_EXPORT VLXList * setList(VLXList *)
Definition: VLXValue.cpp:143
An array of 64 bits floating point numbers, can also have a tag.
Definition: VLXValue.hpp:143
const std::string & setID(const char *str)
Definition: VLXValue.hpp:475
std::string mEncoding
Definition: VLXParser.hpp:97
#define VL_INSTRUMENT_CLASS(ClassName, BaseClass)
Definition: TypeInfo.hpp:122
Tokenizer used to parse VLT files.
Visualization Library main namespace.
const std::string & uid() const
Definition: VLXValue.hpp:604
A block of raw text.
Definition: VLXValue.hpp:70
VLCORE_EXPORT VLXArray * setArray(VLXArray *)
Definition: VLXValue.cpp:224
Key/value pair used by VLXStructure.
Definition: VLXValue.hpp:581
bool parseList(VLXList *list)
unsigned short mVersion
Definition: VLXParser.hpp:98
bool getToken(VLTToken &token)
const std::string & setIdentifier(const char *str)
Definition: VLXValue.hpp:463
void setLineNumber(int line)
Definition: VLXValue.hpp:520
Wrapper for all VLX value types.
Definition: VLXValue.hpp:239
void setLineNumber(int line)
Definition: VLXValue.hpp:56
An array of 64 bits integers, can also have a tag.
Definition: VLXValue.hpp:132
bool setBool(bool val)
Definition: VLXValue.hpp:509
const std::string & setString(const char *str)
Definition: VLXValue.hpp:451
A simple sequence of VLXValue objects, can also have a tag.
Definition: VLXValue.hpp:633
A token of information as defined by VLT specification.
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
VLCORE_EXPORT VLXRawtextBlock * setRawtextBlock(VLXRawtextBlock *)
Definition: VLXValue.cpp:155
std::vector< VLXValue > & value()
Definition: VLXValue.hpp:651
bool parseStructure(VLXStructure *object)
void parseMetadata()
Moves the <Metadata> key/value pairs in the Metadata map for quick and easy access and removes the <M...
Definition: VLXParser.hpp:63
A list of key/VLXValue pairs, can also have a tag.
Definition: VLXValue.hpp:540
#define VL_CHECK(expr)
Definition: checks.hpp:73
VLTTokenizer * tokenizer()