Panda3D
|
00001 // Filename: xFileDataDef.cxx 00002 // Created by: drose (03Oct04) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "xFileDataDef.h" 00016 #include "indent.h" 00017 #include "xLexerDefs.h" 00018 #include "xFileParseData.h" 00019 #include "xFileDataObjectInteger.h" 00020 #include "xFileDataObjectDouble.h" 00021 #include "xFileDataObjectString.h" 00022 #include "xFileDataNodeTemplate.h" 00023 #include "xFileDataObjectArray.h" 00024 #include "string_utils.h" 00025 00026 TypeHandle XFileDataDef::_type_handle; 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: XFileDataDef::Destructor 00030 // Access: Public, Virtual 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 XFileDataDef:: 00034 ~XFileDataDef() { 00035 clear(); 00036 } 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: XFileDataDef::clear 00040 // Access: Public, Virtual 00041 // Description: 00042 //////////////////////////////////////////////////////////////////// 00043 void XFileDataDef:: 00044 clear() { 00045 XFileNode::clear(); 00046 _array_def.clear(); 00047 } 00048 00049 //////////////////////////////////////////////////////////////////// 00050 // Function: XFileDataDef::add_array_def 00051 // Access: Public 00052 // Description: Adds an additional array dimension to the data 00053 // description. 00054 //////////////////////////////////////////////////////////////////// 00055 void XFileDataDef:: 00056 add_array_def(const XFileArrayDef &array_def) { 00057 _array_def.push_back(array_def); 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: XFileDataDef::write_text 00062 // Access: Public, Virtual 00063 // Description: Writes a suitable representation of this node to an 00064 // .x file in text mode. 00065 //////////////////////////////////////////////////////////////////// 00066 void XFileDataDef:: 00067 write_text(ostream &out, int indent_level) const { 00068 indent(out, indent_level); 00069 00070 if (!_array_def.empty()) { 00071 out << "array "; 00072 } 00073 00074 switch (_type) { 00075 case T_word: 00076 out << "WORD"; 00077 break; 00078 00079 case T_dword: 00080 out << "DWORD"; 00081 break; 00082 00083 case T_float: 00084 out << "FLOAT"; 00085 break; 00086 00087 case T_double: 00088 out << "DOUBLE"; 00089 break; 00090 00091 case T_char: 00092 out << "CHAR"; 00093 break; 00094 00095 case T_uchar: 00096 out << "UCHAR"; 00097 break; 00098 00099 case T_sword: 00100 out << "SWORD"; 00101 break; 00102 00103 case T_sdword: 00104 out << "SDWORD"; 00105 break; 00106 00107 case T_string: 00108 out << "STRING"; 00109 break; 00110 00111 case T_cstring: 00112 out << "CSTRING"; 00113 break; 00114 00115 case T_unicode: 00116 out << "UNICODE"; 00117 break; 00118 00119 case T_template: 00120 out << _template->get_name(); 00121 break; 00122 } 00123 00124 if (has_name()) { 00125 out << " " << get_name(); 00126 } 00127 00128 ArrayDef::const_iterator ai; 00129 for (ai = _array_def.begin(); ai != _array_def.end(); ++ai) { 00130 (*ai).output(out); 00131 } 00132 00133 out << ";\n"; 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: XFileDataDef::repack_data 00138 // Access: Public, Virtual 00139 // Description: This is called on the template that defines an 00140 // object, once the data for the object has been parsed. 00141 // It is responsible for identifying which component of 00142 // the template owns each data element, and packing the 00143 // data elements appropriately back into the object. 00144 // 00145 // It returns true on success, or false on an error 00146 // (e.g. not enough data elements, mismatched data 00147 // type). 00148 //////////////////////////////////////////////////////////////////// 00149 bool XFileDataDef:: 00150 repack_data(XFileDataObject *object, 00151 const XFileParseDataList &parse_data_list, 00152 XFileDataDef::PrevData &prev_data, 00153 size_t &index, size_t &sub_index) const { 00154 // We'll fill this in with the data value we pack, if any. 00155 PT(XFileDataObject) data_value; 00156 00157 // What kind of data element are we expecting? 00158 switch (_type) { 00159 case T_word: 00160 case T_dword: 00161 case T_char: 00162 case T_uchar: 00163 case T_sword: 00164 case T_sdword: 00165 // Expected integer data. 00166 data_value = unpack_value(parse_data_list, 0, 00167 prev_data, index, sub_index, 00168 &XFileDataDef::unpack_integer_value); 00169 break; 00170 00171 case T_float: 00172 case T_double: 00173 data_value = unpack_value(parse_data_list, 0, 00174 prev_data, index, sub_index, 00175 &XFileDataDef::unpack_double_value); 00176 break; 00177 00178 case T_string: 00179 case T_cstring: 00180 case T_unicode: 00181 data_value = unpack_value(parse_data_list, 0, 00182 prev_data, index, sub_index, 00183 &XFileDataDef::unpack_string_value); 00184 break; 00185 00186 case T_template: 00187 data_value = unpack_value(parse_data_list, 0, 00188 prev_data, index, sub_index, 00189 &XFileDataDef::unpack_template_value); 00190 break; 00191 } 00192 00193 if (data_value != (XFileDataObject *)NULL) { 00194 object->add_element(data_value); 00195 prev_data[this] = data_value; 00196 } 00197 00198 return XFileNode::repack_data(object, parse_data_list, 00199 prev_data, index, sub_index); 00200 } 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: XFileDataDef::fill_zero_data 00204 // Access: Public, Virtual 00205 // Description: This is similar to repack_data(), except it is used 00206 // to fill the initial values for a newly-created 00207 // template object to zero. 00208 //////////////////////////////////////////////////////////////////// 00209 bool XFileDataDef:: 00210 fill_zero_data(XFileDataObject *object) const { 00211 PT(XFileDataObject) data_value; 00212 00213 // What kind of data element are we expecting? 00214 switch (_type) { 00215 case T_word: 00216 case T_dword: 00217 case T_char: 00218 case T_uchar: 00219 case T_sword: 00220 case T_sdword: 00221 data_value = zero_fill_value(0, &XFileDataDef::zero_fill_integer_value); 00222 break; 00223 00224 case T_float: 00225 case T_double: 00226 data_value = zero_fill_value(0, &XFileDataDef::zero_fill_double_value); 00227 break; 00228 00229 case T_string: 00230 case T_cstring: 00231 case T_unicode: 00232 data_value = zero_fill_value(0, &XFileDataDef::zero_fill_string_value); 00233 break; 00234 00235 case T_template: 00236 data_value = zero_fill_value(0, &XFileDataDef::zero_fill_template_value); 00237 break; 00238 } 00239 00240 if (data_value != (XFileDataObject *)NULL) { 00241 object->add_element(data_value); 00242 } 00243 00244 return XFileNode::fill_zero_data(object); 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: XFileDataDef::matches 00249 // Access: Public, Virtual 00250 // Description: Returns true if the node, particularly a template 00251 // node, is structurally equivalent to the other node 00252 // (which must be of the same type). This checks data 00253 // element types, but does not compare data element 00254 // names. 00255 //////////////////////////////////////////////////////////////////// 00256 bool XFileDataDef:: 00257 matches(const XFileNode *other) const { 00258 if (!XFileNode::matches(other)) { 00259 return false; 00260 } 00261 00262 const XFileDataDef *data_def = DCAST(XFileDataDef, other); 00263 if (data_def->get_data_type() != get_data_type()) { 00264 return false; 00265 } 00266 00267 if (get_data_type() == T_template && 00268 !get_template()->matches(data_def->get_template())) { 00269 return false; 00270 } 00271 00272 if (data_def->get_num_array_defs() != get_num_array_defs()) { 00273 return false; 00274 } 00275 00276 for (int i = 0; i < get_num_array_defs(); i++) { 00277 if (!get_array_def(i).matches(data_def->get_array_def(i), 00278 this, data_def)) { 00279 return false; 00280 } 00281 } 00282 00283 return true; 00284 } 00285 00286 00287 //////////////////////////////////////////////////////////////////// 00288 // Function: XFileDataDef::unpack_integer_value 00289 // Access: Private 00290 // Description: Unpacks and returns the next sequential integer value 00291 // from the parse_data_list. 00292 //////////////////////////////////////////////////////////////////// 00293 PT(XFileDataObject) XFileDataDef:: 00294 unpack_integer_value(const XFileParseDataList &parse_data_list, 00295 const XFileDataDef::PrevData &prev_data, 00296 size_t &index, size_t &sub_index) const { 00297 nassertr(index < parse_data_list._list.size(), NULL); 00298 const XFileParseData &parse_data = parse_data_list._list[index]; 00299 00300 PT(XFileDataObject) data_value; 00301 00302 if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) { 00303 nassertr(sub_index < parse_data._int_list.size(), NULL); 00304 int value = parse_data._int_list[sub_index]; 00305 data_value = new XFileDataObjectInteger(this, value); 00306 00307 sub_index++; 00308 if (sub_index >= parse_data._int_list.size()) { 00309 index++; 00310 sub_index = 0; 00311 } 00312 00313 } else { 00314 parse_data.yyerror("Expected integer data for " + get_name()); 00315 } 00316 00317 return data_value; 00318 } 00319 00320 //////////////////////////////////////////////////////////////////// 00321 // Function: XFileDataDef::unpack_double_value 00322 // Access: Private 00323 // Description: Unpacks and returns the next sequential double value 00324 // from the parse_data_list. 00325 //////////////////////////////////////////////////////////////////// 00326 PT(XFileDataObject) XFileDataDef:: 00327 unpack_double_value(const XFileParseDataList &parse_data_list, 00328 const XFileDataDef::PrevData &prev_data, 00329 size_t &index, size_t &sub_index) const { 00330 nassertr(index < parse_data_list._list.size(), NULL); 00331 const XFileParseData &parse_data = parse_data_list._list[index]; 00332 00333 PT(XFileDataObject) data_value; 00334 00335 if ((parse_data._parse_flags & XFileParseData::PF_double) != 0) { 00336 nassertr(sub_index < parse_data._double_list.size(), NULL); 00337 double value = parse_data._double_list[sub_index]; 00338 data_value = new XFileDataObjectDouble(this, value); 00339 00340 sub_index++; 00341 if (sub_index >= parse_data._double_list.size()) { 00342 index++; 00343 sub_index = 0; 00344 } 00345 00346 } else if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) { 00347 nassertr(sub_index < parse_data._int_list.size(), NULL); 00348 int value = parse_data._int_list[sub_index]; 00349 data_value = new XFileDataObjectDouble(this, value); 00350 00351 sub_index++; 00352 if (sub_index >= parse_data._int_list.size()) { 00353 index++; 00354 sub_index = 0; 00355 } 00356 00357 } else { 00358 parse_data.yyerror("Expected floating-point data for " + get_name()); 00359 } 00360 00361 return data_value; 00362 } 00363 00364 //////////////////////////////////////////////////////////////////// 00365 // Function: XFileDataDef::unpack_string_value 00366 // Access: Private 00367 // Description: Unpacks and returns the next sequential string value 00368 // from the parse_data_list. 00369 //////////////////////////////////////////////////////////////////// 00370 PT(XFileDataObject) XFileDataDef:: 00371 unpack_string_value(const XFileParseDataList &parse_data_list, 00372 const XFileDataDef::PrevData &prev_data, 00373 size_t &index, size_t &sub_index) const { 00374 nassertr(index < parse_data_list._list.size(), NULL); 00375 const XFileParseData &parse_data = parse_data_list._list[index]; 00376 00377 PT(XFileDataObject) data_value; 00378 00379 if ((parse_data._parse_flags & XFileParseData::PF_string) != 0) { 00380 data_value = new XFileDataObjectString(this, parse_data._string); 00381 index++; 00382 sub_index = 0; 00383 00384 } else { 00385 parse_data.yyerror("Expected string data for " + get_name()); 00386 } 00387 00388 return data_value; 00389 } 00390 00391 //////////////////////////////////////////////////////////////////// 00392 // Function: XFileDataDef::unpack_template_value 00393 // Access: Private 00394 // Description: Unpacks a nested template object's data. 00395 //////////////////////////////////////////////////////////////////// 00396 PT(XFileDataObject) XFileDataDef:: 00397 unpack_template_value(const XFileParseDataList &parse_data_list, 00398 const XFileDataDef::PrevData &prev_data, 00399 size_t &index, size_t &sub_index) const { 00400 PT(XFileDataNodeTemplate) data_value = 00401 new XFileDataNodeTemplate(get_x_file(), get_name(), _template); 00402 00403 PrevData nested_prev_data(prev_data); 00404 if (!_template->repack_data(data_value, parse_data_list, 00405 nested_prev_data, index, sub_index)) { 00406 return NULL; 00407 } 00408 00409 return data_value.p(); 00410 } 00411 00412 //////////////////////////////////////////////////////////////////// 00413 // Function: XFileDataDef::unpack_value 00414 // Access: Private 00415 // Description: Unpacks and returns the next sequential value, of the 00416 // type supported by the unpack_method. If the value 00417 // is an array type, unpacks all the elements of the 00418 // array. 00419 //////////////////////////////////////////////////////////////////// 00420 PT(XFileDataObject) XFileDataDef:: 00421 unpack_value(const XFileParseDataList &parse_data_list, int array_index, 00422 const XFileDataDef::PrevData &prev_data, 00423 size_t &index, size_t &sub_index, 00424 XFileDataDef::UnpackMethod unpack_method) const { 00425 PT(XFileDataObject) data_value; 00426 00427 if (array_index == (int)_array_def.size()) { 00428 if (index >= parse_data_list._list.size()) { 00429 xyyerror("Not enough data elements in structure at " + get_name()); 00430 return NULL; 00431 } 00432 data_value = (this->*unpack_method)(parse_data_list, prev_data, 00433 index, sub_index); 00434 00435 } else { 00436 data_value = new XFileDataObjectArray(this); 00437 int array_size = _array_def[array_index].get_size(prev_data); 00438 00439 for (int i = 0; i < array_size; i++) { 00440 if (index >= parse_data_list._list.size()) { 00441 xyyerror(string("Expected ") + format_string(array_size) 00442 + " array elements, found " + format_string(i)); 00443 return data_value; 00444 } 00445 00446 PT(XFileDataObject) array_element = 00447 unpack_value(parse_data_list, array_index + 1, 00448 prev_data, index, sub_index, 00449 unpack_method); 00450 if (array_element == (XFileDataObject *)NULL) { 00451 return data_value; 00452 } 00453 data_value->add_element(array_element); 00454 } 00455 } 00456 00457 return data_value; 00458 } 00459 00460 //////////////////////////////////////////////////////////////////// 00461 // Function: XFileDataDef::zero_fill_integer_value 00462 // Access: Private 00463 // Description: Returns a newly-allocated zero integer value. 00464 //////////////////////////////////////////////////////////////////// 00465 PT(XFileDataObject) XFileDataDef:: 00466 zero_fill_integer_value() const { 00467 return new XFileDataObjectInteger(this, 0); 00468 } 00469 00470 //////////////////////////////////////////////////////////////////// 00471 // Function: XFileDataDef::zero_fill_double_value 00472 // Access: Private 00473 // Description: Returns a newly-allocated zero floating-point value. 00474 //////////////////////////////////////////////////////////////////// 00475 PT(XFileDataObject) XFileDataDef:: 00476 zero_fill_double_value() const { 00477 return new XFileDataObjectDouble(this, 0.0); 00478 } 00479 00480 //////////////////////////////////////////////////////////////////// 00481 // Function: XFileDataDef::zero_fill_string_value 00482 // Access: Private 00483 // Description: Returns a newly-allocated empty string value. 00484 //////////////////////////////////////////////////////////////////// 00485 PT(XFileDataObject) XFileDataDef:: 00486 zero_fill_string_value() const { 00487 return new XFileDataObjectString(this, ""); 00488 } 00489 00490 //////////////////////////////////////////////////////////////////// 00491 // Function: XFileDataDef::zero_fill_template_value 00492 // Access: Private 00493 // Description: Returns a newly-allocated zero-filled nested template 00494 // value. 00495 //////////////////////////////////////////////////////////////////// 00496 PT(XFileDataObject) XFileDataDef:: 00497 zero_fill_template_value() const { 00498 PT(XFileDataObject) data_value = 00499 new XFileDataNodeTemplate(get_x_file(), get_name(), _template); 00500 if (!_template->fill_zero_data(data_value)) { 00501 return NULL; 00502 } 00503 00504 return data_value; 00505 } 00506 00507 //////////////////////////////////////////////////////////////////// 00508 // Function: XFileDataDef::zero_fill_value 00509 // Access: Private 00510 // Description: Creates a zero-valued element for the next sequential 00511 // value, of the type returned by the zero_fill_method. 00512 // If the value is a fixed-size array type, zero-fills 00513 // all the elements of the array. 00514 //////////////////////////////////////////////////////////////////// 00515 PT(XFileDataObject) XFileDataDef:: 00516 zero_fill_value(int array_index, 00517 XFileDataDef::ZeroFillMethod zero_fill_method) const { 00518 PT(XFileDataObject) data_value; 00519 00520 if (array_index == (int)_array_def.size()) { 00521 data_value = (this->*zero_fill_method)(); 00522 00523 } else { 00524 data_value = new XFileDataObjectArray(this); 00525 int array_size = 0; 00526 if (_array_def[array_index].is_fixed_size()) { 00527 array_size = _array_def[array_index].get_fixed_size(); 00528 } 00529 00530 for (int i = 0; i < array_size; i++) { 00531 PT(XFileDataObject) array_element = 00532 zero_fill_value(array_index + 1, zero_fill_method); 00533 if (array_element == (XFileDataObject *)NULL) { 00534 return NULL; 00535 } 00536 data_value->add_element(array_element); 00537 } 00538 } 00539 00540 return data_value; 00541 }