HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_JSONParser.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_JSONParser.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_JSONParser__
12 #define __UT_JSONParser__
13 
14 #include "UT_API.h"
15 #include "UT_ArrayMap.h"
16 #include "UT_JSONDefines.h"
17 #include "UT_StackBuffer.h"
18 #include "UT_StringArray.h"
19 #include "UT_StringHolder.h"
20 #include "UT_ValArray.h"
21 #include "UT_WorkBuffer.h"
22 
23 #include <SYS/fpreal16Limits.h>
24 #include <SYS/SYS_Math.h>
25 #include <SYS/SYS_Types.h>
26 
27 #include <istream>
28 #include <limits>
29 #include <streambuf>
30 
31 
32 class UT_BitArray;
33 class UT_IStream;
34 class UT_JSONHandle;
35 class UT_JSONValue;
36 
37 class ut_JValue;
38 class ut_SimpleJSONObjectHandle;
39 
40 
41 /// @brief JSON reader class which handles parsing of JSON or bJSON files
42 ///
43 /// The JSON format (http://www.json.org) is a generic way to store data.
44 /// Houdini extends JSON to a byte-stream binary encoding. This class is used
45 /// to parse JSON (binary or ASCII) and provides callbacks to handle the data.
46 ///
47 /// For binary JSON files, Houdini has extended JSON slightly to support
48 /// compact versions for specific data representations. The @c ua methods
49 /// callback methods on the JSONHandle are used to process a uniform array of
50 /// simple types. Data for the uniform array can be read directly from the
51 /// stream. Care must be taken for uaBool() and uaString() which encode the
52 /// array data. uaReadString() can be used to read a string from the data
53 /// stream. The uniform array of uaBool encodes the bits into 32-bit words.
54 ///
55 /// The standard implementation of the uaInt16() method is:
56 /// @code
57 /// bool
58 /// UT_JSONParser::uaInt16(int64 length) {
59 /// int16 value;
60 /// if (!jsonBeginArray())
61 /// return false;
62 /// for (int64 i=0; i < length; i++) {
63 /// if (!read(&value, sizeof(int16)))
64 /// return false;
65 /// if (getSwapFlag())
66 /// UTswapBytes(&value, 1);
67 /// if (!jsonInt(value))
68 /// return false;
69 /// }
70 /// return jsonEndArray();
71 /// }
72 /// @endcode
73 ///
74 /// There are several ways to use a UT_JSONParser instance to parse a JSON
75 /// stream.
76 ///
77 /// 1. The UT_JSONParser::parseObject() method can be used to parse a single
78 /// JSON object from a supplied stream, with a subclass of UT_JSONHandle
79 /// processing the individual tokens.
80 /// 2. A UT_JSONValue can be used to load a JSON object in its entirety using
81 /// UT_JSONValue:parseValue().
82 /// 3. The UT_AutoJSONParser wrapper can be used to associate a UT_JSONParser
83 /// with a stream and the individual UT_JSONParser::parseFoo() methods can
84 /// be called
85 ///
86 /// @see UT_JID, UT_JSONHandle, UT_JSONValue, UT_AutoJSONParser
88 {
89 public:
91 
92  UT_JSONParser();
93  ~UT_JSONParser();
94 
95  UT_JSONParser(const UT_JSONParser &) = delete;
96  UT_JSONParser &operator=(const UT_JSONParser &) = delete;
97 
98  /// Seek the parser to a specific location in stream (see streams
99  /// seekg)
100  /// If the reset flag is true then the parser will be reset so it
101  /// expects to see the beginning of a JSON stream.
102  bool seekg(exint pos, int dir, bool reset = true);
103 
104  /// Retrieves the stream that is being used internally to read
105  /// This is used for seekable geometry files to read the footer
106  /// without parsing it as JSON.
107  /// Normally using this should be avoided.
108  UT_IStream* getInternalStream();
109 
110  /// Set's binary to given value. This is used to read BJSON without
111  /// having the magic infront of it (for embedded geometry)
112  void setBinary(bool isBinary) { myBinary = isBinary; }
113 
114  /// Parse a single object.
115  /// @param handle @n
116  /// The UT_JSONHandle to perform interpretation of the JSON tokens
117  /// @param is @n
118  /// If specified, data will be read from this stream. The initial
119  /// parseObject() call must have a stream.
120  bool parseObject(UT_JSONHandle &handle, UT_IStream*is=0);
121 
122  /// @{
123  /// Simple convenience method to parse a single string (keys not valid)
124  /// This is done by reading the next object using UT_JSONValue.
125  /// The method fails if the next object in the stream is not a string.
126  bool parseString(UT_WorkBuffer &v);
127  bool parseString(UT_StringHolder &v);
128  /// @}
129 
130  /// @{
131  /// Simple convenience method to parse a single map key (strings not valid)
132  /// This is done by reading the next object using UT_JSONValue
133  /// The method fails if the next object in the stream is not a key.
134  bool parseKey(UT_WorkBuffer &v);
135  bool parseKey(UT_StringHolder &v);
136  /// @}
137  /// Simple convenience method to parse a single string (keys not valid)
138  /// This is done by reading the next object using UT_JSONValue.
139  /// The method fails if the next object in the stream is not a string.
140  bool parseBool(bool &v);
141  /// Simple convenience method to parse a single integer
142  /// This is done by reading the next object using UT_JSONValue
143  /// The method fails if the next object in the stream is not a number or
144  /// bool. Real values are cast to integers.
145  bool parseInteger(int64 &v);
146  /// Alternate short-form
147  bool parseInt(int64 &v) { return parseInteger(v); }
148  /// Simple convenience method to parse a single real
149  /// This is done by reading the next object using UT_JSONValue
150  /// The method fails if the next object in the stream is not a number
151  bool parseReal(fpreal64 &v);
152  /// Generic parsing of a number (int)
153  bool parseNumber(int8 &v);
154  bool parseNumber(int16 &v);
155  bool parseNumber(int32 &v);
156  bool parseNumber(int64 &v) { return parseInteger(v); }
157  bool parseNumber(uint8 &v);
158  bool parseNumber(uint16 &v);
159  /// Generic parsing of a number (real)
160  bool parseNumber(fpreal16 &v);
161  bool parseNumber(fpreal32 &v);
162  bool parseNumber(fpreal64 &v) { return parseReal(v); }
163 
164  bool parseValue(UT_WorkBuffer &v){ return parseString(v); }
165  bool parseValue(UT_StringHolder &v){ return parseString(v); }
166  bool parseValue(bool &v) { return parseBool(v); }
167  bool parseValue(int8 &v) { return parseNumber(v); }
168  bool parseValue(int16 &v) { return parseNumber(v); }
169  bool parseValue(int32 &v) { return parseNumber(v); }
170  bool parseValue(int64 &v) { return parseNumber(v); }
171  bool parseValue(uint8 &v) { return parseNumber(v); }
172  bool parseValue(uint16 &v) { return parseNumber(v); }
173  bool parseValue(fpreal16 &v) { return parseNumber(v); }
174  bool parseValue(fpreal32 &v) { return parseNumber(v); }
175  bool parseValue(fpreal64 &v) { return parseNumber(v); }
176 
177  /// A utility method to load a uniform array of data (ie. those written
178  /// out by UT_JSONWriter::uniformArray()). Returns the number of elements
179  /// successfully extracted from the parser. A maximum of len elements will
180  /// be saved in data.
181  template <typename T>
183  {
184  iterator it = beginArray();
185  int64 array_size = getUniformArraySize();
186  int64 load_size = SYSmin(len, array_size);
187  int64 i;
188 
189  switch (getUniformArrayType())
190  {
191  case UT_JID_INT8:
192  i = UniformArrayHelper<int8, T>::load(it, data, load_size);
193  break;
194  case UT_JID_INT16:
195  i = UniformArrayHelper<int16, T>::load(it, data, load_size);
196  break;
197  case UT_JID_INT32:
198  i = UniformArrayHelper<int32, T>::load(it, data, load_size);
199  break;
200  case UT_JID_INT64:
201  i = UniformArrayHelper<int64, T>::load(it, data, load_size);
202  break;
203  case UT_JID_REAL16:
204  i = UniformArrayHelper<fpreal16, T>::load(it, data, load_size);
205  break;
206  case UT_JID_REAL32:
207  i = UniformArrayHelper<fpreal32, T>::load(it, data, load_size);
208  break;
209  case UT_JID_REAL64:
210  i = UniformArrayHelper<fpreal64, T>::load(it, data, load_size);
211  break;
212  default:
213  i = 0;
214  load_size = 0;
215  break;
216  }
217 
218  if (i < load_size) // error occurred during load
219  return i;
220 
221  // TODO: We eat any trailing array entries for the cases handled above
222  // here as well, and this could be done more efficiently.
223  for ( ; !it.atEnd(); ++it, ++i)
224  {
225  T val;
226  if (!parseValue(val))
227  break;
228  if (i < len)
229  data[i] = val;
230  }
231  return i;
232  }
233 
234  /// A utility method to load blocks of values from an array which can
235  /// load data from uniform arrays very efficiently. Returns the number
236  /// of elements successfully extracted from the parser. A maximum of len
237  /// elements will be saved in data.
238  template <typename T>
240  {
241  int64 unread_size = getUniformArrayUnreadSize();
242  int64 load_size = SYSmin(len, unread_size);
243  int64 i;
244 
245  switch (getUniformArrayType())
246  {
247  case UT_JID_INT8:
248  i = UniformArrayHelper<int8, T>::load(it, data, load_size);
249  break;
250  case UT_JID_INT16:
251  i = UniformArrayHelper<int16, T>::load(it, data, load_size);
252  break;
253  case UT_JID_INT32:
254  i = UniformArrayHelper<int32, T>::load(it, data, load_size);
255  break;
256  case UT_JID_INT64:
257  i = UniformArrayHelper<int64, T>::load(it, data, load_size);
258  break;
259  case UT_JID_REAL16:
260  i = UniformArrayHelper<fpreal16, T>::load(it, data, load_size);
261  break;
262  case UT_JID_REAL32:
263  i = UniformArrayHelper<fpreal32, T>::load(it, data, load_size);
264  break;
265  case UT_JID_REAL64:
266  i = UniformArrayHelper<fpreal64, T>::load(it, data, load_size);
267  break;
268  default:
269  for (i = 0; !it.atEnd() && i < len; ++it, ++i)
270  {
271  T val;
272  if (!parseValue(val))
273  break;
274  data[i] = val;
275  }
276  break;
277  }
278 
279  return i;
280  }
281 
282  /// A utility method to load a uniform array of data (ie. those written
283  /// out by UT_JSONWriter::uniformArray()). Returns the number of elements
284  /// successfully extracted from the parser. A maximum of len elements will
285  /// be saved in data.
286  int64 parseUniformBoolArray(UT_BitArray &data, int64 len);
287 
288 private:
289  /// @private - Used by loadPODArray
290  template <typename OP_TYPE, typename T> bool
291  loadPODUniformArray(OP_TYPE &op, iterator &it, int64 size)
292  {
293  UT_StackBuffer<T> b(size);
294  if (!it.readUniformArray(b.array(), size))
295  return false;
296  bool success = op.setArray((const T*)b, size);
297  return success;
298  }
299  /// @private - Used by parseUniformArray
300  template <typename INTERNAL_T, typename T>
301  class UniformArrayHelper
302  {
303  public:
304  /// size MUST be <= it.getUniformArraySize(), so a return value
305  /// less than size indicates an error occurred.
306  static int64 load(iterator &it, T *data, int64 size)
307  {
309  if (!it.readUniformArray(b.array(), size))
310  return 0;
313  std::numeric_limits<INTERNAL_T>::digits >
314  std::numeric_limits<T>::digits)
315  {
316  for (int64 i = 0; i < size; ++i)
317  {
318  INTERNAL_T v = b[i];
319  // Ondrej says INTERNAL_T should always be the larger
320  // precision type right here.
321  if (v < INTERNAL_T(std::numeric_limits<T>::min()) ||
322  v > INTERNAL_T(std::numeric_limits<T>::max()))
323  return i;
324  data[i] = static_cast<T>(v);
325  }
326  return size;
327  }
328  else
329  {
330  for (int64 i = 0; i < size; ++i)
331  data[i] = static_cast<T>(b[i]);
332  return size;
333  }
334  }
335  };
336  /// @private - Used by parseUniformArray
337  template <typename T>
338  class UniformArrayHelper<T,T>
339  {
340  public:
341  /// size MUST be <= it.getUniformArraySize(), so a return value
342  /// less than size indicates an error occurred.
343  static int64 load(iterator &it, T *data, int64 size)
344  {
345  if (!it.readUniformArray(data, size))
346  return 0;
347  return size;
348  }
349  };
350 public:
351  /// @private Used by iterator to determine uniform array information
352  UT_JID getUniformArrayType() const;
353  /// @private Used by iterator to determine uniform array information
354  int64 getUniformArraySize() const;
355  /// @private Used by iterator to determine uniform array information
356  int64 getUniformArrayUnreadSize() const;
357  /// @{
358  /// @private Used by iterator
359  bool readUniformArray(int8 *buffer, int64 buffer_size);
360  bool readUniformArray(int16 *buffer, int64 buffer_size);
361  bool readUniformArray(int32 *buffer, int64 buffer_size);
362  bool readUniformArray(int64 *buffer, int64 buffer_size);
363  bool readUniformArray(uint8 *buffer, int64 buffer_size);
364  bool readUniformArray(uint16 *buffer, int64 buffer_size);
365  bool readUniformArray(fpreal16 *buffer, int64 buffer_size);
366  bool readUniformArray(fpreal32 *buffer, int64 buffer_size);
367  bool readUniformArray(fpreal64 *buffer, int64 buffer_size);
368  /// @}
369 
370  /// Load an entire array of POD data using the operator passed in.
371  /// This method may allocate a temporary buffer to load a uniform
372  /// array.
373  template <typename OP_TYPE, typename POD_TYPE>
374  bool loadPODArray(OP_TYPE &op)
375  {
376  iterator it = beginArray();
377  int64 n = getUniformArraySize();
378  switch (getUniformArrayType())
379  {
380  case UT_JID_INT8:
381  return loadPODUniformArray<OP_TYPE, int8>
382  (op, it, n);
383  case UT_JID_INT16:
384  return loadPODUniformArray<OP_TYPE, int16>
385  (op, it, n);
386  case UT_JID_INT32:
387  return loadPODUniformArray<OP_TYPE, int32>
388  (op, it, n);
389  case UT_JID_INT64:
390  return loadPODUniformArray<OP_TYPE, int64>
391  (op, it, n);
392  case UT_JID_REAL16:
393  return loadPODUniformArray<OP_TYPE, fpreal16>
394  (op, it, n);
395  case UT_JID_REAL32:
396  return loadPODUniformArray<OP_TYPE, fpreal32>
397  (op, it, n);
398  case UT_JID_REAL64:
399  return loadPODUniformArray<OP_TYPE, fpreal64>
400  (op, it, n);
401  default:
402  break;
403  }
404  POD_TYPE val;
405  for (int64 i = 0; !it.atEnd(); ++it, ++i)
406  {
407  if (!parseNumber(val))
408  return false;
409  if (!op.set(i, val))
410  return false;
411  }
412  return true;
413  }
414 
415  /// Returns true if the next token was the start of a map. If there was an
416  /// error parsing the stream, then error will be set, otherwise the error
417  /// parameter will remain unchanged.
418  bool parseBeginMap(bool &error);
419  /// Returns true if the next token was the start of an array. If there was
420  /// an error parsing the stream, then error will be set, otherwise the
421  /// error parameter will remain unchanged.
422  bool parseBeginArray(bool &error);
423  /// Returns true if the next token was an end map. If there was an error
424  /// parsing the stream, then error will be set, otherwise the error
425  /// parameter will remain unchanged.
426  inline bool parseEndMap(bool &error)
427  {
428  UT_JSONHandle *push = myHandle;
429  myHandle = nullptr;
430  bool ok = parseBeginEnd(UT_JID_MAP_END, error);
431  myHandle = push;
432  return ok;
433  }
434  /// Returns true if the next token was an end of an array. If there was an
435  /// error parsing the stream, then error will be set, otherwise the error
436  /// parameter will remain unchanged.
437  inline bool parseEndArray(bool &error)
438  {
439  UT_JSONHandle *push = myHandle;
440  myHandle = nullptr;
441  bool ok = parseBeginEnd(UT_JID_ARRAY_END, error);
442  myHandle = push;
443  return ok;
444  }
445  /// Simple convenience method to skip the next object in the stream
446  bool skipNextObject();
447 
448  /// Get resulting warnings/errors
449  const UT_StringArray &getErrors() const { return myErrors; }
450 
451  /// The read method should be called whenever data needs to be read from
452  /// the stream. It keeps line counts & character offsets.
453  bool readBytes(void *data, exint bytes);
454 
455  /// Returns whether we're reading a binary or ASCII file
456  bool getBinary() const { return myBinary; }
457 
458  /// Returns the current position in the input stream
459  int64 getStreamLineCount() const;
460  int64 getStreamLineStartPosition() const;
461  int64 getStreamPosition() const;
462 
463  /// Returns the true and sets the filename if the stream supports random
464  /// seeks.
465  bool isRandomAccessFile(UT_WorkBuffer &filename) const;
466 
467  /// When reading raw binary data, this returns whether the endianness of
468  /// the file is different than the endianness of the processor (requiring
469  /// byte swapping). There are convenience methods to read integer/real
470  /// data which automatically swap. However, when reading uniform arrays in
471  /// batch mode, it is more efficient to swap the entire array rather than
472  /// piecemeal.
473  bool getSwapFlag() const { return mySwap; }
474 
475  /// Convenience method to a int8 values
476  bool readValue(int8 *v, exint n) { return readBytes(v, n); }
477  /// Convenience method to read int16 values (possibly byte-swapped)
478  bool readValue(int16 *v, exint n);
479  /// Convenience method to read int32 values (possibly byte-swapped)
480  bool readValue(int32 *v, exint n);
481  /// Convenience method to read int64 values (possibly byte-swapped)
482  bool readValue(int64 *v, exint n);
483 
484  /// Convenience method to read uint8 values
485  bool readValue(uint8 *v, exint n) { return readBytes(v, n); }
486  /// Convenience method to read uint16 values (possibly byte-swapped)
487  bool readValue(uint16 *v, exint n);
488  /// Convenience method to read uint32 values (possibly byte-swapped)
489  bool readValue(uint32 *v, exint n);
490  /// Convenience method to read uint64 values (possibly byte-swapped)
491  bool readValue(uint64 *v, exint n);
492 
493  /// Convenience method to read fpreal16 values (possibly byte-swapped)
494  bool readValue(fpreal16 *v, exint n);
495  /// Convenience method to read fpreal32 values (possibly byte-swapped)
496  bool readValue(fpreal32 *v, exint n);
497  /// Convenience method to read fpreal64 values (possibly byte-swapped)
498  bool readValue(fpreal64 *v, exint n);
499 
500  /// @{
501  /// Convenience method to read a binary encoded string.@n
502  /// @note This should be used when reading uniform arrays of UT_JID_STRING
503  /// type.
506  /// @}
507 
508  /// @{
509  /// Convenience method to read a binary encoded string token. Instead of
510  /// reading an encoded string (readString()), an integer token will be
511  /// read. This indexes the shared string table (see UT_JID_TOKENDEF,
512  /// UT_JID_TOKENREF).
513  /// @note This should be used when reading uniform arrays of
514  /// UT_JID_TOKENREF type.
515  bool readStringToken(UT_WorkBuffer &storage);
516  bool readStringToken(UT_StringHolder &str);
517  /// @}
518 
519  /// Add an error message. If the terminate flag is set, parsing will be
520  /// terminated.
521  void addFatal(const char *fmt, ...)
523  void addWarning(const char *fmt, ...)
525 
526  /// Steal errors from another parser (leaves the other parser intact)
527  void stealErrors(const UT_JSONParser &parser);
528 
529  /// @brief Traverse an array object in the parser
530  ///
531  /// This class will iterate over an array. There is no object associated
532  /// with the array, it's up to the caller to load the objects
533  ///
534  /// There is no rewind() operation available on this iterator
535  /// @code
536  /// UT_JSONParser::iterator it;
537  /// for (it = UT_JSONParser::beginMap(); !it.atEnd(); ++it)
538  /// or
539  /// for (it = UT_JSONParser::beginArray(); !it.atEnd(); ++it)
540  /// @endcode
542  {
543  public:
545  : myParser(nullptr)
546  , myMap(false)
547  , myValid(false)
548  , myError(false)
549  {
550  }
551  iterator(const iterator &src)
552  {
553  *this = src;
554  }
556 
557  const iterator &operator=(const iterator &src)
558  {
559  myParser = src.myParser;
560  myMap = src.myMap;
561  myValid = src.myValid;
562  myError = src.myError;
563  return *this;
564  }
565 
566  /// ++iterator
567  iterator &operator++() { advance(); return *this; }
568  /// Caution: The post-increment operator has side effects and is
569  /// equivalent to the iterator @b after the increment is performed.
570  iterator &operator++(int) { advance(); return *this; }
571 
572  bool atEnd() const { return !myValid || myError; }
573  void advance()
574  {
575  if (myParser && !myError)
576  {
577  bool hit;
578  hit = (myMap) ? myParser->parseEndMap(myError)
579  : myParser->parseEndArray(myError);
580  if (hit || myError)
581  myValid = false;
582  }
583  }
584  /// Get the key from the map.
585  /// If we're iterating over an array, this assumes that the next
586  /// array element will be a string token. This allows for
587  /// "ordered" maps to be stored in an array of tuples
588  /// (string,value)
589  ///
590  /// The T template can be either UT_WorkBuffer or UT_StringHolder
591  template <typename T>
592  bool getKey(T &key)
593  {
594  if (myParser && myValid)
595  {
596  return myMap ? myParser->parseKey(key)
597  : myParser->parseString(key);
598  }
599  if (myParser)
600  {
601  myParser->addWarning(
602  "Missing key while parsing map");
603  }
604  myValid = false;
605  myError = true;
606  return false;
607  }
608 
609  /// Get a lower case map key (for case insensitive maps)
610  template <typename T>
611  bool getLowerKey(T &key)
612  {
613  if (getKey(key))
614  {
615  toLower(key);
616  return true;
617  }
618  return false;
619  }
620 
621  /// The error state records whether any errors were encountered
622  /// during the iterator's parse operations.
623  bool getErrorState() const { return myError; }
624 
625  /// Return the uniform array type (UT_JID_NULL if not uniform array)
627  {
628  return myParser ? myParser->getUniformArrayType()
629  : UT_JID_NULL;
630  }
631  /// Return the number of elements in the uniform array (0 if empty)
633  {
634  return myParser ? myParser->getUniformArraySize()
635  : -1;
636  }
637  /// Return the remaining number of elements in the uniform array
638  /// (0 if empty)
640  {
641  return myParser ?
642  myParser->getUniformArrayUnreadSize() : -1;
643  }
644 
645  /// Read uniform array straight into a buffer. This template only
646  /// works for int8, int16, int32, int64, fpreal16, fpreal32,
647  /// fpreal64.
648  template <typename T>
650  {
651  if (!myParser)
652  return (myError = false);
653  if (!myParser->readUniformArray(buffer, size))
654  return (myError = false);
655  // Now, advance to check end condition of array
656  advance();
657  return !myError;
658  }
659 
660  private:
661  static inline void toLower(UT_WorkBuffer &w) { w.lower(); }
662  static void toLower(UT_StringHolder &w) { w = w.toLower(); }
663  iterator(UT_JSONParser *p, bool map)
664  : myParser(p)
665  , myMap(map)
666  , myValid(false)
667  , myError(false)
668  {
669  if (myParser)
670  {
671  if (myMap)
672  {
673  if ((myValid = myParser->parseBeginMap(myError)))
674  {
675  // Check for an empty map
676  if (!myError)
677  myValid = !myParser->parseEndMap(myError);
678  }
679  }
680  else
681  {
682  if ((myValid = myParser->parseBeginArray(myError)))
683  {
684  if (!myError)
685  myValid = !myParser->parseEndArray(myError);
686  }
687  }
688  if (myError)
689  myValid = false;
690  }
691  }
692 
693  UT_JSONParser *myParser;
694  bool myMap;
695  bool myValid;
696  bool myError;
697 
698  friend class UT_JSONParser;
699  };
700  typedef iterator traverser; // For backward compatibility
701 
702  iterator beginMap() { return iterator(this, true); }
703  iterator beginArray() { return iterator(this, false); }
704 
705  /// The TiledStream class reads data that was generated by a
706  /// UT_JSONWriter::TiledStream. The reader expects an array, followed by
707  /// multiple arrays of uint8. The multiple arrays appear as a single
708  /// stream to the user. To read a tiled stream from a JSON file, you would
709  /// do something like: @code
710  /// bool copyStream(UT_JSONParser &p, ostream &os)
711  /// {
712  /// UT_JSONParser::TiledStream is(p);
713  /// while (true)
714  /// {
715  /// char buffer[128];
716  /// exint nread = is.read(buffer, 128);
717  /// if (nread < 0)
718  /// return false; // See p.getErrors() for error message
719  /// if (nread == 0) // Read to end of stream
720  /// break;
721  /// os.write(buffer, nread);
722  /// }
723  /// return true;
724  /// }
725  /// @endcode
726  class UT_API TiledStreamBuf : public std::streambuf
727  {
728  public:
730  ~TiledStreamBuf() override;
731 
732  TiledStreamBuf(const TiledStreamBuf &) = delete;
733  TiledStreamBuf &operator=(const TiledStreamBuf &) = delete;
734 
735  int_type underflow() override;
736 
737  private:
738  /// Returns the number of bytes read or less than 0 on error.
739  exint read(void *buffer, exint bufsize);
740  exint loadBuffer();
741  UT_JSONParser &myParser;
743  char *myBuffer;
744  exint mySize;
745  exint myCapacity;
746  };
747 
748  class UT_API TiledStream : public std::istream
749  {
750  public:
752  ~TiledStream() override;
753  private:
754  TiledStreamBuf myBuf;
755  };
756 
757 private:
758  // Different parsing states
759  enum ut_JParseState
760  {
761  JSON_START, // Prior to parsing JSON file
762  JSON_COMPLETE, // Successful parsing
763  JSON_ERROR, // Error thrown
764 
765  JSON_MAP_START, // Starting a map (almost same as JSON_MAP_NEED_KEY)
766  JSON_MAP_SEP, // Expecting a map separator
767  JSON_MAP_NEED_VAL, // Expecting a map value
768  JSON_MAP_GOT_VAL, // Expecting end of map or value separator
769  JSON_MAP_NEED_KEY, // Expecting a map key (string)
770 
771  JSON_ARRAY_START, // Starting an array
772  JSON_ARRAY_NEED_VAL, // Expecting a value for an array
773  JSON_ARRAY_GOT_VAL, // Expecting end of array or value separator
774  };
775 
776  /// @private Set a stream for the parser.
777  UT_IStream *setIStream(UT_IStream *is);
778 
779  /// @private Parse the stream
780  bool parseStream(exint nobjects);
781 
782  /// @private Parse a single token
783  bool parseToken(UT_JID &token);
784 
785  /// @private Parse a simple object
786  bool parseSimpleObject(ut_SimpleJSONObjectHandle &h);
787 
788  /// @private Test if next token is an end-object
789  bool parseBeginEnd(UT_JID type, bool &error);
790 
791  /// @private: Read an encoded length
792  /// @see UT_JID
793  bool readLength(int64 &l);
794  /// @private: Peek at the next token. The result will be in myPeek
795  bool peekToken();
796  /// @private: Process a token
797  bool readToken(ut_JValue &value);
798  /// @private: Push parse state
799  bool pushState(ut_JParseState state); // Push state
800  /// @private: Set parse state
801  void setState(ut_JParseState state); // Set top of stack
802  /// @private: Pop parse state
803  bool popState(); // Pop state
804  /// @private: Query parse state
805  ut_JParseState getState() const { return myState; }
806  /// @private: Read UTF-8 quoted string
807  bool readQuotedString(UT_StringHolder &buf);
808  /// @private: Read number/null/true/false
809  bool readNumber(ut_JValue &value);
810  /// @private: defineToken()
811  bool defineToken();
812  /// @private: undefineToken()
813  bool undefineToken();
814  /// @private: undefineToken()
815  void undefineToken(int64 id);
816  /// @private: lookupToken()
817  bool lookupToken(UT_StringHolder &value);
818  /// @private: clearTokens()
819  void clearTokens();
820 
821  typedef UT_ArrayMap<int64, UT_StringHolder> TokenMap;
822 
823  UT_JSONHandle *myHandle;
824  UT_IStream *myStream;
825  ut_JValue *myPeek;
826  ut_JValue *myPeekCache;
827  UT_StringArray myErrors;
828  UT_IntArray myStack; // State stack
829  TokenMap myTokens;
830  ut_JParseState myState;
831  int64 myLineCount;
832  int64 myLineStartPosition;
833  bool mySwap;
834  bool myBinary;
835 
836  friend class UT_AutoJSONParser;
837 };
838 
839 /// Convenience class to create a JSON parser from a simple input
840 ///
841 /// For example: @code
842 /// // Function to parse the JSON stream
843 /// bool load(UT_JSONParser &p) { ... }
844 ///
845 /// // Function to parse from a std::string
846 /// bool load(const std::string &str)
847 /// {
848 /// UT_JSONAutoParser p(str.c_str(), str.size());
849 /// return load(*p);
850 /// }
851 ///
852 /// // Function to parse from a UT_JSONValue
853 /// bool load(const UT_JSONValue &v)
854 /// {
855 /// UT_JSONAutoParser p(v);
856 /// return load(*p);
857 /// }
858 /// @endcode
859 ///
861 {
862 public:
864 
865  /// Load JSON from the given UT_IStream
867 
868  /// Load JSON from the given string
869  UT_AutoJSONParser(const char *buffer, int64 size);
870 
871  /// Load JSON from the UT_JSONValue
873 
874  UT_AutoJSONParser(const UT_AutoJSONParser &) = delete;
875  UT_AutoJSONParser &operator=(const UT_AutoJSONParser &) = delete;
876 
878  {
879  close();
880  }
881 
882  void attach(UT_IStream &is);
883 
884  /// @{
885  /// Access to the parser
886  UT_JSONParser &parser() { return myParser; }
887  UT_JSONParser &operator*() { return myParser; }
888  UT_JSONParser *operator->() { return &myParser; }
889  /// @}
890 
891  // Implicit casting to a UT_JSONParser
892  operator UT_JSONParser &() { return myParser; }
893 
894  /// Close the parser
895  void close();
896 
897 private:
898 
899  UT_JSONParser myParser;
900  UT_WorkBuffer myBuffer;
901  UT_IStream* myIStream;
902  bool myAllocatedIStream;
903 };
904 
905 #endif
The following byte represents an 8 bit integer.
*pool push(my_func, arg1,...)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
unsigned short uint16
Definition: SYS_Types.h:38
No data follows the NULL token.
GT_API const UT_StringHolder filename
GLenum GLuint GLsizei bufsize
Definition: glcorearb.h:1818
int int32
Definition: SYS_Types.h:39
The following 4 bytes represent an 32 bit real (float)
UT_JID
The UT_JID enums are used in byte-stream encoding of binary JSON.
void setBinary(bool isBinary)
*get result *(waiting if necessary)*A common idiom is to fire a bunch of sub tasks at the and then *wait for them to all complete We provide a helper class
Definition: thread.h:623
Marks the end of an array object.
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
const GLdouble * v
Definition: glcorearb.h:837
0x23 and 0x24 are reserved for future use (32/64 bit unsigned)
int64 parseArrayValues(iterator &it, T *data, int64 len)
bool_constant< is_integral< T >::value &&!std::is_same< T, bool >::value &&!std::is_same< T, char >::value &&!std::is_same< T, wchar_t >::value > is_integer
Definition: format.h:2010
bool parseValue(fpreal64 &v)
UT_JSONHandle processes events from a UT_JSONParser parser.
Definition: UT_JSONHandle.h:36
int64 exint
Definition: SYS_Types.h:125
int64 getUniformArraySize() const
Return the number of elements in the uniform array (0 if empty)
UT_JID getUniformArrayType() const
Return the uniform array type (UT_JID_NULL if not uniform array)
iterator & operator++()
++iterator
iterator beginArray()
bool parseValue(fpreal16 &v)
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:87
#define UT_API
Definition: UT_API.h:14
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
**But if you need a result
Definition: thread.h:613
void close() override
unsigned long long uint64
Definition: SYS_Types.h:117
float fpreal32
Definition: SYS_Types.h:200
void read(T &in, bool &v)
Definition: ImfXdr.h:502
const UT_StringArray & getErrors() const
Get resulting warnings/errors.
bool parseNumber(int64 &v)
< returns > If no error
Definition: snippets.dox:2
double fpreal64
Definition: SYS_Types.h:201
unsigned char uint8
Definition: SYS_Types.h:36
The following 8 bytes represent an 64 bit real (float)
bool parseInt(int64 &v)
Alternate short-form.
The following 8 bytes represent an 64 bit integer.
bool parseValue(int8 &v)
bool readValue(int8 *v, exint n)
Convenience method to a int8 values.
GLdouble n
Definition: glcorearb.h:2008
const iterator & operator=(const iterator &src)
Definition: core.h:760
The following 2 bytes represent an 16 bit integer.
GLboolean reset
Definition: glad.h:5138
int64 getUniformArrayUnreadSize() const
UT_JSONParser & parser()
bool parseValue(fpreal32 &v)
UT_JSONParser & operator*()
bool readValue(uint8 *v, exint n)
Convenience method to read uint8 values.
#define SYS_PRINTF_CHECK_ATTRIBUTE(string_index, first_to_check)
Definition: SYS_Types.h:447
Traverse an array object in the parser.
long long int64
Definition: SYS_Types.h:116
bool parseValue(int64 &v)
bool getErrorState() const
signed char int8
Definition: SYS_Types.h:35
The following 4 bytes represent an 32 bit integer.
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
iterator(const iterator &src)
bool getBinary() const
Returns whether we're reading a binary or ASCII file.
bool getSwapFlag() const
int64 parseUniformArray(T *data, int64 len)
GLsizeiptr size
Definition: glcorearb.h:664
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
Marks the end of a map object.
bool parseValue(UT_WorkBuffer &v)
class UT_API iterator
Definition: UT_JSONParser.h:90
short int16
Definition: SYS_Types.h:37
bool parseEndArray(bool &error)
SYS_NO_DISCARD_RESULT UT_StringRef toLower() const
bool loadPODArray(OP_TYPE &op)
UT_JSONParser * operator->()
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLuint GLfloat * val
Definition: glcorearb.h:1608
bool readUniformArray(T *buffer, int64 size)
iterator & operator++(int)
Name readString(std::istream &is)
Definition: Name.h:22
Class to store JSON objects as C++ objects.
Definition: UT_JSONValue.h:99
unsigned int uint32
Definition: SYS_Types.h:40
bool parseValue(uint16 &v)
bool parseValue(int16 &v)
bool parseValue(UT_StringHolder &v)
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
Definition: core.h:1131
bool parseEndMap(bool &error)
#define const
Definition: zconf.h:214
bool parseValue(int32 &v)
iterator beginMap()
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
bool parseValue(bool &v)
type
Definition: core.h:1059
bool parseValue(uint8 &v)
void lower()
Convert string to lower case.
bool getLowerKey(T &key)
Get a lower case map key (for case insensitive maps)
Definition: format.h:895
iterator traverser
Definition: format.h:2459
bool parseNumber(fpreal64 &v)
GLenum src
Definition: glcorearb.h:1793