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 }
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
XFileArrayDef
Defines one level of array bounds for an associated XFileDataDef element.
Definition: xFileArrayDef.h:26
XFileDataDef::fill_zero_data
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: xFileDataDef.cxx:192
XFileDataObject
The abstract base class for a number of different types of data elements that may be stored in the X ...
Definition: xFileDataObject.h:30
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileDataDef::add_array_def
void add_array_def(const XFileArrayDef &array_def)
Adds an additional array dimension to the data description.
Definition: xFileDataDef.cxx:48
XFileDataObjectInteger
An integer-valued data element.
Definition: xFileDataObjectInteger.h:24
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
xFileDataNodeTemplate.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileNode
A single node of an X file.
Definition: xFileNode.h:39
XFileDataObjectArray
An array of nested data elements.
Definition: xFileDataObjectArray.h:23
xLexerDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileDataDef::get_num_array_defs
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
xFileDataObjectInteger.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileNode::clear
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
Definition: xFileNode.cxx:209
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
XFileParseDataList
A container for a pvector of the above objects.
Definition: xFileParseData.h:62
XFileDataObjectString
An string-valued data element.
Definition: xFileDataObjectString.h:24
XFileDataDef::get_template
XFileTemplate * get_template() const
If get_data_type() returned T_template, this returns the particular template pointer that this object...
Definition: xFileDataDef.I:40
XFileDataDef::get_array_def
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
XFileNode::matches
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
xFileDataObjectString.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileParseData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileNode::fill_zero_data
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
xFileDataObjectDouble.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileDataDef
A definition of a single data element appearing within a template record.
Definition: xFileDataDef.h:31
XFileDataNodeTemplate
This is a node which contains all of the data elements defined by a template.
Definition: xFileDataNodeTemplate.h:30
Namable::has_name
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:44
XFileParseData::yyerror
void yyerror(const std::string &message) const
Reports a parsing error message to the user, showing the line and column from which this object was o...
Definition: xFileParseData.cxx:37
XFileNode::repack_data
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
xFileDataObjectArray.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataDef.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileDataObjectDouble
An double-valued data element.
Definition: xFileDataObjectDouble.h:24
XFileParseData
This class is used to fill up the data into an XFileDataNodeTemplate object as the data values are pa...
Definition: xFileParseData.h:30
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
XFileDataDef::matches
virtual bool matches(const XFileNode *other) const
Returns true if the node, particularly a template node, is structurally equivalent to the other node ...
Definition: xFileDataDef.cxx:235
XFileArrayDef::matches
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 ...
Definition: xFileArrayDef.cxx:55
XFileDataDef::write_text
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.
Definition: xFileDataDef.cxx:56
XFileDataDef::repack_data
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: xFileDataDef.cxx:135
XFileDataDef::clear
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
Definition: xFileDataDef.cxx:39
XFileDataDef::get_data_type
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