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