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