Panda3D
dcSimpleParameter.cxx
Go to the documentation of this file.
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 dcSimpleParameter.cxx
10  * @author drose
11  * @date 2004-06-15
12  */
13 
14 #include "dcSimpleParameter.h"
15 #include "dcPackData.h"
16 #include "dcTypedef.h"
17 #include "dcArrayParameter.h"
18 #include "dcClassParameter.h"
19 #include "dcClass.h"
20 #include "hashGenerator.h"
21 #include <math.h>
22 
23 using std::string;
24 
25 DCSimpleParameter::NestedFieldMap DCSimpleParameter::_nested_field_map;
26 DCClassParameter *DCSimpleParameter::_uint32uint8_type = nullptr;
27 
28 /**
29  *
30  */
31 DCSimpleParameter::
32 DCSimpleParameter(DCSubatomicType type, unsigned int divisor) :
33  _type(type),
34  _divisor(1),
35  _has_modulus(false)
36 {
37  _pack_type = PT_invalid;
38  _nested_type = ST_invalid;
39  _has_nested_fields = false;
40  _bytes_per_element = 0;
41  _num_length_bytes = 2;
42 
43  // Check for one of the built-in array types. For these types, we must
44  // present a packing interface that has a variable number of nested fields
45  // of the appropriate type.
46  switch (_type) {
47  case ST_int8array:
48  _pack_type = PT_array;
49  _nested_type = ST_int8;
50  _has_nested_fields = true;
51  _bytes_per_element = 1;
52  break;
53 
54  case ST_int16array:
55  _pack_type = PT_array;
56  _nested_type = ST_int16;
57  _has_nested_fields = true;
58  _bytes_per_element = 2;
59  break;
60 
61  case ST_int32array:
62  _pack_type = PT_array;
63  _nested_type = ST_int32;
64  _has_nested_fields = true;
65  _bytes_per_element = 4;
66  break;
67 
68  case ST_uint8array:
69  _pack_type = PT_array;
70  _nested_type = ST_uint8;
71  _has_nested_fields = true;
72  _bytes_per_element = 1;
73  break;
74 
75  case ST_uint16array:
76  _pack_type = PT_array;
77  _nested_type = ST_uint16;
78  _has_nested_fields = true;
79  _bytes_per_element = 2;
80  break;
81 
82  case ST_uint32array:
83  _pack_type = PT_array;
84  _nested_type = ST_uint32;
85  _has_nested_fields = true;
86  _bytes_per_element = 4;
87  break;
88 
89  case ST_uint32uint8array:
90  _pack_type = PT_array;
91  _has_nested_fields = true;
92  _bytes_per_element = 5;
93  break;
94 
95  case ST_blob32:
96  _num_length_bytes = 4;
97  // fall through
98  case ST_blob:
99  // For blob and string, we will present an array interface as an array of
100  // uint8, but we will also accept a set_value() with a string parameter.
101  _pack_type = PT_blob;
102  _nested_type = ST_uint8;
103  _has_nested_fields = true;
104  _bytes_per_element = 1;
105  break;
106 
107  case ST_string:
108  _pack_type = PT_string;
109  _nested_type = ST_char;
110  _has_nested_fields = true;
111  _bytes_per_element = 1;
112  break;
113 
114  // The simple types can be packed directly.
115  case ST_int8:
116  _pack_type = PT_int;
117  _has_fixed_byte_size = true;
118  _fixed_byte_size = 1;
119  break;
120 
121  case ST_int16:
122  _pack_type = PT_int;
123  _has_fixed_byte_size = true;
124  _fixed_byte_size = 2;
125  break;
126 
127  case ST_int32:
128  _pack_type = PT_int;
129  _has_fixed_byte_size = true;
130  _fixed_byte_size = 4;
131  break;
132 
133  case ST_int64:
134  _pack_type = PT_int64;
135  _has_fixed_byte_size = true;
136  _fixed_byte_size = 8;
137  break;
138 
139  case ST_char:
140  _pack_type = PT_string;
141  _has_fixed_byte_size = true;
142  _fixed_byte_size = 1;
143  break;
144 
145  case ST_uint8:
146  _pack_type = PT_uint;
147  _has_fixed_byte_size = true;
148  _fixed_byte_size = 1;
149  break;
150 
151  case ST_uint16:
152  _pack_type = PT_uint;
153  _has_fixed_byte_size = true;
154  _fixed_byte_size = 2;
155  break;
156 
157  case ST_uint32:
158  _pack_type = PT_uint;
159  _has_fixed_byte_size = true;
160  _fixed_byte_size = 4;
161  break;
162 
163  case ST_uint64:
164  _pack_type = PT_uint64;
165  _has_fixed_byte_size = true;
166  _fixed_byte_size = 8;
167  break;
168 
169  case ST_float64:
170  _pack_type = PT_double;
171  _has_fixed_byte_size = true;
172  _fixed_byte_size = 8;
173  break;
174 
175  case ST_invalid:
176  break;
177  }
178  _has_fixed_structure = _has_fixed_byte_size;
179 
180  set_divisor(divisor);
181 
182  if (_nested_type != ST_invalid) {
183  _nested_field = create_nested_field(_nested_type, _divisor);
184 
185  } else if (_type == ST_uint32uint8array) {
186  // This one is a special case. We must create a special nested type that
187  // accepts a uint32 followed by a uint8 for each element.
188  _nested_field = create_uint32uint8_type();
189 
190  } else {
191  _nested_field = nullptr;
192  }
193 }
194 
195 /**
196  *
197  */
198 DCSimpleParameter::
199 DCSimpleParameter(const DCSimpleParameter &copy) :
200  DCParameter(copy),
201  _type(copy._type),
202  _divisor(copy._divisor),
203  _nested_field(copy._nested_field),
204  _bytes_per_element(copy._bytes_per_element),
205  _orig_range(copy._orig_range),
206  _has_modulus(copy._has_modulus),
207  _orig_modulus(copy._orig_modulus),
208  _int_range(copy._int_range),
209  _uint_range(copy._uint_range),
210  _int64_range(copy._int64_range),
211  _uint64_range(copy._uint64_range),
212  _double_range(copy._double_range),
213  _uint_modulus(copy._uint_modulus),
214  _uint64_modulus(copy._uint64_modulus),
215  _double_modulus(copy._double_modulus)
216 {
217 }
218 
219 /**
220  *
221  */
222 DCSimpleParameter *DCSimpleParameter::
223 as_simple_parameter() {
224  return this;
225 }
226 
227 /**
228  *
229  */
230 const DCSimpleParameter *DCSimpleParameter::
231 as_simple_parameter() const {
232  return this;
233 }
234 
235 /**
236  *
237  */
238 DCParameter *DCSimpleParameter::
239 make_copy() const {
240  return new DCSimpleParameter(*this);
241 }
242 
243 /**
244  * Returns false if the type is an invalid type (e.g. declared from an
245  * undefined typedef), true if it is valid.
246  */
248 is_valid() const {
249  return _type != ST_invalid;
250 }
251 
252 /**
253  * Returns the particular subatomic type represented by this instance.
254  */
256 get_type() const {
257  return _type;
258 }
259 
260 /**
261  * Returns true if there is a modulus associated, false otherwise.,
262  */
264 has_modulus() const {
265  return _has_modulus;
266 }
267 
268 /**
269  * Returns the modulus associated with this type, if any. It is an error to
270  * call this if has_modulus() returned false.
271  *
272  * If present, this is the modulus that is used to constrain the numeric value
273  * of the field before it is packed (and range-checked).
274  */
276 get_modulus() const {
277  return _orig_modulus;
278 }
279 
280 /**
281  * Returns the divisor associated with this type. This is 1 by default, but
282  * if this is other than one it represents the scale to apply when packing and
283  * unpacking numeric values (to store fixed-point values in an integer field).
284  * It is only meaningful for numeric-type fields.
285  */
287 get_divisor() const {
288  return _divisor;
289 }
290 
291 /**
292  * Returns true if the type is a numeric type (and therefore can accept a
293  * divisor and/or a modulus), or false if it is some string-based type.
294  */
296 is_numeric_type() const {
297  return !(_pack_type == PT_string || _pack_type == PT_blob);
298 }
299 
300 /**
301  * Assigns the indicated modulus to the simple type. Any packed value will be
302  * constrained to be within [0, modulus).
303  *
304  * Returns true if assigned, false if this type cannot accept a modulus or if
305  * the modulus is invalid.
306  */
308 set_modulus(double modulus) {
309  if (_pack_type == PT_string || _pack_type == PT_blob || modulus <= 0.0) {
310  return false;
311  }
312 
313  _has_modulus = true;
314  _orig_modulus = modulus;
315 
316  bool range_error = false;
317  _double_modulus = modulus * _divisor;
318  _uint64_modulus = (uint64_t)floor(_double_modulus + 0.5);
319  _uint_modulus = (unsigned int)_uint64_modulus;
320 
321  // Check the range. The legitimate range for a modulus value is 1 through
322  // (maximum_value + 1).
323  switch (_type) {
324  case ST_int8:
325  case ST_int8array:
326  validate_uint64_limits(_uint64_modulus - 1, 7, range_error);
327  break;
328 
329  case ST_int16:
330  case ST_int16array:
331  validate_uint64_limits(_uint64_modulus - 1, 15, range_error);
332  break;
333 
334  case ST_int32:
335  case ST_int32array:
336  validate_uint64_limits(_uint64_modulus - 1, 31, range_error);
337  break;
338 
339  case ST_int64:
340  validate_uint64_limits(_uint64_modulus - 1, 63, range_error);
341  break;
342 
343  case ST_char:
344  case ST_uint8:
345  case ST_uint8array:
346  validate_uint64_limits(_uint64_modulus - 1, 8, range_error);
347  break;
348 
349  case ST_uint16:
350  case ST_uint16array:
351  validate_uint64_limits(_uint64_modulus - 1, 16, range_error);
352  break;
353 
354  case ST_uint32:
355  case ST_uint32array:
356  validate_uint64_limits(_uint64_modulus - 1, 32, range_error);
357  break;
358 
359  case ST_uint64:
360  case ST_float64:
361  break;
362 
363  default:
364  return false;
365  }
366 
367  return !range_error;
368 }
369 
370 /**
371  * Assigns the indicated divisor to the simple type. Returns true if
372  * assigned, false if this type cannot accept a divisor or if the divisor is
373  * invalid.
374  */
376 set_divisor(unsigned int divisor) {
377  if (_pack_type == PT_string || _pack_type == PT_blob || divisor == 0) {
378  return false;
379  }
380 
381  _divisor = divisor;
382  if ((_divisor != 1) &&
383  (_pack_type == PT_int || _pack_type == PT_int64 ||
384  _pack_type == PT_uint || _pack_type == PT_uint64)) {
385  _pack_type = PT_double;
386  }
387 
388  if (_has_range_limits) {
389  set_range(_orig_range);
390  }
391  if (_has_modulus) {
392  set_modulus(_orig_modulus);
393  }
394 
395  return true;
396 }
397 
398 /**
399  * Sets the parameter with the indicated range. A DCDoubleRange is used for
400  * specification, since this is the most generic type; but it is converted to
401  * the appropriate type internally. The return value is true if successful,
402  * or false if the range is inappropriate for the type.
403  */
405 set_range(const DCDoubleRange &range) {
406  bool range_error = false;
407  int num_ranges = range.get_num_ranges();
408  int i;
409 
410  _has_range_limits = (num_ranges != 0);
411  _orig_range = range;
412 
413  switch (_type) {
414  case ST_int8:
415  case ST_int8array:
416  _int_range.clear();
417  for (i = 0; i < num_ranges; i++) {
418  int64_t min = (int64_t)floor(range.get_min(i) * _divisor + 0.5);
419  int64_t max = (int64_t)floor(range.get_max(i) * _divisor + 0.5);
420  validate_int64_limits(min, 8, range_error);
421  validate_int64_limits(max, 8, range_error);
422  _int_range.add_range((int)min, (int)max);
423  }
424  break;
425 
426  case ST_int16:
427  case ST_int16array:
428  _int_range.clear();
429  for (i = 0; i < num_ranges; i++) {
430  int64_t min = (int64_t)floor(range.get_min(i) * _divisor + 0.5);
431  int64_t max = (int64_t)floor(range.get_max(i) * _divisor + 0.5);
432  validate_int64_limits(min, 16, range_error);
433  validate_int64_limits(max, 16, range_error);
434  _int_range.add_range((int)min, (int)max);
435  }
436  break;
437 
438  case ST_int32:
439  case ST_int32array:
440  _int_range.clear();
441  for (i = 0; i < num_ranges; i++) {
442  int64_t min = (int64_t)floor(range.get_min(i) * _divisor + 0.5);
443  int64_t max = (int64_t)floor(range.get_max(i) * _divisor + 0.5);
444  validate_int64_limits(min, 32, range_error);
445  validate_int64_limits(max, 32, range_error);
446  _int_range.add_range((int)min, (int)max);
447  }
448  break;
449 
450  case ST_int64:
451  _int64_range.clear();
452  for (i = 0; i < num_ranges; i++) {
453  int64_t min = (int64_t)floor(range.get_min(i) * _divisor + 0.5);
454  int64_t max = (int64_t)floor(range.get_max(i) * _divisor + 0.5);
455  _int64_range.add_range(min, max);
456  }
457  break;
458 
459  case ST_char:
460  case ST_uint8:
461  case ST_uint8array:
462  _uint_range.clear();
463  for (i = 0; i < num_ranges; i++) {
464  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
465  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
466  validate_uint64_limits(min, 8, range_error);
467  validate_uint64_limits(max, 8, range_error);
468  _uint_range.add_range((unsigned int)min, (unsigned int)max);
469  }
470  break;
471 
472  case ST_uint16:
473  case ST_uint16array:
474  _uint_range.clear();
475  for (i = 0; i < num_ranges; i++) {
476  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
477  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
478  validate_uint64_limits(min, 16, range_error);
479  validate_uint64_limits(max, 16, range_error);
480  _uint_range.add_range((unsigned int)min, (unsigned int)max);
481  }
482  break;
483 
484  case ST_uint32:
485  case ST_uint32array:
486  _uint_range.clear();
487  for (i = 0; i < num_ranges; i++) {
488  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
489  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
490  validate_uint64_limits(min, 32, range_error);
491  validate_uint64_limits(max, 32, range_error);
492  _uint_range.add_range((unsigned int)min, (unsigned int)max);
493  }
494  break;
495 
496  case ST_uint64:
497  _uint64_range.clear();
498  for (i = 0; i < num_ranges; i++) {
499  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
500  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
501  _uint64_range.add_range(min, max);
502  }
503  break;
504 
505  case ST_float64:
506  _double_range.clear();
507  for (i = 0; i < num_ranges; i++) {
508  double min = range.get_min(i) * _divisor;
509  double max = range.get_max(i) * _divisor;
510  _double_range.add_range(min, max);
511  }
512  break;
513 
514  case ST_string:
515  case ST_blob:
516  _uint_range.clear();
517  for (i = 0; i < num_ranges; i++) {
518  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
519  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
520  validate_uint64_limits(min, 16, range_error);
521  validate_uint64_limits(max, 16, range_error);
522  _uint_range.add_range((unsigned int)min, (unsigned int)max);
523  }
524  if (_uint_range.has_one_value()) {
525  // If we now have a fixed-length string requirement, we don't need a
526  // leading number of bytes.
527  _num_length_bytes = 0;
528  _has_fixed_byte_size = true;
529  _fixed_byte_size = _uint_range.get_one_value();
530  _has_fixed_structure = true;
531  } else {
532  _num_length_bytes = 2;
533  _has_fixed_byte_size = false;
534  _has_fixed_structure = false;
535  }
536  break;
537 
538  case ST_blob32:
539  _uint_range.clear();
540  for (i = 0; i < num_ranges; i++) {
541  uint64_t min = (uint64_t)floor(range.get_min(i) * _divisor + 0.5);
542  uint64_t max = (uint64_t)floor(range.get_max(i) * _divisor + 0.5);
543  validate_uint64_limits(min, 32, range_error);
544  validate_uint64_limits(max, 32, range_error);
545  _uint_range.add_range((unsigned int)min, (unsigned int)max);
546  }
547  if (_uint_range.has_one_value()) {
548  // If we now have a fixed-length string requirement, we don't need a
549  // leading number of bytes.
550  _num_length_bytes = 0;
551  _has_fixed_byte_size = true;
552  _fixed_byte_size = _uint_range.get_one_value();
553  _has_fixed_structure = true;
554  } else {
555  _num_length_bytes = 4;
556  _has_fixed_byte_size = false;
557  _has_fixed_structure = false;
558  }
559  break;
560 
561  default:
562  return false;
563  }
564 
565  return !range_error;
566 }
567 
568 /**
569  * This flavor of get_num_nested_fields is used during unpacking. It returns
570  * the number of nested fields to expect, given a certain length in bytes (as
571  * read from the _num_length_bytes stored in the stream on the push). This
572  * will only be called if _num_length_bytes is nonzero.
573  */
575 calc_num_nested_fields(size_t length_bytes) const {
576  if (_bytes_per_element != 0) {
577  return length_bytes / _bytes_per_element;
578  }
579  return 0;
580 }
581 
582 /**
583  * Returns the DCPackerInterface object that represents the nth nested field.
584  * This may return NULL if there is no such field (but it shouldn't do this if
585  * n is in the range 0 <= n < get_num_nested_fields()).
586  */
588 get_nested_field(int) const {
589  return _nested_field;
590 }
591 
592 /**
593  * Packs the indicated numeric or string value into the stream.
594  */
596 pack_double(DCPackData &pack_data, double value,
597  bool &pack_error, bool &range_error) const {
598  double real_value = value * _divisor;
599  if (_has_modulus) {
600  if (real_value < 0.0) {
601  real_value = _double_modulus - fmod(-real_value, _double_modulus);
602  if (real_value == _double_modulus) {
603  real_value = 0.0;
604  }
605  } else {
606  real_value = fmod(real_value, _double_modulus);
607  }
608  }
609 
610  switch (_type) {
611  case ST_int8:
612  {
613  int int_value = (int)floor(real_value + 0.5);
614  _int_range.validate(int_value, range_error);
615  validate_int_limits(int_value, 8, range_error);
616  do_pack_int8(pack_data.get_write_pointer(1), int_value);
617  }
618  break;
619 
620  case ST_int16:
621  {
622  int int_value = (int)floor(real_value + 0.5);
623  _int_range.validate(int_value, range_error);
624  validate_int_limits(int_value, 16, range_error);
625  do_pack_int16(pack_data.get_write_pointer(2), int_value);
626  }
627  break;
628 
629  case ST_int32:
630  {
631  int int_value = (int)floor(real_value + 0.5);
632  _int_range.validate(int_value, range_error);
633  do_pack_int32(pack_data.get_write_pointer(4), int_value);
634  }
635  break;
636 
637  case ST_int64:
638  {
639  int64_t int64_value = (int64_t)floor(real_value + 0.5);
640  _int64_range.validate(int64_value, range_error);
641  do_pack_int64(pack_data.get_write_pointer(8), int64_value);
642  }
643  break;
644 
645  case ST_char:
646  case ST_uint8:
647  {
648  unsigned int int_value = (unsigned int)floor(real_value + 0.5);
649  _uint_range.validate(int_value, range_error);
650  validate_uint_limits(int_value, 8, range_error);
651  do_pack_uint8(pack_data.get_write_pointer(1), int_value);
652  }
653  break;
654 
655  case ST_uint16:
656  {
657  unsigned int int_value = (unsigned int)floor(real_value + 0.5);
658  _uint_range.validate(int_value, range_error);
659  validate_uint_limits(int_value, 16, range_error);
660  do_pack_uint16(pack_data.get_write_pointer(2), int_value);
661  }
662  break;
663 
664  case ST_uint32:
665  {
666  unsigned int int_value = (unsigned int)floor(real_value + 0.5);
667  _uint_range.validate(int_value, range_error);
668  do_pack_uint32(pack_data.get_write_pointer(4), int_value);
669  }
670  break;
671 
672  case ST_uint64:
673  {
674  uint64_t int64_value = (uint64_t)floor(real_value + 0.5);
675  _uint64_range.validate(int64_value, range_error);
676  do_pack_uint64(pack_data.get_write_pointer(8), int64_value);
677  }
678  break;
679 
680  case ST_float64:
681  _double_range.validate(real_value, range_error);
682  do_pack_float64(pack_data.get_write_pointer(8), real_value);
683  break;
684 
685  default:
686  pack_error = true;
687  }
688 }
689 
690 /**
691  * Packs the indicated numeric or string value into the stream.
692  */
694 pack_int(DCPackData &pack_data, int value,
695  bool &pack_error, bool &range_error) const {
696  int int_value = value * _divisor;
697 
698  if (value != 0 && (int_value / value) != (int)_divisor) {
699  // If we've experienced overflow after applying the divisor, pack it as an
700  // int64 instead.
701  pack_int64(pack_data, (int64_t)value, pack_error, range_error);
702  return;
703  }
704 
705  if (_has_modulus && _uint_modulus != 0) {
706  if (int_value < 0) {
707  int_value = _uint_modulus - 1 - (-int_value - 1) % _uint_modulus;
708  } else {
709  int_value = int_value % _uint_modulus;
710  }
711  }
712 
713  switch (_type) {
714  case ST_int8:
715  _int_range.validate(int_value, range_error);
716  validate_int_limits(int_value, 8, range_error);
717  do_pack_int8(pack_data.get_write_pointer(1), int_value);
718  break;
719 
720  case ST_int16:
721  _int_range.validate(int_value, range_error);
722  validate_int_limits(int_value, 16, range_error);
723  do_pack_int16(pack_data.get_write_pointer(2), int_value);
724  break;
725 
726  case ST_int32:
727  _int_range.validate(int_value, range_error);
728  do_pack_int32(pack_data.get_write_pointer(4), int_value);
729  break;
730 
731  case ST_int64:
732  _int64_range.validate(int_value, range_error);
733  do_pack_int64(pack_data.get_write_pointer(8), int_value);
734  break;
735 
736  case ST_char:
737  case ST_uint8:
738  if (int_value < 0) {
739  range_error = true;
740  }
741  _uint_range.validate((unsigned int)int_value, range_error);
742  validate_uint_limits((unsigned int)int_value, 8, range_error);
743  do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
744  break;
745 
746  case ST_uint16:
747  if (int_value < 0) {
748  range_error = true;
749  }
750  _uint_range.validate((unsigned int)int_value, range_error);
751  validate_uint_limits((unsigned int)int_value, 16, range_error);
752  do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
753  break;
754 
755  case ST_uint32:
756  if (int_value < 0) {
757  range_error = true;
758  }
759  _uint_range.validate((unsigned int)int_value, range_error);
760  do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
761  break;
762 
763  case ST_uint64:
764  if (int_value < 0) {
765  range_error = true;
766  }
767  _uint64_range.validate((unsigned int)int_value, range_error);
768  do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value);
769  break;
770 
771  case ST_float64:
772  _double_range.validate(int_value, range_error);
773  do_pack_float64(pack_data.get_write_pointer(8), int_value);
774  break;
775 
776  default:
777  pack_error = true;
778  }
779 }
780 
781 /**
782  * Packs the indicated numeric or string value into the stream.
783  */
785 pack_uint(DCPackData &pack_data, unsigned int value,
786  bool &pack_error, bool &range_error) const {
787  unsigned int int_value = value * _divisor;
788  if (_has_modulus && _uint_modulus != 0) {
789  int_value = int_value % _uint_modulus;
790  }
791 
792  switch (_type) {
793  case ST_int8:
794  if ((int)int_value < 0) {
795  range_error = true;
796  }
797  _int_range.validate((int)int_value, range_error);
798  validate_int_limits((int)int_value, 8, range_error);
799  do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
800  break;
801 
802  case ST_int16:
803  if ((int)int_value < 0) {
804  range_error = true;
805  }
806  _int_range.validate((int)int_value, range_error);
807  validate_int_limits((int)int_value, 16, range_error);
808  do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
809  break;
810 
811  case ST_int32:
812  if ((int)int_value < 0) {
813  range_error = true;
814  }
815  _int_range.validate((int)int_value, range_error);
816  do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
817  break;
818 
819  case ST_int64:
820  if ((int)int_value < 0) {
821  range_error = true;
822  }
823  _int64_range.validate((int)int_value, range_error);
824  do_pack_int64(pack_data.get_write_pointer(8), (int)int_value);
825  break;
826 
827  case ST_char:
828  case ST_uint8:
829  _uint_range.validate(int_value, range_error);
830  validate_uint_limits(int_value, 8, range_error);
831  do_pack_uint8(pack_data.get_write_pointer(1), int_value);
832  break;
833 
834  case ST_uint16:
835  _uint_range.validate(int_value, range_error);
836  validate_uint_limits(int_value, 16, range_error);
837  do_pack_uint16(pack_data.get_write_pointer(2), int_value);
838  break;
839 
840  case ST_uint32:
841  _uint_range.validate(int_value, range_error);
842  do_pack_uint32(pack_data.get_write_pointer(4), int_value);
843  break;
844 
845  case ST_uint64:
846  _uint64_range.validate(int_value, range_error);
847  do_pack_uint64(pack_data.get_write_pointer(8), int_value);
848  break;
849 
850  case ST_float64:
851  _double_range.validate(int_value, range_error);
852  do_pack_float64(pack_data.get_write_pointer(8), int_value);
853  break;
854 
855  default:
856  pack_error = true;
857  }
858 }
859 
860 /**
861  * Packs the indicated numeric or string value into the stream.
862  */
864 pack_int64(DCPackData &pack_data, int64_t value,
865  bool &pack_error, bool &range_error) const {
866  int64_t int_value = value * _divisor;
867  if (_has_modulus && _uint64_modulus != 0) {
868  if (int_value < 0) {
869  int_value = _uint64_modulus - 1 - (-int_value - 1) % _uint64_modulus;
870  } else {
871  int_value = int_value % _uint64_modulus;
872  }
873  }
874 
875  switch (_type) {
876  case ST_int8:
877  _int_range.validate((int)int_value, range_error);
878  validate_int64_limits(int_value, 8, range_error);
879  do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
880  break;
881 
882  case ST_int16:
883  _int_range.validate((int)int_value, range_error);
884  validate_int64_limits(int_value, 16, range_error);
885  do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
886  break;
887 
888  case ST_int32:
889  _int_range.validate((int)int_value, range_error);
890  validate_int64_limits(int_value, 32, range_error);
891  do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
892  break;
893 
894  case ST_int64:
895  _int64_range.validate(int_value, range_error);
896  do_pack_int64(pack_data.get_write_pointer(8), int_value);
897  break;
898 
899  case ST_char:
900  case ST_uint8:
901  if (int_value < 0) {
902  range_error = true;
903  }
904  _uint_range.validate((unsigned int)(uint64_t)int_value, range_error);
905  validate_uint64_limits((uint64_t)int_value, 8, range_error);
906  do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(uint64_t)int_value);
907  break;
908 
909  case ST_uint16:
910  if (int_value < 0) {
911  range_error = true;
912  }
913  _uint_range.validate((unsigned int)(uint64_t)int_value, range_error);
914  validate_uint64_limits((uint64_t)int_value, 16, range_error);
915  do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(uint64_t)int_value);
916  break;
917 
918  case ST_uint32:
919  if (int_value < 0) {
920  range_error = true;
921  }
922  _uint_range.validate((unsigned int)(uint64_t)int_value, range_error);
923  validate_uint64_limits((uint64_t)int_value, 32, range_error);
924  do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(uint64_t)int_value);
925  break;
926 
927  case ST_uint64:
928  if (int_value < 0) {
929  range_error = true;
930  }
931  _uint64_range.validate((uint64_t)int_value, range_error);
932  do_pack_uint64(pack_data.get_write_pointer(8), (uint64_t)int_value);
933  break;
934 
935  case ST_float64:
936  _double_range.validate((double)int_value, range_error);
937  do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
938  break;
939 
940  default:
941  pack_error = true;
942  }
943 }
944 
945 /**
946  * Packs the indicated numeric or string value into the stream.
947  */
949 pack_uint64(DCPackData &pack_data, uint64_t value,
950  bool &pack_error, bool &range_error) const {
951  uint64_t int_value = value * _divisor;
952  if (_has_modulus && _uint64_modulus != 0) {
953  int_value = int_value % _uint64_modulus;
954  }
955 
956  switch (_type) {
957  case ST_int8:
958  if ((int64_t)int_value < 0) {
959  range_error = true;
960  }
961  _int_range.validate((int)(int64_t)int_value, range_error);
962  validate_int64_limits((int64_t)int_value, 8, range_error);
963  do_pack_int8(pack_data.get_write_pointer(1), (int)(int64_t)int_value);
964  break;
965 
966  case ST_int16:
967  if ((int64_t)int_value < 0) {
968  range_error = true;
969  }
970  _int_range.validate((int)(int64_t)int_value, range_error);
971  validate_int64_limits((int64_t)int_value, 16, range_error);
972  do_pack_int16(pack_data.get_write_pointer(2), (int)(int64_t)int_value);
973  break;
974 
975  case ST_int32:
976  if ((int64_t)int_value < 0) {
977  range_error = true;
978  }
979  _int_range.validate((int)(int64_t)int_value, range_error);
980  validate_int64_limits((int64_t)int_value, 32, range_error);
981  do_pack_int32(pack_data.get_write_pointer(4), (int)(int64_t)int_value);
982  break;
983 
984  case ST_int64:
985  if ((int64_t)int_value < 0) {
986  range_error = true;
987  }
988  _int64_range.validate((int64_t)int_value, range_error);
989  do_pack_int64(pack_data.get_write_pointer(8), (int64_t)int_value);
990  break;
991 
992  case ST_char:
993  case ST_uint8:
994  _uint_range.validate((unsigned int)int_value, range_error);
995  validate_uint64_limits(int_value, 8, range_error);
996  do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
997  break;
998 
999  case ST_uint16:
1000  _uint_range.validate((unsigned int)int_value, range_error);
1001  validate_uint64_limits(int_value, 16, range_error);
1002  do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
1003  break;
1004 
1005  case ST_uint32:
1006  _uint_range.validate((unsigned int)int_value, range_error);
1007  validate_uint64_limits(int_value, 32, range_error);
1008  do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
1009  break;
1010 
1011  case ST_uint64:
1012  _uint64_range.validate(int_value, range_error);
1013  do_pack_uint64(pack_data.get_write_pointer(8), int_value);
1014  break;
1015 
1016  case ST_float64:
1017  _double_range.validate((double)int_value, range_error);
1018  do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
1019  break;
1020 
1021  default:
1022  pack_error = true;
1023  }
1024 }
1025 
1026 /**
1027  * Packs the indicated numeric or string value into the stream.
1028  */
1030 pack_string(DCPackData &pack_data, const string &value,
1031  bool &pack_error, bool &range_error) const {
1032  size_t string_length = value.length();
1033 
1034  switch (_type) {
1035  case ST_char:
1036  case ST_uint8:
1037  case ST_int8:
1038  if (string_length == 0) {
1039  pack_error = true;
1040  } else {
1041  if (string_length != 1) {
1042  range_error = true;
1043  }
1044  _uint_range.validate((unsigned int)value[0], range_error);
1045  do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)value[0]);
1046  }
1047  break;
1048 
1049  case ST_string:
1050  case ST_blob:
1051  _uint_range.validate(string_length, range_error);
1052  validate_uint_limits(string_length, 16, range_error);
1053  if (_num_length_bytes != 0) {
1054  do_pack_uint16(pack_data.get_write_pointer(2), string_length);
1055  }
1056  pack_data.append_data(value.data(), string_length);
1057  break;
1058 
1059  case ST_blob32:
1060  _uint_range.validate(string_length, range_error);
1061  if (_num_length_bytes != 0) {
1062  do_pack_uint32(pack_data.get_write_pointer(4), string_length);
1063  }
1064  pack_data.append_data(value.data(), string_length);
1065  break;
1066 
1067  default:
1068  pack_error = true;
1069  }
1070 }
1071 
1072 /**
1073  * Packs the indicated numeric or string value into the stream.
1074  */
1076 pack_blob(DCPackData &pack_data, const vector_uchar &value,
1077  bool &pack_error, bool &range_error) const {
1078  size_t blob_size = value.size();
1079 
1080  switch (_type) {
1081  case ST_char:
1082  case ST_uint8:
1083  case ST_int8:
1084  if (blob_size == 0) {
1085  pack_error = true;
1086  } else {
1087  if (blob_size != 1) {
1088  range_error = true;
1089  }
1090  _uint_range.validate((unsigned int)value[0], range_error);
1091  do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)value[0]);
1092  }
1093  break;
1094 
1095  case ST_string:
1096  case ST_blob:
1097  _uint_range.validate(blob_size, range_error);
1098  validate_uint_limits(blob_size, 16, range_error);
1099  if (_num_length_bytes != 0) {
1100  do_pack_uint16(pack_data.get_write_pointer(2), blob_size);
1101  }
1102  pack_data.append_data((const char *)value.data(), blob_size);
1103  break;
1104 
1105  case ST_blob32:
1106  _uint_range.validate(blob_size, range_error);
1107  if (_num_length_bytes != 0) {
1108  do_pack_uint32(pack_data.get_write_pointer(4), blob_size);
1109  }
1110  pack_data.append_data((const char *)value.data(), blob_size);
1111  break;
1112 
1113  default:
1114  pack_error = true;
1115  }
1116 }
1117 
1118 /**
1119  * Packs the simpleParameter's specified default value (or a sensible default
1120  * if no value is specified) into the stream. Returns true if the default
1121  * value is packed, false if the simpleParameter doesn't know how to pack its
1122  * default value.
1123  */
1125 pack_default_value(DCPackData &pack_data, bool &pack_error) const {
1126  if (has_default_value()) {
1127  return DCField::pack_default_value(pack_data, pack_error);
1128  }
1129 
1130  if (_has_nested_fields) {
1131  // If the simple type is an array (or string) type, pack the appropriate
1132  // length array, with code similar to
1133  // DCArrayParameter::pack_default_value().
1134 
1135  unsigned int minimum_length = 0;
1136  if (!_uint_range.is_empty()) {
1137  minimum_length = _uint_range.get_min(0);
1138  }
1139 
1140  DCPacker packer;
1141  packer.begin_pack(this);
1142  packer.push();
1143  for (unsigned int i = 0; i < minimum_length; i++) {
1144  packer.pack_default_value();
1145  }
1146  packer.pop();
1147  if (!packer.end_pack()) {
1148  pack_error = true;
1149 
1150  } else {
1151  pack_data.append_data(packer.get_data(), packer.get_length());
1152  }
1153 
1154  } else {
1155  // Otherwise, if it's just a simple numeric type, pack a zero or the
1156  // minimum value.
1157  switch (_type) {
1158  case ST_int8:
1159  case ST_int16:
1160  case ST_int32:
1161  if (_int_range.is_in_range(0)) {
1162  pack_int(pack_data, 0, pack_error, pack_error);
1163  } else {
1164  pack_int(pack_data, _int_range.get_min(0), pack_error, pack_error);
1165  }
1166  break;
1167 
1168  case ST_int64:
1169  if (_int64_range.is_in_range(0)) {
1170  pack_int64(pack_data, 0, pack_error, pack_error);
1171  } else {
1172  pack_int64(pack_data, _int64_range.get_min(0), pack_error, pack_error);
1173  }
1174  break;
1175 
1176  case ST_char:
1177  case ST_uint8:
1178  case ST_uint16:
1179  case ST_uint32:
1180  if (_uint_range.is_in_range(0)) {
1181  pack_uint(pack_data, 0, pack_error, pack_error);
1182  } else {
1183  pack_uint(pack_data, _uint_range.get_min(0), pack_error, pack_error);
1184  }
1185  break;
1186 
1187  case ST_uint64:
1188  if (_uint64_range.is_in_range(0)) {
1189  pack_uint64(pack_data, 0, pack_error, pack_error);
1190  } else {
1191  pack_uint64(pack_data, _uint64_range.get_min(0), pack_error, pack_error);
1192  }
1193  break;
1194 
1195  case ST_float64:
1196  if (_double_range.is_in_range(0.0)) {
1197  pack_double(pack_data, 0.0, pack_error, pack_error);
1198  } else {
1199  pack_double(pack_data, _double_range.get_min(0), pack_error, pack_error);
1200  }
1201  break;
1202 
1203  default:
1204  pack_error = true;
1205  }
1206  }
1207  return true;
1208 }
1209 
1210 
1211 
1212 /**
1213  * Unpacks the current numeric or string value from the stream.
1214  */
1216 unpack_double(const char *data, size_t length, size_t &p, double &value,
1217  bool &pack_error, bool &range_error) const {
1218  switch (_type) {
1219  case ST_int8:
1220  {
1221  if (p + 1 > length) {
1222  pack_error = true;
1223  return;
1224  }
1225  int int_value = do_unpack_int8(data + p);
1226  _int_range.validate(int_value, range_error);
1227  value = int_value;
1228  p++;
1229  }
1230  break;
1231 
1232  case ST_int16:
1233  {
1234  if (p + 2 > length) {
1235  pack_error = true;
1236  return;
1237  }
1238  int int_value = do_unpack_int16(data + p);
1239  _int_range.validate(int_value, range_error);
1240  value = int_value;
1241  p += 2;
1242  }
1243  break;
1244 
1245  case ST_int32:
1246  {
1247  if (p + 4 > length) {
1248  pack_error = true;
1249  return;
1250  }
1251  int int_value = do_unpack_int32(data + p);
1252  _int_range.validate(int_value, range_error);
1253  value = int_value;
1254  p += 4;
1255  }
1256  break;
1257 
1258  case ST_int64:
1259  {
1260  if (p + 8 > length) {
1261  pack_error = true;
1262  return;
1263  }
1264  int64_t int_value = do_unpack_int64(data + p);
1265  _int64_range.validate(int_value, range_error);
1266  value = (double)int_value;
1267  p += 8;
1268  }
1269  break;
1270 
1271  case ST_char:
1272  case ST_uint8:
1273  {
1274  if (p + 1 > length) {
1275  pack_error = true;
1276  return;
1277  }
1278  unsigned int uint_value = do_unpack_uint8(data + p);
1279  _uint_range.validate(uint_value, range_error);
1280  value = uint_value;
1281  p++;
1282  }
1283  break;
1284 
1285  case ST_uint16:
1286  {
1287  if (p + 2 > length) {
1288  pack_error = true;
1289  return;
1290  }
1291  unsigned int uint_value = do_unpack_uint16(data + p);
1292  _uint_range.validate(uint_value, range_error);
1293  value = uint_value;
1294  p += 2;
1295  }
1296  break;
1297 
1298  case ST_uint32:
1299  {
1300  if (p + 4 > length) {
1301  pack_error = true;
1302  return;
1303  }
1304  unsigned int uint_value = do_unpack_uint32(data + p);
1305  _uint_range.validate(uint_value, range_error);
1306  value = uint_value;
1307  p += 4;
1308  }
1309  break;
1310 
1311  case ST_uint64:
1312  {
1313  if (p + 8 > length) {
1314  pack_error = true;
1315  return;
1316  }
1317  uint64_t uint_value = do_unpack_uint64(data + p);
1318  _uint64_range.validate(uint_value, range_error);
1319  value = (double)uint_value;
1320  p += 8;
1321  }
1322  break;
1323 
1324  case ST_float64:
1325  {
1326  if (p + 8 > length) {
1327  pack_error = true;
1328  return;
1329  }
1330  value = do_unpack_float64(data + p);
1331  _double_range.validate(value, range_error);
1332  p += 8;
1333  }
1334  break;
1335 
1336  default:
1337  pack_error = true;
1338  return;
1339  }
1340 
1341  if (_divisor != 1) {
1342  value = value / _divisor;
1343  }
1344 
1345  return;
1346 }
1347 
1348 /**
1349  * Unpacks the current numeric or string value from the stream.
1350  */
1352 unpack_int(const char *data, size_t length, size_t &p, int &value,
1353  bool &pack_error, bool &range_error) const {
1354  switch (_type) {
1355  case ST_int8:
1356  if (p + 1 > length) {
1357  pack_error = true;
1358  return;
1359  }
1360  value = do_unpack_int8(data + p);
1361  _int_range.validate(value, range_error);
1362  p++;
1363  break;
1364 
1365  case ST_int16:
1366  if (p + 2 > length) {
1367  pack_error = true;
1368  return;
1369  }
1370  value = do_unpack_int16(data + p);
1371  _int_range.validate(value, range_error);
1372  p += 2;
1373  break;
1374 
1375  case ST_int32:
1376  if (p + 4 > length) {
1377  pack_error = true;
1378  return;
1379  }
1380  value = do_unpack_int32(data + p);
1381  _int_range.validate(value, range_error);
1382  p += 4;
1383  break;
1384 
1385  case ST_int64:
1386  {
1387  if (p + 8 > length) {
1388  pack_error = true;
1389  return;
1390  }
1391  int64_t int_value = do_unpack_uint64(data + p);
1392  _int64_range.validate(int_value, range_error);
1393  value = (int)int_value;
1394  if (value != int_value) {
1395  // uint exceeded the storage capacity of a signed int.
1396  pack_error = true;
1397  }
1398  p += 8;
1399  }
1400  break;
1401 
1402  case ST_char:
1403  case ST_uint8:
1404  {
1405  if (p + 1 > length) {
1406  pack_error = true;
1407  return;
1408  }
1409  unsigned int uint_value = do_unpack_uint8(data + p);
1410  _uint_range.validate(uint_value, range_error);
1411  value = uint_value;
1412  p++;
1413  }
1414  break;
1415 
1416  case ST_uint16:
1417  {
1418  if (p + 2 > length) {
1419  pack_error = true;
1420  return;
1421  }
1422  unsigned int uint_value = do_unpack_uint16(data + p);
1423  _uint_range.validate(uint_value, range_error);
1424  value = (int)uint_value;
1425  p += 2;
1426  }
1427  break;
1428 
1429  case ST_uint32:
1430  {
1431  if (p + 4 > length) {
1432  pack_error = true;
1433  return;
1434  }
1435  unsigned int uint_value = do_unpack_uint32(data + p);
1436  _uint_range.validate(uint_value, range_error);
1437  value = (int)uint_value;
1438  if (value < 0) {
1439  pack_error = true;
1440  }
1441  p += 4;
1442  }
1443  break;
1444 
1445  case ST_uint64:
1446  {
1447  if (p + 8 > length) {
1448  pack_error = true;
1449  return;
1450  }
1451  uint64_t uint_value = do_unpack_uint64(data + p);
1452  _uint64_range.validate(uint_value, range_error);
1453  value = (int)(unsigned int)uint_value;
1454  if ((unsigned int)value != uint_value || value < 0) {
1455  pack_error = true;
1456  }
1457  p += 8;
1458  }
1459  break;
1460 
1461  case ST_float64:
1462  {
1463  if (p + 8 > length) {
1464  pack_error = true;
1465  return;
1466  }
1467  double real_value = do_unpack_float64(data + p);
1468  _double_range.validate(real_value, range_error);
1469  value = (int)real_value;
1470  p += 8;
1471  }
1472  break;
1473 
1474  default:
1475  pack_error = true;
1476  return;
1477  }
1478 
1479  if (_divisor != 1) {
1480  value = value / _divisor;
1481  }
1482 
1483  return;
1484 }
1485 
1486 /**
1487  * Unpacks the current numeric or string value from the stream.
1488  */
1490 unpack_uint(const char *data, size_t length, size_t &p, unsigned int &value,
1491  bool &pack_error, bool &range_error) const {
1492  switch (_type) {
1493  case ST_int8:
1494  {
1495  if (p + 1 > length) {
1496  pack_error = true;
1497  return;
1498  }
1499  int int_value = do_unpack_int8(data + p);
1500  _int_range.validate(int_value, range_error);
1501  if (int_value < 0) {
1502  pack_error = true;
1503  }
1504  value = (unsigned int)int_value;
1505  p++;
1506  }
1507  break;
1508 
1509  case ST_int16:
1510  {
1511  if (p + 2 > length) {
1512  pack_error = true;
1513  return;
1514  }
1515  int int_value = do_unpack_int16(data + p);
1516  _int_range.validate(int_value, range_error);
1517  if (int_value < 0) {
1518  pack_error = true;
1519  }
1520  value = (unsigned int)int_value;
1521  p += 2;
1522  }
1523  break;
1524 
1525  case ST_int32:
1526  {
1527  if (p + 4 > length) {
1528  pack_error = true;
1529  return;
1530  }
1531  int int_value = do_unpack_int32(data + p);
1532  _int_range.validate(int_value, range_error);
1533  if (int_value < 0) {
1534  pack_error = true;
1535  }
1536  value = (unsigned int)int_value;
1537  p += 4;
1538  }
1539  break;
1540 
1541  case ST_int64:
1542  {
1543  if (p + 8 > length) {
1544  pack_error = true;
1545  return;
1546  }
1547  int64_t int_value = do_unpack_int64(data + p);
1548  _int64_range.validate(int_value, range_error);
1549  if (int_value < 0) {
1550  pack_error = true;
1551  }
1552  value = (unsigned int)(int)int_value;
1553  if (value != int_value) {
1554  pack_error = true;
1555  }
1556  p += 8;
1557  }
1558  break;
1559 
1560  case ST_char:
1561  case ST_uint8:
1562  if (p + 1 > length) {
1563  pack_error = true;
1564  return;
1565  }
1566  value = do_unpack_uint8(data + p);
1567  _uint_range.validate(value, range_error);
1568  p++;
1569  break;
1570 
1571  case ST_uint16:
1572  if (p + 2 > length) {
1573  pack_error = true;
1574  return;
1575  }
1576  value = do_unpack_uint16(data + p);
1577  _uint_range.validate(value, range_error);
1578  p += 2;
1579  break;
1580 
1581  case ST_uint32:
1582  if (p + 4 > length) {
1583  pack_error = true;
1584  return;
1585  }
1586  value = do_unpack_uint32(data + p);
1587  _uint_range.validate(value, range_error);
1588  p += 4;
1589  break;
1590 
1591  case ST_uint64:
1592  {
1593  if (p + 8 > length) {
1594  pack_error = true;
1595  return;
1596  }
1597  uint64_t uint_value = do_unpack_uint64(data + p);
1598  _uint64_range.validate(uint_value, range_error);
1599  value = (unsigned int)uint_value;
1600  if (value != uint_value) {
1601  pack_error = true;
1602  }
1603  p += 8;
1604  }
1605  break;
1606 
1607  case ST_float64:
1608  {
1609  if (p + 8 > length) {
1610  pack_error = true;
1611  return;
1612  }
1613  double real_value = do_unpack_float64(data + p);
1614  _double_range.validate(real_value, range_error);
1615  value = (unsigned int)real_value;
1616  p += 8;
1617  }
1618  break;
1619 
1620  default:
1621  pack_error = true;
1622  return;
1623  }
1624 
1625  if (_divisor != 1) {
1626  value = value / _divisor;
1627  }
1628 
1629  return;
1630 }
1631 
1632 /**
1633  * Unpacks the current numeric or string value from the stream.
1634  */
1636 unpack_int64(const char *data, size_t length, size_t &p, int64_t &value,
1637  bool &pack_error, bool &range_error) const {
1638  switch (_type) {
1639  case ST_int8:
1640  {
1641  if (p + 1 > length) {
1642  pack_error = true;
1643  return;
1644  }
1645  int int_value = do_unpack_int8(data + p);
1646  _int_range.validate(int_value, range_error);
1647  value = (int64_t)int_value;
1648  p++;
1649  }
1650  break;
1651 
1652  case ST_int16:
1653  {
1654  if (p + 2 > length) {
1655  pack_error = true;
1656  return;
1657  }
1658  int int_value = do_unpack_int16(data + p);
1659  _int_range.validate(int_value, range_error);
1660  value = (int64_t)int_value;
1661  p += 2;
1662  }
1663  break;
1664 
1665  case ST_int32:
1666  {
1667  if (p + 4 > length) {
1668  pack_error = true;
1669  return;
1670  }
1671  int int_value = do_unpack_int32(data + p);
1672  _int_range.validate(int_value, range_error);
1673  value = (int64_t)int_value;
1674  p += 4;
1675  }
1676  break;
1677 
1678  case ST_int64:
1679  if (p + 8 > length) {
1680  pack_error = true;
1681  return;
1682  }
1683  value = do_unpack_int64(data + p);
1684  _int64_range.validate(value, range_error);
1685  p += 8;
1686  break;
1687 
1688  case ST_char:
1689  case ST_uint8:
1690  {
1691  if (p + 1 > length) {
1692  pack_error = true;
1693  return;
1694  }
1695  unsigned int uint_value = do_unpack_uint8(data + p);
1696  _uint_range.validate(uint_value, range_error);
1697  value = (int64_t)(int)uint_value;
1698  p++;
1699  }
1700  break;
1701 
1702  case ST_uint16:
1703  {
1704  if (p + 2 > length) {
1705  pack_error = true;
1706  return;
1707  }
1708  unsigned int uint_value = do_unpack_uint16(data + p);
1709  _uint_range.validate(uint_value, range_error);
1710  value = (int64_t)(int)uint_value;
1711  p += 2;
1712  }
1713  break;
1714 
1715  case ST_uint32:
1716  {
1717  if (p + 4 > length) {
1718  pack_error = true;
1719  return;
1720  }
1721  unsigned int uint_value = do_unpack_uint32(data + p);
1722  _uint_range.validate(uint_value, range_error);
1723  value = (int64_t)(int)uint_value;
1724  p += 4;
1725  }
1726  break;
1727 
1728  case ST_uint64:
1729  {
1730  if (p + 8 > length) {
1731  pack_error = true;
1732  return;
1733  }
1734  uint64_t uint_value = do_unpack_uint64(data + p);
1735  _uint64_range.validate(uint_value, range_error);
1736  value = (int64_t)uint_value;
1737  if (value < 0) {
1738  pack_error = true;
1739  }
1740  p += 8;
1741  }
1742  break;
1743 
1744  case ST_float64:
1745  {
1746  if (p + 8 > length) {
1747  pack_error = true;
1748  return;
1749  }
1750  double real_value = do_unpack_float64(data + p);
1751  _double_range.validate(real_value, range_error);
1752  value = (int64_t)real_value;
1753  p += 8;
1754  }
1755  break;
1756 
1757  default:
1758  pack_error = true;
1759  return;
1760  }
1761 
1762  if (_divisor != 1) {
1763  value = value / _divisor;
1764  }
1765 
1766  return;
1767 }
1768 
1769 /**
1770  * Unpacks the current numeric or string value from the stream.
1771  */
1773 unpack_uint64(const char *data, size_t length, size_t &p, uint64_t &value,
1774  bool &pack_error, bool &range_error) const {
1775  switch (_type) {
1776  case ST_int8:
1777  {
1778  if (p + 1 > length) {
1779  pack_error = true;
1780  return;
1781  }
1782  int int_value = do_unpack_int8(data + p);
1783  _int_range.validate(int_value, range_error);
1784  if (int_value < 0) {
1785  pack_error = true;
1786  }
1787  value = (uint64_t)(unsigned int)int_value;
1788  p++;
1789  }
1790  break;
1791 
1792  case ST_int16:
1793  {
1794  if (p + 2 > length) {
1795  pack_error = true;
1796  return;
1797  }
1798  int int_value = do_unpack_int16(data + p);
1799  _int_range.validate(int_value, range_error);
1800  if (int_value < 0) {
1801  pack_error = true;
1802  }
1803  value = (uint64_t)(unsigned int)int_value;
1804  p += 2;
1805  }
1806  break;
1807 
1808  case ST_int32:
1809  {
1810  if (p + 4 > length) {
1811  pack_error = true;
1812  return;
1813  }
1814  int int_value = do_unpack_int32(data + p);
1815  _int_range.validate(int_value, range_error);
1816  if (int_value < 0) {
1817  pack_error = true;
1818  }
1819  value = (uint64_t)(unsigned int)int_value;
1820  p += 4;
1821  }
1822  break;
1823 
1824  case ST_int64:
1825  {
1826  if (p + 8 > length) {
1827  pack_error = true;
1828  return;
1829  }
1830  int64_t int_value = do_unpack_int64(data + p);
1831  _int64_range.validate(int_value, range_error);
1832  if (int_value < 0) {
1833  pack_error = true;
1834  }
1835  value = (uint64_t)int_value;
1836  p += 8;
1837  }
1838  break;
1839 
1840  case ST_char:
1841  case ST_uint8:
1842  {
1843  if (p + 1 > length) {
1844  pack_error = true;
1845  return;
1846  }
1847  unsigned int uint_value = do_unpack_uint8(data + p);
1848  _uint_range.validate(uint_value, range_error);
1849  value = (uint64_t)uint_value;
1850  p++;
1851  }
1852  break;
1853 
1854  case ST_uint16:
1855  {
1856  if (p + 2 > length) {
1857  pack_error = true;
1858  return;
1859  }
1860  unsigned int uint_value = do_unpack_uint16(data + p);
1861  _uint_range.validate(uint_value, range_error);
1862  value = (uint64_t)uint_value;
1863  p += 2;
1864  }
1865  break;
1866 
1867  case ST_uint32:
1868  {
1869  if (p + 4 > length) {
1870  pack_error = true;
1871  return;
1872  }
1873  unsigned int uint_value = do_unpack_uint32(data + p);
1874  _uint_range.validate(uint_value, range_error);
1875  value = (uint64_t)uint_value;
1876  p += 4;
1877  }
1878  break;
1879 
1880  case ST_uint64:
1881  if (p + 8 > length) {
1882  pack_error = true;
1883  return;
1884  }
1885  value = do_unpack_uint64(data + p);
1886  _uint64_range.validate(value, range_error);
1887  p += 8;
1888  break;
1889 
1890  case ST_float64:
1891  {
1892  if (p + 8 > length) {
1893  pack_error = true;
1894  return;
1895  }
1896  double real_value = do_unpack_float64(data + p);
1897  _double_range.validate(real_value, range_error);
1898  value = (uint64_t)real_value;
1899  p += 8;
1900  }
1901  break;
1902 
1903  default:
1904  pack_error = true;
1905  return;
1906  }
1907 
1908  if (_divisor != 1) {
1909  value = value / _divisor;
1910  }
1911 
1912  return;
1913 }
1914 
1915 /**
1916  * Unpacks the current numeric or string value from the stream.
1917  */
1919 unpack_string(const char *data, size_t length, size_t &p, string &value,
1920  bool &pack_error, bool &range_error) const {
1921  // If the type is a single byte, unpack it into a string of length 1.
1922  switch (_type) {
1923  case ST_char:
1924  case ST_int8:
1925  case ST_uint8:
1926  {
1927  if (p + 1 > length) {
1928  pack_error = true;
1929  return;
1930  }
1931  unsigned int int_value = do_unpack_uint8(data + p);
1932  _uint_range.validate(int_value, range_error);
1933  value.assign(1, int_value);
1934  p++;
1935  }
1936  return;
1937 
1938  default:
1939  break;
1940  }
1941 
1942  size_t string_length;
1943 
1944  if (_num_length_bytes == 0) {
1945  string_length = _fixed_byte_size;
1946 
1947  } else {
1948  switch (_type) {
1949  case ST_string:
1950  case ST_blob:
1951  if (p + 2 > length) {
1952  pack_error = true;
1953  return;
1954  }
1955  string_length = do_unpack_uint16(data + p);
1956  p += 2;
1957  break;
1958 
1959  case ST_blob32:
1960  if (p + 4 > length) {
1961  pack_error = true;
1962  return;
1963  }
1964  string_length = do_unpack_uint32(data + p);
1965  p += 4;
1966  break;
1967 
1968  default:
1969  pack_error = true;
1970  return;
1971  }
1972  }
1973 
1974  _uint_range.validate(string_length, range_error);
1975 
1976  if (p + string_length > length) {
1977  pack_error = true;
1978  return;
1979  }
1980  value.assign(data + p, string_length);
1981  p += string_length;
1982 
1983  return;
1984 }
1985 
1986 /**
1987  * Unpacks the current numeric or string value from the stream.
1988  */
1990 unpack_blob(const char *data, size_t length, size_t &p, vector_uchar &value,
1991  bool &pack_error, bool &range_error) const {
1992  // If the type is a single byte, unpack it into a string of length 1.
1993  switch (_type) {
1994  case ST_char:
1995  case ST_int8:
1996  case ST_uint8:
1997  {
1998  if (p + 1 > length) {
1999  pack_error = true;
2000  return;
2001  }
2002  unsigned int int_value = do_unpack_uint8(data + p);
2003  _uint_range.validate(int_value, range_error);
2004  value.resize(1);
2005  value[0] = int_value;
2006  p++;
2007  }
2008  return;
2009 
2010  default:
2011  break;
2012  }
2013 
2014  size_t blob_size;
2015 
2016  if (_num_length_bytes == 0) {
2017  blob_size = _fixed_byte_size;
2018 
2019  } else {
2020  switch (_type) {
2021  case ST_string:
2022  case ST_blob:
2023  if (p + 2 > length) {
2024  pack_error = true;
2025  return;
2026  }
2027  blob_size = do_unpack_uint16(data + p);
2028  p += 2;
2029  break;
2030 
2031  case ST_blob32:
2032  if (p + 4 > length) {
2033  pack_error = true;
2034  return;
2035  }
2036  blob_size = do_unpack_uint32(data + p);
2037  p += 4;
2038  break;
2039 
2040  default:
2041  pack_error = true;
2042  return;
2043  }
2044  }
2045 
2046  _uint_range.validate(blob_size, range_error);
2047 
2048  if (p + blob_size > length) {
2049  pack_error = true;
2050  return;
2051  }
2052  value = vector_uchar((const unsigned char *)data + p,
2053  (const unsigned char *)data + p + blob_size);
2054  p += blob_size;
2055 
2056  return;
2057 }
2058 
2059 /**
2060  * Internally unpacks the current numeric or string value and validates it
2061  * against the type range limits, but does not return the value. Returns true
2062  * on success, false on failure (e.g. we don't know how to validate this
2063  * field).
2064  */
2066 unpack_validate(const char *data, size_t length, size_t &p,
2067  bool &pack_error, bool &range_error) const {
2068  if (!_has_range_limits) {
2069  return unpack_skip(data, length, p, pack_error);
2070  }
2071  switch (_type) {
2072  case ST_int8:
2073  {
2074  if (p + 1 > length) {
2075  pack_error = true;
2076  return true;
2077  }
2078  int int_value = do_unpack_int8(data + p);
2079  _int_range.validate(int_value, range_error);
2080  p++;
2081  }
2082  break;
2083 
2084  case ST_int16:
2085  {
2086  if (p + 2 > length) {
2087  pack_error = true;
2088  return true;
2089  }
2090  int int_value = do_unpack_int16(data + p);
2091  _int_range.validate(int_value, range_error);
2092  p += 2;
2093  }
2094  break;
2095 
2096  case ST_int32:
2097  {
2098  if (p + 4 > length) {
2099  pack_error = true;
2100  return true;
2101  }
2102  int int_value = do_unpack_int32(data + p);
2103  _int_range.validate(int_value, range_error);
2104  p += 4;
2105  }
2106  break;
2107 
2108  case ST_int64:
2109  {
2110  if (p + 8 > length) {
2111  pack_error = true;
2112  return true;
2113  }
2114  int64_t int_value = do_unpack_int64(data + p);
2115  _int64_range.validate(int_value, range_error);
2116  p += 8;
2117  }
2118  break;
2119 
2120  case ST_char:
2121  case ST_uint8:
2122  {
2123  if (p + 1 > length) {
2124  pack_error = true;
2125  return true;
2126  }
2127  unsigned int uint_value = do_unpack_uint8(data + p);
2128  _uint_range.validate(uint_value, range_error);
2129  p++;
2130  }
2131  break;
2132 
2133  case ST_uint16:
2134  {
2135  if (p + 2 > length) {
2136  pack_error = true;
2137  return true;
2138  }
2139  unsigned int uint_value = do_unpack_uint16(data + p);
2140  _uint_range.validate(uint_value, range_error);
2141  p += 2;
2142  }
2143  break;
2144 
2145  case ST_uint32:
2146  {
2147  if (p + 4 > length) {
2148  pack_error = true;
2149  return true;
2150  }
2151  unsigned int uint_value = do_unpack_uint32(data + p);
2152  _uint_range.validate(uint_value, range_error);
2153  p += 4;
2154  }
2155  break;
2156 
2157  case ST_uint64:
2158  {
2159  if (p + 8 > length) {
2160  pack_error = true;
2161  return true;
2162  }
2163  uint64_t uint_value = do_unpack_uint64(data + p);
2164  _uint64_range.validate(uint_value, range_error);
2165  p += 8;
2166  }
2167  break;
2168 
2169  case ST_float64:
2170  {
2171  if (p + 8 > length) {
2172  pack_error = true;
2173  return true;
2174  }
2175  double real_value = do_unpack_float64(data + p);
2176  _double_range.validate(real_value, range_error);
2177  p += 8;
2178  }
2179  break;
2180 
2181  case ST_string:
2182  case ST_blob:
2183  if (_num_length_bytes == 0) {
2184  p += _fixed_byte_size;
2185 
2186  } else {
2187  if (p + 2 > length) {
2188  pack_error = true;
2189  return true;
2190  }
2191  size_t string_length = do_unpack_uint16(data + p);
2192  _uint_range.validate(string_length, range_error);
2193  p += 2 + string_length;
2194  }
2195  break;
2196 
2197  case ST_blob32:
2198  if (_num_length_bytes == 0) {
2199  p += _fixed_byte_size;
2200 
2201  } else {
2202  if (p + 4 > length) {
2203  pack_error = true;
2204  return true;
2205  }
2206  size_t string_length = do_unpack_uint32(data + p);
2207  _uint_range.validate(string_length, range_error);
2208  p += 4 + string_length;
2209  }
2210  break;
2211 
2212  default:
2213  return false;
2214  }
2215 
2216  return true;
2217 }
2218 
2219 /**
2220  * Increments p to the end of the current field without actually unpacking any
2221  * data or performing any range validation. Returns true on success, false on
2222  * failure (e.g. we don't know how to skip this field).
2223  */
2225 unpack_skip(const char *data, size_t length, size_t &p,
2226  bool &pack_error) const {
2227  size_t string_length;
2228 
2229  switch (_type) {
2230  case ST_char:
2231  case ST_int8:
2232  case ST_uint8:
2233  p++;
2234  break;
2235 
2236  case ST_int16:
2237  case ST_uint16:
2238  p += 2;
2239  break;
2240 
2241  case ST_int32:
2242  case ST_uint32:
2243  p += 4;
2244  break;
2245 
2246  case ST_int64:
2247  case ST_uint64:
2248  case ST_float64:
2249  p += 8;
2250  break;
2251 
2252  case ST_string:
2253  case ST_blob:
2254  if (_num_length_bytes == 0) {
2255  p += _fixed_byte_size;
2256 
2257  } else {
2258  if (p + 2 > length) {
2259  return false;
2260  }
2261  string_length = do_unpack_uint16(data + p);
2262  p += 2 + string_length;
2263  }
2264  break;
2265 
2266  case ST_blob32:
2267  if (_num_length_bytes == 0) {
2268  p += _fixed_byte_size;
2269 
2270  } else {
2271  if (p + 4 > length) {
2272  return false;
2273  }
2274  string_length = do_unpack_uint32(data + p);
2275  p += 4 + string_length;
2276  }
2277  break;
2278 
2279  default:
2280  return false;
2281  }
2282 
2283  if (p > length) {
2284  pack_error = true;
2285  }
2286 
2287  return true;
2288 }
2289 
2290 /**
2291  * Formats the parameter in the C++-like dc syntax as a typename and
2292  * identifier.
2293  */
2295 output_instance(std::ostream &out, bool brief, const string &prename,
2296  const string &name, const string &postname) const {
2297  if (get_typedef() != nullptr) {
2298  output_typedef_name(out, brief, prename, name, postname);
2299 
2300  } else {
2301  out << _type;
2302  if (_has_modulus) {
2303  out << "%" << _orig_modulus;
2304  }
2305  if (_divisor != 1) {
2306  out << "/" << _divisor;
2307  }
2308 
2309  switch (_type) {
2310  case ST_int8:
2311  case ST_int16:
2312  case ST_int32:
2313  if (!_int_range.is_empty()) {
2314  out << "(";
2315  _int_range.output(out, _divisor);
2316  out << ")";
2317  }
2318  break;
2319 
2320  case ST_int64:
2321  if (!_int64_range.is_empty()) {
2322  out << "(";
2323  _int64_range.output(out, _divisor);
2324  out << ")";
2325  }
2326  break;
2327 
2328  case ST_uint8:
2329  case ST_uint16:
2330  case ST_uint32:
2331  if (!_uint_range.is_empty()) {
2332  out << "(";
2333  _uint_range.output(out, _divisor);
2334  out << ")";
2335  }
2336  break;
2337 
2338  case ST_char:
2339  if (!_uint_range.is_empty()) {
2340  out << "(";
2341  _uint_range.output_char(out, _divisor);
2342  out << ")";
2343  }
2344  break;
2345 
2346  case ST_uint64:
2347  if (!_uint64_range.is_empty()) {
2348  out << "(";
2349  _uint64_range.output(out, _divisor);
2350  out << ")";
2351  }
2352  break;
2353 
2354  case ST_float64:
2355  if (!_double_range.is_empty()) {
2356  out << "(";
2357  _double_range.output(out, _divisor);
2358  out << ")";
2359  }
2360  break;
2361 
2362  case ST_blob:
2363  case ST_blob32:
2364  case ST_string:
2365  if (!_uint_range.is_empty()) {
2366  out << "(";
2367  _uint_range.output(out, _divisor);
2368  out << ")";
2369  }
2370  break;
2371  default:
2372  break;
2373  }
2374 
2375  if (!prename.empty() || !name.empty() || !postname.empty()) {
2376  out << " " << prename << name << postname;
2377  }
2378  }
2379 }
2380 
2381 /**
2382  * Accumulates the properties of this type into the hash.
2383  */
2385 generate_hash(HashGenerator &hashgen) const {
2386  DCParameter::generate_hash(hashgen);
2387 
2388  hashgen.add_int(_type);
2389  hashgen.add_int(_divisor);
2390  if (_has_modulus) {
2391  hashgen.add_int((int)_double_modulus);
2392  }
2393 
2394  _int_range.generate_hash(hashgen);
2395  _int64_range.generate_hash(hashgen);
2396  _uint_range.generate_hash(hashgen);
2397  _uint64_range.generate_hash(hashgen);
2398  _double_range.generate_hash(hashgen);
2399 }
2400 
2401 /**
2402  * Returns true if the other interface is bitwise the same as this one--that
2403  * is, a uint32 only matches a uint32, etc. Names of components, and range
2404  * limits, are not compared.
2405  */
2406 bool DCSimpleParameter::
2407 do_check_match(const DCPackerInterface *other) const {
2408  return other->do_check_match_simple_parameter(this);
2409 }
2410 
2411 /**
2412  * Returns true if this field matches the indicated simple parameter, false
2413  * otherwise.
2414  */
2415 bool DCSimpleParameter::
2416 do_check_match_simple_parameter(const DCSimpleParameter *other) const {
2417  if (_divisor != other->_divisor) {
2418  return false;
2419  }
2420 
2421  if (_type == other->_type) {
2422  return true;
2423  }
2424 
2425  // Check for certain types that are considered equivalent to each other.
2426  switch (_type) {
2427  case ST_uint8:
2428  case ST_char:
2429  switch (other->_type) {
2430  case ST_uint8:
2431  case ST_char:
2432  return true;
2433 
2434  default:
2435  return false;
2436  }
2437 
2438  case ST_string:
2439  case ST_blob:
2440  case ST_uint8array:
2441  switch (other->_type) {
2442  case ST_string:
2443  case ST_blob:
2444  case ST_uint8array:
2445  return true;
2446 
2447  default:
2448  return false;
2449  }
2450 
2451  default:
2452  return false;
2453  }
2454 }
2455 
2456 /**
2457  * Returns true if this field matches the indicated array parameter, false
2458  * otherwise.
2459  */
2460 bool DCSimpleParameter::
2461 do_check_match_array_parameter(const DCArrayParameter *other) const {
2462  if (other->get_array_size() != -1) {
2463  // We cannot match a fixed-size array.
2464  return false;
2465  }
2466  if (_nested_field == nullptr) {
2467  // Only an array-style simple parameter can match a DCArrayParameter.
2468  return false;
2469  }
2470 
2471  return _nested_field->check_match(other->get_element_type());
2472 }
2473 
2474 /**
2475  * Creates the one instance of the DCSimpleParameter corresponding to this
2476  * combination of type and divisor if it is not already created.
2477  */
2478 DCSimpleParameter *DCSimpleParameter::
2479 create_nested_field(DCSubatomicType type, unsigned int divisor) {
2480  DivisorMap &divisor_map = _nested_field_map[type];
2481  DivisorMap::iterator di;
2482  di = divisor_map.find(divisor);
2483  if (di != divisor_map.end()) {
2484  return (*di).second;
2485  }
2486 
2487  DCSimpleParameter *nested_field = new DCSimpleParameter(type, divisor);
2488  divisor_map[divisor] = nested_field;
2489  return nested_field;
2490 }
2491 
2492 /**
2493  * Creates the one instance of the Uint32Uint8Type object if it is not already
2494  * created.
2495  */
2496 DCPackerInterface *DCSimpleParameter::
2497 create_uint32uint8_type() {
2498  if (_uint32uint8_type == nullptr) {
2499  DCClass *dclass = new DCClass(nullptr, "", true, false);
2500  dclass->add_field(new DCSimpleParameter(ST_uint32));
2501  dclass->add_field(new DCSimpleParameter(ST_uint8));
2502  _uint32uint8_type = new DCClassParameter(dclass);
2503  }
2504  return _uint32uint8_type;
2505 }
This represents an array of some other kind of object, meaning this parameter type accepts an arbitra...
int get_array_size() const
Returns the fixed number of elements in this array, or -1 if the array may contain a variable number ...
DCParameter * get_element_type() const
Returns the type of the individual elements of this array.
This represents a class (or struct) object used as a parameter itself.
Defines a particular DistributedClass as read from an input .dc file.
Definition: dcClass.h:44
bool add_field(DCField *field)
Adds the newly-allocated field to the class.
Definition: dcClass.cxx:1260
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
Definition: dcField.I:36
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the field's specified default value (or a sensible default if no value is specified) into the s...
Definition: dcField.cxx:487
bool add_range(Number min, Number max)
Adds a new minmax to the list of ranges.
bool has_one_value() const
Returns true if the numeric range specifies exactly one legal value, false if multiple values are leg...
Number get_max(int n) const
Returns the maximum value defined by the nth component.
Number get_min(int n) const
Returns the minimum value defined by the nth component.
int get_num_ranges() const
Returns the number of minmax components in the range description.
void output_char(std::ostream &out, Number divisor=1) const
Outputs the range, formatting the numeric values as quoted ASCII characters.
void validate(Number num, bool &range_error) const
Convenience function to validate the indicated number.
bool is_empty() const
Returns true if the range contains no elements (and thus allows all numbers), false if it contains at...
Number get_one_value() const
If has_one_value() returns true, this returns the one legal value accepted by the numeric range.
bool is_in_range(Number num) const
Returns true if the indicated number is within the specified range, false otherwise.
This is a block of data that receives the results of DCPacker.
Definition: dcPackData.h:22
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:47
char * get_write_pointer(size_t size)
Adds the indicated number of bytes to the end of the data without initializing them,...
Definition: dcPackData.I:57
This defines the internal interface for packing values into a DCField.
static void validate_uint_limits(unsigned int value, int num_bits, bool &range_error)
Confirms that the unsigned value fits within num_bits bits.
virtual bool do_check_match_simple_parameter(const DCSimpleParameter *other) const
Returns true if this field matches the indicated simple parameter, false otherwise.
static void validate_int_limits(int value, int num_bits, bool &range_error)
Confirms that the signed value fits within num_bits bits.
static void validate_uint64_limits(uint64_t value, int num_bits, bool &range_error)
Confirms that the unsigned value fits within num_bits bits.
static void validate_int64_limits(int64_t value, int num_bits, bool &range_error)
Confirms that the signed value fits within num_bits bits.
bool check_match(const DCPackerInterface *other) const
Returns true if the other interface is bitwise the same as this one–that is, a uint32 only matches a ...
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
void push()
Marks the beginning of a nested series of fields.
Definition: dcPacker.cxx:411
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
void pop()
Marks the end of a nested series of fields.
Definition: dcPacker.cxx:495
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
Represents the type specification for a single parameter within a field specification.
Definition: dcParameter.h:35
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
const DCTypedef * get_typedef() const
If this type has been referenced from a typedef, returns the DCTypedef instance, or NULL if the type ...
void output_typedef_name(std::ostream &out, bool brief, const std::string &prename, const std::string &name, const std::string &postname) const
Formats the instance like output_instance, but uses the typedef name instead.
This is the most fundamental kind of parameter type: a single number or string, one of the DCSubatomi...
virtual void pack_blob(DCPackData &pack_data, const std::vector< unsigned char > &value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
DCSubatomicType get_type() const
Returns the particular subatomic type represented by this instance.
bool set_range(const DCDoubleRange &range)
Sets the parameter with the indicated range.
virtual void pack_double(DCPackData &pack_data, double value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
virtual void pack_int(DCPackData &pack_data, int value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
virtual void unpack_string(const char *data, size_t length, size_t &p, std::string &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual bool unpack_skip(const char *data, size_t length, size_t &p, bool &pack_error) const
Increments p to the end of the current field without actually unpacking any data or performing any ra...
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
virtual bool is_valid() const
Returns false if the type is an invalid type (e.g.
virtual void output_instance(std::ostream &out, bool brief, const std::string &prename, const std::string &name, const std::string &postname) const
Formats the parameter in the C++-like dc syntax as a typename and identifier.
double get_modulus() const
Returns the modulus associated with this type, if any.
virtual void unpack_int(const char *data, size_t length, size_t &p, int &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual void unpack_blob(const char *data, size_t length, size_t &p, std::vector< unsigned char > &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual void unpack_uint(const char *data, size_t length, size_t &p, unsigned int &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual void pack_uint64(DCPackData &pack_data, uint64_t value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the simpleParameter's specified default value (or a sensible default if no value is specified) ...
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
bool set_modulus(double modulus)
Assigns the indicated modulus to the simple type.
virtual void unpack_uint64(const char *data, size_t length, size_t &p, uint64_t &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
virtual void unpack_int64(const char *data, size_t length, size_t &p, int64_t &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
bool has_modulus() const
Returns true if there is a modulus associated, false otherwise.,.
virtual void pack_uint(DCPackData &pack_data, unsigned int value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
bool set_divisor(unsigned int divisor)
Assigns the indicated divisor to the simple type.
virtual void pack_int64(DCPackData &pack_data, int64_t value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
int get_divisor() const
Returns the divisor associated with this type.
virtual bool unpack_validate(const char *data, size_t length, size_t &p, bool &pack_error, bool &range_error) const
Internally unpacks the current numeric or string value and validates it against the type range limits...
virtual void unpack_double(const char *data, size_t length, size_t &p, double &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
virtual void pack_string(DCPackData &pack_data, const std::string &value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
bool is_numeric_type() const
Returns true if the type is a numeric type (and therefore can accept a divisor and/or a modulus),...
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:23
void add_int(int num)
Adds another integer to the hash so far.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DCSubatomicType
This defines the numeric type of each element of a DCAtomicField; that is, the particular values that...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.