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  */
131 get_element_type() const {
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 }
This represents an array of some other kind of object, meaning this parameter type accepts an arbitra...
int get_array_size() const
Returns the fixed number of elements in this array, or -1 if the array may contain a variable number ...
virtual bool validate_num_nested_fields(int num_nested_fields) const
After a number of fields have been packed via push() .
virtual int calc_num_nested_fields(size_t length_bytes) const
This flavor of get_num_nested_fields is used during unpacking.
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...
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
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.
virtual DCParameter * append_array_specification(const DCUnsignedIntRange &size)
Returns the type represented by this_type[size].
DCParameter * get_element_type() const
Returns the type of the individual elements of this array.
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.
virtual void pack_blob(DCPackData &pack_data, const std::vector< unsigned char > &value, bool &pack_error, bool &range_error) const
Packs the indicated numeric or string value into the stream.
virtual bool is_valid() const
Returns false if the type is an invalid type (e.g.
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.
virtual void unpack_blob(const char *data, size_t length, size_t &p, std::vector< unsigned char > &value, bool &pack_error, bool &range_error) const
Unpacks the current numeric or string value from the stream.
This represents a class (or struct) object used as a parameter itself.
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
Number get_min(int n) const
Returns the minimum value defined by the nth component.
void validate(Number num, bool &range_error) const
Convenience function to validate the indicated number.
bool is_empty() const
Returns true if the range contains no elements (and thus allows all numbers), false if it contains at...
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
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
This defines the internal interface for packing values into a DCField.
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.
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 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 ...
virtual bool do_check_match_array_parameter(const DCArrayParameter *other) const
Returns true if this field matches the indicated array parameter, false otherwise.
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
void push()
Marks the beginning of a nested series of fields.
Definition: dcPacker.cxx:411
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
void pop()
Marks the end of a nested series of fields.
Definition: dcPacker.cxx:495
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
Represents the type specification for a single parameter within a field specification.
Definition: dcParameter.h:35
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this type into the hash.
const DCTypedef * get_typedef() const
If this type has been referenced from a typedef, returns the DCTypedef instance, or NULL if the type ...
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.
virtual DCParameter * append_array_specification(const DCUnsignedIntRange &size)
Returns the type represented by this_type[size].
This is the most fundamental kind of parameter type: a single number or string, one of the DCSubatomi...
DCSubatomicType get_type() const
Returns the particular subatomic type represented by this instance.
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:23
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.