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