625 lines
20 KiB
C++
625 lines
20 KiB
C++
// Filename: dcAtomicField.cxx
|
|
// Created by: drose (05Oct00)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d@yahoogroups.com .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "dcAtomicField.h"
|
|
#include "hashGenerator.h"
|
|
#include "dcindent.h"
|
|
|
|
#include <math.h>
|
|
|
|
ostream &
|
|
operator << (ostream &out, const DCAtomicField::ElementType &et) {
|
|
out << et._type;
|
|
if (et._divisor != 1) {
|
|
out << " / " << et._divisor;
|
|
}
|
|
if (!et._name.empty()) {
|
|
out << " " << et._name;
|
|
}
|
|
if (et._has_default_value) {
|
|
out << " = <" << hex;
|
|
string::const_iterator si;
|
|
for (si = et._default_value.begin(); si != et._default_value.end(); ++si) {
|
|
out << setw(2) << setfill('0') << (int)(unsigned char)(*si);
|
|
}
|
|
out << dec << ">";
|
|
}
|
|
return out;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCAtomicField::ElementType::
|
|
ElementType() {
|
|
_type = ST_invalid;
|
|
_divisor = 1;
|
|
_has_default_value = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::set_default_value
|
|
// Access: Public
|
|
// Description: Stores the indicated value as the default value for
|
|
// this element.
|
|
//
|
|
// Returns true if the element type reasonably accepts a
|
|
// default value of numeric type, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
set_default_value(double num) {
|
|
switch (_type) {
|
|
// Only fields of these types accept numbers.
|
|
case ST_int8:
|
|
case ST_int16:
|
|
case ST_int32:
|
|
case ST_uint8:
|
|
case ST_uint16:
|
|
case ST_uint32:
|
|
case ST_float64:
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
string formatted;
|
|
if (!format_default_value(num, formatted)) {
|
|
return false;
|
|
}
|
|
|
|
_default_value = formatted;
|
|
_has_default_value = true;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::set_default_value
|
|
// Access: Public
|
|
// Description: Stores the indicated value as the default value for
|
|
// this element.
|
|
//
|
|
// Returns true if the element type reasonably accepts a
|
|
// default value of string type, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
set_default_value(const string &str) {
|
|
if (_type != ST_string && _type != ST_blob) {
|
|
// Only fields of type string or blob accept quoted strings.
|
|
return false;
|
|
}
|
|
|
|
_default_value = str;
|
|
_has_default_value = true;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::set_default_value_literal
|
|
// Access: Public
|
|
// Description: Explicitly sets the default value to the given
|
|
// pre-formatted string.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
set_default_value_literal(const string &str) {
|
|
_default_value = str;
|
|
_has_default_value = true;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::add_default_value
|
|
// Access: Public
|
|
// Description: Appends the indicated value as the next array element
|
|
// value for the default value for this type.
|
|
//
|
|
// Returns true if the element type reasonably accepts a
|
|
// default value of numeric type, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
add_default_value(double num) {
|
|
string formatted;
|
|
if (!format_default_value(num, formatted)) {
|
|
return false;
|
|
}
|
|
|
|
_default_value += formatted;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::add_default_value
|
|
// Access: Public
|
|
// Description: Appends the indicated value as the next array element
|
|
// value for the default value for this type.
|
|
//
|
|
// Returns true if the element type reasonably accepts a
|
|
// default value of numeric type, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
add_default_value(const string &str) {
|
|
string formatted;
|
|
if (!format_default_value(str, formatted)) {
|
|
return false;
|
|
}
|
|
|
|
_default_value += formatted;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::add_default_value_literal
|
|
// Access: Public
|
|
// Description: Appends the indicated value as the next array element
|
|
// value for the default value for this type.
|
|
//
|
|
// Returns true if the element type reasonably accepts a
|
|
// default value of numeric type, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
add_default_value_literal(const string &str) {
|
|
if (_type != ST_blob) {
|
|
// Only blobs can have literal hex strings nested within arrays.
|
|
return false;
|
|
}
|
|
|
|
_default_value += str;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::end_array
|
|
// Access: Public
|
|
// Description: Called by the parser after a number of calls to
|
|
// add_default_value(), to indicate the array has been
|
|
// completed.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
end_array() {
|
|
switch (_type) {
|
|
case ST_int8array:
|
|
case ST_int16array:
|
|
case ST_int32array:
|
|
case ST_uint8array:
|
|
case ST_uint16array:
|
|
case ST_uint32array:
|
|
case ST_blob:
|
|
// These types accept arrays.
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::format_default_value
|
|
// Access: Private
|
|
// Description: Formats the indicated default value to a sequence of
|
|
// bytes, according to the element type. Returns true
|
|
// if the element type reasonably accepts a number,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
format_default_value(double num, string &formatted) const {
|
|
double real_value = num * _divisor;
|
|
int int_value = (int)floor(real_value + 0.5);
|
|
|
|
switch (_type) {
|
|
case ST_int8:
|
|
case ST_uint8:
|
|
case ST_int8array:
|
|
case ST_uint8array:
|
|
case ST_blob:
|
|
formatted = string(1, (char)(int_value & 0xff));
|
|
break;
|
|
|
|
case ST_int16:
|
|
case ST_uint16:
|
|
case ST_int16array:
|
|
case ST_uint16array:
|
|
formatted =
|
|
string(1, (char)(int_value & 0xff)) +
|
|
string(1, (char)((int_value >> 8) & 0xff));
|
|
break;
|
|
|
|
case ST_int32:
|
|
case ST_uint32:
|
|
case ST_int32array:
|
|
case ST_uint32array:
|
|
formatted =
|
|
string(1, (char)(int_value & 0xff)) +
|
|
string(1, (char)((int_value >> 8) & 0xff)) +
|
|
string(1, (char)((int_value >> 16) & 0xff)) +
|
|
string(1, (char)((int_value >> 24) & 0xff));
|
|
break;
|
|
|
|
case ST_int64:
|
|
// We don't fully support default values for int64. The
|
|
// high-order 32 bits cannot be specified.
|
|
formatted =
|
|
string(1, (char)(int_value & 0xff)) +
|
|
string(1, (char)((int_value >> 8) & 0xff)) +
|
|
string(1, (char)((int_value >> 16) & 0xff)) +
|
|
string(1, (char)((int_value >> 24) & 0xff)) +
|
|
((int_value & 0x80000000) != 0 ? string(4, '\xff') : string(4, '\0'));
|
|
break;
|
|
|
|
case ST_uint64:
|
|
// We don't fully support default values for int64. The
|
|
// high-order 32 bits cannot be specified.
|
|
formatted =
|
|
string(1, (char)(int_value & 0xff)) +
|
|
string(1, (char)((int_value >> 8) & 0xff)) +
|
|
string(1, (char)((int_value >> 16) & 0xff)) +
|
|
string(1, (char)((int_value >> 24) & 0xff)) +
|
|
string(4, '\0');
|
|
break;
|
|
|
|
case ST_float64:
|
|
// This may not be fully portable.
|
|
formatted = string((char *)&real_value, 8);
|
|
#ifdef IS_BIG_ENDIAN
|
|
{
|
|
// Reverse the byte ordering for big-endian machines.
|
|
string str;
|
|
str.reserve(8);
|
|
|
|
int length = str.length();
|
|
for (size_t i = 0; i < 8; i++) {
|
|
str += formatted[length - 1 - i];
|
|
}
|
|
formatted = str;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case ST_string:
|
|
// It doesn't make sense to assign a numeric default value to a
|
|
// string.
|
|
return false;
|
|
|
|
case ST_invalid:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::ElementType::format_default_value
|
|
// Access: Private
|
|
// Description: Formats the indicated default value to a sequence of
|
|
// bytes, according to the element type. Returns true
|
|
// if the element type reasonably accepts a string,
|
|
// false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::ElementType::
|
|
format_default_value(const string &str, string &formatted) const {
|
|
switch (_type) {
|
|
case ST_string:
|
|
case ST_blob:
|
|
{
|
|
int length = str.length();
|
|
formatted =
|
|
string(1, (char)(length & 0xff)) +
|
|
string(1, (char)((length >> 8) & 0xff)) +
|
|
str;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// It doesn't make sense to assign a string default to a number.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::as_atomic_field
|
|
// Access: Public, Virtual
|
|
// Description: Returns the same field pointer converted to an atomic
|
|
// field pointer, if this is in fact an atomic field;
|
|
// otherwise, returns NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
DCAtomicField *DCAtomicField::
|
|
as_atomic_field() {
|
|
return this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::get_num_elements
|
|
// Access: Public
|
|
// Description: Returns the number of elements of the atomic field.
|
|
////////////////////////////////////////////////////////////////////
|
|
int DCAtomicField::
|
|
get_num_elements() const {
|
|
return _elements.size();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::get_element_type
|
|
// Access: Public
|
|
// Description: Returns the numeric type of the nth element of the
|
|
// field.
|
|
////////////////////////////////////////////////////////////////////
|
|
DCSubatomicType DCAtomicField::
|
|
get_element_type(int n) const {
|
|
nassertr(n >= 0 && n < (int)_elements.size(), ST_invalid);
|
|
return _elements[n]._type;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::get_element_name
|
|
// Access: Public
|
|
// Description: Returns the name of the nth element of the field.
|
|
// This name is strictly for documentary purposes; it
|
|
// does not generally affect operation. If a name is
|
|
// not specified, this will be the empty string.
|
|
////////////////////////////////////////////////////////////////////
|
|
string DCAtomicField::
|
|
get_element_name(int n) const {
|
|
nassertr(n >= 0 && n < (int)_elements.size(), string());
|
|
return _elements[n]._name;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::get_element_divisor
|
|
// Access: Public
|
|
// Description: Returns the divisor associated with the nth element
|
|
// of the field. This implements an implicit
|
|
// fixed-point system; floating-point values are to be
|
|
// multiplied by this value before encoding into a
|
|
// packet, and divided by this number after decoding.
|
|
////////////////////////////////////////////////////////////////////
|
|
int DCAtomicField::
|
|
get_element_divisor(int n) const {
|
|
nassertr(n >= 0 && n < (int)_elements.size(), 1);
|
|
return _elements[n]._divisor;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::get_element_default
|
|
// Access: Public
|
|
// Description: Returns the pre-formatted default value associated
|
|
// with the nth element of the field. This is only
|
|
// valid if has_element_default() returns true, in which
|
|
// case this string represents the bytes that should be
|
|
// assigned to the field as a default value.
|
|
//
|
|
// If the element is an array-type element, the returned
|
|
// value will include the two-byte length preceding the
|
|
// array data.
|
|
////////////////////////////////////////////////////////////////////
|
|
string DCAtomicField::
|
|
get_element_default(int n) const {
|
|
nassertr(has_element_default(n), string());
|
|
nassertr(n >= 0 && n < (int)_elements.size(), string());
|
|
|
|
string default_value = _elements[n]._default_value;
|
|
|
|
switch (_elements[n]._type) {
|
|
case ST_int8array:
|
|
case ST_int16array:
|
|
case ST_int32array:
|
|
case ST_uint8array:
|
|
case ST_uint16array:
|
|
case ST_uint32array:
|
|
case ST_blob:
|
|
case ST_string:
|
|
// These array types also want an implicit length.
|
|
{
|
|
int length = default_value.length();
|
|
default_value =
|
|
string(1, (char)(length & 0xff)) +
|
|
string(1, (char)((length >> 8) & 0xff)) +
|
|
default_value;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return default_value;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::has_element_default
|
|
// Access: Public
|
|
// Description: Returns true if the nth element of the field has a
|
|
// default value specified, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
has_element_default(int n) const {
|
|
nassertr(n >= 0 && n < (int)_elements.size(), false);
|
|
return _elements[n]._has_default_value;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_required
|
|
// Access: Public
|
|
// Description: Returns true if the "required" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_required() const {
|
|
return (_flags & F_required) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_broadcast
|
|
// Access: Public
|
|
// Description: Returns true if the "broadcast" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_broadcast() const {
|
|
return (_flags & F_broadcast) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_p2p
|
|
// Access: Public
|
|
// Description: Returns true if the "p2p" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_p2p() const {
|
|
return (_flags & F_p2p) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_ram
|
|
// Access: Public
|
|
// Description: Returns true if the "ram" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_ram() const {
|
|
return (_flags & F_ram) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_db
|
|
// Access: Public
|
|
// Description: Returns true if the "db" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_db() const {
|
|
return (_flags & F_db) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_clsend
|
|
// Access: Public
|
|
// Description: Returns true if the "clsend" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_clsend() const {
|
|
return (_flags & F_clsend) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_clrecv
|
|
// Access: Public
|
|
// Description: Returns true if the "clrecv" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_clrecv() const {
|
|
return (_flags & F_clrecv) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::is_ownsend
|
|
// Access: Public
|
|
// Description: Returns true if the "ownsend" flag is set for this
|
|
// field, false otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool DCAtomicField::
|
|
is_ownsend() const {
|
|
return (_flags & F_ownsend) != 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
DCAtomicField::
|
|
DCAtomicField() {
|
|
_number = 0;
|
|
_flags = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::write
|
|
// Access: Public, Virtual
|
|
// Description: Generates a parseable description of the object to
|
|
// the indicated output stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCAtomicField::
|
|
write(ostream &out, int indent_level) const {
|
|
indent(out, indent_level)
|
|
<< _name << "(";
|
|
|
|
if (!_elements.empty()) {
|
|
Elements::const_iterator ei = _elements.begin();
|
|
out << (*ei);
|
|
++ei;
|
|
while (ei != _elements.end()) {
|
|
out << ", " << (*ei);
|
|
++ei;
|
|
}
|
|
}
|
|
out << ")";
|
|
|
|
if ((_flags & F_required) != 0) {
|
|
out << " required";
|
|
}
|
|
if ((_flags & F_broadcast) != 0) {
|
|
out << " broadcast";
|
|
}
|
|
if ((_flags & F_p2p) != 0) {
|
|
out << " p2p";
|
|
}
|
|
if ((_flags & F_ram) != 0) {
|
|
out << " ram";
|
|
}
|
|
if ((_flags & F_db) != 0) {
|
|
out << " db";
|
|
}
|
|
if ((_flags & F_clsend) != 0) {
|
|
out << " clsend";
|
|
}
|
|
if ((_flags & F_clrecv) != 0) {
|
|
out << " clrecv";
|
|
}
|
|
if ((_flags & F_ownsend) != 0) {
|
|
out << " ownsend";
|
|
}
|
|
|
|
out << "; // field " << _number << "\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: DCAtomicField::generate_hash
|
|
// Access: Public, Virtual
|
|
// Description: Accumulates the properties of this field into the
|
|
// hash.
|
|
////////////////////////////////////////////////////////////////////
|
|
void DCAtomicField::
|
|
generate_hash(HashGenerator &hash) const {
|
|
DCField::generate_hash(hash);
|
|
|
|
hash.add_int(_elements.size());
|
|
Elements::const_iterator ei;
|
|
for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
|
|
const ElementType &element = (*ei);
|
|
hash.add_int(element._type);
|
|
hash.add_int(element._divisor);
|
|
}
|
|
hash.add_int(_flags);
|
|
}
|