Panda3D
Loading...
Searching...
No Matches
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
23using std::string;
24
25DCSimpleParameter::NestedFieldMap DCSimpleParameter::_nested_field_map;
26DCClassParameter *DCSimpleParameter::_uint32uint8_type = nullptr;
27
28/**
29 *
30 */
31DCSimpleParameter::
32DCSimpleParameter(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 */
198DCSimpleParameter::
199DCSimpleParameter(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 */
222DCSimpleParameter *DCSimpleParameter::
223as_simple_parameter() {
224 return this;
225}
226
227/**
228 *
229 */
230const DCSimpleParameter *DCSimpleParameter::
231as_simple_parameter() const {
232 return this;
233}
234
235/**
236 *
237 */
238DCParameter *DCSimpleParameter::
239make_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 */
248is_valid() const {
249 return _type != ST_invalid;
250}
251
252/**
253 * Returns the particular subatomic type represented by this instance.
254 */
256get_type() const {
257 return _type;
258}
259
260/**
261 * Returns true if there is a modulus associated, false otherwise.,
262 */
264has_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 */
276get_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 */
287get_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 */
296is_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 */
308set_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 */
376set_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 */
405set_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 */
575calc_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 */
588get_nested_field(int) const {
589 return _nested_field;
590}
591
592/**
593 * Packs the indicated numeric or string value into the stream.
594 */
596pack_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 */
694pack_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 */
785pack_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 */
864pack_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 */
949pack_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 */
1030pack_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 */
1076pack_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 */
1125pack_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 */
1216unpack_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 */
1352unpack_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 */
1490unpack_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 */
1636unpack_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 */
1773unpack_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 */
1919unpack_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 */
1990unpack_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 */
2066unpack_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 */
2225unpack_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 */
2295output_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 */
2385generate_hash(HashGenerator &hashgen) const {
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 */
2406bool DCSimpleParameter::
2407do_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 */
2415bool DCSimpleParameter::
2416do_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 */
2460bool DCSimpleParameter::
2461do_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 */
2478DCSimpleParameter *DCSimpleParameter::
2479create_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 */
2496DCPackerInterface *DCSimpleParameter::
2497create_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.
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.