Panda3D
xFileDataDef.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 xFileDataDef.cxx
10  * @author drose
11  * @date 2004-10-03
12  */
13 
14 #include "xFileDataDef.h"
15 #include "indent.h"
16 #include "xLexerDefs.h"
17 #include "xFileParseData.h"
18 #include "xFileDataObjectInteger.h"
19 #include "xFileDataObjectDouble.h"
20 #include "xFileDataObjectString.h"
21 #include "xFileDataNodeTemplate.h"
22 #include "xFileDataObjectArray.h"
23 #include "string_utils.h"
24 
25 TypeHandle XFileDataDef::_type_handle;
26 
27 /**
28  *
29  */
30 XFileDataDef::
31 ~XFileDataDef() {
32  clear();
33 }
34 
35 /**
36  *
37  */
38 void XFileDataDef::
39 clear() {
41  _array_def.clear();
42 }
43 
44 /**
45  * Adds an additional array dimension to the data description.
46  */
47 void XFileDataDef::
48 add_array_def(const XFileArrayDef &array_def) {
49  _array_def.push_back(array_def);
50 }
51 
52 /**
53  * Writes a suitable representation of this node to an .x file in text mode.
54  */
55 void XFileDataDef::
56 write_text(std::ostream &out, int indent_level) const {
57  indent(out, indent_level);
58 
59  if (!_array_def.empty()) {
60  out << "array ";
61  }
62 
63  switch (_type) {
64  case T_word:
65  out << "WORD";
66  break;
67 
68  case T_dword:
69  out << "DWORD";
70  break;
71 
72  case T_float:
73  out << "FLOAT";
74  break;
75 
76  case T_double:
77  out << "DOUBLE";
78  break;
79 
80  case T_char:
81  out << "CHAR";
82  break;
83 
84  case T_uchar:
85  out << "UCHAR";
86  break;
87 
88  case T_sword:
89  out << "SWORD";
90  break;
91 
92  case T_sdword:
93  out << "SDWORD";
94  break;
95 
96  case T_string:
97  out << "STRING";
98  break;
99 
100  case T_cstring:
101  out << "CSTRING";
102  break;
103 
104  case T_unicode:
105  out << "UNICODE";
106  break;
107 
108  case T_template:
109  out << _template->get_name();
110  break;
111  }
112 
113  if (has_name()) {
114  out << " " << get_name();
115  }
116 
117  ArrayDef::const_iterator ai;
118  for (ai = _array_def.begin(); ai != _array_def.end(); ++ai) {
119  (*ai).output(out);
120  }
121 
122  out << ";\n";
123 }
124 
125 /**
126  * This is called on the template that defines an object, once the data for
127  * the object has been parsed. It is responsible for identifying which
128  * component of the template owns each data element, and packing the data
129  * elements appropriately back into the object.
130  *
131  * It returns true on success, or false on an error (e.g. not enough data
132  * elements, mismatched data type).
133  */
134 bool XFileDataDef::
136  const XFileParseDataList &parse_data_list,
137  XFileDataDef::PrevData &prev_data,
138  size_t &index, size_t &sub_index) const {
139  // We'll fill this in with the data value we pack, if any.
140  PT(XFileDataObject) data_value;
141 
142  // What kind of data element are we expecting?
143  switch (_type) {
144  case T_word:
145  case T_dword:
146  case T_char:
147  case T_uchar:
148  case T_sword:
149  case T_sdword:
150  // Expected integer data.
151  data_value = unpack_value(parse_data_list, 0,
152  prev_data, index, sub_index,
153  &XFileDataDef::unpack_integer_value);
154  break;
155 
156  case T_float:
157  case T_double:
158  data_value = unpack_value(parse_data_list, 0,
159  prev_data, index, sub_index,
160  &XFileDataDef::unpack_double_value);
161  break;
162 
163  case T_string:
164  case T_cstring:
165  case T_unicode:
166  data_value = unpack_value(parse_data_list, 0,
167  prev_data, index, sub_index,
168  &XFileDataDef::unpack_string_value);
169  break;
170 
171  case T_template:
172  data_value = unpack_value(parse_data_list, 0,
173  prev_data, index, sub_index,
174  &XFileDataDef::unpack_template_value);
175  break;
176  }
177 
178  if (data_value != nullptr) {
179  object->add_element(data_value);
180  prev_data[this] = data_value;
181  }
182 
183  return XFileNode::repack_data(object, parse_data_list,
184  prev_data, index, sub_index);
185 }
186 
187 /**
188  * This is similar to repack_data(), except it is used to fill the initial
189  * values for a newly-created template object to zero.
190  */
191 bool XFileDataDef::
193  PT(XFileDataObject) data_value;
194 
195  // What kind of data element are we expecting?
196  switch (_type) {
197  case T_word:
198  case T_dword:
199  case T_char:
200  case T_uchar:
201  case T_sword:
202  case T_sdword:
203  data_value = zero_fill_value(0, &XFileDataDef::zero_fill_integer_value);
204  break;
205 
206  case T_float:
207  case T_double:
208  data_value = zero_fill_value(0, &XFileDataDef::zero_fill_double_value);
209  break;
210 
211  case T_string:
212  case T_cstring:
213  case T_unicode:
214  data_value = zero_fill_value(0, &XFileDataDef::zero_fill_string_value);
215  break;
216 
217  case T_template:
218  data_value = zero_fill_value(0, &XFileDataDef::zero_fill_template_value);
219  break;
220  }
221 
222  if (data_value != nullptr) {
223  object->add_element(data_value);
224  }
225 
226  return XFileNode::fill_zero_data(object);
227 }
228 
229 /**
230  * Returns true if the node, particularly a template node, is structurally
231  * equivalent to the other node (which must be of the same type). This checks
232  * data element types, but does not compare data element names.
233  */
234 bool XFileDataDef::
235 matches(const XFileNode *other) const {
236  if (!XFileNode::matches(other)) {
237  return false;
238  }
239 
240  const XFileDataDef *data_def = DCAST(XFileDataDef, other);
241  if (data_def->get_data_type() != get_data_type()) {
242  return false;
243  }
244 
245  if (get_data_type() == T_template &&
246  !get_template()->matches(data_def->get_template())) {
247  return false;
248  }
249 
250  if (data_def->get_num_array_defs() != get_num_array_defs()) {
251  return false;
252  }
253 
254  for (int i = 0; i < get_num_array_defs(); i++) {
255  if (!get_array_def(i).matches(data_def->get_array_def(i),
256  this, data_def)) {
257  return false;
258  }
259  }
260 
261  return true;
262 }
263 
264 
265 /**
266  * Unpacks and returns the next sequential integer value from the
267  * parse_data_list.
268  */
269 PT(XFileDataObject) XFileDataDef::
270 unpack_integer_value(const XFileParseDataList &parse_data_list,
271  const XFileDataDef::PrevData &prev_data,
272  size_t &index, size_t &sub_index) const {
273  nassertr(index < parse_data_list._list.size(), nullptr);
274  const XFileParseData &parse_data = parse_data_list._list[index];
275 
276  PT(XFileDataObject) data_value;
277 
278  if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) {
279  nassertr(sub_index < parse_data._int_list.size(), nullptr);
280  int value = parse_data._int_list[sub_index];
281  data_value = new XFileDataObjectInteger(this, value);
282 
283  sub_index++;
284  if (sub_index >= parse_data._int_list.size()) {
285  index++;
286  sub_index = 0;
287  }
288 
289  } else {
290  parse_data.yyerror("Expected integer data for " + get_name());
291  }
292 
293  return data_value;
294 }
295 
296 /**
297  * Unpacks and returns the next sequential double value from the
298  * parse_data_list.
299  */
300 PT(XFileDataObject) XFileDataDef::
301 unpack_double_value(const XFileParseDataList &parse_data_list,
302  const XFileDataDef::PrevData &prev_data,
303  size_t &index, size_t &sub_index) const {
304  nassertr(index < parse_data_list._list.size(), nullptr);
305  const XFileParseData &parse_data = parse_data_list._list[index];
306 
307  PT(XFileDataObject) data_value;
308 
309  if ((parse_data._parse_flags & XFileParseData::PF_double) != 0) {
310  nassertr(sub_index < parse_data._double_list.size(), nullptr);
311  double value = parse_data._double_list[sub_index];
312  data_value = new XFileDataObjectDouble(this, value);
313 
314  sub_index++;
315  if (sub_index >= parse_data._double_list.size()) {
316  index++;
317  sub_index = 0;
318  }
319 
320  } else if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) {
321  nassertr(sub_index < parse_data._int_list.size(), nullptr);
322  int value = parse_data._int_list[sub_index];
323  data_value = new XFileDataObjectDouble(this, value);
324 
325  sub_index++;
326  if (sub_index >= parse_data._int_list.size()) {
327  index++;
328  sub_index = 0;
329  }
330 
331  } else {
332  parse_data.yyerror("Expected floating-point data for " + get_name());
333  }
334 
335  return data_value;
336 }
337 
338 /**
339  * Unpacks and returns the next sequential string value from the
340  * parse_data_list.
341  */
342 PT(XFileDataObject) XFileDataDef::
343 unpack_string_value(const XFileParseDataList &parse_data_list,
344  const XFileDataDef::PrevData &prev_data,
345  size_t &index, size_t &sub_index) const {
346  nassertr(index < parse_data_list._list.size(), nullptr);
347  const XFileParseData &parse_data = parse_data_list._list[index];
348 
349  PT(XFileDataObject) data_value;
350 
351  if ((parse_data._parse_flags & XFileParseData::PF_string) != 0) {
352  data_value = new XFileDataObjectString(this, parse_data._string);
353  index++;
354  sub_index = 0;
355 
356  } else {
357  parse_data.yyerror("Expected string data for " + get_name());
358  }
359 
360  return data_value;
361 }
362 
363 /**
364  * Unpacks a nested template object's data.
365  */
366 PT(XFileDataObject) XFileDataDef::
367 unpack_template_value(const XFileParseDataList &parse_data_list,
368  const XFileDataDef::PrevData &prev_data,
369  size_t &index, size_t &sub_index) const {
370  PT(XFileDataNodeTemplate) data_value =
371  new XFileDataNodeTemplate(get_x_file(), get_name(), _template);
372 
373  PrevData nested_prev_data(prev_data);
374  if (!_template->repack_data(data_value, parse_data_list,
375  nested_prev_data, index, sub_index)) {
376  return nullptr;
377  }
378 
379  return data_value;
380 }
381 
382 /**
383  * Unpacks and returns the next sequential value, of the type supported by the
384  * unpack_method. If the value is an array type, unpacks all the elements of
385  * the array.
386  */
387 PT(XFileDataObject) XFileDataDef::
388 unpack_value(const XFileParseDataList &parse_data_list, int array_index,
389  const XFileDataDef::PrevData &prev_data,
390  size_t &index, size_t &sub_index,
391  XFileDataDef::UnpackMethod unpack_method) const {
392  PT(XFileDataObject) data_value;
393 
394  if (array_index == (int)_array_def.size()) {
395  if (index >= parse_data_list._list.size()) {
396  xyyerror("Not enough data elements in structure at " + get_name());
397  return nullptr;
398  }
399  data_value = (this->*unpack_method)(parse_data_list, prev_data,
400  index, sub_index);
401 
402  } else {
403  data_value = new XFileDataObjectArray(this);
404  int array_size = _array_def[array_index].get_size(prev_data);
405 
406  for (int i = 0; i < array_size; i++) {
407  if (index >= parse_data_list._list.size()) {
408  xyyerror(std::string("Expected ") + format_string(array_size)
409  + " array elements, found " + format_string(i));
410  return data_value;
411  }
412 
413  PT(XFileDataObject) array_element =
414  unpack_value(parse_data_list, array_index + 1,
415  prev_data, index, sub_index,
416  unpack_method);
417  if (array_element == nullptr) {
418  return data_value;
419  }
420  data_value->add_element(array_element);
421  }
422  }
423 
424  return data_value;
425 }
426 
427 /**
428  * Returns a newly-allocated zero integer value.
429  */
430 PT(XFileDataObject) XFileDataDef::
431 zero_fill_integer_value() const {
432  return new XFileDataObjectInteger(this, 0);
433 }
434 
435 /**
436  * Returns a newly-allocated zero floating-point value.
437  */
438 PT(XFileDataObject) XFileDataDef::
439 zero_fill_double_value() const {
440  return new XFileDataObjectDouble(this, 0.0);
441 }
442 
443 /**
444  * Returns a newly-allocated empty string value.
445  */
446 PT(XFileDataObject) XFileDataDef::
447 zero_fill_string_value() const {
448  return new XFileDataObjectString(this, "");
449 }
450 
451 /**
452  * Returns a newly-allocated zero-filled nested template value.
453  */
454 PT(XFileDataObject) XFileDataDef::
455 zero_fill_template_value() const {
456  PT(XFileDataObject) data_value =
457  new XFileDataNodeTemplate(get_x_file(), get_name(), _template);
458  if (!_template->fill_zero_data(data_value)) {
459  return nullptr;
460  }
461 
462  return data_value;
463 }
464 
465 /**
466  * Creates a zero-valued element for the next sequential value, of the type
467  * returned by the zero_fill_method. If the value is a fixed-size array type,
468  * zero-fills all the elements of the array.
469  */
470 PT(XFileDataObject) XFileDataDef::
471 zero_fill_value(int array_index,
472  XFileDataDef::ZeroFillMethod zero_fill_method) const {
473  PT(XFileDataObject) data_value;
474 
475  if (array_index == (int)_array_def.size()) {
476  data_value = (this->*zero_fill_method)();
477 
478  } else {
479  data_value = new XFileDataObjectArray(this);
480  int array_size = 0;
481  if (_array_def[array_index].is_fixed_size()) {
482  array_size = _array_def[array_index].get_fixed_size();
483  }
484 
485  for (int i = 0; i < array_size; i++) {
486  PT(XFileDataObject) array_element =
487  zero_fill_value(array_index + 1, zero_fill_method);
488  if (array_element == nullptr) {
489  return nullptr;
490  }
491  data_value->add_element(array_element);
492  }
493  }
494 
495  return data_value;
496 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
virtual bool matches(const XFileNode *other) const
Returns true if the node, particularly a template node, is structurally equivalent to the other node ...
void add_array_def(const XFileArrayDef &array_def)
Adds an additional array dimension to the data description.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool matches(const XFileNode *other) const
Returns true if the node, particularly a template node, is structurally equivalent to the other node ...
Definition: xFileNode.cxx:278
Defines one level of array bounds for an associated XFileDataDef element.
Definition: xFileArrayDef.h:26
An string-valued data element.
This class is used to fill up the data into an XFileDataNodeTemplate object as the data values are pa...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_num_array_defs() const
Returns the number of dimensions of array elements on this data object, or 0 if the data object is no...
Definition: xFileDataDef.I:49
A definition of a single data element appearing within a template record.
Definition: xFileDataDef.h:31
This is a node which contains all of the data elements defined by a template.
virtual bool matches(const XFileNode *other) const
Returns true if the node, particularly a template node, is structurally equivalent to the other node ...
Type get_data_type() const
Returns the primitive type of this element, or T_template if this represents a nested template object...
Definition: xFileDataDef.I:31
A single node of an X file.
Definition: xFileNode.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool repack_data(XFileDataObject *object, const XFileParseDataList &parse_data_list, PrevData &prev_data, size_t &index, size_t &sub_index) const
This is called on the template that defines an object, once the data for the object has been parsed.
XFileTemplate * get_template() const
If get_data_type() returned T_template, this returns the particular template pointer that this object...
Definition: xFileDataDef.I:40
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An integer-valued data element.
virtual bool fill_zero_data(XFileDataObject *object) const
This is similar to repack_data(), except it is used to fill the initial values for a newly-created te...
A container for a pvector of the above objects.
virtual bool repack_data(XFileDataObject *object, const XFileParseDataList &parse_data_list, PrevData &prev_data, size_t &index, size_t &sub_index) const
This is called on the template that defines an object, once the data for the object has been parsed.
Definition: xFileNode.cxx:236
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
Definition: xFileNode.cxx:209
An double-valued data element.
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
virtual void write_text(std::ostream &out, int indent_level) const
Writes a suitable representation of this node to an .x file in text mode.
virtual bool fill_zero_data(XFileDataObject *object) const
This is similar to repack_data(), except it is used to fill the initial values for a newly-created te...
Definition: xFileNode.cxx:261
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:44
An array of nested data elements.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
const XFileArrayDef & get_array_def(int i) const
Returns the description of the nth dimension of array elements on this data object.
Definition: xFileDataDef.I:58
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool matches(const XFileArrayDef &other, const XFileDataDef *parent, const XFileDataDef *other_parent) const
Returns true if the node, particularly a template node, is structurally equivalent to the other node ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The abstract base class for a number of different types of data elements that may be stored in the X ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.