Panda3D

xFileDataDef.cxx

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 }
 All Classes Functions Variables Enumerations