Panda3D
|
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 }