Panda3D
 All Classes Functions Variables Enumerations
dcPacker.cxx
00001 // Filename: dcPacker.cxx
00002 // Created by:  drose (15Jun04)
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 "dcPacker.h"
00016 #include "dcSwitch.h"
00017 #include "dcParserDefs.h"
00018 #include "dcLexerDefs.h"
00019 #include "dcClassParameter.h"
00020 #include "dcSwitchParameter.h"
00021 #include "dcClass.h"
00022 
00023 DCPacker::StackElement *DCPacker::StackElement::_deleted_chain = NULL;
00024 int DCPacker::StackElement::_num_ever_allocated = 0;
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: DCPacker::Constructor
00028 //       Access: Published
00029 //  Description: 
00030 ////////////////////////////////////////////////////////////////////
00031 DCPacker::
00032 DCPacker() {
00033   _mode = M_idle;
00034   _unpack_data = NULL;
00035   _unpack_length = 0;
00036   _owns_unpack_data = false;
00037   _unpack_p = 0;
00038   _live_catalog = NULL;
00039   _parse_error = false;
00040   _pack_error = false;
00041   _range_error = false;
00042   _stack = NULL;
00043   
00044   clear();
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: DCPacker::Destructor
00049 //       Access: Published
00050 //  Description: 
00051 ////////////////////////////////////////////////////////////////////
00052 DCPacker::
00053 ~DCPacker() {
00054   clear_data();
00055   clear();
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: DCPacker::begin_pack
00060 //       Access: Published
00061 //  Description: Begins a packing session.  The parameter is the DC
00062 //               object that describes the packing format; it may be a
00063 //               DCParameter or DCField.
00064 //
00065 //               Unless you call clear_data() between sessions,
00066 //               multiple packing sessions will be concatenated
00067 //               together into the same buffer.  If you wish to add
00068 //               bytes to the buffer between packing sessions, use
00069 //               append_data() or get_write_pointer().
00070 ////////////////////////////////////////////////////////////////////
00071 void DCPacker::
00072 begin_pack(const DCPackerInterface *root) {
00073   nassertv(_mode == M_idle);
00074   
00075   _mode = M_pack;
00076   _parse_error = false;
00077   _pack_error = false;
00078   _range_error = false;
00079 
00080   _root = root;
00081   _catalog = NULL;
00082   _live_catalog = NULL;
00083 
00084   _current_field = root;
00085   _current_parent = NULL;
00086   _current_field_index = 0;
00087   _num_nested_fields = 0;
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: DCPacker::end_pack
00092 //       Access: Published, Virtual
00093 //  Description: Finishes a packing session.
00094 //
00095 //               The return value is true on success, or false if
00096 //               there has been some error during packing.
00097 ////////////////////////////////////////////////////////////////////
00098 bool DCPacker::
00099 end_pack() {
00100   nassertr(_mode == M_pack, false);
00101   
00102   _mode = M_idle;
00103 
00104   if (_stack != NULL || _current_field != NULL || _current_parent != NULL) {
00105     _pack_error = true;
00106   }
00107 
00108   clear();
00109 
00110   return !had_error();
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: DCPacker::set_unpack_data
00115 //       Access: Public
00116 //  Description: Sets up the unpack_data pointer.  You may call this
00117 //               before calling the version of begin_unpack() that
00118 //               takes only one parameter.
00119 ////////////////////////////////////////////////////////////////////
00120 void DCPacker::
00121 set_unpack_data(const string &data) {
00122   nassertv(_mode == M_idle);
00123 
00124   char *buffer = new char[data.length()];
00125   memcpy(buffer, data.data(), data.length());
00126   set_unpack_data(buffer, data.length(), true);
00127 }
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: DCPacker::set_unpack_data
00131 //       Access: Public
00132 //  Description: Sets up the unpack_data pointer.  You may call this
00133 //               before calling the version of begin_unpack() that
00134 //               takes only one parameter.
00135 ////////////////////////////////////////////////////////////////////
00136 void DCPacker::
00137 set_unpack_data(const char *unpack_data, size_t unpack_length, 
00138                 bool owns_unpack_data) {
00139   nassertv(_mode == M_idle);
00140 
00141   if (_owns_unpack_data) {
00142     delete[] _unpack_data;
00143   }
00144   _unpack_data = unpack_data;
00145   _unpack_length = unpack_length;
00146   _owns_unpack_data = owns_unpack_data;
00147   _unpack_p = 0;
00148 }
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: DCPacker::begin_unpack
00152 //       Access: Public
00153 //  Description: Begins an unpacking session.  You must have
00154 //               previously called set_unpack_data() to specify a
00155 //               buffer to unpack.
00156 //
00157 //               If there was data left in the buffer after a previous
00158 //               begin_unpack() .. end_unpack() session, the new
00159 //               session will resume from the current point.  This
00160 //               method may be used, therefore, to unpack a sequence
00161 //               of objects from the same buffer.
00162 ////////////////////////////////////////////////////////////////////
00163 void DCPacker::
00164 begin_unpack(const DCPackerInterface *root) {
00165   nassertv(_mode == M_idle);
00166   nassertv(_unpack_data != NULL);
00167   
00168   _mode = M_unpack;
00169   _parse_error = false;
00170   _pack_error = false;
00171   _range_error = false;
00172 
00173   _root = root;
00174   _catalog = NULL;
00175   _live_catalog = NULL;
00176 
00177   _current_field = root;
00178   _current_parent = NULL;
00179   _current_field_index = 0;
00180   _num_nested_fields = 0;
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: DCPacker::end_unpack
00185 //       Access: Published
00186 //  Description: Finishes the unpacking session.
00187 //
00188 //               The return value is true on success, or false if
00189 //               there has been some error during unpacking (or if all
00190 //               fields have not been unpacked).
00191 ////////////////////////////////////////////////////////////////////
00192 bool DCPacker::
00193 end_unpack() {
00194   nassertr(_mode == M_unpack, false);
00195   
00196   _mode = M_idle;
00197 
00198   if (_stack != NULL || _current_field != NULL || _current_parent != NULL) {
00199     // This happens if we have not unpacked all of the fields.
00200     // However, this is not an error if we have called seek() during
00201     // the unpack session (in which case the _catalog will be
00202     // non-NULL).  On the other hand, if the catalog is still NULL,
00203     // then we have never called seek() and it is an error not to
00204     // unpack all values.
00205     if (_catalog == (DCPackerCatalog *)NULL) {
00206       _pack_error = true;
00207     }
00208   }
00209 
00210   clear();
00211 
00212   return !had_error();
00213 }
00214 
00215 ////////////////////////////////////////////////////////////////////
00216 //     Function: DCPacker::begin_repack
00217 //       Access: Public
00218 //  Description: Begins a repacking session.  You must have previously
00219 //               called set_unpack_data() to specify a buffer to
00220 //               unpack.
00221 //
00222 //               Unlike begin_pack() or begin_unpack() you may not
00223 //               concatenate the results of multiple begin_repack()
00224 //               sessions in one buffer.
00225 //
00226 //               Also, unlike in packing or unpacking modes, you may
00227 //               not walk through the fields from beginning to end, or
00228 //               even pack two consecutive fields at once.  Instead,
00229 //               you must call seek() for each field you wish to
00230 //               modify and pack only that one field; then call seek()
00231 //               again to modify another field.
00232 ////////////////////////////////////////////////////////////////////
00233 void DCPacker::
00234 begin_repack(const DCPackerInterface *root) {
00235   nassertv(_mode == M_idle);
00236   nassertv(_unpack_data != NULL);
00237   nassertv(_unpack_p == 0);
00238   
00239   _mode = M_repack;
00240   _parse_error = false;
00241   _pack_error = false;
00242   _range_error = false;
00243   _pack_data.clear();
00244 
00245   // In repack mode, we immediately get the catalog, since we know
00246   // we'll need it.
00247   _root = root;
00248   _catalog = _root->get_catalog();
00249   _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
00250   if (_live_catalog == NULL) {
00251     _pack_error = true;
00252   }
00253 
00254   // We don't begin at the first field in repack mode.  Instead, you
00255   // must explicitly call seek().
00256   _current_field = NULL;
00257   _current_parent = NULL;
00258   _current_field_index = 0;
00259   _num_nested_fields = 0;
00260 }
00261 
00262 ////////////////////////////////////////////////////////////////////
00263 //     Function: DCPacker::end_repack
00264 //       Access: Published
00265 //  Description: Finishes the repacking session.
00266 //
00267 //               The return value is true on success, or false if
00268 //               there has been some error during repacking (or if all
00269 //               fields have not been repacked).
00270 ////////////////////////////////////////////////////////////////////
00271 bool DCPacker::
00272 end_repack() {
00273   nassertr(_mode == M_repack, false);
00274 
00275   // Put the rest of the data onto the pack stream.
00276   _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
00277   
00278   _mode = M_idle;
00279   clear();
00280 
00281   return !had_error();
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: DCPacker::seek
00286 //       Access: Published
00287 //  Description: Sets the current unpack (or repack) position to the
00288 //               named field.  In unpack mode, the next call to
00289 //               unpack_*() or push() will begin to read the named
00290 //               field.  In repack mode, the next call to pack_*() or
00291 //               push() will modify the named field.
00292 //
00293 //               Returns true if successful, false if the field is not
00294 //               known (or if the packer is in an invalid mode).
00295 ////////////////////////////////////////////////////////////////////
00296 bool DCPacker::
00297 seek(const string &field_name) {
00298   if (_catalog == (DCPackerCatalog *)NULL) {
00299     _catalog = _root->get_catalog();
00300     _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
00301   }
00302   nassertr(_catalog != (DCPackerCatalog *)NULL, false);
00303   if (_live_catalog == NULL) {
00304     _pack_error = true;
00305     return false;
00306   }
00307   
00308   int seek_index = _live_catalog->find_entry_by_name(field_name);
00309   if (seek_index < 0) {
00310     // The field was not known.
00311     _pack_error = true;
00312     return false;
00313   }
00314 
00315   return seek(seek_index);
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: DCPacker::seek
00320 //       Access: Published
00321 //  Description: Seeks to the field indentified by seek_index, which
00322 //               was returned by an earlier call to
00323 //               DCField::find_seek_index() to get the index of some
00324 //               nested field.  Also see the version of seek() that
00325 //               accepts a field name.
00326 //
00327 //               Returns true if successful, false if the field is not
00328 //               known (or if the packer is in an invalid mode).
00329 ////////////////////////////////////////////////////////////////////
00330 bool DCPacker::
00331 seek(int seek_index) {
00332   if (_catalog == (DCPackerCatalog *)NULL) {
00333     _catalog = _root->get_catalog();
00334     _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
00335   }
00336   nassertr(_catalog != (DCPackerCatalog *)NULL, false);
00337   if (_live_catalog == NULL) {
00338     _pack_error = true;
00339     return false;
00340   }
00341   
00342   if (_mode == M_unpack) {
00343     const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(seek_index);
00344 
00345     // If we are seeking, we don't need to remember our current stack
00346     // position.
00347     clear_stack();
00348     _current_field = entry._field;
00349     _current_parent = entry._parent;
00350     _current_field_index = entry._field_index;
00351     _num_nested_fields = _current_parent->get_num_nested_fields();
00352     _unpack_p = _live_catalog->get_begin(seek_index);
00353 
00354     // We don't really need _push_marker and _pop_marker now, except
00355     // that we should set _push_marker in case we have just seeked to
00356     // a switch parameter, and we should set _pop_marker to 0 just so
00357     // it won't get in the way.
00358     _push_marker = _unpack_p;
00359     _pop_marker = 0;
00360 
00361     return true;
00362 
00363   } else if (_mode == M_repack) {
00364     nassertr(_catalog != (DCPackerCatalog *)NULL, false);
00365 
00366     if (_stack != NULL || _current_field != NULL) {
00367       // It is an error to reseek while the stack is nonempty--that
00368       // means we haven't finished packing the current field.
00369       _pack_error = true;
00370       return false;
00371     }
00372     const DCPackerCatalog::Entry &entry = _live_catalog->get_entry(seek_index);
00373 
00374     if (entry._parent->as_switch_parameter() != (DCSwitchParameter *)NULL) {
00375       // If the parent is a DCSwitch, that can only mean that the
00376       // seeked field is a switch parameter.  We can't support seeking
00377       // to a switch parameter and modifying it directly--what would
00378       // happen to all of the related fields?  Instead, you'll have to
00379       // seek to the switch itself and repack the whole entity.
00380       _pack_error = true;
00381       return false;
00382     }
00383 
00384     size_t begin = _live_catalog->get_begin(seek_index);
00385     if (begin < _unpack_p) {
00386       // Whoops, we are seeking fields out-of-order.  That means we
00387       // need to write the entire record and start again. 
00388       _pack_data.append_data(_unpack_data + _unpack_p, _unpack_length - _unpack_p);
00389       size_t length = _pack_data.get_length();
00390       char *buffer = _pack_data.take_data();
00391       set_unpack_data(buffer, length, true);
00392       _unpack_p = 0;
00393 
00394       _catalog->release_live_catalog(_live_catalog);
00395       _live_catalog = _catalog->get_live_catalog(_unpack_data, _unpack_length);
00396 
00397       if (_live_catalog == NULL) {
00398         _pack_error = true;
00399         return false;
00400       }
00401 
00402       begin = _live_catalog->get_begin(seek_index);
00403     }
00404 
00405     // Now copy the bytes from _unpack_p to begin from the
00406     // _unpack_data to the _pack_data.  These are the bytes we just
00407     // skipped over with the call to seek().
00408     _pack_data.append_data(_unpack_data + _unpack_p, begin - _unpack_p);
00409 
00410     // And set the packer up to pack the indicated field (but no
00411     // subsequent fields).
00412     _current_field = entry._field;
00413     _current_parent = entry._parent;
00414     _current_field_index = entry._field_index;
00415     _num_nested_fields = 1;
00416     _unpack_p = _live_catalog->get_end(seek_index);
00417 
00418     // Set up push_marker and pop_marker so we won't try to advance
00419     // beyond this field.
00420     _push_marker = begin;
00421     _pop_marker = _live_catalog->get_end(seek_index);
00422 
00423     return true;
00424   }
00425 
00426   // Invalid mode.
00427   _pack_error = true;
00428   return false;
00429 }
00430 
00431 ////////////////////////////////////////////////////////////////////
00432 //     Function: DCPacker::push
00433 //       Access: Published
00434 //  Description: Marks the beginning of a nested series of fields.
00435 //
00436 //               This must be called before filling the elements of an
00437 //               array or the individual fields in a structure field.
00438 //               It must also be balanced by a matching pop().
00439 //
00440 //               It is necessary to use push() / pop() only if
00441 //               has_nested_fields() returns true.
00442 ////////////////////////////////////////////////////////////////////
00443 void DCPacker::
00444 push() {
00445   if (!has_nested_fields()) {
00446     _pack_error = true;
00447 
00448   } else {
00449     StackElement *element = new StackElement;
00450     element->_current_parent = _current_parent;
00451     element->_current_field_index = _current_field_index;
00452     element->_push_marker = _push_marker;
00453     element->_pop_marker = _pop_marker;
00454     element->_next = _stack;
00455     _stack = element;
00456     _current_parent = _current_field;
00457 
00458 
00459     // Now deal with the length prefix that might or might not be
00460     // before a sequence of nested fields.
00461     int num_nested_fields = _current_parent->get_num_nested_fields();
00462     size_t length_bytes = _current_parent->get_num_length_bytes();
00463     
00464     if (_mode == M_pack || _mode == M_repack) {
00465       // Reserve length_bytes for when we figure out what the length
00466       // is.
00467       _push_marker = _pack_data.get_length();
00468       _pop_marker = 0;
00469       _pack_data.append_junk(length_bytes);
00470 
00471     } else if (_mode == M_unpack) {
00472       // Read length_bytes to determine the end of this nested
00473       // sequence.
00474       _push_marker = _unpack_p;
00475       _pop_marker = 0;
00476 
00477       if (length_bytes != 0) {
00478         if (_unpack_p + length_bytes > _unpack_length) {
00479           _pack_error = true;
00480 
00481         } else {
00482           size_t length;
00483           if (length_bytes == 4) {
00484             length = DCPackerInterface::do_unpack_uint32
00485               (_unpack_data + _unpack_p);
00486             _unpack_p += 4;
00487           } else {
00488             length = DCPackerInterface::do_unpack_uint16
00489               (_unpack_data + _unpack_p);
00490             _unpack_p += 2;
00491           }
00492           _pop_marker = _unpack_p + length;
00493         
00494           // The explicit length trumps the number of nested fields
00495           // reported by get_num_nested_fields().
00496           if (length == 0) {
00497             num_nested_fields = 0;
00498           } else {
00499             num_nested_fields = _current_parent->calc_num_nested_fields(length);
00500           }
00501         }
00502       }
00503     } else {
00504       _pack_error = true;
00505     }
00506 
00507 
00508     // Now point to the first field in the nested range.
00509     _num_nested_fields = num_nested_fields;
00510     _current_field_index = 0;
00511 
00512     if (_num_nested_fields >= 0 &&
00513         _current_field_index >= _num_nested_fields) {
00514       _current_field = NULL;
00515       
00516     } else {
00517       _current_field = _current_parent->get_nested_field(_current_field_index);
00518     }
00519   }
00520 }
00521 
00522 ////////////////////////////////////////////////////////////////////
00523 //     Function: DCPacker::pop
00524 //       Access: Published
00525 //  Description: Marks the end of a nested series of fields.
00526 //
00527 //               This must be called to match a previous push() only
00528 //               after all the expected number of nested fields have
00529 //               been packed.  It is an error to call it too early, or
00530 //               too late.
00531 ////////////////////////////////////////////////////////////////////
00532 void DCPacker::
00533 pop() {
00534   if (_current_field != NULL && _num_nested_fields >= 0) {
00535     // Oops, didn't pack or unpack enough values.
00536     _pack_error = true;
00537 
00538   } else if (_mode == M_unpack && _pop_marker != 0 && 
00539              _unpack_p != _pop_marker) {
00540     // Didn't unpack the right number of values.
00541     _pack_error = true;
00542   }
00543 
00544   if (_stack == NULL) {
00545     // Unbalanced pop().
00546     _pack_error = true;
00547 
00548   } else {
00549     if (!_current_parent->validate_num_nested_fields(_current_field_index)) {
00550       // Incorrect number of nested elements.
00551       _pack_error = true;
00552     }
00553 
00554     if (_mode == M_pack || _mode == M_repack) {
00555       size_t length_bytes = _current_parent->get_num_length_bytes();
00556       if (length_bytes != 0) {
00557         // Now go back and fill in the length of the array.
00558         size_t length = _pack_data.get_length() - _push_marker - length_bytes;
00559         if (length_bytes == 4) {
00560           DCPackerInterface::do_pack_uint32
00561             (_pack_data.get_rewrite_pointer(_push_marker, 4), length);
00562         } else {
00563           DCPackerInterface::validate_uint_limits(length, 16, _range_error);
00564           DCPackerInterface::do_pack_uint16
00565             (_pack_data.get_rewrite_pointer(_push_marker, 2), length);
00566         }
00567       }
00568     }
00569 
00570     _current_field = _current_parent;
00571     _current_parent = _stack->_current_parent;
00572     _current_field_index = _stack->_current_field_index;
00573     _push_marker = _stack->_push_marker;
00574     _pop_marker = _stack->_pop_marker;
00575     _num_nested_fields = (_current_parent == NULL) ? 0 : _current_parent->get_num_nested_fields();
00576 
00577     StackElement *next = _stack->_next;
00578     delete _stack;
00579     _stack = next;
00580   }
00581 
00582   advance();
00583 }
00584 
00585 ////////////////////////////////////////////////////////////////////
00586 //     Function: DCPacker::pack_default_value
00587 //       Access: Published
00588 //  Description: Adds the default value for the current element into
00589 //               the stream.  If no default has been set for the
00590 //               current element, creates a sensible default.
00591 ////////////////////////////////////////////////////////////////////
00592 void DCPacker::
00593 pack_default_value() {
00594   nassertv(_mode == M_pack || _mode == M_repack);
00595   if (_current_field == NULL) {
00596     _pack_error = true;
00597   } else {
00598     if (_current_field->pack_default_value(_pack_data, _pack_error)) {
00599       advance();
00600 
00601     } else {
00602       // If the single field didn't know how to pack a default value,
00603       // try packing nested fields.
00604       push();
00605       while (more_nested_fields()) {
00606         pack_default_value();
00607       }
00608       pop();
00609     }
00610   }
00611 }
00612 
00613 ////////////////////////////////////////////////////////////////////
00614 //     Function: DCPacker::unpack_validate
00615 //       Access: Published
00616 //  Description: Internally unpacks the current numeric or string
00617 //               value and validates it against the type range limits,
00618 //               but does not return the value.  If the current field
00619 //               contains nested fields, validates all of them.
00620 ////////////////////////////////////////////////////////////////////
00621 void DCPacker::
00622 unpack_validate() {
00623   nassertv(_mode == M_unpack);
00624   if (_current_field == NULL) {
00625     _pack_error = true;
00626 
00627   } else {
00628     if (_current_field->unpack_validate(_unpack_data, _unpack_length, _unpack_p,
00629                                         _pack_error, _range_error)) {
00630       advance();
00631     } else {
00632       // If the single field couldn't be validated, try validating
00633       // nested fields.
00634       push();
00635       while (more_nested_fields()) {
00636         unpack_validate();
00637       }
00638       pop();
00639     }
00640   }
00641 }
00642 
00643 ////////////////////////////////////////////////////////////////////
00644 //     Function: DCPacker::unpack_skip
00645 //       Access: Published
00646 //  Description: Skips the current field without unpacking it and
00647 //               advances to the next field.  If the current field
00648 //               contains nested fields, skips all of them.
00649 ////////////////////////////////////////////////////////////////////
00650 void DCPacker::
00651 unpack_skip() {
00652   nassertv(_mode == M_unpack);
00653   if (_current_field == NULL) {
00654     _pack_error = true;
00655 
00656   } else {
00657     if (_current_field->unpack_skip(_unpack_data, _unpack_length, _unpack_p,
00658                                     _pack_error)) {
00659       advance();
00660 
00661     } else {
00662       // If the single field couldn't be skipped, try skipping nested fields.
00663       push();
00664       while (more_nested_fields()) {
00665         unpack_skip();
00666       }
00667       pop();
00668     }
00669   }
00670 }
00671 
00672 #ifdef HAVE_PYTHON
00673 ////////////////////////////////////////////////////////////////////
00674 //     Function: DCPacker::pack_object
00675 //       Access: Published
00676 //  Description: Packs the Python object of whatever type into the
00677 //               packer.  Each numeric object and string object maps
00678 //               to the corresponding pack_value() call; a tuple or
00679 //               sequence maps to a push() followed by all of the
00680 //               tuple's contents followed by a pop().
00681 ////////////////////////////////////////////////////////////////////
00682 void DCPacker::
00683 pack_object(PyObject *object) {
00684   nassertv(_mode == M_pack || _mode == M_repack);
00685   DCPackType pack_type = get_pack_type();
00686 
00687   // had to add this for basic 64 and unsigned data to get packed right ..
00688   // Not sure if we can just do the rest this way..
00689 
00690  switch(pack_type)
00691   {
00692   case PT_int64:
00693       if(PyLong_Check(object))
00694       {
00695             pack_int64(PyLong_AsLongLong(object));
00696             return;
00697       }
00698       else if (PyInt_Check(object))
00699       {
00700             pack_int64(PyInt_AsLong(object));
00701             return;
00702       }
00703       break;
00704   case PT_uint64:
00705       if(PyLong_Check(object))
00706       {
00707             pack_uint64(PyLong_AsUnsignedLongLong(object));
00708             return;
00709       }
00710       else if(PyInt_Check(object))
00711       {
00712             PyObject  *obj1 = PyNumber_Long(object);
00713             pack_int(PyLong_AsUnsignedLongLong(obj1));
00714             Py_DECREF(obj1);
00715             return;
00716       }
00717       break;
00718   case PT_int:
00719       if(PyLong_Check(object))
00720       {
00721             pack_int(PyLong_AsLong(object));
00722             return;
00723       }
00724       else if (PyInt_Check(object))
00725       {
00726             pack_int(PyInt_AsLong(object));
00727             return;
00728       }
00729       break;
00730   case PT_uint:
00731       if(PyLong_Check(object))
00732       {
00733             pack_uint(PyLong_AsUnsignedLong(object));
00734             return;
00735       }
00736       else if (PyInt_Check(object))
00737       {
00738             PyObject  *obj1 = PyNumber_Long(object);
00739             pack_uint(PyLong_AsUnsignedLong(obj1));
00740             Py_DECREF(obj1);
00741             return;
00742       }
00743       break;
00744   default:
00745       break;
00746   }
00747   #ifdef USE_PYTHON_2_2_OR_EARLIER
00748   if (PyInt_Check(object)) {
00749   #else
00750   if (PyLong_Check(object)) {
00751     pack_int(PyLong_AsLong(object));
00752   } else if (PyInt_Check(object)) {
00753   #endif
00754     pack_int(PyInt_AS_LONG(object));
00755   } else if (PyFloat_Check(object)) {
00756     pack_double(PyFloat_AS_DOUBLE(object));
00757   } else if (PyLong_Check(object)) {
00758     pack_int64(PyLong_AsLongLong(object));
00759   } else if (PyString_Check(object) || PyUnicode_Check(object)) {
00760     char *buffer;
00761     Py_ssize_t length;
00762     PyString_AsStringAndSize(object, &buffer, &length);
00763     if (buffer) {
00764       pack_string(string(buffer, length));
00765     }
00766   } else {
00767     // For some reason, PySequence_Check() is incorrectly reporting
00768     // that a class instance is a sequence, even if it doesn't provide
00769     // __len__, so we double-check by testing for __len__ explicitly.
00770     bool is_sequence = 
00771       (PySequence_Check(object) != 0) &&
00772       (PyObject_HasAttrString(object, "__len__") != 0);
00773     bool is_instance = false;
00774 
00775     const DCClass *dclass = NULL;
00776     const DCPackerInterface *current_field = get_current_field();
00777     if (current_field != (DCPackerInterface *)NULL) {
00778       const DCClassParameter *class_param = get_current_field()->as_class_parameter();
00779       if (class_param != (DCClassParameter *)NULL) {
00780         dclass = class_param->get_class();
00781         
00782         if (dclass->has_class_def()) {
00783           PyObject *class_def = dclass->get_class_def();
00784           is_instance = (PyObject_IsInstance(object, dclass->get_class_def()) != 0);
00785           Py_DECREF(class_def);
00786         }
00787       }
00788     }
00789 
00790     // If dclass is not NULL, the packer is expecting a class object.
00791     // There are then two cases: (1) the user has supplied a matching
00792     // class object, or (2) the user has supplied a sequence object.
00793     // Unfortunately, it may be difficult to differentiate these two
00794     // cases, since a class object may also be a sequence object.
00795 
00796     // The rule to differentiate them is:
00797 
00798     // (1) If the supplied class object is an instance of the expected
00799     // class object, it is considered to be a class object.
00800 
00801     // (2) Otherwise, if the supplied class object has a __len__()
00802     // method (i.e. PySequence_Check() returns true), then it is
00803     // considered to be a sequence.
00804 
00805     // (3) Otherwise, it is considered to be a class object.
00806 
00807     if (dclass != (DCClass *)NULL && (is_instance || !is_sequence)) {
00808       // The supplied object is either an instance of the expected
00809       // class object, or it is not a sequence--this is case (1) or
00810       // (3).
00811       pack_class_object(dclass, object);
00812     } else if (is_sequence) {
00813       // The supplied object is not an instance of the expected class
00814       // object, but it is a sequence.  This is case (2).
00815       push();
00816       int size = PySequence_Size(object);
00817       for (int i = 0; i < size; ++i) {
00818         PyObject *element = PySequence_GetItem(object, i);
00819         if (element != (PyObject *)NULL) {
00820           pack_object(element);
00821           Py_DECREF(element);
00822         } else {
00823           cerr << "Unable to extract item " << i << " from sequence.\n";
00824         }
00825       }
00826       pop();
00827     } else {
00828       // The supplied object is not a sequence, and we weren't
00829       // expecting a class parameter.  This is none of the above, an
00830       // error.
00831       ostringstream strm;
00832       strm << "Don't know how to pack object: "
00833            << DCField::get_pystr(object);
00834       nassert_raise(strm.str());
00835       _pack_error = true;
00836     }
00837   }
00838 }
00839 #endif  // HAVE_PYTHON
00840 
00841 #ifdef HAVE_PYTHON
00842 ////////////////////////////////////////////////////////////////////
00843 //     Function: DCPacker::unpack_object
00844 //       Access: Published
00845 //  Description: Unpacks a Python object of the appropriate type from
00846 //               the stream for the current field.  This may be an
00847 //               integer or a string for a simple field object; if the
00848 //               current field represents a list of fields it will be
00849 //               a tuple.
00850 ////////////////////////////////////////////////////////////////////
00851 PyObject *DCPacker::
00852 unpack_object() {
00853   PyObject *object = NULL;
00854 
00855   DCPackType pack_type = get_pack_type();
00856 
00857   switch (pack_type) {
00858   case PT_invalid:
00859     object = Py_None;
00860     Py_INCREF(object);
00861     unpack_skip();
00862     break;
00863 
00864   case PT_double:
00865     {
00866       double value = unpack_double();
00867       object = PyFloat_FromDouble(value);
00868     }
00869     break;
00870       
00871   case PT_int:
00872     {
00873       int value = unpack_int();
00874       object = PyInt_FromLong(value);
00875     }
00876     break;
00877       
00878   case PT_uint:
00879     {
00880       unsigned int value = unpack_uint();
00881       if (value & 0x80000000) {
00882         object = PyLong_FromUnsignedLong(value);
00883       } else {
00884         object = PyInt_FromLong(value);
00885       }
00886     }
00887     break;
00888       
00889   case PT_int64:
00890     {
00891       PN_int64 value = unpack_int64();
00892       object = PyLong_FromLongLong(value);
00893     }
00894     break;
00895       
00896   case PT_uint64:
00897     {
00898       PN_uint64 value = unpack_uint64();
00899       object = PyLong_FromUnsignedLongLong(value);
00900     }
00901     break;
00902 
00903   case PT_string:
00904   case PT_blob:
00905     {
00906       string str;
00907       unpack_string(str);
00908       object = PyString_FromStringAndSize(str.data(), str.size());
00909     }
00910     break;
00911 
00912   case PT_class:
00913     {
00914       const DCClassParameter *class_param = get_current_field()->as_class_parameter();
00915       if (class_param != (DCClassParameter *)NULL) {
00916         const DCClass *dclass = class_param->get_class();
00917         if (dclass->has_class_def()) {
00918           // If we know what kind of class object this is and it has a
00919           // valid constructor, create the class object instead of
00920           // just a tuple.
00921           object = unpack_class_object(dclass);
00922           if (object == (PyObject *)NULL) {
00923             cerr << "Unable to construct object of class "
00924                  << dclass->get_name() << "\n";
00925           } else {
00926             break;
00927           }
00928         }
00929       }
00930     }
00931     // Fall through (if no constructor)
00932 
00933     // If we don't know what kind of class object it is, or it doesn't
00934     // have a constructor, fall through and make a tuple.
00935   default:
00936     {
00937       // First, build up a list from the nested objects.
00938       object = PyList_New(0);
00939 
00940       push();
00941       while (more_nested_fields()) {
00942         PyObject *element = unpack_object();
00943         PyList_Append(object, element);
00944         Py_DECREF(element);
00945       }
00946       pop();
00947 
00948       if (pack_type != PT_array) {
00949         // For these other kinds of objects, we'll convert the list
00950         // into a tuple.
00951         PyObject *tuple = PyList_AsTuple(object);
00952         Py_DECREF(object);
00953         object = tuple;
00954       }
00955     }
00956     break;
00957   }
00958 
00959   nassertr(object != (PyObject *)NULL, NULL);
00960   return object;
00961 }
00962 #endif  // HAVE_PYTHON
00963 
00964 
00965 ////////////////////////////////////////////////////////////////////
00966 //     Function: DCPacker::parse_and_pack
00967 //       Access: Published
00968 //  Description: Parses an object's value according to the DC file
00969 //               syntax (e.g. as a default value string) and packs it.
00970 //               Returns true on success, false on a parse error.
00971 ////////////////////////////////////////////////////////////////////
00972 bool DCPacker::
00973 parse_and_pack(const string &formatted_object) {
00974   istringstream strm(formatted_object);
00975   return parse_and_pack(strm);
00976 }
00977 
00978 ////////////////////////////////////////////////////////////////////
00979 //     Function: DCPacker::parse_and_pack
00980 //       Access: Published
00981 //  Description: Parses an object's value according to the DC file
00982 //               syntax (e.g. as a default value string) and packs it.
00983 //               Returns true on success, false on a parse error.
00984 ////////////////////////////////////////////////////////////////////
00985 bool DCPacker::
00986 parse_and_pack(istream &in) {
00987   dc_init_parser_parameter_value(in, "parse_and_pack", *this);
00988   dcyyparse();
00989   dc_cleanup_parser();
00990 
00991   bool parse_error = (dc_error_count() != 0);
00992   if (parse_error) {
00993     _parse_error = true;
00994   }
00995 
00996   return !parse_error;
00997 }
00998 
00999 ////////////////////////////////////////////////////////////////////
01000 //     Function: DCPacker::unpack_and_format
01001 //       Access: Published
01002 //  Description: Unpacks an object and formats its value into a syntax
01003 //               suitable for parsing in the dc file (e.g. as a
01004 //               default value), or as an input to parse_object.
01005 ////////////////////////////////////////////////////////////////////
01006 string DCPacker::
01007 unpack_and_format(bool show_field_names) {
01008   ostringstream strm;
01009   unpack_and_format(strm, show_field_names);
01010   return strm.str();
01011 }
01012 
01013 ////////////////////////////////////////////////////////////////////
01014 //     Function: DCPacker::unpack_and_format
01015 //       Access: Published
01016 //  Description: Unpacks an object and formats its value into a syntax
01017 //               suitable for parsing in the dc file (e.g. as a
01018 //               default value), or as an input to parse_object.
01019 ////////////////////////////////////////////////////////////////////
01020 void DCPacker::
01021 unpack_and_format(ostream &out, bool show_field_names) {
01022   DCPackType pack_type = get_pack_type();
01023 
01024   if (show_field_names && !get_current_field_name().empty()) {
01025     nassertv(_current_field != (DCPackerInterface *)NULL);
01026     const DCField *field = _current_field->as_field();
01027     if (field != (DCField *)NULL && 
01028         field->as_parameter() != (DCParameter *)NULL) {
01029       out << field->get_name() << " = ";
01030     }
01031   }
01032 
01033   switch (pack_type) {
01034   case PT_invalid:
01035     out << "<invalid>";
01036     break;
01037 
01038   case PT_double:
01039     out << unpack_double();
01040     break;
01041       
01042   case PT_int:
01043     out << unpack_int();
01044     break;
01045       
01046   case PT_uint:
01047     out << unpack_uint();
01048     break;
01049       
01050   case PT_int64:
01051     out << unpack_int64();
01052     break;
01053       
01054   case PT_uint64:
01055     out << unpack_uint64();
01056     break;
01057 
01058   case PT_string:
01059     enquote_string(out, '"', unpack_string());
01060     break;
01061 
01062   case PT_blob:
01063     output_hex_string(out, unpack_literal_value());
01064     break;
01065 
01066   default:
01067     {
01068       switch (pack_type) {
01069       case PT_array:
01070         out << '[';
01071         break;
01072 
01073       case PT_field:
01074       case PT_switch:
01075         out << '(';
01076         break;
01077 
01078       case PT_class:
01079       default:
01080         out << '{';
01081         break;
01082       }
01083 
01084       push();
01085       while (more_nested_fields() && !had_pack_error()) {
01086         unpack_and_format(out, show_field_names);
01087 
01088         if (more_nested_fields()) {
01089           out << ", ";
01090         }
01091       }
01092       pop();
01093 
01094       switch (pack_type) {
01095       case PT_array:
01096         out << ']';
01097         break;
01098 
01099       case PT_field:
01100       case PT_switch:
01101         out << ')';
01102         break;
01103 
01104       case PT_class:
01105       default:
01106         out << '}';
01107         break;
01108       }
01109     }
01110     break;
01111   }
01112 }
01113 
01114 ////////////////////////////////////////////////////////////////////
01115 //     Function: DCPacker::enquote_string
01116 //       Access: Public, Static
01117 //  Description: Outputs the indicated string within quotation marks.
01118 ////////////////////////////////////////////////////////////////////
01119 void DCPacker::
01120 enquote_string(ostream &out, char quote_mark, const string &str) {
01121   out << quote_mark;
01122   for (string::const_iterator pi = str.begin();
01123        pi != str.end();
01124        ++pi) {
01125     if ((*pi) == quote_mark || (*pi) == '\\') {
01126       out << '\\' << (*pi);
01127 
01128     } else if (!isprint(*pi)) {
01129       char buffer[10];
01130       sprintf(buffer, "%02x", (unsigned char)(*pi));
01131       out << "\\x" << buffer;
01132 
01133     } else {
01134       out << (*pi);
01135     }
01136   }
01137   out << quote_mark;
01138 }
01139 
01140 ////////////////////////////////////////////////////////////////////
01141 //     Function: DCPacker::output_hex_string
01142 //       Access: Public, Static
01143 //  Description: Outputs the indicated string as a hex constant.
01144 ////////////////////////////////////////////////////////////////////
01145 void DCPacker::
01146 output_hex_string(ostream &out, const string &str) {
01147   out << '<';
01148   for (string::const_iterator pi = str.begin();
01149        pi != str.end();
01150        ++pi) {
01151     char buffer[10];
01152     sprintf(buffer, "%02x", (unsigned char)(*pi));
01153     out << buffer;
01154   }
01155   out << '>';
01156 }
01157 
01158 ////////////////////////////////////////////////////////////////////
01159 //     Function: DCPacker::handle_switch
01160 //       Access: Private
01161 //  Description: When we advance past the key field on a switch
01162 //               record, we suddenly have more fields available--all
01163 //               the appropriate alternate fields in the switch.
01164 //
01165 //               This function is called when we detect this
01166 //               condition; it switches the _current_parent to the
01167 //               appropriate case of the switch record.
01168 ////////////////////////////////////////////////////////////////////
01169 void DCPacker::
01170 handle_switch(const DCSwitchParameter *switch_parameter) {
01171   // First, get the value from the key.  This is either found in the
01172   // unpack or the pack data, depending on what mode we're in.
01173   const DCPackerInterface *new_parent = NULL;
01174 
01175   if (_mode == M_pack || _mode == M_repack) {
01176     const char *data = _pack_data.get_data();
01177     new_parent = switch_parameter->apply_switch
01178       (data + _push_marker, _pack_data.get_length() - _push_marker);
01179 
01180   } else if (_mode == M_unpack) {
01181     new_parent = switch_parameter->apply_switch
01182       (_unpack_data + _push_marker, _unpack_p - _push_marker);
01183   }
01184 
01185   if (new_parent == (DCPackerInterface *)NULL) {
01186     // This means an invalid value was packed for the key.
01187     _range_error = true;
01188     return;
01189   }
01190 
01191   _last_switch = switch_parameter;
01192 
01193   // Now substitute in the switch case for the previous parent (which
01194   // replaces the switch node itself).  This will suddenly make a slew
01195   // of new fields appear.
01196   _current_parent = new_parent;
01197   _num_nested_fields = _current_parent->get_num_nested_fields();
01198 
01199   if (_num_nested_fields < 0 ||
01200       _current_field_index < _num_nested_fields) {
01201     _current_field = _current_parent->get_nested_field(_current_field_index);
01202   }
01203 }
01204 
01205 ////////////////////////////////////////////////////////////////////
01206 //     Function: DCPacker::clear
01207 //       Access: Private
01208 //  Description: Resets the data structures after a pack or unpack
01209 //               sequence.
01210 ////////////////////////////////////////////////////////////////////
01211 void DCPacker::
01212 clear() {
01213   clear_stack();
01214   _current_field = NULL;
01215   _current_parent = NULL;
01216   _current_field_index = 0;
01217   _num_nested_fields = 0;
01218   _push_marker = 0;
01219   _pop_marker = 0;
01220   _last_switch = NULL;
01221 
01222   if (_live_catalog != (DCPackerCatalog::LiveCatalog *)NULL) {
01223     _catalog->release_live_catalog(_live_catalog);
01224     _live_catalog = NULL;
01225   }
01226   _catalog = NULL;
01227   _root = NULL;
01228 }
01229 
01230 ////////////////////////////////////////////////////////////////////
01231 //     Function: DCPacker::clear_stack
01232 //       Access: Private
01233 //  Description: Empties the stack.
01234 ////////////////////////////////////////////////////////////////////
01235 void DCPacker::
01236 clear_stack() {
01237   while (_stack != (StackElement *)NULL) {
01238     StackElement *next = _stack->_next;
01239     delete _stack;
01240     _stack = next;
01241   }
01242 }
01243 
01244 #ifdef HAVE_PYTHON
01245 ////////////////////////////////////////////////////////////////////
01246 //     Function: DCPacker::pack_class_object
01247 //       Access: Private
01248 //  Description: Given that the current element is a ClassParameter
01249 //               for a Python class object, try to extract the
01250 //               appropriate values from the class object and pack in.
01251 ////////////////////////////////////////////////////////////////////
01252 void DCPacker::
01253 pack_class_object(const DCClass *dclass, PyObject *object) {
01254   push();
01255   while (more_nested_fields() && !_pack_error) {
01256     const DCField *field = get_current_field()->as_field();
01257     nassertv(field != (DCField *)NULL);
01258     get_class_element(dclass, object, field);
01259   }
01260   pop();
01261 }
01262 #endif  // HAVE_PYTHON
01263 
01264 #ifdef HAVE_PYTHON
01265 ////////////////////////////////////////////////////////////////////
01266 //     Function: DCPacker::unpack_class_object
01267 //       Access: Private
01268 //  Description: Given that the current element is a ClassParameter
01269 //               for a Python class for which we have a valid
01270 //               constructor, unpack it and fill in its values.
01271 ////////////////////////////////////////////////////////////////////
01272 PyObject *DCPacker::
01273 unpack_class_object(const DCClass *dclass) {
01274   PyObject *class_def = dclass->get_class_def();
01275   nassertr(class_def != (PyObject *)NULL, NULL);
01276 
01277   PyObject *object = NULL;
01278 
01279   if (!dclass->has_constructor()) {
01280     // If the class uses a default constructor, go ahead and create
01281     // the Python object for it now.
01282     object = PyObject_CallObject(class_def, NULL);
01283     if (object == (PyObject *)NULL) {
01284       return NULL;
01285     }
01286   }
01287 
01288   push();
01289   if (object == (PyObject *)NULL && more_nested_fields()) {
01290     // The first nested field will be the constructor.
01291     const DCField *field = get_current_field()->as_field();
01292     nassertr(field != (DCField *)NULL, object);
01293     nassertr(field == dclass->get_constructor(), object);
01294 
01295     set_class_element(class_def, object, field);
01296 
01297     // By now, the object should have been constructed.
01298     if (object == (PyObject *)NULL) {
01299       return NULL;
01300     }
01301   }
01302   while (more_nested_fields()) {
01303     const DCField *field = get_current_field()->as_field();
01304     nassertr(field != (DCField *)NULL, object);
01305 
01306     set_class_element(class_def, object, field);
01307   }
01308   pop();
01309 
01310   return object;
01311 }
01312 #endif  // HAVE_PYTHON
01313 
01314 
01315 #ifdef HAVE_PYTHON
01316 ////////////////////////////////////////////////////////////////////
01317 //     Function: DCPacker::set_class_element
01318 //       Access: Private
01319 //  Description: Unpacks the current element and stuffs it on the
01320 //               Python class object in whatever way is appropriate.
01321 ////////////////////////////////////////////////////////////////////
01322 void DCPacker::
01323 set_class_element(PyObject *class_def, PyObject *&object, 
01324                   const DCField *field) {
01325   string field_name = field->get_name();
01326   DCPackType pack_type = get_pack_type();
01327 
01328   if (field_name.empty()) {
01329     switch (pack_type) {
01330     case PT_class:
01331     case PT_switch:
01332       // If the field has no name, but it is one of these container
01333       // objects, we want to unpack its nested objects directly into
01334       // the class.
01335       push();
01336       while (more_nested_fields()) {
01337         const DCField *field = get_current_field()->as_field();
01338         nassertv(field != (DCField *)NULL);
01339         nassertv(object != (PyObject *)NULL);
01340         set_class_element(class_def, object, field);
01341       }
01342       pop();
01343       break;
01344 
01345     default:
01346       // Otherwise, we just skip over the field.
01347       unpack_skip();
01348     }
01349 
01350   } else {
01351     // If the field does have a name, we will want to store it on the
01352     // class, either by calling a method (for a PT_field pack_type) or
01353     // by setting a value (for any other kind of pack_type).
01354 
01355     PyObject *element = unpack_object();
01356 
01357     if (pack_type == PT_field) {
01358       if (object == (PyObject *)NULL) {
01359         // If the object hasn't been constructed yet, assume this is
01360         // the constructor.
01361         object = PyObject_CallObject(class_def, element);
01362 
01363       } else {
01364         if (PyObject_HasAttrString(object, (char *)field_name.c_str())) {
01365           PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str());
01366           if (func != (PyObject *)NULL) {
01367             PyObject *result = PyObject_CallObject(func, element);
01368             Py_XDECREF(result);
01369             Py_DECREF(func);
01370           }
01371         }
01372       }
01373       
01374     } else {
01375       nassertv(object != (PyObject *)NULL);
01376       PyObject_SetAttrString(object, (char *)field_name.c_str(), element);
01377     }
01378 
01379     Py_DECREF(element);
01380   }
01381 }
01382 #endif  // HAVE_PYTHON
01383 
01384 
01385 #ifdef HAVE_PYTHON
01386 ////////////////////////////////////////////////////////////////////
01387 //     Function: DCPacker::get_class_element
01388 //       Access: Private
01389 //  Description: Gets the current element from the Python object and
01390 //               packs it.
01391 ////////////////////////////////////////////////////////////////////
01392 void DCPacker::
01393 get_class_element(const DCClass *dclass, PyObject *object, 
01394                   const DCField *field) {
01395   string field_name = field->get_name();
01396   DCPackType pack_type = get_pack_type();
01397 
01398   if (field_name.empty()) {
01399     switch (pack_type) {
01400     case PT_class:
01401     case PT_switch:
01402       // If the field has no name, but it is one of these container
01403       // objects, we want to get its nested objects directly from
01404       // the class.
01405       push();
01406       while (more_nested_fields() && !_pack_error) {
01407         const DCField *field = get_current_field()->as_field();
01408         nassertv(field != (DCField *)NULL);
01409         get_class_element(dclass, object, field);
01410       }
01411       pop();
01412       break;
01413 
01414     default:
01415       // Otherwise, we just pack the default value.
01416       pack_default_value();
01417     }
01418 
01419   } else {
01420     // If the field does have a name, we will want to get it from the
01421     // class and pack it.  It just so happens that there's already a
01422     // method that does this on DCClass.
01423 
01424     if (!dclass->pack_required_field(*this, object, field)) {
01425       _pack_error = true;
01426     }
01427   }
01428 }
01429 #endif  // HAVE_PYTHON
 All Classes Functions Variables Enumerations