Panda3D

Loading...
Searching...
No Matches
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 */
30XFileDataDef::
31~XFileDataDef() {
32 clear();
33}
34
35/**
36 *
37 */
38 void XFileDataDef::
39 clear() {
40 XFileNode::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::
135 repack_data(XFileDataObject *object,
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::
192 fill_zero_data(XFileDataObject *object) const {
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 */
269PT(XFileDataObject) XFileDataDef::
270unpack_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 */
300PT(XFileDataObject) XFileDataDef::
301unpack_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 */
342PT(XFileDataObject) XFileDataDef::
343unpack_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 */
366PT(XFileDataObject) XFileDataDef::
367unpack_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 */
387PT(XFileDataObject) XFileDataDef::
388unpack_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 */
430PT(XFileDataObject) XFileDataDef::
431zero_fill_integer_value() const {
432 return new XFileDataObjectInteger(this, 0);
433}
434
435/**
436 * Returns a newly-allocated zero floating-point value.
437 */
438PT(XFileDataObject) XFileDataDef::
439zero_fill_double_value() const {
440 return new XFileDataObjectDouble(this, 0.0);
441}
442
443/**
444 * Returns a newly-allocated empty string value.
445 */
446PT(XFileDataObject) XFileDataDef::
447zero_fill_string_value() const {
448 return new XFileDataObjectString(this, "");
449}
450
451/**
452 * Returns a newly-allocated zero-filled nested template value.
453 */
454PT(XFileDataObject) XFileDataDef::
455zero_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 */
470PT(XFileDataObject) XFileDataDef::
471zero_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}
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
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
XFileArrayDef
Defines one level of array bounds for an associated XFileDataDef element.
Definition xFileArrayDef.h:26
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
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
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
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::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
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::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
XFileDataDef::clear
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
Definition xFileDataDef.cxx:39
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
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
XFileDataObjectInteger
An integer-valued data element.
Definition xFileDataObjectInteger.h:24
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
XFileNode::clear
virtual void clear()
Removes all children from the node, and otherwise resets it to its initial state.
Definition xFileNode.cxx:209
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
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
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
XFileParseDataList
A container for a pvector of the above objects.
Definition xFileParseData.h:62
XFileParseData
This class is used to fill up the data into an XFileDataNodeTemplate object as the data values are pa...
Definition xFileParseData.h:30
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
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataDef.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataNodeTemplate.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataObjectArray.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataObjectDouble.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataObjectInteger.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileDataObjectString.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xFileParseData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xLexerDefs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.