00001 // Filename: xFileDataNodeTemplate.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 "xFileDataNodeTemplate.h" 00016 #include "indent.h" 00017 #include "xFileParseData.h" 00018 #include "xLexerDefs.h" 00019 #include "config_xfile.h" 00020 00021 TypeHandle XFileDataNodeTemplate::_type_handle; 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: XFileDataNodeTemplate::Constructor 00025 // Access: Public 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 XFileDataNodeTemplate:: 00029 XFileDataNodeTemplate(XFile *x_file, const string &name, 00030 XFileTemplate *xtemplate) : 00031 XFileDataNode(x_file, name, xtemplate) 00032 { 00033 } 00034 00035 //////////////////////////////////////////////////////////////////// 00036 // Function: XFileDataNodeTemplate::zero_fill 00037 // Access: Public 00038 // Description: Fills the data node with zero-valued elements 00039 // appropriate to the template. 00040 //////////////////////////////////////////////////////////////////// 00041 void XFileDataNodeTemplate:: 00042 zero_fill() { 00043 _template->fill_zero_data(this); 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: XFileDataNodeTemplate::is_complex_object 00048 // Access: Public, Virtual 00049 // Description: Returns true if this kind of data object is a complex 00050 // object that can hold nested data elements, false 00051 // otherwise. 00052 //////////////////////////////////////////////////////////////////// 00053 bool XFileDataNodeTemplate:: 00054 is_complex_object() const { 00055 return true; 00056 } 00057 00058 //////////////////////////////////////////////////////////////////// 00059 // Function: XFileDataNodeTemplate::add_parse_double 00060 // Access: Public 00061 // Description: Adds the indicated list of doubles as a data element 00062 // encountered in the parser. It will later be 00063 // processed by finalize_parse_data(). 00064 //////////////////////////////////////////////////////////////////// 00065 void XFileDataNodeTemplate:: 00066 add_parse_double(PTA_double double_list) { 00067 XFileParseData pdata; 00068 pdata._double_list = double_list; 00069 pdata._parse_flags = XFileParseData::PF_double; 00070 00071 _parse_data_list._list.push_back(pdata); 00072 } 00073 00074 //////////////////////////////////////////////////////////////////// 00075 // Function: XFileDataNodeTemplate::add_parse_int 00076 // Access: Public 00077 // Description: Adds the indicated list of ints as a data element 00078 // encountered in the parser. It will later be 00079 // processed by finalize_parse_data(). 00080 //////////////////////////////////////////////////////////////////// 00081 void XFileDataNodeTemplate:: 00082 add_parse_int(PTA_int int_list) { 00083 XFileParseData pdata; 00084 pdata._int_list = int_list; 00085 pdata._parse_flags = XFileParseData::PF_int; 00086 00087 _parse_data_list._list.push_back(pdata); 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: XFileDataNodeTemplate::add_parse_string 00092 // Access: Public 00093 // Description: Adds the indicated string as a data element 00094 // encountered in the parser. It will later be 00095 // processed by finalize_parse_data(). 00096 //////////////////////////////////////////////////////////////////// 00097 void XFileDataNodeTemplate:: 00098 add_parse_string(const string &str) { 00099 XFileParseData pdata; 00100 pdata._string = str; 00101 pdata._parse_flags = XFileParseData::PF_string; 00102 00103 _parse_data_list._list.push_back(pdata); 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: XFileDataNodeTemplate::finalize_parse_data 00108 // Access: Public 00109 // Description: Processes all of the data elements added by 00110 // add_parse_*(), checks them for syntactic and semantic 00111 // correctness against the Template definition, and 00112 // stores the appropriate child data elements. Returns 00113 // true on success, false if there is a mismatch. 00114 //////////////////////////////////////////////////////////////////// 00115 bool XFileDataNodeTemplate:: 00116 finalize_parse_data() { 00117 // Recursively walk through our template definition, while 00118 // simultaneously walking through the list of parse data elements we 00119 // encountered, and re-pack them as actual nested elements. 00120 PrevData prev_data; 00121 size_t index = 0; 00122 size_t sub_index = 0; 00123 00124 if (!_template->repack_data(this, _parse_data_list, 00125 prev_data, index, sub_index)) { 00126 return false; 00127 } 00128 00129 if (index != _parse_data_list._list.size()) { 00130 xyywarning("Too many data elements in structure."); 00131 } 00132 00133 return true; 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: XFileDataNodeTemplate::add_element 00138 // Access: Public, Virtual 00139 // Description: Adds the indicated element as a nested data element, 00140 // if this data object type supports it. Returns true 00141 // if added successfully, false if the data object type 00142 // does not support nested data elements. 00143 //////////////////////////////////////////////////////////////////// 00144 bool XFileDataNodeTemplate:: 00145 add_element(XFileDataObject *element) { 00146 _nested_elements.push_back(element); 00147 return true; 00148 } 00149 00150 //////////////////////////////////////////////////////////////////// 00151 // Function: XFileDataNodeTemplate::write_text 00152 // Access: Public, Virtual 00153 // Description: Writes a suitable representation of this node to an 00154 // .x file in text mode. 00155 //////////////////////////////////////////////////////////////////// 00156 void XFileDataNodeTemplate:: 00157 write_text(ostream &out, int indent_level) const { 00158 indent(out, indent_level) 00159 << _template->get_name(); 00160 if (has_name()) { 00161 out << " " << get_name(); 00162 } 00163 out << " {\n"; 00164 00165 NestedElements::const_iterator ni; 00166 for (ni = _nested_elements.begin(); ni != _nested_elements.end(); ++ni) { 00167 (*ni)->write_data(out, indent_level + 2, ";"); 00168 } 00169 00170 XFileNode::write_text(out, indent_level + 2); 00171 indent(out, indent_level) 00172 << "}\n"; 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: XFileDataNodeTemplate::write_data 00177 // Access: Public, Virtual 00178 // Description: Writes a suitable representation of this node to an 00179 // .x file in text mode. 00180 //////////////////////////////////////////////////////////////////// 00181 void XFileDataNodeTemplate:: 00182 write_data(ostream &out, int indent_level, const char *separator) const { 00183 if (!_nested_elements.empty()) { 00184 bool indented = false; 00185 for (size_t i = 0; i < _nested_elements.size() - 1; i++) { 00186 XFileDataObject *object = _nested_elements[i]; 00187 if (object->is_complex_object()) { 00188 // If we have a "complex" nested object, output it on its own 00189 // line. 00190 if (indented) { 00191 out << "\n"; 00192 indented = false; 00193 } 00194 object->write_data(out, indent_level, ";"); 00195 00196 } else { 00197 // Otherwise, output them all on the same line. 00198 if (!indented) { 00199 indent(out, indent_level); 00200 indented = true; 00201 } 00202 out << *object << "; "; 00203 } 00204 } 00205 00206 // The last object is the set is different, because it gets 00207 // separator appended to it, and it always gets a newline. 00208 XFileDataObject *object = _nested_elements.back(); 00209 if (object->is_complex_object()) { 00210 if (indented) { 00211 out << "\n"; 00212 } 00213 string combined_separator = string(";") + string(separator); 00214 object->write_data(out, indent_level, combined_separator.c_str()); 00215 00216 } else { 00217 if (!indented) { 00218 indent(out, indent_level); 00219 } 00220 out << *object << ";" << separator << "\n"; 00221 } 00222 } 00223 } 00224 00225 //////////////////////////////////////////////////////////////////// 00226 // Function: XFileDataNodeTemplate::get_num_elements 00227 // Access: Protected, Virtual 00228 // Description: Returns the number of nested data elements within the 00229 // object. This may be, e.g. the size of the array, if 00230 // it is an array. 00231 //////////////////////////////////////////////////////////////////// 00232 int XFileDataNodeTemplate:: 00233 get_num_elements() const { 00234 return _nested_elements.size(); 00235 } 00236 00237 //////////////////////////////////////////////////////////////////// 00238 // Function: XFileDataNodeTemplate::get_element 00239 // Access: Protected, Virtual 00240 // Description: Returns the nth nested data element within the 00241 // object. 00242 //////////////////////////////////////////////////////////////////// 00243 XFileDataObject *XFileDataNodeTemplate:: 00244 get_element(int n) { 00245 nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL); 00246 return _nested_elements[n]; 00247 } 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: XFileDataNodeTemplate::get_element 00251 // Access: Protected, Virtual 00252 // Description: Returns the nested data element within the 00253 // object that has the indicated name. 00254 //////////////////////////////////////////////////////////////////// 00255 XFileDataObject *XFileDataNodeTemplate:: 00256 get_element(const string &name) { 00257 int child_index = _template->find_child_index(name); 00258 if (child_index >= 0) { 00259 return get_element(child_index); 00260 } 00261 xfile_cat.warning() 00262 << "\"" << name << "\" not a member of " << _template->get_name() 00263 << "\n"; 00264 return NULL; 00265 }