770 lines
27 KiB
C++
770 lines
27 KiB
C++
// 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 "p3dPythonObject.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, (P3D_object *)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();
|
|
|
|
nout << "main." << method_name << "(";
|
|
for (int i = 0; i < num_params; ++i) {
|
|
if (i != 0) {
|
|
nout << ", ";
|
|
}
|
|
int buffer_size = P3D_OBJECT_GET_REPR(params[i], NULL, 0);
|
|
char *buffer = new char[buffer_size];
|
|
P3D_OBJECT_GET_REPR(params[i], buffer, buffer_size);
|
|
nout.write(buffer, buffer_size);
|
|
delete[] buffer;
|
|
}
|
|
nout << ")\n";
|
|
|
|
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 == this) {
|
|
// We are setting a reference directly to ourselves. This happens
|
|
// when the application has accepted the main object we gave it in
|
|
// set_instance_info(). This means the application is directly
|
|
// manipulating this object as its appRunner.main. In this case,
|
|
// we don't actually need to set the reference; instead, we clear
|
|
// anything we had set.
|
|
nout << "application shares main object\n";
|
|
pyobj = NULL;
|
|
|
|
} else if (pyobj != NULL) {
|
|
// In the alternate case, the application has its own, separate
|
|
// appRunner.main object. Thus, we do need to set the pointer.
|
|
nout << "application has its own main object\n";
|
|
}
|
|
|
|
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.
|
|
apply_properties(_pyobj);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// 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::apply_properties
|
|
// Access: Public
|
|
// Description: Applies the locally-set properties onto the indicated
|
|
// Python object, but does not store the object. This
|
|
// is a one-time copy of the locally-set properties
|
|
// (like "coreapiHostUrl" and the like) onto the
|
|
// indicated Python object.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DMainObject::
|
|
apply_properties(P3D_object *pyobj) {
|
|
P3DPythonObject *p3dpyobj = NULL;
|
|
if (pyobj->_class == &P3DObject::_object_class) {
|
|
p3dpyobj = ((P3DObject *)pyobj)->as_python_object();
|
|
}
|
|
|
|
Properties::const_iterator pi;
|
|
for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
|
|
const string &property_name = (*pi).first;
|
|
P3D_object *value = (*pi).second;
|
|
if (p3dpyobj != NULL && P3D_OBJECT_GET_TYPE(value) != P3D_OT_object) {
|
|
// If we know we have an actual P3DPythonObject (we really
|
|
// expect this), then we can call set_property_insecure()
|
|
// directly, because we want to allow setting the initial
|
|
// properties even if Javascript has no permissions to write
|
|
// into Python. But we don't allow setting objects this way in
|
|
// any event.
|
|
p3dpyobj->set_property_insecure(property_name, false, value);
|
|
} else {
|
|
// Otherwise, we go through the generic interface.
|
|
P3D_OBJECT_SET_PROPERTY(pyobj, property_name.c_str(), false, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// 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.
|
|
nout << "read_game_log: error: game log name unknown" << "\n";
|
|
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) {
|
|
nout << "read_log: error: not enough parameters" << "\n";
|
|
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.
|
|
nout << "read_log: error: invalid filename" << "\n";
|
|
return inst_mgr->new_undefined_object();
|
|
}
|
|
|
|
size_t slash = log_filename.find('/');
|
|
if (slash != string::npos) {
|
|
// No slashes allowed.
|
|
nout << "read_log: error: invalid filename" << "\n";
|
|
return inst_mgr->new_undefined_object();
|
|
}
|
|
|
|
slash = log_filename.find('\\');
|
|
if (slash != string::npos) {
|
|
// Nor backslashes.
|
|
nout << "read_log: error: invalid filename" << "\n";
|
|
return inst_mgr->new_undefined_object();
|
|
}
|
|
|
|
size_t colon = log_filename.find(':');
|
|
if (colon != string::npos) {
|
|
// Nor colons, for that matter.
|
|
nout << "read_log: error: invalid filename" << "\n";
|
|
return inst_mgr->new_undefined_object();
|
|
}
|
|
|
|
string log_pathname = inst_mgr->get_log_directory() + log_filename;
|
|
P3D_object *result = read_log(log_pathname, params + 1, num_params - 1);
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// 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);
|
|
}
|
|
// Check the fourth parameter, if any--if given, it specifies the
|
|
// first n bytes to retrieve from previous copies of this file.
|
|
size_t head_bytes_prev = 0;
|
|
if (num_params > 3) {
|
|
head_bytes_prev = (size_t)max(P3D_OBJECT_GET_INT(params[3]), 0);
|
|
}
|
|
|
|
// Determine the base of the log file names
|
|
nout << "log_pathname: " << log_pathname << "\n";
|
|
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_leafname_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 += "-";
|
|
}
|
|
}
|
|
|
|
// Read matching files
|
|
vector<string> all_logs;
|
|
int log_matches_found = 0;
|
|
string log_matching_pathname;
|
|
inst_mgr->scan_directory(log_directory, all_logs);
|
|
for (int i=(int)all_logs.size()-1; i>=0; --i) {
|
|
if ((all_logs[i] == log_leafname_primary) ||
|
|
(all_logs[i].find(log_basename) == 0) &&
|
|
(all_logs[i].size() > 4) &&
|
|
(all_logs[i].substr(all_logs[i].size() - 4) == string(".log"))) {
|
|
log_matches_found++;
|
|
log_matching_pathname = (log_directory + all_logs[i]);
|
|
read_log_file(log_matching_pathname, tail_bytes, head_bytes, log_data);
|
|
tail_bytes = tail_bytes_prev;
|
|
head_bytes = head_bytes_prev;
|
|
}
|
|
}
|
|
|
|
if (log_matches_found == 0) {
|
|
nout << "read_log: warning: no matching file(s) on disk." << "\n";
|
|
}
|
|
|
|
string log_data_str = log_data.str();
|
|
P3D_object *result = new P3DStringObject(log_data_str);
|
|
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
|
|
|
|
// Render log file header to log_data
|
|
log_data << "=======================================";
|
|
log_data << "=======================================" << "\n";
|
|
log_data << "== PandaLog-" << log_pathname << "\n";
|
|
|
|
// load file
|
|
ifstream log(log_pathname.c_str(), ios::in);
|
|
if (!log) {
|
|
log_data << "== PandaLog-" << "Error opening file";
|
|
log_data << " " << "(" << log_leafname << ")" << "\n";
|
|
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";
|
|
|
|
// Early out if the file is empty
|
|
if (file_size == (size_t)0) {
|
|
log_data << "== PandaLog-" << "Empty File";
|
|
log_data << " " << "(" << log_leafname << ")" << "\n";
|
|
return;
|
|
}
|
|
|
|
// 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 = max(max(full_bytes, head_bytes), tail_bytes) + 1;
|
|
nout << "allocating " << buffer_bytes << " bytes to read at a time from file of size " << file_size << ".\n";
|
|
char *buffer = new char[buffer_bytes];
|
|
if (buffer == NULL) {
|
|
log_data << "== PandaLog-" << "Error allocating buffer";
|
|
log_data << " " << "(" << log_leafname << ")" << "\n";
|
|
return;
|
|
}
|
|
|
|
// Render log data if full file is to be fetched
|
|
if (full_bytes > 0) {
|
|
log.seekg(0, ios::beg);
|
|
log.read(buffer, full_bytes);
|
|
streamsize read_bytes = log.gcount();
|
|
assert(read_bytes < (streamsize)buffer_bytes);
|
|
buffer[read_bytes] = '\0';
|
|
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);
|
|
streamsize read_bytes = log.gcount();
|
|
assert(read_bytes < (streamsize)buffer_bytes);
|
|
buffer[read_bytes] = '\0';
|
|
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);
|
|
streamsize read_bytes = log.gcount();
|
|
assert(read_bytes < (streamsize)buffer_bytes);
|
|
buffer[read_bytes] = '\0';
|
|
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";
|
|
bool success = false;
|
|
if (mode == "host") {
|
|
success = _inst->uninstall_host();
|
|
} else {
|
|
success = _inst->uninstall_packages();
|
|
}
|
|
return inst_mgr->new_bool_object(success);
|
|
}
|
|
|
|
nout << "couldn't uninstall; no instance.\n";
|
|
return inst_mgr->new_bool_object(false);
|
|
}
|