| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- // Filename: p3dMainObject.cxx
- // Created by: drose (10Jul09)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) Carnegie Mellon University. All rights reserved.
- //
- // All use of this software is subject to the terms of the revised BSD
- // license. You should have received a copy of this license along
- // with this source code in a file named "LICENSE."
- //
- ////////////////////////////////////////////////////////////////////
- #include "p3dMainObject.h"
- #include "p3dInstance.h"
- #include "p3dSession.h"
- #include "p3dStringObject.h"
- #include "p3dInstanceManager.h"
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- P3DMainObject::
- P3DMainObject() :
- _pyobj(NULL),
- _inst(NULL),
- _unauth_play(false)
- {
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::Destructor
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- P3DMainObject::
- ~P3DMainObject() {
- set_pyobj(NULL);
- // Clear the local properties.
- Properties::const_iterator pi;
- for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
- P3D_object *value = (*pi).second;
- P3D_OBJECT_DECREF(value);
- }
- _properties.clear();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_type
- // Access: Public, Virtual
- // Description: Returns the fundamental type of this kind of object.
- ////////////////////////////////////////////////////////////////////
- P3D_object_type P3DMainObject::
- get_type() {
- return P3D_OT_object;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_bool
- // Access: Public, Virtual
- // Description: Returns the object value coerced to a boolean, if
- // possible.
- ////////////////////////////////////////////////////////////////////
- bool P3DMainObject::
- get_bool() {
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_int
- // Access: Public, Virtual
- // Description: Returns the object value coerced to an integer, if
- // possible.
- ////////////////////////////////////////////////////////////////////
- int P3DMainObject::
- get_int() {
- return 0;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_float
- // Access: Public, Virtual
- // Description: Returns the object value coerced to a floating-point
- // value, if possible.
- ////////////////////////////////////////////////////////////////////
- double P3DMainObject::
- get_float() {
- return 0.0;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::make_string
- // Access: Public, Virtual
- // Description: Fills the indicated C++ string object with the value
- // of this object coerced to a string.
- ////////////////////////////////////////////////////////////////////
- void P3DMainObject::
- make_string(string &value) {
- if (_pyobj == NULL) {
- value = "P3DMainObject";
- } else {
- int size = P3D_OBJECT_GET_STRING(_pyobj, NULL, 0);
- char *buffer = new char[size];
- P3D_OBJECT_GET_STRING(_pyobj, buffer, size);
- value = string(buffer, size);
- delete[] buffer;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_property
- // Access: Public, Virtual
- // Description: Returns the named property element in the object. The
- // return value is a new-reference P3D_object, or NULL
- // on error.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- get_property(const string &property) {
- if (_pyobj == NULL) {
- // Without a pyobj, we just report whatever's been stored locally.
- Properties::const_iterator pi;
- pi = _properties.find(property);
- if (pi != _properties.end()) {
- P3D_object *result = (*pi).second;
- P3D_OBJECT_INCREF(result);
- return result;
- }
- return NULL;
- }
- // With a pyobj, we pass the query down to it.
- return P3D_OBJECT_GET_PROPERTY(_pyobj, property.c_str());
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::set_property
- // Access: Public, Virtual
- // Description: Modifies (or deletes, if value is NULL) the named
- // property element in the object. Returns true on
- // success, false on failure.
- ////////////////////////////////////////////////////////////////////
- bool P3DMainObject::
- set_property(const string &property, bool needs_response, P3D_object *value) {
- // First, we set the property locally.
- if (value != NULL) {
- Properties::iterator pi;
- pi = _properties.insert(Properties::value_type(property, NULL)).first;
- assert(pi != _properties.end());
- P3D_object *orig_value = (*pi).second;
- if (orig_value != value) {
- P3D_OBJECT_XDECREF(orig_value);
- (*pi).second = value;
- P3D_OBJECT_INCREF(value);
- }
- } else {
- // (Or delete the property locally.)
- Properties::iterator pi;
- pi = _properties.find(property);
- if (pi != _properties.end()) {
- P3D_object *orig_value = (*pi).second;
- P3D_OBJECT_DECREF(orig_value);
- _properties.erase(pi);
- }
- }
- if (_pyobj == NULL) {
- // Without a pyobj, that's all we do.
- return true;
- }
- // With a pyobj, we also pass this request down.
- return P3D_OBJECT_SET_PROPERTY(_pyobj, property.c_str(), needs_response, value);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::has_method
- // Access: Public, Virtual
- // Description: Returns true if the named method exists on this
- // object, false otherwise.
- ////////////////////////////////////////////////////////////////////
- bool P3DMainObject::
- has_method(const string &method_name) {
- // Some special-case methods implemented in-place.
- if (method_name == "play") {
- return true;
- } else if (method_name == "read_game_log") {
- return true;
- } else if (method_name == "read_system_log") {
- return true;
- } else if (method_name == "read_log") {
- return true;
- } else if (method_name == "uninstall") {
- return true;
- }
- if (_pyobj == NULL) {
- // No methods until we get our pyobj.
- return false;
- }
- return P3D_OBJECT_HAS_METHOD(_pyobj, method_name.c_str());
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call
- // Access: Public, Virtual
- // Description: Invokes the named method on the object, passing the
- // indicated parameters. If the method name is empty,
- // invokes the object itself.
- //
- // If needs_response is true, the return value is a
- // new-reference P3D_object on success, or NULL on
- // failure. If needs_response is false, the return
- // value is always NULL, and there is no way to
- // determine success or failure.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call(const string &method_name, bool needs_response,
- P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- if (method_name == "play") {
- return call_play(params, num_params);
- } else if (method_name == "read_game_log") {
- return call_read_game_log(params, num_params);
- } else if (method_name == "read_system_log") {
- return call_read_system_log(params, num_params);
- } else if (method_name == "read_log") {
- return call_read_log(params, num_params);
- } else if (method_name == "uninstall") {
- return call_uninstall(params, num_params);
- }
- if (_pyobj == NULL) {
- // No methods until we get our pyobj.
- return NULL;
- }
- return P3D_OBJECT_CALL(_pyobj, method_name.c_str(), needs_response,
- params, num_params);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::output
- // Access: Public, Virtual
- // Description: Writes a formatted representation of the value to the
- // indicated string. This is intended for developer
- // assistance.
- ////////////////////////////////////////////////////////////////////
- void P3DMainObject::
- output(ostream &out) {
- out << "P3DMainObject";
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::set_pyobj
- // Access: Public
- // Description: Changes the internal pyobj pointer. This is the
- // P3D_object that references the actual PyObject held
- // within the child process, corresponding to the true
- // main object there. The new object's reference
- // count is incremented, and the previous object's is
- // decremented.
- ////////////////////////////////////////////////////////////////////
- void P3DMainObject::
- set_pyobj(P3D_object *pyobj) {
- if (_pyobj != pyobj) {
- P3D_OBJECT_XDECREF(_pyobj);
- _pyobj = pyobj;
- if (_pyobj != NULL) {
- P3D_OBJECT_INCREF(_pyobj);
- // Now that we have a pyobj, we have to transfer down all of the
- // properties we'd set locally.
- Properties::const_iterator pi;
- for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
- const string &property_name = (*pi).first;
- P3D_object *value = (*pi).second;
- P3D_OBJECT_SET_PROPERTY(_pyobj, property_name.c_str(), false, value);
- }
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::get_pyobj
- // Access: Public
- // Description: Returns the internal pyobj pointer, or NULL if it has
- // not yet been set.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- get_pyobj() const {
- return _pyobj;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::set_instance
- // Access: Public
- // Description: Sets a callback pointer to the instance that owns
- // this object. When this instance destructs, it clears
- // this pointer to NULL.
- ////////////////////////////////////////////////////////////////////
- void P3DMainObject::
- set_instance(P3DInstance *inst) {
- if (_inst != NULL) {
- // Save the game log filename of the instance just before it goes
- // away, in case JavaScript asks for it later.
- _game_log_pathname = _inst->get_log_pathname();
- }
- _inst = inst;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call_play
- // Access: Private
- // Description: Starts the process remotely, as if the play button
- // had been clicked. If the application has not yet
- // been validated, this pops up the validation dialog.
- //
- // Only applicable if the application was in the ready
- // state, or the unauth state. Returns true if the
- // application is now started, false otherwise.
- //
- // This may be invoked from the unauth state only once.
- // If the user chooses not to authorize the plugin at
- // that time, it may not be invoked automatically again.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call_play(P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- if (_inst == NULL) {
- return inst_mgr->new_bool_object(false);
- }
- // I guess there's no harm in allowing JavaScript to call play(),
- // with or without explicit scripting authorization.
- nout << "play() called from JavaScript\n";
- if (!_inst->is_trusted()) {
- // Requires authorization. We allow this only once; beyond that,
- // and you're only annoying the user.
- if (!_unauth_play) {
- _unauth_play = true;
- _inst->splash_button_clicked_main_thread();
- }
- } else if (!_inst->is_started()) {
- // We allow calling play() from a ready state without limit, but
- // probably only once will be necessary.
- _inst->splash_button_clicked_main_thread();
- }
-
- return inst_mgr->new_bool_object(_inst->is_started());
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call_read_game_log
- // Access: Private
- // Description: Reads the entire logfile as a string, and returns it
- // to the calling JavaScript process.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call_read_game_log(P3D_object *params[], int num_params) {
- if (_inst != NULL) {
- string log_pathname = _inst->get_log_pathname();
- return read_log(log_pathname, params, num_params);
- }
- if (!_game_log_pathname.empty()) {
- // The instance has already finished, but we saved its log
- // filename.
- return read_log(_game_log_pathname, params, num_params);
- }
- // No log available for us.
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- return inst_mgr->new_undefined_object();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call_read_system_log
- // Access: Private
- // Description: As above, but reads the system log, the logfile for
- // the installation process.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call_read_system_log(P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- string log_pathname = inst_mgr->get_log_pathname();
- return read_log(log_pathname, params, num_params);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call_read_log
- // Access: Private
- // Description: Reads a named logfile. The filename must end
- // in ".log" and must not contain any slashes or colons
- // (it must be found within the log directory).
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call_read_log(P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- if (num_params < 1) {
- return inst_mgr->new_undefined_object();
- }
- int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0);
- char *buffer = new char[size];
- P3D_OBJECT_GET_STRING(params[0], buffer, size);
- string log_filename = string(buffer, size);
- delete[] buffer;
- if (log_filename.size() < 4 || log_filename.substr(log_filename.size() - 4) != string(".log")) {
- // Wrong filename extension.
- return inst_mgr->new_undefined_object();
- }
- size_t slash = log_filename.find('/');
- if (slash != string::npos) {
- // No slashes allowed.
- return inst_mgr->new_undefined_object();
- }
- slash = log_filename.find('\\');
- if (slash != string::npos) {
- // Nor backslashes.
- return inst_mgr->new_undefined_object();
- }
- size_t colon = log_filename.find(':');
- if (colon != string::npos) {
- // Nor colons, for that matter.
- return inst_mgr->new_undefined_object();
- }
- string log_pathname = inst_mgr->get_log_directory() + log_filename;
- return read_log(log_pathname, params + 1, num_params - 1);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::read_log
- // Access: Private
- // Description: log-reader meta function that handles reading
- // previous log files in addition to the present one
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- read_log(const string &log_pathname, P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- string log_directory = inst_mgr->get_log_directory();
- ostringstream log_data;
- // Check the first parameter, if any--if given, it specifies the
- // last n bytes to retrieve.
- size_t tail_bytes = 0;
- if (num_params > 0) {
- tail_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[0]), 0);
- }
- // Check the second parameter, if any--if given, it specifies the
- // first n bytes to retrieve.
- size_t head_bytes = 0;
- if (num_params > 1) {
- head_bytes = (size_t)max(P3D_OBJECT_GET_INT(params[1]), 0);
- }
- // Check the third parameter, if any--if given, it specifies the
- // last n bytes to retrieve from previous copies of this file.
- size_t tail_bytes_prev = 0;
- if (num_params > 2) {
- tail_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[2]), 0);
- }
- // Read the log data from the primary file
- read_log_file(log_pathname, tail_bytes, head_bytes, log_data);
- // Read data from previous logs if requested
- if (tail_bytes_prev > 0) {
- // Determine the base of the log file names
- string log_basename = log_pathname;
- size_t slash = log_basename.rfind('/');
- if (slash != string::npos) {
- log_basename = log_basename.substr(slash + 1);
- }
- #ifdef _WIN32
- slash = log_basename.rfind('\\');
- if (slash != string::npos) {
- log_basename = log_basename.substr(slash + 1);
- }
- #endif // _WIN32
- string log_basename_primary = log_basename;
- int dash = log_basename.rfind("-");
- if (dash != string::npos) {
- log_basename = log_basename.substr(0, dash+1);
- } else {
- int dotLog = log_basename.rfind(".log");
- if (dotLog != string::npos) {
- log_basename = log_basename.substr(0, dotLog);
- log_basename += "-";
- }
- }
- // Find matching files
- vector<string> all_logs;
- inst_mgr->scan_directory(log_directory, all_logs);
- for (int i=(int)all_logs.size()-1; i>=0; --i) {
- if ((all_logs[i].find(log_basename) == 0) &&
- (all_logs[i] != log_basename_primary) &&
- (all_logs[i].size() > 4) &&
- (all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
- read_log_file((log_directory+all_logs[i]), tail_bytes_prev, 0, log_data);
- }
- }
- }
- P3D_object *result = new P3DStringObject(log_data.str().c_str(), log_data.tellp());
- return result;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::read_log_file
- // Access: Private
- // Description: The generic log-reader function.
- ////////////////////////////////////////////////////////////////////
- void P3DMainObject::
- read_log_file(const string &log_pathname,
- size_t tail_bytes, size_t head_bytes,
- ostringstream &log_data) {
-
- // Get leaf name
- string log_leafname = log_pathname;
- size_t slash = log_leafname.rfind('/');
- if (slash != string::npos) {
- log_leafname = log_leafname.substr(slash + 1);
- }
- #ifdef _WIN32
- slash = log_leafname.rfind('\\');
- if (slash != string::npos) {
- log_leafname = log_leafname.substr(slash + 1);
- }
- #endif // _WIN32
- // load file
- ifstream log(log_pathname.c_str(), ios::in);
- if (!log) {
- return;
- }
- // Get the size of the file.
- log.seekg(0, ios::end);
- size_t file_size = (size_t)log.tellg();
- nout << "read_log: " << log_pathname << " is " << file_size
- << " bytes, tail_bytes = " << tail_bytes << ", head_bytes = "
- << head_bytes << "\n";
- // Check if we are getting the full file
- size_t full_bytes = 0;
- if (file_size <= head_bytes + tail_bytes) {
- // We will return the entire log.
- full_bytes = file_size;
- head_bytes = 0;
- tail_bytes = 0;
- }
- // Allocate a temp buffer to hold file data
- size_t buffer_bytes = full_bytes + head_bytes + tail_bytes + 1;
- nout << "allocating " << buffer_bytes << " bytes to read from file.\n";
- char *buffer = new char[buffer_bytes];
- if (buffer == NULL) {
- return;
- }
- // Render log file header to log_data
- log_data << "=======================================";
- log_data << "=======================================" << "\n";
- log_data << "== PandaLog-" << log_pathname << "\n";
- // Render log data if full file is to be fetched
- if (full_bytes > 0) {
- log.seekg(0, ios::beg);
- log.read(buffer, full_bytes);
- buffer[log.gcount()] = NULL;
- log_data << "== PandaLog-" << "Full Start";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- log_data << buffer;
- log_data << "== PandaLog-" << "Full End";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- }
- // Render log data if head bytes are to be fetched
- if (head_bytes > 0) {
- log.seekg(0, ios::beg);
- log.read(buffer, head_bytes);
- buffer[log.gcount()] = NULL;
- log_data << "== PandaLog-" << "Head Start";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- log_data << buffer << "\n";
- log_data << "== PandaLog-" << "Head End";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- }
- // Render separator if head & tail bytes are to be fetched
- if ((head_bytes > 0) && (tail_bytes > 0)) {
- log_data << "== PandaLog-" << "truncated";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- }
- // Render log data if tail bytes are to be fetched
- if (tail_bytes > 0) {
- log.seekg(file_size - tail_bytes, ios::beg);
- log.read(buffer, tail_bytes);
- buffer[log.gcount()] = NULL;
- log_data << "== PandaLog-" << "Tail Start";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- log_data << buffer;
- log_data << "== PandaLog-" << "Tail End";
- log_data << " " << "(" << log_leafname << ")" << "\n";
- }
- // Render log file footer to log_data
- //log_data << "=======================================";
- //log_data << "=======================================" << "\n";
- // cleanup
- delete[] buffer;
- buffer = NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: P3DMainObject::call_uninstall
- // Access: Private
- // Description: Implements the uninstall() plugin method, which
- // removes all Panda installed files for a particular
- // host, or referenced by a particular p3d file.
- ////////////////////////////////////////////////////////////////////
- P3D_object *P3DMainObject::
- call_uninstall(P3D_object *params[], int num_params) {
- P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
- // Get the first parameter, the uninstall mode.
- string mode;
- if (num_params > 0) {
- int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0);
- char *buffer = new char[size];
- P3D_OBJECT_GET_STRING(params[0], buffer, size);
- mode = string(buffer, size);
- delete[] buffer;
- }
- if (mode == "all") {
- nout << "uninstall all\n";
- inst_mgr->uninstall_all();
- return inst_mgr->new_bool_object(true);
- }
- if (_inst != NULL) {
- nout << "uninstall " << mode << " for " << _inst << "\n";
- if (mode == "host") {
- _inst->uninstall_host();
- } else {
- _inst->uninstall_packages();
- }
- return inst_mgr->new_bool_object(true);
- }
- nout << "couldn't uninstall; no instance.\n";
- return inst_mgr->new_bool_object(false);
- }
|