open_toontown_panda3d/direct/src/dcparser/dcSimpleParameter.cxx

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 &copy) :
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;
}