Panda3D
Loading...
Searching...
No Matches
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
19using std::string;
20
21/**
22 *
23 */
24DCArrayParameter::
25DCArrayParameter(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 */
77DCArrayParameter::
78DCArrayParameter(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 */
89DCArrayParameter::
90~DCArrayParameter() {
91 delete _element_type;
92}
93
94/**
95 *
96 */
97DCArrayParameter *DCArrayParameter::
98as_array_parameter() {
99 return this;
100}
101
102/**
103 *
104 */
105const DCArrayParameter *DCArrayParameter::
106as_array_parameter() const {
107 return this;
108}
109
110/**
111 *
112 */
113DCParameter *DCArrayParameter::
114make_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 */
123is_valid() const {
124 return _element_type->is_valid();
125}
126
127/**
128 * Returns the type of the individual elements of this array.
129 */
131get_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 */
140get_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 */
170calc_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 */
183get_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 */
194validate_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 */
206output_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 */
227generate_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 */
237pack_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 */
269pack_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 */
304pack_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 */
339unpack_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 */
378unpack_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 */
419bool DCArrayParameter::
420do_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 */
428bool DCArrayParameter::
429do_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 */
437bool DCArrayParameter::
438do_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 */
446bool DCArrayParameter::
447do_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.
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.