Panda3D
|
00001 // Filename: dcPackerCatalog.cxx 00002 // Created by: drose (21Jun04) 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 "dcPackerCatalog.h" 00016 #include "dcPackerInterface.h" 00017 #include "dcPacker.h" 00018 #include "dcSwitchParameter.h" 00019 00020 //////////////////////////////////////////////////////////////////// 00021 // Function: DCPackerCatalog::Constructor 00022 // Access: Private 00023 // Description: The catalog is created only by 00024 // DCPackerInterface::get_catalog(). 00025 //////////////////////////////////////////////////////////////////// 00026 DCPackerCatalog:: 00027 DCPackerCatalog(const DCPackerInterface *root) : _root(root) { 00028 _live_catalog = NULL; 00029 } 00030 00031 //////////////////////////////////////////////////////////////////// 00032 // Function: DCPackerCatalog::Copy Constructor 00033 // Access: Private 00034 // Description: The copy constructor is used only internally, in 00035 // update_switch_fields(). 00036 //////////////////////////////////////////////////////////////////// 00037 DCPackerCatalog:: 00038 DCPackerCatalog(const DCPackerCatalog ©) : 00039 _root(copy._root), 00040 _entries(copy._entries), 00041 _entries_by_name(copy._entries_by_name), 00042 _entries_by_field(copy._entries_by_field) 00043 { 00044 _live_catalog = NULL; 00045 } 00046 00047 //////////////////////////////////////////////////////////////////// 00048 // Function: DCPackerCatalog::Destructor 00049 // Access: Private 00050 // Description: The catalog is destroyed only by 00051 // ~DCPackerInterface(). 00052 //////////////////////////////////////////////////////////////////// 00053 DCPackerCatalog:: 00054 ~DCPackerCatalog() { 00055 if (_live_catalog != (LiveCatalog *)NULL) { 00056 delete _live_catalog; 00057 } 00058 00059 SwitchCatalogs::iterator si; 00060 for (si = _switch_catalogs.begin(); si != _switch_catalogs.end(); ++si) { 00061 delete (*si).second; 00062 } 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: DCPackerCatalog::find_entry_by_name 00067 // Access: Public 00068 // Description: Returns the index number of the entry with the 00069 // indicated name, or -1 if no entry has the indicated 00070 // name. The return value is suitable for passing to 00071 // get_entry(). 00072 //////////////////////////////////////////////////////////////////// 00073 int DCPackerCatalog:: 00074 find_entry_by_name(const string &name) const { 00075 EntriesByName::const_iterator ni; 00076 ni = _entries_by_name.find(name); 00077 if (ni != _entries_by_name.end()) { 00078 return (*ni).second; 00079 } 00080 return -1; 00081 } 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: DCPackerCatalog::find_entry_by_field 00085 // Access: Public 00086 // Description: Returns the index number of the entry with the 00087 // indicated field, or -1 if no entry has the indicated 00088 // field. The return value is suitable for passing to 00089 // get_entry(). 00090 //////////////////////////////////////////////////////////////////// 00091 int DCPackerCatalog:: 00092 find_entry_by_field(const DCPackerInterface *field) const { 00093 EntriesByField::const_iterator ni; 00094 ni = _entries_by_field.find(field); 00095 if (ni != _entries_by_field.end()) { 00096 return (*ni).second; 00097 } 00098 return -1; 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: DCPackerCatalog::get_live_catalog 00103 // Access: Public 00104 // Description: Returns a LiveCatalog object indicating the positions 00105 // within the indicated data record of each field within 00106 // the catalog. If the catalog's fields are all 00107 // fixed-width, this may return a statically-allocated 00108 // LiveCatalog object that is the same for all data 00109 // records; otherwise, it will allocate a new 00110 // LiveCatalog object that must be freed with a later 00111 // call to release_live_catalog(). 00112 //////////////////////////////////////////////////////////////////// 00113 const DCPackerCatalog::LiveCatalog *DCPackerCatalog:: 00114 get_live_catalog(const char *data, size_t length) const { 00115 if (_live_catalog != (LiveCatalog *)NULL) { 00116 // Return the previously-allocated live catalog; it will be the 00117 // same as this one since it's based on a fixed-length field. 00118 return _live_catalog; 00119 } 00120 00121 LiveCatalog *live_catalog = new LiveCatalog; 00122 live_catalog->_catalog = this; 00123 live_catalog->_live_entries.reserve(_entries.size()); 00124 LiveCatalogEntry zero_entry; 00125 zero_entry._begin = 0; 00126 zero_entry._end = 0; 00127 for (size_t i = 0; i < _entries.size(); i++) { 00128 live_catalog->_live_entries.push_back(zero_entry); 00129 } 00130 00131 DCPacker packer; 00132 packer.set_unpack_data(data, length, false); 00133 packer.begin_unpack(_root); 00134 const DCSwitchParameter *last_switch = NULL; 00135 r_fill_live_catalog(live_catalog, packer, last_switch); 00136 bool okflag = packer.end_unpack(); 00137 00138 if (!okflag) { 00139 delete live_catalog; 00140 return NULL; 00141 } 00142 00143 if (_root->has_fixed_structure()) { 00144 // If our root field has a fixed structure, then the live catalog 00145 // will always be the same every time, so we might as well keep 00146 // this one around as an optimization. 00147 ((DCPackerCatalog *)this)->_live_catalog = live_catalog; 00148 } 00149 00150 return live_catalog; 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: DCPackerCatalog::release_live_catalog 00155 // Access: Public 00156 // Description: Releases the LiveCatalog object that was returned by 00157 // an earlier call to get_live_catalog(). If this 00158 // represents a newly-allocated live catalog, it will 00159 // free it; otherwise, it will do nothing. 00160 // 00161 // It is therefore always correct (and necessary) to 00162 // match a call to get_live_catalog() with a later call 00163 // to release_live_catalog(). 00164 //////////////////////////////////////////////////////////////////// 00165 void DCPackerCatalog:: 00166 release_live_catalog(const DCPackerCatalog::LiveCatalog *live_catalog) const { 00167 if (live_catalog != _live_catalog) { 00168 delete (LiveCatalog *)live_catalog; 00169 } 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: DCPackerCatalog::add_entry 00174 // Access: Private 00175 // Description: Called only by DCPackerInterface::r_fill_catalog(), 00176 // this adds a new entry to the catalog. 00177 //////////////////////////////////////////////////////////////////// 00178 void DCPackerCatalog:: 00179 add_entry(const string &name, const DCPackerInterface *field, 00180 const DCPackerInterface *parent, int field_index) { 00181 Entry entry; 00182 entry._name = name; 00183 entry._field = field; 00184 entry._parent = parent; 00185 entry._field_index = field_index; 00186 00187 int entry_index = (int)_entries.size(); 00188 _entries.push_back(entry); 00189 _entries_by_field.insert(EntriesByField::value_type(field, entry_index)); 00190 00191 // Add an entry for the fully-qualified field name 00192 // (e.g. dna.topTex). If there was another entry for this name 00193 // previously, completely replace it--the fully-qualified name is 00194 // supposed to be unique and trumps the local field names (which are 00195 // not necessarily unique). 00196 _entries_by_name[name] = entry_index; 00197 00198 // We'll also add an entry for the local field name, for the user's 00199 // convenience. This won't override a fully-qualified name that 00200 // might already have been recorded, and a fully-qualified name 00201 // discovered later that conflicts with this name will replace it. 00202 string local_name = field->get_name(); 00203 if (local_name != name) { 00204 _entries_by_name.insert(EntriesByName::value_type(local_name, entry_index)); 00205 } 00206 } 00207 00208 //////////////////////////////////////////////////////////////////// 00209 // Function: DCPackerCatalog::r_fill_catalog 00210 // Access: Private 00211 // Description: Called by DCPackerInterface to recursively fill up a 00212 // newly-allocated reference catalog. Also called by 00213 // update_switch_fields to append fields to a catalog 00214 // after a DCSwitch node is selected. 00215 //////////////////////////////////////////////////////////////////// 00216 void DCPackerCatalog:: 00217 r_fill_catalog(const string &name_prefix, const DCPackerInterface *field, 00218 const DCPackerInterface *parent, int field_index) { 00219 string next_name_prefix = name_prefix; 00220 00221 if (parent != (const DCPackerInterface *)NULL && !field->get_name().empty()) { 00222 // Record this entry in the catalog. 00223 next_name_prefix += field->get_name(); 00224 add_entry(next_name_prefix, field, parent, field_index); 00225 00226 next_name_prefix += "."; 00227 } 00228 00229 const DCSwitchParameter *switch_parameter = field->as_switch_parameter(); 00230 if (switch_parameter != (DCSwitchParameter *)NULL) { 00231 // If we come upon a DCSwitch while building the catalog, save the 00232 // name_prefix at this point so we'll have it again when we later 00233 // encounter the switch while unpacking a live record (and so we 00234 // can return to this point in the recursion from 00235 // update_switch_fields). 00236 _switch_prefixes[switch_parameter] = next_name_prefix; 00237 } 00238 00239 // Add any children. 00240 if (field->has_nested_fields()) { 00241 int num_nested = field->get_num_nested_fields(); 00242 // It's ok if num_nested is -1. 00243 for (int i = 0; i < num_nested; i++) { 00244 DCPackerInterface *nested = field->get_nested_field(i); 00245 if (nested != (DCPackerInterface *)NULL) { 00246 r_fill_catalog(next_name_prefix, nested, field, i); 00247 } 00248 } 00249 } 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: DCPackerCatalog::r_fill_live_catalog 00254 // Access: Private 00255 // Description: Recursively walks through all of the fields on the 00256 // catalog and fills the live catalog with the 00257 // appropriate offsets. 00258 //////////////////////////////////////////////////////////////////// 00259 void DCPackerCatalog:: 00260 r_fill_live_catalog(LiveCatalog *live_catalog, DCPacker &packer, 00261 const DCSwitchParameter *&last_switch) const { 00262 const DCPackerInterface *current_field = packer.get_current_field(); 00263 00264 int field_index = live_catalog->find_entry_by_field(current_field); 00265 if (field_index >= 0) { 00266 nassertv(field_index < (int)live_catalog->_live_entries.size()); 00267 live_catalog->_live_entries[field_index]._begin = packer.get_num_unpacked_bytes(); 00268 } 00269 00270 if (packer.has_nested_fields() && 00271 (packer.get_pack_type() != PT_string && packer.get_pack_type() != PT_blob)) { 00272 packer.push(); 00273 while (packer.more_nested_fields()) { 00274 r_fill_live_catalog(live_catalog, packer, last_switch); 00275 } 00276 packer.pop(); 00277 00278 } else { 00279 packer.unpack_skip(); 00280 } 00281 00282 if (field_index >= 0) { 00283 live_catalog->_live_entries[field_index]._end = packer.get_num_unpacked_bytes(); 00284 } 00285 00286 if (last_switch != packer.get_last_switch()) { 00287 // We've just invoked a new DCSwitch. That means we must add the 00288 // new fields revealed by the switch to the reference catalog. 00289 last_switch = packer.get_last_switch(); 00290 00291 const DCPackerInterface *switch_case = packer.get_current_parent(); 00292 nassertv(switch_case != (DCPackerInterface *)NULL); 00293 const DCPackerCatalog *switch_catalog = 00294 live_catalog->_catalog->update_switch_fields(last_switch, switch_case); 00295 nassertv(switch_catalog != (DCPackerCatalog *)NULL); 00296 live_catalog->_catalog = switch_catalog; 00297 00298 // And we also have to expand the live catalog to hold the new 00299 // entries. 00300 LiveCatalogEntry zero_entry; 00301 zero_entry._begin = 0; 00302 zero_entry._end = 0; 00303 for (size_t i = live_catalog->_live_entries.size(); 00304 i < switch_catalog->_entries.size(); 00305 i++) { 00306 live_catalog->_live_entries.push_back(zero_entry); 00307 } 00308 } 00309 } 00310 00311 //////////////////////////////////////////////////////////////////// 00312 // Function: DCPackerCatalog::update_switch_fields 00313 // Access: Private 00314 // Description: Returns a new DCPackerCatalog that includes all of 00315 // the fields in this object, with the addition of the 00316 // fields named by switch_case. 00317 // 00318 // This is used to implement switches, which change the 00319 // set of fields they make available according to the 00320 // data in the record, and therefore present a different 00321 // catalog under different circumstances. 00322 // 00323 // This returned pointer is allocated one time for each 00324 // different switch_case instance; if a given same 00325 // switch_case is supplied twice, the same pointer is 00326 // returned both times. The ownership of the returned 00327 // pointer is kept by this object. 00328 //////////////////////////////////////////////////////////////////// 00329 const DCPackerCatalog *DCPackerCatalog:: 00330 update_switch_fields(const DCSwitchParameter *switch_parameter, 00331 const DCPackerInterface *switch_case) const { 00332 SwitchCatalogs::const_iterator si = _switch_catalogs.find(switch_case); 00333 if (si != _switch_catalogs.end()) { 00334 return (*si).second; 00335 } 00336 00337 // Look up the name_prefix will we use for all of the fields that 00338 // descend from this switch. This should be stored in this record 00339 // because we must have come across the DCSwitch when building the 00340 // catalog the first time. 00341 SwitchPrefixes::const_iterator pi = _switch_prefixes.find(switch_parameter); 00342 if (pi == _switch_prefixes.end()) { 00343 // If it's not stored in the record, the switch must be hidden 00344 // within some non-seekable object, like an array; in this case, 00345 // never mind. 00346 return this; 00347 } 00348 00349 string name_prefix = (*pi).second; 00350 00351 // Start by creating a new DCPackerCatalog object that contains all 00352 // of the fields that this one contains. 00353 DCPackerCatalog *switch_catalog = new DCPackerCatalog(*this); 00354 00355 // Now record all of the fields of the switch case in the new 00356 // catalog. We start with the second field of the switch case, 00357 // since the first field will be the switch parameter itself, which 00358 // we would have already recorded the first time around. 00359 int num_nested = switch_case->get_num_nested_fields(); 00360 for (int i = 1; i < num_nested; i++) { 00361 DCPackerInterface *nested = switch_case->get_nested_field(i); 00362 if (nested != (DCPackerInterface *)NULL) { 00363 switch_catalog->r_fill_catalog(name_prefix, nested, switch_case, i); 00364 } 00365 } 00366 00367 // Store the newly-generated switch catalog in the record so the 00368 // same pointer can be returned in the future. 00369 ((DCPackerCatalog *)this)->_switch_catalogs[switch_case] = switch_catalog; 00370 00371 return switch_catalog; 00372 }