2492 lines
66 KiB
C++
2492 lines
66 KiB
C++
// Filename: dcSimpleParameter.cxx
|
|
// Created by: drose (15Jun04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "dcSimpleParameter.h"
|
|
#include "dcPackData.h"
|
|
#include "dcTypedef.h"
|
|
#include "dcArrayParameter.h"
|
|
#include "dcClassParameter.h"
|
|
#include "dcClass.h"
|
|
#include "hashGenerator.h"
|
|
#include <math.h>
|
|
|
|
DCSimpleParameter::NestedFieldMap DCSimpleParameter::_nested_field_map;
|
|
DCClassParameter *DCSimpleParameter::_uint32uint8_type = NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSimpleParameter::
|
|
DCSimpleParameter(DCSubatomicType type, unsigned int divisor) :
|
|
_type(type),
|
|
_divisor(1),
|
|
_has_modulus(false)
|
|
{
|
|
_pack_type = PT_invalid;
|
|
_nested_type = ST_invalid;
|
|
_has_nested_fields = false;
|
|
_bytes_per_element = 0;
|
|
_num_length_bytes = 2;
|
|
|
|
// Check for one of the built-in array types. For these types, we
|
|
// must present a packing interface that has a variable number of
|
|
// nested fields of the appropriate type.
|
|
switch (_type) {
|
|
case ST_int8array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_int8;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 1;
|
|
break;
|
|
|
|
case ST_int16array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_int16;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 2;
|
|
break;
|
|
|
|
case ST_int32array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_int32;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 4;
|
|
break;
|
|
|
|
case ST_uint8array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_uint8;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 1;
|
|
break;
|
|
|
|
case ST_uint16array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_uint16;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 2;
|
|
break;
|
|
|
|
case ST_uint32array:
|
|
_pack_type = PT_array;
|
|
_nested_type = ST_uint32;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 4;
|
|
break;
|
|
|
|
case ST_uint32uint8array:
|
|
_pack_type = PT_array;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 5;
|
|
break;
|
|
|
|
case ST_blob32:
|
|
_num_length_bytes = 4;
|
|
// fall through
|
|
case ST_blob:
|
|
// For blob and string, we will present an array interface
|
|
// as an array of uint8, but we will also accept a set_value()
|
|
// with a string parameter.
|
|
_pack_type = PT_blob;
|
|
_nested_type = ST_uint8;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 1;
|
|
break;
|
|
|
|
case ST_string:
|
|
_pack_type = PT_string;
|
|
_nested_type = ST_char;
|
|
_has_nested_fields = true;
|
|
_bytes_per_element = 1;
|
|
break;
|
|
|
|
// The simple types can be packed directly.
|
|
case ST_int8:
|
|
_pack_type = PT_int;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 1;
|
|
break;
|
|
|
|
case ST_int16:
|
|
_pack_type = PT_int;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 2;
|
|
break;
|
|
|
|
case ST_int32:
|
|
_pack_type = PT_int;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 4;
|
|
break;
|
|
|
|
case ST_int64:
|
|
_pack_type = PT_int64;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 8;
|
|
break;
|
|
|
|
case ST_char:
|
|
_pack_type = PT_string;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 1;
|
|
break;
|
|
|
|
case ST_uint8:
|
|
_pack_type = PT_uint;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 1;
|
|
break;
|
|
|
|
case ST_uint16:
|
|
_pack_type = PT_uint;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 2;
|
|
break;
|
|
|
|
case ST_uint32:
|
|
_pack_type = PT_uint;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 4;
|
|
break;
|
|
|
|
case ST_uint64:
|
|
_pack_type = PT_uint64;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 8;
|
|
break;
|
|
|
|
case ST_float64:
|
|
_pack_type = PT_double;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = 8;
|
|
break;
|
|
|
|
case ST_invalid:
|
|
break;
|
|
}
|
|
_has_fixed_structure = _has_fixed_byte_size;
|
|
|
|
set_divisor(divisor);
|
|
|
|
if (_nested_type != ST_invalid) {
|
|
_nested_field = create_nested_field(_nested_type, _divisor);
|
|
|
|
} else if (_type == ST_uint32uint8array) {
|
|
// This one is a special case. We must create a special nested
|
|
// type that accepts a uint32 followed by a uint8 for each
|
|
// element.
|
|
_nested_field = create_uint32uint8_type();
|
|
|
|
} else {
|
|
_nested_field = NULL;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::Copy Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSimpleParameter::
|
|
DCSimpleParameter(const DCSimpleParameter ©) :
|
|
DCParameter(copy),
|
|
_type(copy._type),
|
|
_divisor(copy._divisor),
|
|
_nested_field(copy._nested_field),
|
|
_bytes_per_element(copy._bytes_per_element),
|
|
_orig_range(copy._orig_range),
|
|
_has_modulus(copy._has_modulus),
|
|
_orig_modulus(copy._orig_modulus),
|
|
_int_range(copy._int_range),
|
|
_uint_range(copy._uint_range),
|
|
_int64_range(copy._int64_range),
|
|
_uint64_range(copy._uint64_range),
|
|
_double_range(copy._double_range),
|
|
_uint_modulus(copy._uint_modulus),
|
|
_uint64_modulus(copy._uint64_modulus),
|
|
_double_modulus(copy._double_modulus)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::as_simple_parameter
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSimpleParameter *DCSimpleParameter::
|
|
as_simple_parameter() {
|
|
return this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::as_simple_parameter
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
const DCSimpleParameter *DCSimpleParameter::
|
|
as_simple_parameter() const {
|
|
return this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::make_copy
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCParameter *DCSimpleParameter::
|
|
make_copy() const {
|
|
return new DCSimpleParameter(*this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::is_valid
|
|
// Access: Published, Virtual
|
|
// Description: Returns false if the type is an invalid type
|
|
// (e.g. declared from an undefined typedef), true if
|
|
// it is valid.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
is_valid() const {
|
|
return _type != ST_invalid;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::get_type
|
|
// Access: Published
|
|
// Description: Returns the particular subatomic type represented by
|
|
// this instance.
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSubatomicType DCSimpleParameter::
|
|
get_type() const {
|
|
return _type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::has_modulus
|
|
// Access: Published
|
|
// Description: Returns true if there is a modulus associated, false
|
|
// otherwise.,
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
has_modulus() const {
|
|
return _has_modulus;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::get_modulus
|
|
// Access: Published
|
|
// Description: Returns the modulus associated with this type, if
|
|
// any. It is an error to call this if has_modulus()
|
|
// returned false.
|
|
//
|
|
// If present, this is the modulus that is used to
|
|
// constrain the numeric value of the field before it is
|
|
// packed (and range-checked).
|
|
////////////////////////////////////////////////////////////////////
|
|
double DCSimpleParameter::
|
|
get_modulus() const {
|
|
return _orig_modulus;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::get_divisor
|
|
// Access: Published
|
|
// Description: Returns the divisor associated with this type. This
|
|
// is 1 by default, but if this is other than one it
|
|
// represents the scale to apply when packing and
|
|
// unpacking numeric values (to store fixed-point values
|
|
// in an integer field). It is only meaningful for
|
|
// numeric-type fields.
|
|
////////////////////////////////////////////////////////////////////
|
|
int DCSimpleParameter::
|
|
get_divisor() const {
|
|
return _divisor;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::is_numeric_type
|
|
// Access: Public
|
|
// Description: Returns true if the type is a numeric type (and
|
|
// therefore can accept a divisor and/or a modulus), or
|
|
// false if it is some string-based type.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
is_numeric_type() const {
|
|
return !(_pack_type == PT_string || _pack_type == PT_blob);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::set_modulus
|
|
// Access: Public
|
|
// Description: Assigns the indicated modulus to the simple type.
|
|
// Any packed value will be constrained to be within [0,
|
|
// modulus).
|
|
//
|
|
// Returns true if assigned, false if this type cannot
|
|
// accept a modulus or if the modulus is invalid.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
set_modulus(double modulus) {
|
|
if (_pack_type == PT_string || _pack_type == PT_blob || modulus <= 0.0) {
|
|
return false;
|
|
}
|
|
|
|
_has_modulus = true;
|
|
_orig_modulus = modulus;
|
|
|
|
bool range_error = false;
|
|
_double_modulus = modulus * _divisor;
|
|
_uint64_modulus = (PN_uint64)floor(_double_modulus + 0.5);
|
|
_uint_modulus = (unsigned int)_uint64_modulus;
|
|
|
|
// Check the range. The legitimate range for a modulus value is 1
|
|
// through (maximum_value + 1).
|
|
switch (_type) {
|
|
case ST_int8:
|
|
case ST_int8array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 7, range_error);
|
|
break;
|
|
|
|
case ST_int16:
|
|
case ST_int16array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 15, range_error);
|
|
break;
|
|
|
|
case ST_int32:
|
|
case ST_int32array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 31, range_error);
|
|
break;
|
|
|
|
case ST_int64:
|
|
validate_uint64_limits(_uint64_modulus - 1, 63, range_error);
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
case ST_uint8array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 8, range_error);
|
|
break;
|
|
|
|
case ST_uint16:
|
|
case ST_uint16array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 16, range_error);
|
|
break;
|
|
|
|
case ST_uint32:
|
|
case ST_uint32array:
|
|
validate_uint64_limits(_uint64_modulus - 1, 32, range_error);
|
|
break;
|
|
|
|
case ST_uint64:
|
|
case ST_float64:
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return !range_error;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::set_divisor
|
|
// Access: Public
|
|
// Description: Assigns the indicated divisor to the simple type.
|
|
// Returns true if assigned, false if this type cannot
|
|
// accept a divisor or if the divisor is invalid.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
set_divisor(unsigned int divisor) {
|
|
if (_pack_type == PT_string || _pack_type == PT_blob || divisor == 0) {
|
|
return false;
|
|
}
|
|
|
|
_divisor = divisor;
|
|
if ((_divisor != 1) &&
|
|
(_pack_type == PT_int || _pack_type == PT_int64 ||
|
|
_pack_type == PT_uint || _pack_type == PT_uint64)) {
|
|
_pack_type = PT_double;
|
|
}
|
|
|
|
if (_has_range_limits) {
|
|
set_range(_orig_range);
|
|
}
|
|
if (_has_modulus) {
|
|
set_modulus(_orig_modulus);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::set_range
|
|
// Access: Public
|
|
// Description: Sets the parameter with the indicated range. A
|
|
// DCDoubleRange is used for specification, since this
|
|
// is the most generic type; but it is converted to the
|
|
// appropriate type internally. The return value is
|
|
// true if successful, or false if the range is
|
|
// inappropriate for the type.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
set_range(const DCDoubleRange &range) {
|
|
bool range_error = false;
|
|
int num_ranges = range.get_num_ranges();
|
|
int i;
|
|
|
|
_has_range_limits = (num_ranges != 0);
|
|
_orig_range = range;
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
case ST_int8array:
|
|
_int_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_int64 min = (PN_int64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_int64 max = (PN_int64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_int64_limits(min, 8, range_error);
|
|
validate_int64_limits(max, 8, range_error);
|
|
_int_range.add_range((int)min, (int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
case ST_int16array:
|
|
_int_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_int64 min = (PN_int64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_int64 max = (PN_int64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_int64_limits(min, 16, range_error);
|
|
validate_int64_limits(max, 16, range_error);
|
|
_int_range.add_range((int)min, (int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
case ST_int32array:
|
|
_int_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_int64 min = (PN_int64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_int64 max = (PN_int64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_int64_limits(min, 32, range_error);
|
|
validate_int64_limits(max, 32, range_error);
|
|
_int_range.add_range((int)min, (int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
_int64_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_int64 min = (PN_int64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_int64 max = (PN_int64)floor(range.get_max(i) * _divisor + 0.5);
|
|
_int64_range.add_range(min, max);
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
case ST_uint8array:
|
|
_uint_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_uint64_limits(min, 8, range_error);
|
|
validate_uint64_limits(max, 8, range_error);
|
|
_uint_range.add_range((unsigned int)min, (unsigned int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
case ST_uint16array:
|
|
_uint_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_uint64_limits(min, 16, range_error);
|
|
validate_uint64_limits(max, 16, range_error);
|
|
_uint_range.add_range((unsigned int)min, (unsigned int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
case ST_uint32array:
|
|
_uint_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_uint64_limits(min, 32, range_error);
|
|
validate_uint64_limits(max, 32, range_error);
|
|
_uint_range.add_range((unsigned int)min, (unsigned int)max);
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
_uint64_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
_uint64_range.add_range(min, max);
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
double min = range.get_min(i) * _divisor;
|
|
double max = range.get_max(i) * _divisor;
|
|
_double_range.add_range(min, max);
|
|
}
|
|
break;
|
|
|
|
case ST_string:
|
|
case ST_blob:
|
|
_uint_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_uint64_limits(min, 16, range_error);
|
|
validate_uint64_limits(max, 16, range_error);
|
|
_uint_range.add_range((unsigned int)min, (unsigned int)max);
|
|
}
|
|
if (_uint_range.has_one_value()) {
|
|
// If we now have a fixed-length string requirement, we don't
|
|
// need a leading number of bytes.
|
|
_num_length_bytes = 0;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = _uint_range.get_one_value();
|
|
_has_fixed_structure = true;
|
|
} else {
|
|
_num_length_bytes = 2;
|
|
_has_fixed_byte_size = false;
|
|
_has_fixed_structure = false;
|
|
}
|
|
break;
|
|
|
|
case ST_blob32:
|
|
_uint_range.clear();
|
|
for (i = 0; i < num_ranges; i++) {
|
|
PN_uint64 min = (PN_uint64)floor(range.get_min(i) * _divisor + 0.5);
|
|
PN_uint64 max = (PN_uint64)floor(range.get_max(i) * _divisor + 0.5);
|
|
validate_uint64_limits(min, 32, range_error);
|
|
validate_uint64_limits(max, 32, range_error);
|
|
_uint_range.add_range((unsigned int)min, (unsigned int)max);
|
|
}
|
|
if (_uint_range.has_one_value()) {
|
|
// If we now have a fixed-length string requirement, we don't
|
|
// need a leading number of bytes.
|
|
_num_length_bytes = 0;
|
|
_has_fixed_byte_size = true;
|
|
_fixed_byte_size = _uint_range.get_one_value();
|
|
_has_fixed_structure = true;
|
|
} else {
|
|
_num_length_bytes = 4;
|
|
_has_fixed_byte_size = false;
|
|
_has_fixed_structure = false;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return !range_error;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::calc_num_nested_fields
|
|
// Access: Public, Virtual
|
|
// Description: This flavor of get_num_nested_fields is used during
|
|
// unpacking. It returns the number of nested fields to
|
|
// expect, given a certain length in bytes (as read from
|
|
// the _num_length_bytes stored in the stream on the
|
|
// push). This will only be called if _num_length_bytes
|
|
// is nonzero.
|
|
////////////////////////////////////////////////////////////////////
|
|
int DCSimpleParameter::
|
|
calc_num_nested_fields(size_t length_bytes) const {
|
|
if (_bytes_per_element != 0) {
|
|
return length_bytes / _bytes_per_element;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::get_nested_field
|
|
// Access: Public, Virtual
|
|
// Description: Returns the DCPackerInterface object that represents
|
|
// the nth nested field. This may return NULL if there
|
|
// is no such field (but it shouldn't do this if n is in
|
|
// the range 0 <= n < get_num_nested_fields()).
|
|
////////////////////////////////////////////////////////////////////
|
|
DCPackerInterface *DCSimpleParameter::
|
|
get_nested_field(int) const {
|
|
return _nested_field;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_double
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_double(DCPackData &pack_data, double value,
|
|
bool &pack_error, bool &range_error) const {
|
|
double real_value = value * _divisor;
|
|
if (_has_modulus) {
|
|
if (real_value < 0.0) {
|
|
real_value = _double_modulus - fmod(-real_value, _double_modulus);
|
|
if (real_value == _double_modulus) {
|
|
real_value = 0.0;
|
|
}
|
|
} else {
|
|
real_value = fmod(real_value, _double_modulus);
|
|
}
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
int int_value = (int)floor(real_value + 0.5);
|
|
_int_range.validate(int_value, range_error);
|
|
validate_int_limits(int_value, 8, range_error);
|
|
do_pack_int8(pack_data.get_write_pointer(1), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
int int_value = (int)floor(real_value + 0.5);
|
|
_int_range.validate(int_value, range_error);
|
|
validate_int_limits(int_value, 16, range_error);
|
|
do_pack_int16(pack_data.get_write_pointer(2), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
int int_value = (int)floor(real_value + 0.5);
|
|
_int_range.validate(int_value, range_error);
|
|
do_pack_int32(pack_data.get_write_pointer(4), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
PN_int64 int64_value = (PN_int64)floor(real_value + 0.5);
|
|
_int64_range.validate(int64_value, range_error);
|
|
do_pack_int64(pack_data.get_write_pointer(8), int64_value);
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
unsigned int int_value = (unsigned int)floor(real_value + 0.5);
|
|
_uint_range.validate(int_value, range_error);
|
|
validate_uint_limits(int_value, 8, range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
unsigned int int_value = (unsigned int)floor(real_value + 0.5);
|
|
_uint_range.validate(int_value, range_error);
|
|
validate_uint_limits(int_value, 16, range_error);
|
|
do_pack_uint16(pack_data.get_write_pointer(2), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
unsigned int int_value = (unsigned int)floor(real_value + 0.5);
|
|
_uint_range.validate(int_value, range_error);
|
|
do_pack_uint32(pack_data.get_write_pointer(4), int_value);
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
PN_uint64 int64_value = (PN_uint64)floor(real_value + 0.5);
|
|
_uint64_range.validate(int64_value, range_error);
|
|
do_pack_uint64(pack_data.get_write_pointer(8), int64_value);
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.validate(real_value, range_error);
|
|
do_pack_float64(pack_data.get_write_pointer(8), real_value);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_int
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_int(DCPackData &pack_data, int value,
|
|
bool &pack_error, bool &range_error) const {
|
|
int int_value = value * _divisor;
|
|
|
|
if (value != 0 && (int_value / value) != (int)_divisor) {
|
|
// If we've experienced overflow after applying the divisor, pack
|
|
// it as an int64 instead.
|
|
pack_int64(pack_data, (PN_int64)value, pack_error, range_error);
|
|
return;
|
|
}
|
|
|
|
if (_has_modulus && _uint_modulus != 0) {
|
|
if (int_value < 0) {
|
|
int_value = _uint_modulus - 1 - (-int_value - 1) % _uint_modulus;
|
|
} else {
|
|
int_value = int_value % _uint_modulus;
|
|
}
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
_int_range.validate(int_value, range_error);
|
|
validate_int_limits(int_value, 8, range_error);
|
|
do_pack_int8(pack_data.get_write_pointer(1), int_value);
|
|
break;
|
|
|
|
case ST_int16:
|
|
_int_range.validate(int_value, range_error);
|
|
validate_int_limits(int_value, 16, range_error);
|
|
do_pack_int16(pack_data.get_write_pointer(2), int_value);
|
|
break;
|
|
|
|
case ST_int32:
|
|
_int_range.validate(int_value, range_error);
|
|
do_pack_int32(pack_data.get_write_pointer(4), int_value);
|
|
break;
|
|
|
|
case ST_int64:
|
|
_int64_range.validate(int_value, range_error);
|
|
do_pack_int64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
validate_uint_limits((unsigned int)int_value, 8, range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint16:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
validate_uint_limits((unsigned int)int_value, 16, range_error);
|
|
do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint32:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint64:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint64_range.validate((unsigned int)int_value, range_error);
|
|
do_pack_uint64(pack_data.get_write_pointer(8), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.validate(int_value, range_error);
|
|
do_pack_float64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_uint
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_uint(DCPackData &pack_data, unsigned int value,
|
|
bool &pack_error, bool &range_error) const {
|
|
unsigned int int_value = value * _divisor;
|
|
if (_has_modulus && _uint_modulus != 0) {
|
|
int_value = int_value % _uint_modulus;
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
if ((int)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)int_value, range_error);
|
|
validate_int_limits((int)int_value, 8, range_error);
|
|
do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
|
|
break;
|
|
|
|
case ST_int16:
|
|
if ((int)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)int_value, range_error);
|
|
validate_int_limits((int)int_value, 16, range_error);
|
|
do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
|
|
break;
|
|
|
|
case ST_int32:
|
|
if ((int)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)int_value, range_error);
|
|
do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
|
|
break;
|
|
|
|
case ST_int64:
|
|
if ((int)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int64_range.validate((int)int_value, range_error);
|
|
do_pack_int64(pack_data.get_write_pointer(8), (int)int_value);
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
_uint_range.validate(int_value, range_error);
|
|
validate_uint_limits(int_value, 8, range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), int_value);
|
|
break;
|
|
|
|
case ST_uint16:
|
|
_uint_range.validate(int_value, range_error);
|
|
validate_uint_limits(int_value, 16, range_error);
|
|
do_pack_uint16(pack_data.get_write_pointer(2), int_value);
|
|
break;
|
|
|
|
case ST_uint32:
|
|
_uint_range.validate(int_value, range_error);
|
|
do_pack_uint32(pack_data.get_write_pointer(4), int_value);
|
|
break;
|
|
|
|
case ST_uint64:
|
|
_uint64_range.validate(int_value, range_error);
|
|
do_pack_uint64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.validate(int_value, range_error);
|
|
do_pack_float64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_int64
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_int64(DCPackData &pack_data, PN_int64 value,
|
|
bool &pack_error, bool &range_error) const {
|
|
PN_int64 int_value = value * _divisor;
|
|
if (_has_modulus && _uint64_modulus != 0) {
|
|
if (int_value < 0) {
|
|
int_value = _uint64_modulus - 1 - (-int_value - 1) % _uint64_modulus;
|
|
} else {
|
|
int_value = int_value % _uint64_modulus;
|
|
}
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
_int_range.validate((int)int_value, range_error);
|
|
validate_int64_limits(int_value, 8, range_error);
|
|
do_pack_int8(pack_data.get_write_pointer(1), (int)int_value);
|
|
break;
|
|
|
|
case ST_int16:
|
|
_int_range.validate((int)int_value, range_error);
|
|
validate_int64_limits(int_value, 16, range_error);
|
|
do_pack_int16(pack_data.get_write_pointer(2), (int)int_value);
|
|
break;
|
|
|
|
case ST_int32:
|
|
_int_range.validate((int)int_value, range_error);
|
|
validate_int64_limits(int_value, 32, range_error);
|
|
do_pack_int32(pack_data.get_write_pointer(4), (int)int_value);
|
|
break;
|
|
|
|
case ST_int64:
|
|
_int64_range.validate(int_value, range_error);
|
|
do_pack_int64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)(PN_uint64)int_value, range_error);
|
|
validate_uint64_limits((PN_uint64)int_value, 8, range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)(PN_uint64)int_value);
|
|
break;
|
|
|
|
case ST_uint16:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)(PN_uint64)int_value, range_error);
|
|
validate_uint64_limits((PN_uint64)int_value, 16, range_error);
|
|
do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)(PN_uint64)int_value);
|
|
break;
|
|
|
|
case ST_uint32:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)(PN_uint64)int_value, range_error);
|
|
validate_uint64_limits((PN_uint64)int_value, 32, range_error);
|
|
do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)(PN_uint64)int_value);
|
|
break;
|
|
|
|
case ST_uint64:
|
|
if (int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_uint64_range.validate((PN_uint64)int_value, range_error);
|
|
do_pack_uint64(pack_data.get_write_pointer(8), (PN_uint64)int_value);
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.validate((double)int_value, range_error);
|
|
do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_uint64
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_uint64(DCPackData &pack_data, PN_uint64 value,
|
|
bool &pack_error, bool &range_error) const {
|
|
PN_uint64 int_value = value * _divisor;
|
|
if (_has_modulus && _uint64_modulus != 0) {
|
|
int_value = int_value % _uint64_modulus;
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
if ((PN_int64)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)(PN_int64)int_value, range_error);
|
|
validate_int64_limits((PN_int64)int_value, 8, range_error);
|
|
do_pack_int8(pack_data.get_write_pointer(1), (int)(PN_int64)int_value);
|
|
break;
|
|
|
|
case ST_int16:
|
|
if ((PN_int64)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)(PN_int64)int_value, range_error);
|
|
validate_int64_limits((PN_int64)int_value, 16, range_error);
|
|
do_pack_int16(pack_data.get_write_pointer(2), (int)(PN_int64)int_value);
|
|
break;
|
|
|
|
case ST_int32:
|
|
if ((PN_int64)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int_range.validate((int)(PN_int64)int_value, range_error);
|
|
validate_int64_limits((PN_int64)int_value, 32, range_error);
|
|
do_pack_int32(pack_data.get_write_pointer(4), (int)(PN_int64)int_value);
|
|
break;
|
|
|
|
case ST_int64:
|
|
if ((PN_int64)int_value < 0) {
|
|
range_error = true;
|
|
}
|
|
_int64_range.validate((PN_int64)int_value, range_error);
|
|
do_pack_int64(pack_data.get_write_pointer(8), (PN_int64)int_value);
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
validate_uint64_limits(int_value, 8, range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint16:
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
validate_uint64_limits(int_value, 16, range_error);
|
|
do_pack_uint16(pack_data.get_write_pointer(2), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint32:
|
|
_uint_range.validate((unsigned int)int_value, range_error);
|
|
validate_uint64_limits(int_value, 32, range_error);
|
|
do_pack_uint32(pack_data.get_write_pointer(4), (unsigned int)int_value);
|
|
break;
|
|
|
|
case ST_uint64:
|
|
_uint64_range.validate(int_value, range_error);
|
|
do_pack_uint64(pack_data.get_write_pointer(8), int_value);
|
|
break;
|
|
|
|
case ST_float64:
|
|
_double_range.validate((double)int_value, range_error);
|
|
do_pack_float64(pack_data.get_write_pointer(8), (double)int_value);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_string
|
|
// Access: Published, Virtual
|
|
// Description: Packs the indicated numeric or string value into the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
pack_string(DCPackData &pack_data, const string &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
size_t string_length = value.length();
|
|
|
|
switch (_type) {
|
|
case ST_char:
|
|
case ST_uint8:
|
|
case ST_int8:
|
|
if (string_length == 0) {
|
|
pack_error = true;
|
|
} else {
|
|
if (string_length != 1) {
|
|
range_error = true;
|
|
}
|
|
_uint_range.validate((unsigned int)value[0], range_error);
|
|
do_pack_uint8(pack_data.get_write_pointer(1), (unsigned int)value[0]);
|
|
}
|
|
break;
|
|
|
|
case ST_string:
|
|
case ST_blob:
|
|
_uint_range.validate(string_length, range_error);
|
|
validate_uint_limits(string_length, 16, range_error);
|
|
if (_num_length_bytes != 0) {
|
|
do_pack_uint16(pack_data.get_write_pointer(2), string_length);
|
|
}
|
|
pack_data.append_data(value.data(), string_length);
|
|
break;
|
|
|
|
case ST_blob32:
|
|
_uint_range.validate(string_length, range_error);
|
|
if (_num_length_bytes != 0) {
|
|
do_pack_uint32(pack_data.get_write_pointer(4), string_length);
|
|
}
|
|
pack_data.append_data(value.data(), string_length);
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::pack_default_value
|
|
// Access: Public, Virtual
|
|
// Description: Packs the simpleParameter's specified default value (or a
|
|
// sensible default if no value is specified) into the
|
|
// stream. Returns true if the default value is packed,
|
|
// false if the simpleParameter doesn't know how to pack its
|
|
// default value.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
pack_default_value(DCPackData &pack_data, bool &pack_error) const {
|
|
if (has_default_value()) {
|
|
return DCField::pack_default_value(pack_data, pack_error);
|
|
}
|
|
|
|
if (_has_nested_fields) {
|
|
// If the simple type is an array (or string) type, pack the
|
|
// appropriate length array, with code similar to
|
|
// DCArrayParameter::pack_default_value().
|
|
|
|
unsigned int minimum_length = 0;
|
|
if (!_uint_range.is_empty()) {
|
|
minimum_length = _uint_range.get_min(0);
|
|
}
|
|
|
|
DCPacker packer;
|
|
packer.begin_pack(this);
|
|
packer.push();
|
|
for (unsigned int i = 0; i < minimum_length; i++) {
|
|
packer.pack_default_value();
|
|
}
|
|
packer.pop();
|
|
if (!packer.end_pack()) {
|
|
pack_error = true;
|
|
|
|
} else {
|
|
pack_data.append_data(packer.get_data(), packer.get_length());
|
|
}
|
|
|
|
} else {
|
|
// Otherwise, if it's just a simple numeric type, pack a zero or
|
|
// the minimum value.
|
|
switch (_type) {
|
|
case ST_int8:
|
|
case ST_int16:
|
|
case ST_int32:
|
|
if (_int_range.is_in_range(0)) {
|
|
pack_int(pack_data, 0, pack_error, pack_error);
|
|
} else {
|
|
pack_int(pack_data, _int_range.get_min(0), pack_error, pack_error);
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
if (_int64_range.is_in_range(0)) {
|
|
pack_int64(pack_data, 0, pack_error, pack_error);
|
|
} else {
|
|
pack_int64(pack_data, _int64_range.get_min(0), pack_error, pack_error);
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
case ST_uint16:
|
|
case ST_uint32:
|
|
if (_uint_range.is_in_range(0)) {
|
|
pack_uint(pack_data, 0, pack_error, pack_error);
|
|
} else {
|
|
pack_uint(pack_data, _uint_range.get_min(0), pack_error, pack_error);
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
if (_uint64_range.is_in_range(0)) {
|
|
pack_uint64(pack_data, 0, pack_error, pack_error);
|
|
} else {
|
|
pack_uint64(pack_data, _uint64_range.get_min(0), pack_error, pack_error);
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
if (_double_range.is_in_range(0.0)) {
|
|
pack_double(pack_data, 0.0, pack_error, pack_error);
|
|
} else {
|
|
pack_double(pack_data, _double_range.get_min(0), pack_error, pack_error);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_double
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_double(const char *data, size_t length, size_t &p, double &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int8(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = int_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int16(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = int_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int32(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = int_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_int64 int_value = do_unpack_int64(data + p);
|
|
_int64_range.validate(int_value, range_error);
|
|
value = (double)int_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = uint_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = uint_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = uint_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_uint64 uint_value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(uint_value, range_error);
|
|
value = (double)uint_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_float64(data + p);
|
|
_double_range.validate(value, range_error);
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
|
|
if (_divisor != 1) {
|
|
value = value / _divisor;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_int
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_int(const char *data, size_t length, size_t &p, int &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
switch (_type) {
|
|
case ST_int8:
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_int8(data + p);
|
|
_int_range.validate(value, range_error);
|
|
p++;
|
|
break;
|
|
|
|
case ST_int16:
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_int16(data + p);
|
|
_int_range.validate(value, range_error);
|
|
p += 2;
|
|
break;
|
|
|
|
case ST_int32:
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_int32(data + p);
|
|
_int_range.validate(value, range_error);
|
|
p += 4;
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_int64 int_value = do_unpack_uint64(data + p);
|
|
_int64_range.validate(int_value, range_error);
|
|
value = (int)int_value;
|
|
if (value != int_value) {
|
|
// uint exceeded the storage capacity of a signed int.
|
|
pack_error = true;
|
|
}
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = uint_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (int)uint_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (int)uint_value;
|
|
if (value < 0) {
|
|
pack_error = true;
|
|
}
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_uint64 uint_value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(uint_value, range_error);
|
|
value = (int)(unsigned int)uint_value;
|
|
if ((unsigned int)value != uint_value || value < 0) {
|
|
pack_error = true;
|
|
}
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
double real_value = do_unpack_float64(data + p);
|
|
_double_range.validate(real_value, range_error);
|
|
value = (int)real_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
|
|
if (_divisor != 1) {
|
|
value = value / _divisor;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_uint
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_uint(const char *data, size_t length, size_t &p, unsigned int &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int8(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (unsigned int)int_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int16(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (unsigned int)int_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int32(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (unsigned int)int_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_int64 int_value = do_unpack_int64(data + p);
|
|
_int64_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (unsigned int)(int)int_value;
|
|
if (value != int_value) {
|
|
pack_error = true;
|
|
}
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(value, range_error);
|
|
p++;
|
|
break;
|
|
|
|
case ST_uint16:
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(value, range_error);
|
|
p += 2;
|
|
break;
|
|
|
|
case ST_uint32:
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(value, range_error);
|
|
p += 4;
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_uint64 uint_value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(uint_value, range_error);
|
|
value = (unsigned int)uint_value;
|
|
if (value != uint_value) {
|
|
pack_error = true;
|
|
}
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
double real_value = do_unpack_float64(data + p);
|
|
_double_range.validate(real_value, range_error);
|
|
value = (unsigned int)real_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
|
|
if (_divisor != 1) {
|
|
value = value / _divisor;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_int64
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_int64(const char *data, size_t length, size_t &p, PN_int64 &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int8(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = (PN_int64)int_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int16(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = (PN_int64)int_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int32(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
value = (PN_int64)int_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_int64(data + p);
|
|
_int64_range.validate(value, range_error);
|
|
p += 8;
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_int64)(int)uint_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_int64)(int)uint_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_int64)(int)uint_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_uint64 uint_value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(uint_value, range_error);
|
|
value = (PN_int64)uint_value;
|
|
if (value < 0) {
|
|
pack_error = true;
|
|
}
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
double real_value = do_unpack_float64(data + p);
|
|
_double_range.validate(real_value, range_error);
|
|
value = (PN_int64)real_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
|
|
if (_divisor != 1) {
|
|
value = value / _divisor;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_uint64
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_uint64(const char *data, size_t length, size_t &p, PN_uint64 &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int8(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (PN_uint64)(unsigned int)int_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int16(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (PN_uint64)(unsigned int)int_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
int int_value = do_unpack_int32(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (PN_uint64)(unsigned int)int_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
PN_int64 int_value = do_unpack_int64(data + p);
|
|
_int64_range.validate(int_value, range_error);
|
|
if (int_value < 0) {
|
|
pack_error = true;
|
|
}
|
|
value = (PN_uint64)int_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_uint64)uint_value;
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_uint64)uint_value;
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
value = (PN_uint64)uint_value;
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(value, range_error);
|
|
p += 8;
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
double real_value = do_unpack_float64(data + p);
|
|
_double_range.validate(real_value, range_error);
|
|
value = (PN_uint64)real_value;
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
|
|
if (_divisor != 1) {
|
|
value = value / _divisor;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_string
|
|
// Access: Public, Virtual
|
|
// Description: Unpacks the current numeric or string value from the
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
unpack_string(const char *data, size_t length, size_t &p, string &value,
|
|
bool &pack_error, bool &range_error) const {
|
|
// If the type is a single byte, unpack it into a string of length 1.
|
|
switch (_type) {
|
|
case ST_char:
|
|
case ST_int8:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
unsigned int int_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(int_value, range_error);
|
|
value.assign(1, int_value);
|
|
p++;
|
|
}
|
|
return;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
size_t string_length;
|
|
|
|
if (_num_length_bytes == 0) {
|
|
string_length = _fixed_byte_size;
|
|
|
|
} else {
|
|
switch (_type) {
|
|
case ST_string:
|
|
case ST_blob:
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
string_length = do_unpack_uint16(data + p);
|
|
p += 2;
|
|
break;
|
|
|
|
case ST_blob32:
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
string_length = do_unpack_uint32(data + p);
|
|
p += 4;
|
|
break;
|
|
|
|
default:
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
_uint_range.validate(string_length, range_error);
|
|
|
|
if (p + string_length > length) {
|
|
pack_error = true;
|
|
return;
|
|
}
|
|
value.assign(data + p, string_length);
|
|
p += string_length;
|
|
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_validate
|
|
// Access: Public, Virtual
|
|
// Description: Internally unpacks the current numeric or string
|
|
// value and validates it against the type range limits,
|
|
// but does not return the value. Returns true on
|
|
// success, false on failure (e.g. we don't know how to
|
|
// validate this field).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
unpack_validate(const char *data, size_t length, size_t &p,
|
|
bool &pack_error, bool &range_error) const {
|
|
if (!_has_range_limits) {
|
|
return unpack_skip(data, length, p, pack_error);
|
|
}
|
|
switch (_type) {
|
|
case ST_int8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
int int_value = do_unpack_int8(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_int16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
int int_value = do_unpack_int16(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_int32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
int int_value = do_unpack_int32(data + p);
|
|
_int_range.validate(int_value, range_error);
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
PN_int64 int_value = do_unpack_int64(data + p);
|
|
_int64_range.validate(int_value, range_error);
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
case ST_uint8:
|
|
{
|
|
if (p + 1 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint8(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
p++;
|
|
}
|
|
break;
|
|
|
|
case ST_uint16:
|
|
{
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint16(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
p += 2;
|
|
}
|
|
break;
|
|
|
|
case ST_uint32:
|
|
{
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
unsigned int uint_value = do_unpack_uint32(data + p);
|
|
_uint_range.validate(uint_value, range_error);
|
|
p += 4;
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
PN_uint64 uint_value = do_unpack_uint64(data + p);
|
|
_uint64_range.validate(uint_value, range_error);
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
{
|
|
if (p + 8 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
double real_value = do_unpack_float64(data + p);
|
|
_double_range.validate(real_value, range_error);
|
|
p += 8;
|
|
}
|
|
break;
|
|
|
|
case ST_string:
|
|
case ST_blob:
|
|
if (_num_length_bytes == 0) {
|
|
p += _fixed_byte_size;
|
|
|
|
} else {
|
|
if (p + 2 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
size_t string_length = do_unpack_uint16(data + p);
|
|
_uint_range.validate(string_length, range_error);
|
|
p += 2 + string_length;
|
|
}
|
|
break;
|
|
|
|
case ST_blob32:
|
|
if (_num_length_bytes == 0) {
|
|
p += _fixed_byte_size;
|
|
|
|
} else {
|
|
if (p + 4 > length) {
|
|
pack_error = true;
|
|
return true;
|
|
}
|
|
size_t string_length = do_unpack_uint32(data + p);
|
|
_uint_range.validate(string_length, range_error);
|
|
p += 4 + string_length;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::unpack_skip
|
|
// Access: Public, Virtual
|
|
// Description: Increments p to the end of the current field without
|
|
// actually unpacking any data or performing any range
|
|
// validation. Returns true on success, false on
|
|
// failure (e.g. we don't know how to skip this field).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
unpack_skip(const char *data, size_t length, size_t &p,
|
|
bool &pack_error) const {
|
|
size_t string_length;
|
|
|
|
switch (_type) {
|
|
case ST_char:
|
|
case ST_int8:
|
|
case ST_uint8:
|
|
p++;
|
|
break;
|
|
|
|
case ST_int16:
|
|
case ST_uint16:
|
|
p += 2;
|
|
break;
|
|
|
|
case ST_int32:
|
|
case ST_uint32:
|
|
p += 4;
|
|
break;
|
|
|
|
case ST_int64:
|
|
case ST_uint64:
|
|
case ST_float64:
|
|
p += 8;
|
|
break;
|
|
|
|
case ST_string:
|
|
case ST_blob:
|
|
if (_num_length_bytes == 0) {
|
|
p += _fixed_byte_size;
|
|
|
|
} else {
|
|
if (p + 2 > length) {
|
|
return false;
|
|
}
|
|
string_length = do_unpack_uint16(data + p);
|
|
p += 2 + string_length;
|
|
}
|
|
break;
|
|
|
|
case ST_blob32:
|
|
if (_num_length_bytes == 0) {
|
|
p += _fixed_byte_size;
|
|
|
|
} else {
|
|
if (p + 4 > length) {
|
|
return false;
|
|
}
|
|
string_length = do_unpack_uint32(data + p);
|
|
p += 4 + string_length;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if (p > length) {
|
|
pack_error = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::output_instance
|
|
// Access: Public, Virtual
|
|
// Description: Formats the parameter in the C++-like dc syntax as a
|
|
// typename and identifier.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
output_instance(ostream &out, bool brief, const string &prename,
|
|
const string &name, const string &postname) const {
|
|
if (get_typedef() != (DCTypedef *)NULL) {
|
|
output_typedef_name(out, brief, prename, name, postname);
|
|
|
|
} else {
|
|
out << _type;
|
|
if (_has_modulus) {
|
|
out << "%" << _orig_modulus;
|
|
}
|
|
if (_divisor != 1) {
|
|
out << "/" << _divisor;
|
|
}
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
case ST_int16:
|
|
case ST_int32:
|
|
if (!_int_range.is_empty()) {
|
|
out << "(";
|
|
_int_range.output(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
case ST_int64:
|
|
if (!_int64_range.is_empty()) {
|
|
out << "(";
|
|
_int64_range.output(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
case ST_uint8:
|
|
case ST_uint16:
|
|
case ST_uint32:
|
|
if (!_uint_range.is_empty()) {
|
|
out << "(";
|
|
_uint_range.output(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
case ST_char:
|
|
if (!_uint_range.is_empty()) {
|
|
out << "(";
|
|
_uint_range.output_char(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
case ST_uint64:
|
|
if (!_uint64_range.is_empty()) {
|
|
out << "(";
|
|
_uint64_range.output(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
case ST_float64:
|
|
if (!_double_range.is_empty()) {
|
|
out << "(";
|
|
_double_range.output(out, _divisor);
|
|
out << ")";
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!prename.empty() || !name.empty() || !postname.empty()) {
|
|
out << " " << prename << name << postname;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::generate_hash
|
|
// Access: Public, Virtual
|
|
// Description: Accumulates the properties of this type into the
|
|
// hash.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCSimpleParameter::
|
|
generate_hash(HashGenerator &hashgen) const {
|
|
DCParameter::generate_hash(hashgen);
|
|
|
|
hashgen.add_int(_type);
|
|
hashgen.add_int(_divisor);
|
|
if (_has_modulus) {
|
|
hashgen.add_int((int)_double_modulus);
|
|
}
|
|
|
|
_int_range.generate_hash(hashgen);
|
|
_int64_range.generate_hash(hashgen);
|
|
_uint_range.generate_hash(hashgen);
|
|
_uint64_range.generate_hash(hashgen);
|
|
_double_range.generate_hash(hashgen);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::do_check_match
|
|
// Access: Protected, Virtual
|
|
// Description: Returns true if the other interface is bitwise the
|
|
// same as this one--that is, a uint32 only matches a
|
|
// uint32, etc. Names of components, and range limits,
|
|
// are not compared.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
do_check_match(const DCPackerInterface *other) const {
|
|
return other->do_check_match_simple_parameter(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::do_check_match_simple_parameter
|
|
// Access: Protected, Virtual
|
|
// Description: Returns true if this field matches the indicated
|
|
// simple parameter, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
do_check_match_simple_parameter(const DCSimpleParameter *other) const {
|
|
if (_divisor != other->_divisor) {
|
|
return false;
|
|
}
|
|
|
|
if (_type == other->_type) {
|
|
return true;
|
|
}
|
|
|
|
// Check for certain types that are considered equivalent to each
|
|
// other.
|
|
switch (_type) {
|
|
case ST_uint8:
|
|
case ST_char:
|
|
switch (other->_type) {
|
|
case ST_uint8:
|
|
case ST_char:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
case ST_string:
|
|
case ST_blob:
|
|
case ST_uint8array:
|
|
switch (other->_type) {
|
|
case ST_string:
|
|
case ST_blob:
|
|
case ST_uint8array:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::do_check_match_array_parameter
|
|
// Access: Protected, Virtual
|
|
// Description: Returns true if this field matches the indicated
|
|
// array parameter, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCSimpleParameter::
|
|
do_check_match_array_parameter(const DCArrayParameter *other) const {
|
|
if (other->get_array_size() != -1) {
|
|
// We cannot match a fixed-size array.
|
|
return false;
|
|
}
|
|
if (_nested_field == NULL) {
|
|
// Only an array-style simple parameter can match a DCArrayParameter.
|
|
return false;
|
|
}
|
|
|
|
return _nested_field->check_match(other->get_element_type());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::create_nested_field
|
|
// Access: Private, Static
|
|
// Description: Creates the one instance of the DCSimpleParameter
|
|
// corresponding to this combination of type and divisor
|
|
// if it is not already created.
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSimpleParameter *DCSimpleParameter::
|
|
create_nested_field(DCSubatomicType type, unsigned int divisor) {
|
|
DivisorMap &divisor_map = _nested_field_map[type];
|
|
DivisorMap::iterator di;
|
|
di = divisor_map.find(divisor);
|
|
if (di != divisor_map.end()) {
|
|
return (*di).second;
|
|
}
|
|
|
|
DCSimpleParameter *nested_field = new DCSimpleParameter(type, divisor);
|
|
divisor_map[divisor] = nested_field;
|
|
return nested_field;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCSimpleParameter::create_uint32uint8_type
|
|
// Access: Private, Static
|
|
// Description: Creates the one instance of the Uint32Uint8Type
|
|
// object if it is not already created.
|
|
////////////////////////////////////////////////////////////////////
|
|
DCPackerInterface *DCSimpleParameter::
|
|
create_uint32uint8_type() {
|
|
if (_uint32uint8_type == NULL) {
|
|
DCClass *dclass = new DCClass(NULL, "", true, false);
|
|
dclass->add_field(new DCSimpleParameter(ST_uint32));
|
|
dclass->add_field(new DCSimpleParameter(ST_uint8));
|
|
_uint32uint8_type = new DCClassParameter(dclass);
|
|
}
|
|
return _uint32uint8_type;
|
|
}
|