dcPackerInterface.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file dcPackerInterface.cxx
  10. * @author drose
  11. * @date 2004-06-15
  12. */
  13. #include "dcPackerInterface.h"
  14. #include "dcPackerCatalog.h"
  15. #include "dcField.h"
  16. #include "dcParserDefs.h"
  17. #include "dcLexerDefs.h"
  18. using std::string;
  19. /**
  20. *
  21. */
  22. DCPackerInterface::
  23. DCPackerInterface(const string &name) :
  24. _name(name)
  25. {
  26. _has_fixed_byte_size = false;
  27. _fixed_byte_size = 0;
  28. _has_fixed_structure = false;
  29. _has_range_limits = false;
  30. _num_length_bytes = 0;
  31. _has_nested_fields = false;
  32. _num_nested_fields = -1;
  33. _pack_type = PT_invalid;
  34. _catalog = nullptr;
  35. }
  36. /**
  37. *
  38. */
  39. DCPackerInterface::
  40. DCPackerInterface(const DCPackerInterface &copy) :
  41. _name(copy._name),
  42. _has_fixed_byte_size(copy._has_fixed_byte_size),
  43. _fixed_byte_size(copy._fixed_byte_size),
  44. _has_fixed_structure(copy._has_fixed_structure),
  45. _has_range_limits(copy._has_range_limits),
  46. _num_length_bytes(copy._num_length_bytes),
  47. _has_nested_fields(copy._has_nested_fields),
  48. _num_nested_fields(copy._num_nested_fields),
  49. _pack_type(copy._pack_type)
  50. {
  51. _catalog = nullptr;
  52. }
  53. /**
  54. *
  55. */
  56. DCPackerInterface::
  57. ~DCPackerInterface() {
  58. delete _catalog;
  59. }
  60. /**
  61. * Returns the index number to be passed to a future call to DCPacker::seek()
  62. * to seek directly to the named field without having to look up the field
  63. * name in a table later, or -1 if the named field cannot be found.
  64. *
  65. * If the named field is nested within a switch or some similar dynamic
  66. * structure that reveals different fields based on the contents of the data,
  67. * this mechanism cannot be used to pre-fetch the field index number--you must
  68. * seek for the field by name.
  69. */
  70. int DCPackerInterface::
  71. find_seek_index(const string &name) const {
  72. return get_catalog()->find_entry_by_name(name);
  73. }
  74. /**
  75. *
  76. */
  77. DCField *DCPackerInterface::
  78. as_field() {
  79. return nullptr;
  80. }
  81. /**
  82. *
  83. */
  84. const DCField *DCPackerInterface::
  85. as_field() const {
  86. return nullptr;
  87. }
  88. /**
  89. *
  90. */
  91. DCSwitchParameter *DCPackerInterface::
  92. as_switch_parameter() {
  93. return nullptr;
  94. }
  95. /**
  96. *
  97. */
  98. const DCSwitchParameter *DCPackerInterface::
  99. as_switch_parameter() const {
  100. return nullptr;
  101. }
  102. /**
  103. *
  104. */
  105. DCClassParameter *DCPackerInterface::
  106. as_class_parameter() {
  107. return nullptr;
  108. }
  109. /**
  110. *
  111. */
  112. const DCClassParameter *DCPackerInterface::
  113. as_class_parameter() const {
  114. return nullptr;
  115. }
  116. /**
  117. * Returns true if this interface is bitwise the same as the interface
  118. * described with the indicated formatted string, e.g. "(uint8, uint8,
  119. * int16)", or false otherwise.
  120. *
  121. * If DCFile is not NULL, it specifies the DCFile that was previously loaded,
  122. * from which some predefined structs and typedefs may be referenced in the
  123. * description string.
  124. */
  125. bool DCPackerInterface::
  126. check_match(const string &description, DCFile *dcfile) const {
  127. bool match = false;
  128. std::istringstream strm(description);
  129. dc_init_parser_parameter_description(strm, "check_match", dcfile);
  130. dcyyparse();
  131. dc_cleanup_parser();
  132. DCField *field = dc_get_parameter_description();
  133. if (field != nullptr) {
  134. match = check_match(field);
  135. delete field;
  136. }
  137. if (dc_error_count() == 0) {
  138. return match;
  139. }
  140. // Parse error: no match is allowed.
  141. return false;
  142. }
  143. /**
  144. * Sets the name of this field.
  145. */
  146. void DCPackerInterface::
  147. set_name(const string &name) {
  148. _name = name;
  149. }
  150. /**
  151. * This flavor of get_num_nested_fields is used during unpacking. It returns
  152. * the number of nested fields to expect, given a certain length in bytes (as
  153. * read from the _num_length_bytes stored in the stream on the push). This
  154. * will only be called if _num_length_bytes is nonzero.
  155. */
  156. int DCPackerInterface::
  157. calc_num_nested_fields(size_t) const {
  158. return 0;
  159. }
  160. /**
  161. * Returns the DCPackerInterface object that represents the nth nested field.
  162. * This may return NULL if there is no such field (but it shouldn't do this if
  163. * n is in the range 0 <= n < get_num_nested_fields()).
  164. */
  165. DCPackerInterface *DCPackerInterface::
  166. get_nested_field(int) const {
  167. return nullptr;
  168. }
  169. /**
  170. * After a number of fields have been packed via push() .. pack_*() .. pop(),
  171. * this is called to confirm that the number of nested fields that were added
  172. * is valid for this type. This is primarily useful for array types with
  173. * dynamic ranges that can't validate the number of fields any other way.
  174. */
  175. bool DCPackerInterface::
  176. validate_num_nested_fields(int) const {
  177. return true;
  178. }
  179. /**
  180. * Packs the indicated numeric or string value into the stream.
  181. */
  182. void DCPackerInterface::
  183. pack_double(DCPackData &, double, bool &pack_error, bool &) const {
  184. pack_error = true;
  185. }
  186. /**
  187. * Packs the indicated numeric or string value into the stream.
  188. */
  189. void DCPackerInterface::
  190. pack_int(DCPackData &, int, bool &pack_error, bool &) const {
  191. pack_error = true;
  192. }
  193. /**
  194. * Packs the indicated numeric or string value into the stream.
  195. */
  196. void DCPackerInterface::
  197. pack_uint(DCPackData &, unsigned int, bool &pack_error, bool &) const {
  198. pack_error = true;
  199. }
  200. /**
  201. * Packs the indicated numeric or string value into the stream.
  202. */
  203. void DCPackerInterface::
  204. pack_int64(DCPackData &, int64_t, bool &pack_error, bool &) const {
  205. pack_error = true;
  206. }
  207. /**
  208. * Packs the indicated numeric or string value into the stream.
  209. */
  210. void DCPackerInterface::
  211. pack_uint64(DCPackData &, uint64_t, bool &pack_error, bool &) const {
  212. pack_error = true;
  213. }
  214. /**
  215. * Packs the indicated numeric or string value into the stream.
  216. */
  217. void DCPackerInterface::
  218. pack_string(DCPackData &, const string &, bool &pack_error, bool &) const {
  219. pack_error = true;
  220. }
  221. /**
  222. * Packs the indicated numeric or string value into the stream.
  223. */
  224. void DCPackerInterface::
  225. pack_blob(DCPackData &, const vector_uchar &, bool &pack_error, bool &) const {
  226. pack_error = true;
  227. }
  228. /**
  229. * Packs the field's specified default value (or a sensible default if no
  230. * value is specified) into the stream. Returns true if the default value is
  231. * packed, false if the field doesn't know how to pack its default value.
  232. */
  233. bool DCPackerInterface::
  234. pack_default_value(DCPackData &, bool &) const {
  235. return false;
  236. }
  237. /**
  238. * Unpacks the current numeric or string value from the stream.
  239. */
  240. void DCPackerInterface::
  241. unpack_double(const char *, size_t, size_t &, double &, bool &pack_error, bool &) const {
  242. pack_error = true;
  243. }
  244. /**
  245. * Unpacks the current numeric or string value from the stream.
  246. */
  247. void DCPackerInterface::
  248. unpack_int(const char *, size_t, size_t &, int &, bool &pack_error, bool &) const {
  249. pack_error = true;
  250. }
  251. /**
  252. * Unpacks the current numeric or string value from the stream.
  253. */
  254. void DCPackerInterface::
  255. unpack_uint(const char *, size_t, size_t &, unsigned int &, bool &pack_error, bool &) const {
  256. pack_error = true;
  257. }
  258. /**
  259. * Unpacks the current numeric or string value from the stream.
  260. */
  261. void DCPackerInterface::
  262. unpack_int64(const char *, size_t, size_t &, int64_t &, bool &pack_error, bool &) const {
  263. pack_error = true;
  264. }
  265. /**
  266. * Unpacks the current numeric or string value from the stream.
  267. */
  268. void DCPackerInterface::
  269. unpack_uint64(const char *, size_t, size_t &, uint64_t &, bool &pack_error, bool &) const {
  270. pack_error = true;
  271. }
  272. /**
  273. * Unpacks the current numeric or string value from the stream.
  274. */
  275. void DCPackerInterface::
  276. unpack_string(const char *, size_t, size_t &, string &, bool &pack_error, bool &) const {
  277. pack_error = true;
  278. }
  279. /**
  280. * Unpacks the current numeric or string value from the stream.
  281. */
  282. void DCPackerInterface::
  283. unpack_blob(const char *, size_t, size_t &, vector_uchar &, bool &pack_error, bool &) const {
  284. pack_error = true;
  285. }
  286. /**
  287. * Internally unpacks the current numeric or string value and validates it
  288. * against the type range limits, but does not return the value. Returns true
  289. * on success, false on failure (e.g. we don't know how to validate this
  290. * field).
  291. */
  292. bool DCPackerInterface::
  293. unpack_validate(const char *data, size_t length, size_t &p,
  294. bool &pack_error, bool &) const {
  295. if (!_has_range_limits) {
  296. return unpack_skip(data, length, p, pack_error);
  297. }
  298. return false;
  299. }
  300. /**
  301. * Increments p to the end of the current field without actually unpacking any
  302. * data or performing any range validation. Returns true on success, false on
  303. * failure (e.g. we don't know how to skip this field).
  304. */
  305. bool DCPackerInterface::
  306. unpack_skip(const char *data, size_t length, size_t &p,
  307. bool &pack_error) const {
  308. if (_has_fixed_byte_size) {
  309. // If this field has a fixed byte size, it's easy to skip.
  310. p += _fixed_byte_size;
  311. if (p > length) {
  312. pack_error = true;
  313. }
  314. return true;
  315. }
  316. if (_has_nested_fields && _num_length_bytes != 0) {
  317. // If we have a length prefix, use that for skipping.
  318. if (p + _num_length_bytes > length) {
  319. pack_error = true;
  320. } else {
  321. if (_num_length_bytes == 4) {
  322. size_t this_length = do_unpack_uint32(data + p);
  323. p += this_length + 4;
  324. } else {
  325. size_t this_length = do_unpack_uint16(data + p);
  326. p += this_length + 2;
  327. }
  328. if (p > length) {
  329. pack_error = true;
  330. }
  331. }
  332. return true;
  333. }
  334. // Otherwise, we don't know how to skip this field (presumably it can be
  335. // skipped by skipping over its nested fields individually).
  336. return false;
  337. }
  338. /**
  339. * Returns the DCPackerCatalog associated with this field, listing all of the
  340. * nested fields by name.
  341. */
  342. const DCPackerCatalog *DCPackerInterface::
  343. get_catalog() const {
  344. if (_catalog == nullptr) {
  345. ((DCPackerInterface *)this)->make_catalog();
  346. }
  347. return _catalog;
  348. }
  349. /**
  350. * Returns true if this field matches the indicated simple parameter, false
  351. * otherwise.
  352. */
  353. bool DCPackerInterface::
  354. do_check_match_simple_parameter(const DCSimpleParameter *) const {
  355. return false;
  356. }
  357. /**
  358. * Returns true if this field matches the indicated class parameter, false
  359. * otherwise.
  360. */
  361. bool DCPackerInterface::
  362. do_check_match_class_parameter(const DCClassParameter *) const {
  363. return false;
  364. }
  365. /**
  366. * Returns true if this field matches the indicated switch parameter, false
  367. * otherwise.
  368. */
  369. bool DCPackerInterface::
  370. do_check_match_switch_parameter(const DCSwitchParameter *) const {
  371. return false;
  372. }
  373. /**
  374. * Returns true if this field matches the indicated array parameter, false
  375. * otherwise.
  376. */
  377. bool DCPackerInterface::
  378. do_check_match_array_parameter(const DCArrayParameter *) const {
  379. return false;
  380. }
  381. /**
  382. * Returns true if this field matches the indicated atomic field, false
  383. * otherwise.
  384. */
  385. bool DCPackerInterface::
  386. do_check_match_atomic_field(const DCAtomicField *) const {
  387. return false;
  388. }
  389. /**
  390. * Returns true if this field matches the indicated molecular field, false
  391. * otherwise.
  392. */
  393. bool DCPackerInterface::
  394. do_check_match_molecular_field(const DCMolecularField *) const {
  395. return false;
  396. }
  397. /**
  398. * Called internally to create a new DCPackerCatalog object.
  399. */
  400. void DCPackerInterface::
  401. make_catalog() {
  402. nassertv(_catalog == nullptr);
  403. _catalog = new DCPackerCatalog(this);
  404. _catalog->r_fill_catalog("", this, nullptr, 0);
  405. }