Panda3D

dcField.cxx

00001 // Filename: dcField.cxx
00002 // Created by:  drose (11Oct00)
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 "dcField.h"
00016 #include "dcFile.h"
00017 #include "dcPacker.h"
00018 #include "dcClass.h"
00019 #include "hashGenerator.h"
00020 #include "dcmsgtypes.h"
00021 
00022 #ifdef WITHIN_PANDA
00023 #include "pStatTimer.h"
00024 #endif
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: DCField::Constructor
00028 //       Access: Public
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 DCField::
00032 DCField() : 
00033   _dclass(NULL)
00034 #ifdef WITHIN_PANDA
00035   ,
00036   _field_update_pcollector("DCField")
00037 #endif
00038 {
00039   _number = -1;
00040   _default_value_stale = true;
00041   _has_default_value = false;
00042 
00043   _bogus_field = false;
00044 
00045   _has_nested_fields = true;
00046   _num_nested_fields = 0;
00047   _pack_type = PT_field;
00048 
00049   _has_fixed_byte_size = true;
00050   _fixed_byte_size = 0;
00051   _has_fixed_structure = true;
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: DCField::Constructor
00056 //       Access: Public
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 DCField::
00060 DCField(const string &name, DCClass *dclass) : 
00061   DCPackerInterface(name),
00062   _dclass(dclass)
00063 #ifdef WITHIN_PANDA
00064   ,
00065   _field_update_pcollector(dclass->_class_update_pcollector, name)
00066 #endif
00067 {
00068   _number = -1;
00069   _has_default_value = false;
00070   _default_value_stale = true;
00071 
00072   _bogus_field = false;
00073 
00074   _has_nested_fields = true;
00075   _num_nested_fields = 0;
00076   _pack_type = PT_field;
00077 
00078   _has_fixed_byte_size = true;
00079   _fixed_byte_size = 0;
00080   _has_fixed_structure = true;
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: DCField::Destructor
00085 //       Access: Public, Virtual
00086 //  Description:
00087 ////////////////////////////////////////////////////////////////////
00088 DCField::
00089 ~DCField() {
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: DCField::as_field
00094 //       Access: Published, Virtual
00095 //  Description: 
00096 ////////////////////////////////////////////////////////////////////
00097 DCField *DCField::
00098 as_field() {
00099   return this;
00100 }
00101 
00102 ////////////////////////////////////////////////////////////////////
00103 //     Function: DCField::as_field
00104 //       Access: Published, Virtual
00105 //  Description: 
00106 ////////////////////////////////////////////////////////////////////
00107 const DCField *DCField::
00108 as_field() const {
00109   return this;
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: DCField::as_atomic_field
00114 //       Access: Published, Virtual
00115 //  Description: Returns the same field pointer converted to an atomic
00116 //               field pointer, if this is in fact an atomic field;
00117 //               otherwise, returns NULL.
00118 ////////////////////////////////////////////////////////////////////
00119 DCAtomicField *DCField::
00120 as_atomic_field() {
00121   return (DCAtomicField *)NULL;
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: DCField::as_atomic_field
00126 //       Access: Published, Virtual
00127 //  Description: Returns the same field pointer converted to an atomic
00128 //               field pointer, if this is in fact an atomic field;
00129 //               otherwise, returns NULL.
00130 ////////////////////////////////////////////////////////////////////
00131 const DCAtomicField *DCField::
00132 as_atomic_field() const {
00133   return (DCAtomicField *)NULL;
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////
00137 //     Function: DCField::as_molecular_field
00138 //       Access: Published, Virtual
00139 //  Description: Returns the same field pointer converted to a
00140 //               molecular field pointer, if this is in fact a
00141 //               molecular field; otherwise, returns NULL.
00142 ////////////////////////////////////////////////////////////////////
00143 DCMolecularField *DCField::
00144 as_molecular_field() {
00145   return (DCMolecularField *)NULL;
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: DCField::as_molecular_field
00150 //       Access: Published, Virtual
00151 //  Description: Returns the same field pointer converted to a
00152 //               molecular field pointer, if this is in fact a
00153 //               molecular field; otherwise, returns NULL.
00154 ////////////////////////////////////////////////////////////////////
00155 const DCMolecularField *DCField::
00156 as_molecular_field() const {
00157   return (DCMolecularField *)NULL;
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: DCField::as_parameter
00162 //       Access: Published, Virtual
00163 //  Description: 
00164 ////////////////////////////////////////////////////////////////////
00165 DCParameter *DCField::
00166 as_parameter() {
00167   return (DCParameter *)NULL;
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: DCField::as_parameter
00172 //       Access: Published, Virtual
00173 //  Description: 
00174 ////////////////////////////////////////////////////////////////////
00175 const DCParameter *DCField::
00176 as_parameter() const {
00177   return (DCParameter *)NULL;
00178 }
00179 
00180 ////////////////////////////////////////////////////////////////////
00181 //     Function: DCField::format_data
00182 //       Access: Published
00183 //  Description: Given a blob that represents the packed data for this
00184 //               field, returns a string formatting it for human
00185 //               consumption.  Returns empty string if there is an error.
00186 ////////////////////////////////////////////////////////////////////
00187 string DCField::
00188 format_data(const string &packed_data, bool show_field_names) {
00189   DCPacker packer;
00190   packer.set_unpack_data(packed_data);
00191   packer.begin_unpack(this);
00192   string result = packer.unpack_and_format(show_field_names);
00193   if (!packer.end_unpack()) {
00194     return string();
00195   }
00196   return result;
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: DCField::parse_string
00201 //       Access: Published
00202 //  Description: Given a human-formatted string (for instance, as
00203 //               returned by format_data(), above) that represents the
00204 //               value of this field, parse the string and return the
00205 //               corresponding packed data.  Returns empty string if
00206 //               there is an error.
00207 ////////////////////////////////////////////////////////////////////
00208 string DCField::
00209 parse_string(const string &formatted_string) {
00210   DCPacker packer;
00211   packer.begin_pack(this);
00212   if (!packer.parse_and_pack(formatted_string)) {
00213     // Parse error.
00214     return string();
00215   }
00216   if (!packer.end_pack()) {
00217     // Data type mismatch.
00218     return string();
00219   }
00220 
00221   return packer.get_string();
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: DCField::validate_ranges
00226 //       Access: Published
00227 //  Description: Verifies that all of the packed values in the field
00228 //               data are within the specified ranges and that there
00229 //               are no extra bytes on the end of the record.  Returns
00230 //               true if all fields are valid, false otherwise.
00231 ////////////////////////////////////////////////////////////////////
00232 bool DCField::
00233 validate_ranges(const string &packed_data) const {
00234   DCPacker packer;
00235   packer.set_unpack_data(packed_data);
00236   packer.begin_unpack(this);
00237   packer.unpack_validate();
00238   if (!packer.end_unpack()) {
00239     return false;
00240   }
00241 
00242   return (packer.get_num_unpacked_bytes() == packed_data.length());
00243 }
00244 
00245 #ifdef HAVE_PYTHON
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: DCField::pack_args
00248 //       Access: Published
00249 //  Description: Packs the Python arguments from the indicated tuple
00250 //               into the packer.  Returns true on success, false on
00251 //               failure.
00252 //
00253 //               It is assumed that the packer is currently positioned
00254 //               on this field.
00255 ////////////////////////////////////////////////////////////////////
00256 bool DCField::
00257 pack_args(DCPacker &packer, PyObject *sequence) const {
00258   nassertr(!packer.had_error(), false);
00259   nassertr(packer.get_current_field() == this, false);
00260 
00261   packer.pack_object(sequence);
00262   if (!packer.had_error()) {
00263     /*
00264     cerr << "pack " << get_name() << get_pystr(sequence) << "\n";
00265     */
00266 
00267     return true;
00268   }
00269 
00270   if (!Notify::ptr()->has_assert_failed()) {
00271     ostringstream strm;
00272     PyObject *exc_type = PyExc_StandardError;
00273 
00274     if (as_parameter() != (DCParameter *)NULL) {
00275       // If it's a parameter-type field, the value may or may not be a
00276       // sequence.
00277       if (packer.had_pack_error()) {
00278         strm << "Incorrect arguments to field: " << get_name()
00279              << " = " << get_pystr(sequence);
00280         exc_type = PyExc_TypeError;
00281       } else {
00282         strm << "Value out of range on field: " << get_name()
00283              << " = " << get_pystr(sequence);
00284         exc_type = PyExc_ValueError;
00285       }
00286 
00287     } else {
00288       // If it's a molecular or atomic field, the value should be a
00289       // sequence.
00290       PyObject *tuple = PySequence_Tuple(sequence);
00291       if (tuple == (PyObject *)NULL) {
00292         strm << "Value for " << get_name() << " not a sequence: " \
00293              << get_pystr(sequence);
00294         exc_type = PyExc_TypeError;
00295 
00296       } else {
00297         if (packer.had_pack_error()) {
00298           strm << "Incorrect arguments to field: " << get_name()
00299                << get_pystr(sequence);
00300           exc_type = PyExc_TypeError;
00301         } else {
00302           strm << "Value out of range on field: " << get_name()
00303                << get_pystr(sequence);
00304           exc_type = PyExc_ValueError;
00305         }
00306         
00307         Py_DECREF(tuple);
00308       }
00309     }
00310 
00311     string message = strm.str();
00312     PyErr_SetString(exc_type, message.c_str());
00313   }
00314   return false;
00315 }
00316 #endif  // HAVE_PYTHON
00317 
00318 #ifdef HAVE_PYTHON
00319 ////////////////////////////////////////////////////////////////////
00320 //     Function: DCField::unpack_args
00321 //       Access: Published
00322 //  Description: Unpacks the values from the packer, beginning at
00323 //               the current point in the unpack_buffer, into a Python
00324 //               tuple and returns the tuple.
00325 //
00326 //               It is assumed that the packer is currently positioned
00327 //               on this field.
00328 ////////////////////////////////////////////////////////////////////
00329 PyObject *DCField::
00330 unpack_args(DCPacker &packer) const {
00331   nassertr(!packer.had_error(), NULL);
00332   nassertr(packer.get_current_field() == this, NULL);
00333 
00334   size_t start_byte = packer.get_num_unpacked_bytes();
00335   PyObject *object = packer.unpack_object();
00336 
00337   if (!packer.had_error()) {
00338     // Successfully unpacked.
00339     /*
00340     cerr << "recv " << get_name() << get_pystr(object) << "\n";
00341     */
00342 
00343     return object;
00344   }
00345 
00346   if (!Notify::ptr()->has_assert_failed()) {
00347     ostringstream strm;
00348     PyObject *exc_type = PyExc_StandardError;
00349 
00350     if (packer.had_pack_error()) {
00351       strm << "Data error unpacking field ";
00352       output(strm, true);
00353       size_t length = packer.get_unpack_length() - start_byte;
00354       strm << "\nGot data (" << (int)length << " bytes):\n";
00355       Datagram dg(packer.get_unpack_data() + start_byte, length);
00356       dg.dump_hex(strm);
00357       size_t error_byte = packer.get_num_unpacked_bytes() - start_byte;
00358       strm << "Error detected on byte " << error_byte
00359            << " (" << hex << error_byte << dec << " hex)";
00360 
00361       exc_type = PyExc_RuntimeError;
00362     } else {
00363       strm << "Value outside specified range when unpacking field " 
00364            << get_name() << ": " << get_pystr(object);
00365       exc_type = PyExc_ValueError;
00366     }
00367     
00368     string message = strm.str();
00369     PyErr_SetString(exc_type, message.c_str());
00370   }
00371 
00372   Py_XDECREF(object);
00373   return NULL;
00374 }
00375 #endif  // HAVE_PYTHON
00376 
00377 #ifdef HAVE_PYTHON
00378 ////////////////////////////////////////////////////////////////////
00379 //     Function: DCField::receive_update
00380 //       Access: Published
00381 //  Description: Extracts the update message out of the datagram and
00382 //               applies it to the indicated object by calling the
00383 //               appropriate method.
00384 ////////////////////////////////////////////////////////////////////
00385 void DCField::
00386 receive_update(DCPacker &packer, PyObject *distobj) const {
00387   if (as_parameter() != (DCParameter *)NULL) {
00388     // If it's a parameter-type field, just store a new value on the
00389     // object.
00390     PyObject *value = unpack_args(packer);
00391     if (value != (PyObject *)NULL) {
00392       PyObject_SetAttrString(distobj, (char *)_name.c_str(), value);
00393     }
00394     Py_DECREF(value);
00395 
00396   } else {
00397     // Otherwise, it must be an atomic or molecular field, so call the
00398     // corresponding method.
00399 
00400     if (!PyObject_HasAttrString(distobj, (char *)_name.c_str())) {
00401       // If there's no Python method to receive this message, don't
00402       // bother unpacking it to a Python tuple--just skip past the
00403       // message.
00404       packer.unpack_skip();
00405 
00406     } else {
00407       // Otherwise, get a Python tuple from the args and call the Python
00408       // method.
00409       PyObject *args = unpack_args(packer);
00410 
00411       if (args != (PyObject *)NULL) {
00412         PyObject *func = PyObject_GetAttrString(distobj, (char *)_name.c_str());
00413         nassertv(func != (PyObject *)NULL);
00414       
00415         PyObject *result;
00416         {
00417 #ifdef WITHIN_PANDA
00418           PStatTimer timer(((DCField *)this)->_field_update_pcollector);
00419 #endif
00420           result = PyObject_CallObject(func, args);
00421         }
00422         Py_XDECREF(result);
00423         Py_DECREF(func);
00424         Py_DECREF(args);
00425       }
00426     }
00427   }
00428 }
00429 #endif  // HAVE_PYTHON
00430 
00431 #ifdef HAVE_PYTHON
00432 ////////////////////////////////////////////////////////////////////
00433 //     Function: DCField::client_format_update
00434 //       Access: Published
00435 //  Description: Generates a datagram containing the message necessary
00436 //               to send an update for the indicated distributed
00437 //               object from the client.
00438 ////////////////////////////////////////////////////////////////////
00439 Datagram DCField::
00440 client_format_update(DOID_TYPE do_id, PyObject *args) const {
00441   DCPacker packer;
00442 
00443   packer.raw_pack_uint16(CLIENT_OBJECT_UPDATE_FIELD);
00444   packer.raw_pack_uint32(do_id);
00445   packer.raw_pack_uint16(_number);
00446 
00447   packer.begin_pack(this);
00448   pack_args(packer, args);
00449   if (!packer.end_pack()) {
00450     return Datagram();
00451   }
00452 
00453   return Datagram(packer.get_data(), packer.get_length());
00454 }
00455 #endif  // HAVE_PYTHON
00456 
00457 #ifdef HAVE_PYTHON
00458 ////////////////////////////////////////////////////////////////////
00459 //     Function: DCField::ai_format_update
00460 //       Access: Published
00461 //  Description: Generates a datagram containing the message necessary
00462 //               to send an update for the indicated distributed
00463 //               object from the AI.
00464 ////////////////////////////////////////////////////////////////////
00465 Datagram DCField::
00466 ai_format_update(DOID_TYPE do_id, CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args) const {
00467   DCPacker packer;
00468 
00469   packer.raw_pack_uint8(1);
00470   packer.RAW_PACK_CHANNEL(to_id);
00471   packer.RAW_PACK_CHANNEL(from_id);
00472   packer.raw_pack_uint16(STATESERVER_OBJECT_UPDATE_FIELD);
00473   packer.raw_pack_uint32(do_id);
00474   packer.raw_pack_uint16(_number);
00475 
00476   packer.begin_pack(this);
00477   pack_args(packer, args);
00478   if (!packer.end_pack()) {
00479     return Datagram();
00480   }
00481 
00482   return Datagram(packer.get_data(), packer.get_length());
00483 }
00484 #endif  // HAVE_PYTHON
00485 
00486 #ifdef HAVE_PYTHON
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: DCField::ai_format_update_msg_type
00489 //       Access: Published
00490 //  Description: Generates a datagram containing the message necessary
00491 //               to send an update, with the msg type,
00492 //               for the indicated distributed
00493 //               object from the AI.
00494 ////////////////////////////////////////////////////////////////////
00495 Datagram DCField::
00496 ai_format_update_msg_type(DOID_TYPE do_id, CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, int msg_type, PyObject *args) const {
00497   DCPacker packer;
00498 
00499   packer.raw_pack_uint8(1);
00500   packer.RAW_PACK_CHANNEL(to_id);
00501   packer.RAW_PACK_CHANNEL(from_id);
00502   packer.raw_pack_uint16(msg_type);
00503   packer.raw_pack_uint32(do_id);
00504   packer.raw_pack_uint16(_number);
00505 
00506   packer.begin_pack(this);
00507   pack_args(packer, args);
00508   if (!packer.end_pack()) {
00509     return Datagram();
00510   }
00511 
00512   return Datagram(packer.get_data(), packer.get_length());
00513 }
00514 #endif  // HAVE_PYTHON
00515 
00516 
00517 ////////////////////////////////////////////////////////////////////
00518 //     Function: DCField::generate_hash
00519 //       Access: Public, Virtual
00520 //  Description: Accumulates the properties of this field into the
00521 //               hash.
00522 ////////////////////////////////////////////////////////////////////
00523 void DCField::
00524 generate_hash(HashGenerator &hashgen) const {
00525   // It shouldn't be necessary to explicitly add _number to the
00526   // hash--this is computed based on the relative position of this
00527   // field with the other fields, so adding it explicitly will be
00528   // redundant.  However, the field name is significant.
00529   hashgen.add_string(_name);
00530 
00531   // Actually, we add _number anyway, since we need to ensure the hash
00532   // code comes out different in the dc_multiple_inheritance case.
00533   if (dc_multiple_inheritance) {
00534     hashgen.add_int(_number);
00535   }
00536 }
00537 
00538 ////////////////////////////////////////////////////////////////////
00539 //     Function: DCField::pack_default_value
00540 //       Access: Public, Virtual
00541 //  Description: Packs the field's specified default value (or a
00542 //               sensible default if no value is specified) into the
00543 //               stream.  Returns true if the default value is packed,
00544 //               false if the field doesn't know how to pack its
00545 //               default value.
00546 ////////////////////////////////////////////////////////////////////
00547 bool DCField::
00548 pack_default_value(DCPackData &pack_data, bool &) const {
00549   // The default behavior is to pack the default value if we got it;
00550   // otherwise, to return false and let the packer visit our nested
00551   // elements.
00552   if (!_default_value_stale) {
00553     pack_data.append_data(_default_value.data(), _default_value.length());
00554     return true;
00555   }
00556 
00557   return false;
00558 }
00559 
00560 ////////////////////////////////////////////////////////////////////
00561 //     Function: DCField::set_name
00562 //       Access: Public, Virtual
00563 //  Description: Sets the name of this field.
00564 ////////////////////////////////////////////////////////////////////
00565 void DCField::
00566 set_name(const string &name) {
00567   DCPackerInterface::set_name(name);
00568   if (_dclass != (DCClass *)NULL) {
00569     _dclass->_dc_file->mark_inherited_fields_stale();
00570   }
00571 }
00572 
00573 #ifdef HAVE_PYTHON
00574 ////////////////////////////////////////////////////////////////////
00575 //     Function: DCField::get_pystr
00576 //       Access: Public, Static
00577 //  Description: Returns the string representation of the indicated
00578 //               Python object.
00579 ////////////////////////////////////////////////////////////////////
00580 string DCField::
00581 get_pystr(PyObject *value) {
00582   if (value == NULL) {
00583     return "(null)";
00584   }
00585 
00586   PyObject *str = PyObject_Str(value);
00587   if (str != NULL) {
00588     string result = PyString_AsString(str);
00589     Py_DECREF(str);
00590     return result;
00591   }
00592 
00593   PyObject *repr = PyObject_Repr(value);
00594   if (repr != NULL) {
00595     string result = PyString_AsString(repr);
00596     Py_DECREF(repr);
00597     return result;
00598   }
00599 
00600   if (value->ob_type != NULL) {
00601     PyObject *typestr = PyObject_Str((PyObject *)(value->ob_type));
00602     if (typestr != NULL) {
00603       string result = PyString_AsString(typestr);
00604       Py_DECREF(typestr);
00605       return result;
00606     }
00607   }
00608 
00609   return "(invalid object)";
00610 }
00611 #endif  // HAVE_PYTHON
00612 
00613 ////////////////////////////////////////////////////////////////////
00614 //     Function: DCField::refresh_default_value
00615 //       Access: Protected
00616 //  Description: Recomputes the default value of the field by
00617 //               repacking it.
00618 ////////////////////////////////////////////////////////////////////
00619 void DCField::
00620 refresh_default_value() {
00621   DCPacker packer;
00622   packer.begin_pack(this);
00623   packer.pack_default_value();
00624   if (!packer.end_pack()) {
00625     cerr << "Error while packing default value for " << get_name() << "\n";
00626   } else {
00627     _default_value.assign(packer.get_data(), packer.get_length());
00628   }
00629   _default_value_stale = false;
00630 }
 All Classes Functions Variables Enumerations