Panda3D
dcArrayParameter.cxx
1 // Filename: dcArrayParameter.cxx
2 // Created by: drose (17Jun04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "dcArrayParameter.h"
16 #include "dcSimpleParameter.h"
17 #include "dcClassParameter.h"
18 #include "hashGenerator.h"
19 
20 ////////////////////////////////////////////////////////////////////
21 // Function: DCArrayParameter::Constructor
22 // Access: Public
23 // Description:
24 ////////////////////////////////////////////////////////////////////
25 DCArrayParameter::
26 DCArrayParameter(DCParameter *element_type, const DCUnsignedIntRange &size) :
27  _element_type(element_type),
28  _array_size_range(size)
29 {
30  set_name(_element_type->get_name());
31  _element_type->set_name(string());
32 
33  _array_size = -1;
34  if (_array_size_range.has_one_value()) {
35  _array_size = _array_size_range.get_one_value();
36  } else {
37  _has_range_limits = true;
38  }
39 
40  if (_array_size >= 0 && _element_type->has_fixed_byte_size()) {
41  _has_fixed_byte_size = true;
42  _fixed_byte_size = _array_size * _element_type->get_fixed_byte_size();
43  _has_fixed_structure = true;
44 
45  } else {
46  // We only need to store the length bytes if the array has a
47  // variable size.
48  _num_length_bytes = 2;
49  }
50 
51  if (_element_type->has_range_limits()) {
52  _has_range_limits = true;
53  }
54 
55  if (_element_type->has_default_value()) {
56  _has_default_value = true;
57  }
58 
59  _has_nested_fields = true;
60  _num_nested_fields = _array_size;
61  _pack_type = PT_array;
62 
63  DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
64  if (simple_type != (DCSimpleParameter *)NULL) {
65  if (simple_type->get_type() == ST_char) {
66  // We make a special case for char[] arrays: these we format as
67  // a string. (It will still accept an array of ints packed into
68  // it.) We don't make this special case for uint8[] or int8[]
69  // arrays, although we will accept a string packed in for them.
70  _pack_type = PT_string;
71  }
72  }
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: DCArrayParameter::Copy Constructor
77 // Access: Public
78 // Description:
79 ////////////////////////////////////////////////////////////////////
80 DCArrayParameter::
81 DCArrayParameter(const DCArrayParameter &copy) :
82  DCParameter(copy),
83  _element_type(copy._element_type->make_copy()),
84  _array_size(copy._array_size),
85  _array_size_range(copy._array_size_range)
86 {
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: DCArrayParameter::Destructor
91 // Access: Public, Virtual
92 // Description:
93 ////////////////////////////////////////////////////////////////////
94 DCArrayParameter::
95 ~DCArrayParameter() {
96  delete _element_type;
97 }
98 
99 ////////////////////////////////////////////////////////////////////
100 // Function: DCArrayParameter::as_array_parameter
101 // Access: Published, Virtual
102 // Description:
103 ////////////////////////////////////////////////////////////////////
104 DCArrayParameter *DCArrayParameter::
105 as_array_parameter() {
106  return this;
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: DCArrayParameter::as_array_parameter
111 // Access: Published, Virtual
112 // Description:
113 ////////////////////////////////////////////////////////////////////
114 const DCArrayParameter *DCArrayParameter::
115 as_array_parameter() const {
116  return this;
117 }
118 
119 ////////////////////////////////////////////////////////////////////
120 // Function: DCArrayParameter::make_copy
121 // Access: Published, Virtual
122 // Description:
123 ////////////////////////////////////////////////////////////////////
124 DCParameter *DCArrayParameter::
125 make_copy() const {
126  return new DCArrayParameter(*this);
127 }
128 
129 ////////////////////////////////////////////////////////////////////
130 // Function: DCArrayParameter::is_valid
131 // Access: Published, Virtual
132 // Description: Returns false if the type is an invalid type
133 // (e.g. declared from an undefined typedef), true if
134 // it is valid.
135 ////////////////////////////////////////////////////////////////////
137 is_valid() const {
138  return _element_type->is_valid();
139 }
140 
141 ////////////////////////////////////////////////////////////////////
142 // Function: DCArrayParameter::get_element_type
143 // Access: Published
144 // Description: Returns the type of the individual elements of this
145 // array.
146 ////////////////////////////////////////////////////////////////////
149  return _element_type;
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: DCArrayParameter::get_array_size
154 // Access: Published
155 // Description: Returns the fixed number of elements in this array,
156 // or -1 if the array may contain a variable number of
157 // elements.
158 ////////////////////////////////////////////////////////////////////
160 get_array_size() const {
161  return _array_size;
162 }
163 
164 ////////////////////////////////////////////////////////////////////
165 // Function: DCArrayParameter::append_array_specification
166 // Access: Public, Virtual
167 // Description: Returns the type represented by this_type[size].
168 //
169 // In the case of a DCArrayParameter, this means it
170 // modifies the current type to append the array
171 // specification on the innermost type, and returns this
172 // same pointer again.
173 ////////////////////////////////////////////////////////////////////
176  if (get_typedef() != (DCTypedef *)NULL) {
177  // If this was a typedef, wrap it directly.
178  return new DCArrayParameter(this, size);
179  }
180 
181  // Otherwise, the brackets get applied to the inner type.
182  _element_type = _element_type->append_array_specification(size);
183  return this;
184 }
185 
186 ////////////////////////////////////////////////////////////////////
187 // Function: DCArrayParameter::calc_num_nested_fields
188 // Access: Public, Virtual
189 // Description: This flavor of get_num_nested_fields is used during
190 // unpacking. It returns the number of nested fields to
191 // expect, given a certain length in bytes (as read from
192 // the get_num_length_bytes() stored in the stream on the
193 // pack). This will only be called if
194 // get_num_length_bytes() returns nonzero.
195 ////////////////////////////////////////////////////////////////////
197 calc_num_nested_fields(size_t length_bytes) const {
198  if (_element_type->has_fixed_byte_size()) {
199  return length_bytes / _element_type->get_fixed_byte_size();
200  }
201  return -1;
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: DCArrayParameter::get_nested_field
206 // Access: Public, Virtual
207 // Description: Returns the DCPackerInterface object that represents
208 // the nth nested field. This may return NULL if there
209 // is no such field (but it shouldn't do this if n is in
210 // the range 0 <= n < get_num_nested_fields()).
211 ////////////////////////////////////////////////////////////////////
213 get_nested_field(int) const {
214  return _element_type;
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: DCArrayParameter::validate_num_nested_fields
219 // Access: Public, Virtual
220 // Description: After a number of fields have been packed via push()
221 // .. pack_*() .. pop(), this is called to confirm that
222 // the number of nested fields that were added is valid
223 // for this type. This is primarily useful for array
224 // types with dynamic ranges that can't validate the
225 // number of fields any other way.
226 ////////////////////////////////////////////////////////////////////
228 validate_num_nested_fields(int num_nested_fields) const {
229  bool range_error = false;
230  _array_size_range.validate(num_nested_fields, range_error);
231 
232  return !range_error;
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: DCArrayParameter::output_instance
237 // Access: Public, Virtual
238 // Description: Formats the parameter in the C++-like dc syntax as a
239 // typename and identifier.
240 ////////////////////////////////////////////////////////////////////
242 output_instance(ostream &out, bool brief, const string &prename,
243  const string &name, const string &postname) const {
244  if (get_typedef() != (DCTypedef *)NULL) {
245  output_typedef_name(out, brief, prename, name, postname);
246 
247  } else {
248  ostringstream strm;
249 
250  strm << "[";
251  _array_size_range.output(strm);
252  strm << "]";
253 
254  _element_type->output_instance(out, brief, prename, name,
255  postname + strm.str());
256  }
257 }
258 
259 ////////////////////////////////////////////////////////////////////
260 // Function: DCArrayParameter::generate_hash
261 // Access: Public, Virtual
262 // Description: Accumulates the properties of this type into the
263 // hash.
264 ////////////////////////////////////////////////////////////////////
266 generate_hash(HashGenerator &hashgen) const {
268  _element_type->generate_hash(hashgen);
269  _array_size_range.generate_hash(hashgen);
270 }
271 
272 ////////////////////////////////////////////////////////////////////
273 // Function: DCArrayParameter::pack_string
274 // Access: Published, Virtual
275 // Description: Packs the indicated numeric or string value into the
276 // stream.
277 ////////////////////////////////////////////////////////////////////
279 pack_string(DCPackData &pack_data, const string &value,
280  bool &pack_error, bool &range_error) const {
281  // We can only pack a string if the array element type is char or
282  // int8.
283  DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
284  if (simple_type == (DCSimpleParameter *)NULL) {
285  pack_error = true;
286  return;
287  }
288 
289  size_t string_length = value.length();
290 
291  switch (simple_type->get_type()) {
292  case ST_char:
293  case ST_uint8:
294  case ST_int8:
295  _array_size_range.validate(string_length, range_error);
296  if (_num_length_bytes != 0) {
297  nassertv(_num_length_bytes == 2);
298  do_pack_uint16(pack_data.get_write_pointer(2), string_length);
299  }
300  pack_data.append_data(value.data(), string_length);
301  break;
302 
303  default:
304  pack_error = true;
305  }
306 }
307 
308 ////////////////////////////////////////////////////////////////////
309 // Function: DCArrayParameter::pack_default_value
310 // Access: Public, Virtual
311 // Description: Packs the arrayParameter's specified default value (or a
312 // sensible default if no value is specified) into the
313 // stream. Returns true if the default value is packed,
314 // false if the arrayParameter doesn't know how to pack its
315 // default value.
316 ////////////////////////////////////////////////////////////////////
318 pack_default_value(DCPackData &pack_data, bool &pack_error) const {
319  // We only want to call up if the DCField can pack the value
320  // immediately--we don't trust the DCField to generate the default
321  // value (since it doesn't know how large the minimum length array
322  // is).
323  if (_has_default_value && !_default_value_stale) {
324  return DCField::pack_default_value(pack_data, pack_error);
325  }
326 
327  // If a default value is not specified for a variable-length array,
328  // the default is the minimum array.
329  unsigned int minimum_length = 0;
330  if (!_array_size_range.is_empty()) {
331  minimum_length = _array_size_range.get_min(0);
332  }
333 
334  DCPacker packer;
335  packer.begin_pack(this);
336  packer.push();
337  for (unsigned int i = 0; i < minimum_length; i++) {
338  packer.pack_default_value();
339  }
340  packer.pop();
341  if (!packer.end_pack()) {
342  pack_error = true;
343  } else {
344  pack_data.append_data(packer.get_data(), packer.get_length());
345  }
346 
347  return true;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: DCArrayParameter::unpack_string
352 // Access: Public, Virtual
353 // Description: Unpacks the current numeric or string value from the
354 // stream.
355 ////////////////////////////////////////////////////////////////////
357 unpack_string(const char *data, size_t length, size_t &p, string &value,
358  bool &pack_error, bool &range_error) const {
359  // We can only unpack a string if the array element type is char or
360  // int8.
361  DCSimpleParameter *simple_type = _element_type->as_simple_parameter();
362  if (simple_type == (DCSimpleParameter *)NULL) {
363  pack_error = true;
364  return;
365  }
366 
367  size_t string_length;
368 
369  switch (simple_type->get_type()) {
370  case ST_char:
371  case ST_uint8:
372  case ST_int8:
373  if (_num_length_bytes != 0) {
374  string_length = do_unpack_uint16(data + p);
375  p += 2;
376  } else {
377  nassertv(_array_size >= 0);
378  string_length = _array_size;
379  }
380  if (p + string_length > length) {
381  pack_error = true;
382  return;
383  }
384  value.assign(data + p, string_length);
385  p += string_length;
386  break;
387 
388  default:
389  pack_error = true;
390  }
391 }
392 
393 ////////////////////////////////////////////////////////////////////
394 // Function: DCArrayParameter::do_check_match
395 // Access: Protected, Virtual
396 // Description: Returns true if the other interface is bitwise the
397 // same as this one--that is, a uint32 only matches a
398 // uint32, etc. Names of components, and range limits,
399 // are not compared.
400 ////////////////////////////////////////////////////////////////////
401 bool DCArrayParameter::
402 do_check_match(const DCPackerInterface *other) const {
403  return other->do_check_match_array_parameter(this);
404 }
405 
406 ////////////////////////////////////////////////////////////////////
407 // Function: DCArrayParameter::do_check_match_simple_parameter
408 // Access: Protected, Virtual
409 // Description: Returns true if this field matches the indicated
410 // simple parameter, false otherwise.
411 ////////////////////////////////////////////////////////////////////
412 bool DCArrayParameter::
413 do_check_match_simple_parameter(const DCSimpleParameter *other) const {
414  return ((const DCPackerInterface *)other)->do_check_match_array_parameter(this);
415 }
416 
417 ////////////////////////////////////////////////////////////////////
418 // Function: DCArrayParameter::do_check_match_class_parameter
419 // Access: Protected, Virtual
420 // Description: Returns true if this field matches the indicated
421 // class parameter, false otherwise.
422 ////////////////////////////////////////////////////////////////////
423 bool DCArrayParameter::
424 do_check_match_class_parameter(const DCClassParameter *other) const {
425  return ((const DCPackerInterface *)other)->do_check_match_array_parameter(this);
426 }
427 
428 ////////////////////////////////////////////////////////////////////
429 // Function: DCArrayParameter::do_check_match_array_parameter
430 // Access: Protected, Virtual
431 // Description: Returns true if this field matches the indicated
432 // array parameter, false otherwise.
433 ////////////////////////////////////////////////////////////////////
434 bool DCArrayParameter::
435 do_check_match_array_parameter(const DCArrayParameter *other) const {
436  if (_array_size != other->_array_size) {
437  return false;
438  }
439  return _element_type->check_match(other->_element_type);
440 }
char * get_write_pointer(size_t size)
Adds the indicated number of bytes to the end of the data without initializing them, and returns a pointer to the beginning of the new data.
Definition: dcPackData.I:70
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
This represents a single typedef declaration in the dc file.
Definition: dcTypedef.h:29
This is a block of data that receives the results of DCPacker.
Definition: dcPackData.h:25
void output_typedef_name(ostream &out, bool brief, const string &prename, const string &name, const string &postname) const
Formats the instance like output_instance, but uses the typedef name instead.
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:57
virtual bool is_valid() const
Returns false if the type is an invalid type (e.g.
virtual bool do_check_match_array_parameter(const DCArrayParameter *other) const
Returns true if this field matches the indicated array parameter, false otherwise.
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
int get_array_size() const
Returns the fixed number of elements in this array, or -1 if the array may contain a variable number ...
This represents a class (or struct) object used as a parameter itself.
This is the most fundamental kind of parameter type: a single number or string, one of the DCSubatomi...
void validate(Number num, bool &range_error) const
Convenience function to validate the indicated number.
virtual void output_instance(ostream &out, bool brief, const string &prename, const string &name, const string &postname) const
Formats the parameter in the C++-like dc syntax as a typename and identifier.
const string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the field&#39;s specified default value (or a sensible default if no value is specified) into the s...
Definition: dcField.cxx:552
bool has_fixed_byte_size() const
Returns true if this field type always packs to the same number of bytes, false if it is variable...
bool has_one_value() const
Returns true if the numeric range specifies exactly one legal value, false if multiple values are leg...
DCSubatomicType get_type() const
Returns the particular subatomic type represented by this instance.
virtual DCParameter * append_array_specification(const DCUnsignedIntRange &size)
Returns the type represented by this_type[size].
virtual void pack_string(DCPackData &pack_data, const string &value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:652
virtual void unpack_string(const char *data, size_t length, size_t &p, string &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
size_t get_fixed_byte_size() const
If has_fixed_byte_size() returns true, this returns the number of bytes this field type will use...
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
bool has_range_limits() const
Returns true if this field, or any sub-field of this field, has a limit imposed in the DC file on its...
Represents the type specification for a single parameter within a field specification.
Definition: dcParameter.h:39
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:597
virtual DCParameter * append_array_specification(const DCUnsignedIntRange &size)
Returns the type represented by this_type[size].
This represents an array of some other kind of object, meaning this parameter type accepts an arbitra...
bool check_match(const DCPackerInterface *other) const
Returns true if the other interface is bitwise the same as this one–that is, a uint32 only matches a...
Number get_one_value() const
If has_one_value() returns true, this returns the one legal value accepted by the numeric range...
void push()
Marks the beginning of a nested series of fields.
Definition: dcPacker.cxx:448
Number get_min(int n) const
Returns the minimum value defined by the nth component.
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise...
Definition: dcField.I:46
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:717
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:26
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the arrayParameter&#39;s specified default value (or a sensible default if no value is specified) i...
bool is_empty() const
Returns true if the range contains no elements (and thus allows all numbers), false if it contains at...
virtual bool validate_num_nested_fields(int num_nested_fields) const
After a number of fields have been packed via push()
const DCTypedef * get_typedef() const
If this type has been referenced from a typedef, returns the DCTypedef instance, or NULL if the type ...
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:76
This class can be used for packing a series of numeric and string data into a binary stream...
Definition: dcPacker.h:38
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
virtual void set_name(const string &name)
Sets the name of this field.
Definition: dcField.cxx:570
DCParameter * get_element_type() const
Returns the type of the individual elements of this array.
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:103
void pop()
Marks the end of a nested series of fields.
Definition: dcPacker.cxx:537
This defines the internal interface for packing values into a DCField.