mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
run plugin safely under a non-ASCII username
This commit is contained in:
parent
4d45de4f1b
commit
c3936305e4
@ -246,12 +246,12 @@ find_root_dir_default() {
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: find_root_dir
|
// Function: find_root_dir_actual
|
||||||
// Description: Returns the path to the installable Panda3D directory
|
// Description: Returns the path to the installable Panda3D directory
|
||||||
// on the user's machine.
|
// on the user's machine.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
string
|
static string
|
||||||
find_root_dir() {
|
find_root_dir_actual() {
|
||||||
string root = find_root_dir_default();
|
string root = find_root_dir_default();
|
||||||
|
|
||||||
// Now look for a config.xml file in that directory, which might
|
// Now look for a config.xml file in that directory, which might
|
||||||
@ -283,3 +283,30 @@ find_root_dir() {
|
|||||||
// We've been redirected to another location. Respect that.
|
// We've been redirected to another location. Respect that.
|
||||||
return new_root;
|
return new_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: find_root_dir
|
||||||
|
// Description: This is the public interface to the above functions.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
string
|
||||||
|
find_root_dir() {
|
||||||
|
string root = find_root_dir_actual();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Now map that (possibly utf-8) filename into its 8.3 equivalent,
|
||||||
|
// so we can safely pass it around to Python and other tools that
|
||||||
|
// might not understand Unicode filenames. Silly Windows, creating
|
||||||
|
// an entirely new and incompatible kind of filename.
|
||||||
|
wstring root_w;
|
||||||
|
string_to_wstring(root_w, root);
|
||||||
|
|
||||||
|
DWORD length = GetShortPathNameW(root_w.c_str(), NULL, 0);
|
||||||
|
wchar_t *short_name = new wchar_t[length];
|
||||||
|
GetShortPathNameW(root_w.c_str(), short_name, length);
|
||||||
|
|
||||||
|
wstring_to_string(root, short_name);
|
||||||
|
delete[] short_name;
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
@ -177,21 +177,43 @@ start_p3dcert() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Populate the new process' environment.
|
// Populate the new process' environment.
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// These are the enviroment variables we forward from the current
|
||||||
|
// environment, if they are set.
|
||||||
|
const wchar_t *keep[] = {
|
||||||
|
L"TMP", L"TEMP", L"HOME", L"USER",
|
||||||
|
L"SYSTEMROOT", L"USERPROFILE", L"COMSPEC",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
wstring env_w;
|
||||||
|
|
||||||
|
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||||
|
wchar_t *value = _wgetenv(keep[ki]);
|
||||||
|
if (value != NULL) {
|
||||||
|
env_w += keep[ki];
|
||||||
|
env_w += L"=";
|
||||||
|
env_w += value;
|
||||||
|
env_w += (wchar_t)'\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring_to_string(_env, env_w);
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
|
||||||
_env = string();
|
_env = string();
|
||||||
|
|
||||||
// These are the enviroment variables we forward from the current
|
// These are the enviroment variables we forward from the current
|
||||||
// environment, if they are set.
|
// environment, if they are set.
|
||||||
const char *keep[] = {
|
const char *keep[] = {
|
||||||
"TMP", "TEMP", "HOME", "USER",
|
"TMP", "TEMP", "HOME", "USER",
|
||||||
#ifdef _WIN32
|
|
||||||
"SYSTEMROOT", "USERPROFILE", "COMSPEC",
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
"DISPLAY", "XAUTHORITY",
|
"DISPLAY", "XAUTHORITY",
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||||
char *value = getenv(keep[ki]);
|
char *value = getenv(keep[ki]);
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
@ -201,6 +223,7 @@ start_p3dcert() {
|
|||||||
_env += '\0';
|
_env += '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
// Define some new environment variables.
|
// Define some new environment variables.
|
||||||
_env += "PATH=";
|
_env += "PATH=";
|
||||||
@ -219,6 +242,9 @@ start_p3dcert() {
|
|||||||
_env += root_dir;
|
_env += root_dir;
|
||||||
_env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
|
nout << "Setting environment:\n";
|
||||||
|
write_env();
|
||||||
|
|
||||||
nout << "Attempting to start p3dcert from " << _p3dcert_exe << "\n";
|
nout << "Attempting to start p3dcert from " << _p3dcert_exe << "\n";
|
||||||
|
|
||||||
bool started_p3dcert = false;
|
bool started_p3dcert = false;
|
||||||
@ -268,6 +294,27 @@ join_wait_thread() {
|
|||||||
_started_wait_thread = false;
|
_started_wait_thread = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DAuthSession::write_env
|
||||||
|
// Access: Private
|
||||||
|
// Description: Writes _env, which is formatted as a string
|
||||||
|
// containing zero-byte-terminated environment
|
||||||
|
// defintions, to the nout stream, one definition per
|
||||||
|
// line.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DAuthSession::
|
||||||
|
write_env() const {
|
||||||
|
size_t p = 0;
|
||||||
|
size_t zero = _env.find('\0', p);
|
||||||
|
while (zero != string::npos) {
|
||||||
|
nout << " ";
|
||||||
|
nout.write(_env.data() + p, zero - p);
|
||||||
|
nout << "\n";
|
||||||
|
p = zero + 1;
|
||||||
|
zero = _env.find('\0', p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DAuthSession::wt_thread_run
|
// Function: P3DAuthSession::wt_thread_run
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -332,7 +379,7 @@ win_create_process() {
|
|||||||
// Make sure we see an error dialog if there is a missing DLL.
|
// Make sure we see an error dialog if there is a missing DLL.
|
||||||
SetErrorMode(0);
|
SetErrorMode(0);
|
||||||
|
|
||||||
STARTUPINFOW startup_info;
|
STARTUPINFO startup_info;
|
||||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||||
startup_info.cb = sizeof(startup_info);
|
startup_info.cb = sizeof(startup_info);
|
||||||
|
|
||||||
@ -340,34 +387,32 @@ win_create_process() {
|
|||||||
startup_info.wShowWindow = SW_SHOW;
|
startup_info.wShowWindow = SW_SHOW;
|
||||||
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
|
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
|
||||||
|
|
||||||
const wchar_t *start_dir_cstr;
|
const char *start_dir_cstr = _start_dir.c_str();
|
||||||
wstring start_dir_w;
|
|
||||||
string_to_wstring(start_dir_w, _start_dir);
|
|
||||||
start_dir_cstr = start_dir_w.c_str();
|
|
||||||
|
|
||||||
// Construct the command-line string, containing the quoted
|
// Construct the command-line string, containing the quoted
|
||||||
// command-line arguments.
|
// command-line arguments.
|
||||||
ostringstream stream;
|
ostringstream stream;
|
||||||
stream << "\"" << _p3dcert_exe << "\" \""
|
stream << "\"" << _p3dcert_exe << "\" \""
|
||||||
<< _cert_filename->get_filename() << "\" \""
|
<< _cert_filename->get_filename() << "\" \"" << _cert_dir << "\"";
|
||||||
<< _cert_dir << "\"";
|
|
||||||
|
|
||||||
// I'm not sure why CreateProcess wants a non-const char pointer for
|
// I'm not sure why CreateProcess wants a non-const char pointer for
|
||||||
// its command-line string, but I'm not taking chances. It gets a
|
// its command-line string, but I'm not taking chances. It gets a
|
||||||
// non-const char array that it can modify.
|
// non-const char array that it can modify.
|
||||||
wstring command_line_str;
|
string command_line_str = stream.str();
|
||||||
string_to_wstring(command_line_str, stream.str());
|
char *command_line = new char[command_line_str.size() + 1];
|
||||||
wchar_t *command_line = new wchar_t[command_line_str.size() + 1];
|
memcpy(command_line, command_line_str.c_str(), command_line_str.size() + 1);
|
||||||
memcpy(command_line, command_line_str.c_str(), sizeof(wchar_t) * command_line_str.size() + 1);
|
|
||||||
|
|
||||||
wstring p3dcert_exe_w;
|
nout << "Command line: " << command_line_str << "\n";
|
||||||
string_to_wstring(p3dcert_exe_w, _p3dcert_exe);
|
|
||||||
|
|
||||||
|
// Something about p3dCert_wx tends to become crashy when we call it
|
||||||
|
// from CreateProcessW(). Something about the way wx parses the
|
||||||
|
// command-line parameters? Well, whatever, we don't really need
|
||||||
|
// the Unicode form anyway.
|
||||||
PROCESS_INFORMATION process_info;
|
PROCESS_INFORMATION process_info;
|
||||||
BOOL result = CreateProcessW
|
BOOL result = CreateProcess
|
||||||
(p3dcert_exe_w.c_str(), command_line, NULL, NULL, TRUE, 0,
|
(_p3dcert_exe.c_str(), command_line, NULL, NULL, TRUE,
|
||||||
(void *)_env.c_str(), start_dir_cstr,
|
0, (void *)_env.c_str(),
|
||||||
&startup_info, &process_info);
|
start_dir_cstr, &startup_info, &process_info);
|
||||||
bool started_program = (result != 0);
|
bool started_program = (result != 0);
|
||||||
|
|
||||||
delete[] command_line;
|
delete[] command_line;
|
||||||
|
@ -44,6 +44,8 @@ private:
|
|||||||
void spawn_wait_thread();
|
void spawn_wait_thread();
|
||||||
void join_wait_thread();
|
void join_wait_thread();
|
||||||
|
|
||||||
|
void write_env() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// These methods run only within the read thread.
|
// These methods run only within the read thread.
|
||||||
THREAD_CALLBACK_DECLARATION(P3DAuthSession, wt_thread_run);
|
THREAD_CALLBACK_DECLARATION(P3DAuthSession, wt_thread_run);
|
||||||
|
@ -124,8 +124,9 @@ OnInitCmdLine(wxCmdLineParser &parser) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool P3DCertApp::
|
bool P3DCertApp::
|
||||||
OnCmdLineParsed(wxCmdLineParser &parser) {
|
OnCmdLineParsed(wxCmdLineParser &parser) {
|
||||||
_cert_filename = parser.GetParam(0);
|
_cert_filename = (const char *)parser.GetParam(0).mb_str();
|
||||||
_cert_dir = parser.GetParam(1);
|
_cert_dir = (const char *)parser.GetParam(1).mb_str();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ END_EVENT_TABLE()
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
AuthDialog::
|
AuthDialog::
|
||||||
AuthDialog(const wxString &cert_filename, const wxString &cert_dir) :
|
AuthDialog(const string &cert_filename, const string &cert_dir) :
|
||||||
// I hate stay-on-top dialogs, but if we don't set this flag, it
|
// I hate stay-on-top dialogs, but if we don't set this flag, it
|
||||||
// doesn't come to the foreground on OSX, and might be lost behind
|
// doesn't come to the foreground on OSX, and might be lost behind
|
||||||
// the browser window.
|
// the browser window.
|
||||||
@ -232,8 +233,7 @@ approve_cert() {
|
|||||||
assert(_cert != NULL);
|
assert(_cert != NULL);
|
||||||
|
|
||||||
// Make sure the directory exists.
|
// Make sure the directory exists.
|
||||||
string cert_dir_str = (const char *)_cert_dir.mb_str();
|
mkdir_complete(_cert_dir, cerr);
|
||||||
mkdir_complete(cert_dir_str, cerr);
|
|
||||||
|
|
||||||
// Look for an unused filename.
|
// Look for an unused filename.
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@ -288,24 +288,24 @@ approve_cert() {
|
|||||||
// passed on the command line into _cert and _stack.
|
// passed on the command line into _cert and _stack.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void AuthDialog::
|
void AuthDialog::
|
||||||
read_cert_file(const wxString &cert_filename) {
|
read_cert_file(const string &cert_filename) {
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wstring cert_filename_w;
|
wstring cert_filename_w;
|
||||||
if (string_to_wstring(cert_filename_w, (const char *)cert_filename.mb_str())) {
|
if (string_to_wstring(cert_filename_w, cert_filename)) {
|
||||||
fp = _wfopen(cert_filename_w.c_str(), L"r");
|
fp = _wfopen(cert_filename_w.c_str(), L"r");
|
||||||
}
|
}
|
||||||
#else // _WIN32
|
#else // _WIN32
|
||||||
fp = fopen(cert_filename.mb_str(), "r");
|
fp = fopen(cert_filename.c_str(), "r");
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
cerr << "Couldn't read " << cert_filename.mb_str() << "\n";
|
cerr << "Couldn't read " << cert_filename << "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_cert = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
_cert = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||||
if (_cert == NULL) {
|
if (_cert == NULL) {
|
||||||
cerr << "Could not read certificate in " << cert_filename.mb_str() << ".\n";
|
cerr << "Could not read certificate in " << cert_filename << ".\n";
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,8 @@ public:
|
|||||||
virtual bool OnCmdLineParsed(wxCmdLineParser &parser);
|
virtual bool OnCmdLineParsed(wxCmdLineParser &parser);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxString _cert_filename;
|
string _cert_filename;
|
||||||
wxString _cert_dir;
|
string _cert_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -67,7 +67,7 @@ private:
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
class AuthDialog : public wxDialog {
|
class AuthDialog : public wxDialog {
|
||||||
public:
|
public:
|
||||||
AuthDialog(const wxString &cert_filename, const wxString &cert_dir);
|
AuthDialog(const string &cert_filename, const string &cert_dir);
|
||||||
virtual ~AuthDialog();
|
virtual ~AuthDialog();
|
||||||
|
|
||||||
void run_clicked(wxCommandEvent &event);
|
void run_clicked(wxCommandEvent &event);
|
||||||
@ -77,7 +77,7 @@ public:
|
|||||||
void approve_cert();
|
void approve_cert();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void read_cert_file(const wxString &cert_filename);
|
void read_cert_file(const string &cert_filename);
|
||||||
void get_friendly_name();
|
void get_friendly_name();
|
||||||
void verify_cert();
|
void verify_cert();
|
||||||
int load_certificates_from_der_ram(X509_STORE *store,
|
int load_certificates_from_der_ram(X509_STORE *store,
|
||||||
@ -93,7 +93,7 @@ private:
|
|||||||
// any class wishing to process wxWidgets events must use this macro
|
// any class wishing to process wxWidgets events must use this macro
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
wxString _cert_dir;
|
string _cert_dir;
|
||||||
X509 *_cert;
|
X509 *_cert;
|
||||||
STACK_OF(X509) *_stack;
|
STACK_OF(X509) *_stack;
|
||||||
|
|
||||||
|
@ -839,7 +839,15 @@ find_cert(X509 *cert) {
|
|||||||
for (si = contents.begin(); si != contents.end(); ++si) {
|
for (si = contents.begin(); si != contents.end(); ++si) {
|
||||||
string filename = this_cert_dir + "/" + (*si);
|
string filename = this_cert_dir + "/" + (*si);
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
FILE *fp = fopen(filename.c_str(), "r");
|
FILE *fp = NULL;
|
||||||
|
#ifdef _WIN32
|
||||||
|
wstring filename_w;
|
||||||
|
if (string_to_wstring(filename_w, filename)) {
|
||||||
|
fp = _wfopen(filename_w.c_str(), L"r");
|
||||||
|
}
|
||||||
|
#else // _WIN32
|
||||||
|
fp = fopen(filename.c_str(), "r");
|
||||||
|
#endif // _WIN32
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@ -882,7 +890,15 @@ read_certlist(P3DPackage *package) {
|
|||||||
if (suffix == ".pem" || suffix == ".crt") {
|
if (suffix == ".pem" || suffix == ".crt") {
|
||||||
string filename = package->get_package_dir() + "/" + basename;
|
string filename = package->get_package_dir() + "/" + basename;
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
FILE *fp = fopen(filename.c_str(), "r");
|
FILE *fp = NULL;
|
||||||
|
#ifdef _WIN32
|
||||||
|
wstring filename_w;
|
||||||
|
if (string_to_wstring(filename_w, filename)) {
|
||||||
|
fp = _wfopen(filename_w.c_str(), L"r");
|
||||||
|
}
|
||||||
|
#else // _WIN32
|
||||||
|
fp = fopen(filename.c_str(), "r");
|
||||||
|
#endif // _WIN32
|
||||||
if (fp != NULL) {
|
if (fp != NULL) {
|
||||||
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
@ -156,16 +156,16 @@ run_python() {
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Of course it's already resident, so use that version.
|
// Of course it's already resident, so use that version.
|
||||||
string basename = Filename::dso_filename("libpandaexpress.so").to_os_specific();
|
wstring basename = Filename::dso_filename("libpandaexpress.so").to_os_specific_w();
|
||||||
HMODULE h = GetModuleHandle(basename.c_str());
|
HMODULE h = GetModuleHandleW(basename.c_str());
|
||||||
|
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
nout << "Can't find libpandaexpress in memory.\n";
|
nout << "Can't find libpandaexpress in memory.\n";
|
||||||
} else {
|
} else {
|
||||||
static const int buffer_size = 4096;
|
static const int buffer_size = 4096;
|
||||||
char buffer[buffer_size];
|
wchar_t buffer[buffer_size];
|
||||||
GetModuleFileName(h, buffer, buffer_size);
|
GetModuleFileNameW(h, buffer, buffer_size);
|
||||||
libpandaexpress = Filename::from_os_specific(buffer);
|
libpandaexpress = Filename::from_os_specific_w(buffer);
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ run_python() {
|
|||||||
libpandaexpress.set_type(Filename::T_general);
|
libpandaexpress.set_type(Filename::T_general);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!libpandaexpress.exists()) {
|
if (!libpandaexpress.exists()) {
|
||||||
nout << "Can't find " << libpandaexpress << "\n";
|
nout << "Can't find " << libpandaexpress << "\n";
|
||||||
return false;
|
return false;
|
||||||
@ -188,15 +188,22 @@ run_python() {
|
|||||||
// We need the "imp" built-in module for that.
|
// We need the "imp" built-in module for that.
|
||||||
PyObject *imp_module = PyImport_ImportModule("imp");
|
PyObject *imp_module = PyImport_ImportModule("imp");
|
||||||
if (imp_module == NULL) {
|
if (imp_module == NULL) {
|
||||||
|
nout << "Failed to import module imp\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And here's where we run into a brick wall attempting to make the
|
||||||
|
// whole plugin system Unicode-safe for Windows. It turns out that
|
||||||
|
// this Python call, imp.load_dynamic(), will not accept a Unicode
|
||||||
|
// pathname. So if the DLL in question is in a location that
|
||||||
|
// contains non-ASCII characters, it can't be loaded.
|
||||||
string os_specific = libpandaexpress.to_os_specific();
|
string os_specific = libpandaexpress.to_os_specific();
|
||||||
PyObject *result = PyObject_CallMethod
|
PyObject *result = PyObject_CallMethod
|
||||||
(imp_module, (char *)"load_dynamic", (char *)"ss",
|
(imp_module, (char *)"load_dynamic", (char *)"ss",
|
||||||
"libpandaexpress", os_specific.c_str());
|
"libpandaexpress", os_specific.c_str());
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
|
nout << "Failed to import libpandaexpress as a module\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -208,6 +215,7 @@ run_python() {
|
|||||||
// available to import as well.
|
// available to import as well.
|
||||||
PyObject *vfsimporter = PyImport_ImportModule("_vfsimporter");
|
PyObject *vfsimporter = PyImport_ImportModule("_vfsimporter");
|
||||||
if (vfsimporter == NULL) {
|
if (vfsimporter == NULL) {
|
||||||
|
nout << "Failed to import _vfsimporter\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -216,6 +224,7 @@ run_python() {
|
|||||||
// And now we can import the VFSImporter module that was so defined.
|
// And now we can import the VFSImporter module that was so defined.
|
||||||
PyObject *vfsimporter_module = PyImport_ImportModule("VFSImporter");
|
PyObject *vfsimporter_module = PyImport_ImportModule("VFSImporter");
|
||||||
if (vfsimporter_module == NULL) {
|
if (vfsimporter_module == NULL) {
|
||||||
|
nout << "Failed to import VFSImporter\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -223,6 +232,7 @@ run_python() {
|
|||||||
// And register the VFSImporter.
|
// And register the VFSImporter.
|
||||||
result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
|
result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
|
nout << "Failed to call VFSImporter.register()\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -248,6 +258,7 @@ run_python() {
|
|||||||
// And finally, we can import the startup module.
|
// And finally, we can import the startup module.
|
||||||
PyObject *app_runner_module = PyImport_ImportModule("direct.p3d.AppRunner");
|
PyObject *app_runner_module = PyImport_ImportModule("direct.p3d.AppRunner");
|
||||||
if (app_runner_module == NULL) {
|
if (app_runner_module == NULL) {
|
||||||
|
nout << "Failed to import direct.p3d.AppRunner\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -255,6 +266,7 @@ run_python() {
|
|||||||
// Get the pointers to the objects needed within the module.
|
// Get the pointers to the objects needed within the module.
|
||||||
PyObject *app_runner_class = PyObject_GetAttrString(app_runner_module, "AppRunner");
|
PyObject *app_runner_class = PyObject_GetAttrString(app_runner_module, "AppRunner");
|
||||||
if (app_runner_class == NULL) {
|
if (app_runner_class == NULL) {
|
||||||
|
nout << "Failed to get AppRunner class\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -262,6 +274,7 @@ run_python() {
|
|||||||
// Construct an instance of AppRunner.
|
// Construct an instance of AppRunner.
|
||||||
_runner = PyObject_CallFunction(app_runner_class, (char *)"");
|
_runner = PyObject_CallFunction(app_runner_class, (char *)"");
|
||||||
if (_runner == NULL) {
|
if (_runner == NULL) {
|
||||||
|
nout << "Failed to construct AppRunner instance\n";
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -795,21 +795,14 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
// This allows the caller's on-disk Python files to shadow the
|
// This allows the caller's on-disk Python files to shadow the
|
||||||
// similar-named files in the p3d file, allowing easy iteration on
|
// similar-named files in the p3d file, allowing easy iteration on
|
||||||
// the code in the p3d file.
|
// the code in the p3d file.
|
||||||
const char *pypath = getenv("PYTHONPATH");
|
if (get_env(python_path, "PYTHONPATH")) {
|
||||||
if (pypath != (char *)NULL) {
|
|
||||||
python_path = pypath;
|
|
||||||
replace_slashes(python_path);
|
replace_slashes(python_path);
|
||||||
python_path += sep;
|
python_path += sep;
|
||||||
python_path += search_path;
|
python_path += search_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also preserve PRC_PATH.
|
// We also preserve PRC_PATH.
|
||||||
const char *prcpath = getenv("PRC_PATH");
|
if (get_env(prc_path, "PRC_PATH") || get_env(prc_path, "PANDA_PRC_PATH")) {
|
||||||
if (prcpath == NULL) {
|
|
||||||
prcpath = getenv("PANDA_PRC_PATH");
|
|
||||||
}
|
|
||||||
if (prcpath != (char *)NULL) {
|
|
||||||
prc_path = prcpath;
|
|
||||||
replace_slashes(prc_path);
|
replace_slashes(prc_path);
|
||||||
prc_path += sep;
|
prc_path += sep;
|
||||||
prc_path += search_path;
|
prc_path += search_path;
|
||||||
@ -891,8 +884,8 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||||
char *value = getenv(keep[ki]);
|
string value;
|
||||||
if (value != NULL) {
|
if (get_env(value, keep[ki])) {
|
||||||
_env += keep[ki];
|
_env += keep[ki];
|
||||||
_env += "=";
|
_env += "=";
|
||||||
_env += value;
|
_env += value;
|
||||||
@ -950,18 +943,18 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
// definitions, even if keep_user_env is not set. This is necessary
|
// definitions, even if keep_user_env is not set. This is necessary
|
||||||
// for os.system() and such to work as expected within the embedded
|
// for os.system() and such to work as expected within the embedded
|
||||||
// app. It's also necessary for webbrowser on Linux.
|
// app. It's also necessary for webbrowser on Linux.
|
||||||
char *orig_path = getenv("PATH");
|
string orig_path;
|
||||||
if (orig_path != NULL) {
|
if (get_env(orig_path, "PATH")) {
|
||||||
sys_path += sep;
|
sys_path += sep;
|
||||||
sys_path += orig_path;
|
sys_path += orig_path;
|
||||||
}
|
}
|
||||||
char *orig_ld_path = getenv("LD_LIBRARY_PATH");
|
string orig_ld_path;
|
||||||
if (orig_ld_path != NULL) {
|
if (get_env(orig_ld_path, "LD_LIBRARY_PATH")) {
|
||||||
ld_path += sep;
|
ld_path += sep;
|
||||||
ld_path += orig_ld_path;
|
ld_path += orig_ld_path;
|
||||||
}
|
}
|
||||||
char *orig_dyld_path = getenv("DYLD_LIBRARY_PATH");
|
string orig_dyld_path;
|
||||||
if (orig_dyld_path != NULL) {
|
if (get_env(orig_dyld_path, "DYLD_LIBRARY_PATH")) {
|
||||||
dyld_path += sep;
|
dyld_path += sep;
|
||||||
dyld_path += orig_dyld_path;
|
dyld_path += orig_dyld_path;
|
||||||
}
|
}
|
||||||
@ -1541,14 +1534,18 @@ win_create_process() {
|
|||||||
wchar_t *command_line = new wchar_t[command_line_str.size() + 1];
|
wchar_t *command_line = new wchar_t[command_line_str.size() + 1];
|
||||||
memcpy(command_line, command_line_str.c_str(), sizeof(wchar_t) * command_line_str.size() + 1);
|
memcpy(command_line, command_line_str.c_str(), sizeof(wchar_t) * command_line_str.size() + 1);
|
||||||
|
|
||||||
|
nout << "Command line: " << command_line_str << "\n";
|
||||||
|
|
||||||
wstring p3dpython_exe_w;
|
wstring p3dpython_exe_w;
|
||||||
string_to_wstring(p3dpython_exe_w, _p3dpython_exe);
|
string_to_wstring(p3dpython_exe_w, _p3dpython_exe);
|
||||||
|
wstring env_w;
|
||||||
|
string_to_wstring(env_w, _env);
|
||||||
|
|
||||||
PROCESS_INFORMATION process_info;
|
PROCESS_INFORMATION process_info;
|
||||||
BOOL result = CreateProcessW
|
BOOL result = CreateProcessW
|
||||||
(p3dpython_exe_w.c_str(), command_line, NULL, NULL, TRUE, 0,
|
(p3dpython_exe_w.c_str(), command_line, NULL, NULL, TRUE,
|
||||||
(void *)_env.c_str(), start_dir_cstr,
|
CREATE_UNICODE_ENVIRONMENT, (void *)env_w.c_str(),
|
||||||
&startup_info, &process_info);
|
start_dir_cstr, &startup_info, &process_info);
|
||||||
bool started_program = (result != 0);
|
bool started_program = (result != 0);
|
||||||
|
|
||||||
if (!started_program) {
|
if (!started_program) {
|
||||||
@ -1810,6 +1807,35 @@ p3dpython_thread_run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::get_env
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Implements getenv(), respecting Windows' Unicode
|
||||||
|
// environment. Returns true if the variable is
|
||||||
|
// defined, false if it is not. If it is defined, fills
|
||||||
|
// value with its definition.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool P3DSession::
|
||||||
|
get_env(string &value, const string &varname) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
wstring varname_w;
|
||||||
|
string_to_wstring(varname_w, varname);
|
||||||
|
const wchar_t *vc = _wgetenv(varname_w.c_str());
|
||||||
|
if (vc == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wstring_to_string(value, vc);
|
||||||
|
return true;
|
||||||
|
#else // _WIN32
|
||||||
|
const char *vc = getenv(varname.c_str());
|
||||||
|
if (vc == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = vc;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DSession::write_env
|
// Function: P3DSession::write_env
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -90,6 +90,7 @@ private:
|
|||||||
THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run);
|
THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run);
|
||||||
void p3dpython_thread_run();
|
void p3dpython_thread_run();
|
||||||
|
|
||||||
|
static bool get_env(string &value, const string &varname);
|
||||||
void write_env() const;
|
void write_env() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -72,111 +72,3 @@ string_to_wstring(wstring &result, const string &source) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: parse_hexdigit
|
|
||||||
// Description: Parses a single hex digit. Returns true on success,
|
|
||||||
// false on failure. On success, fills result with the
|
|
||||||
// parsed value, an integer in the range 0..15.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
bool
|
|
||||||
parse_hexdigit(int &result, char digit) {
|
|
||||||
if (isdigit(digit)) {
|
|
||||||
result = digit - '0';
|
|
||||||
return true;
|
|
||||||
} else if (isxdigit(digit)) {
|
|
||||||
result = tolower(digit) - 'a' + 10;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: url_quote
|
|
||||||
// Description: Applies URL quoting to source and stores the result
|
|
||||||
// in result.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void
|
|
||||||
url_quote(string &result, const string &source) {
|
|
||||||
ostringstream strm;
|
|
||||||
strm << hex << setfill('0');
|
|
||||||
for (size_t p = 0; p < source.length(); ++p) {
|
|
||||||
if (source[p] < 0x20 || source[p] >= 0x7f) {
|
|
||||||
strm << "%" << setw(2) << (unsigned int)(unsigned char)source[p];
|
|
||||||
} else {
|
|
||||||
switch (source[p]) {
|
|
||||||
// We could quote all of these punctuation marks too, the same
|
|
||||||
// way actual URL quoting does. Maybe we will one day in the
|
|
||||||
// future, though I don't think it matters much; mainly we're
|
|
||||||
// relying on quoting to protect the high-bit characters. For
|
|
||||||
// now, then, we leave these unquoted, for compatibility with
|
|
||||||
// the p3dpython from Panda3D 1.7, which didn't expect any
|
|
||||||
// quoting at all.
|
|
||||||
/*
|
|
||||||
case ' ':
|
|
||||||
case '<':
|
|
||||||
case '>':
|
|
||||||
case '#':
|
|
||||||
case '%':
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case '|':
|
|
||||||
case '\\':
|
|
||||||
case '^':
|
|
||||||
case '~':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case '`':
|
|
||||||
case ';':
|
|
||||||
case '?':
|
|
||||||
case ':':
|
|
||||||
case '@':
|
|
||||||
case '=':
|
|
||||||
case '&':
|
|
||||||
case '$':
|
|
||||||
strm << "%" << setw(2) << (unsigned int)(unsigned char)source[p];
|
|
||||||
break;
|
|
||||||
*/
|
|
||||||
|
|
||||||
default:
|
|
||||||
strm << (char)source[p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = strm.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: url_unquote
|
|
||||||
// Description: Removes URL quoting from source and stores the result
|
|
||||||
// in result.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void
|
|
||||||
url_unquote(string &result, const string &source) {
|
|
||||||
result = string();
|
|
||||||
size_t p = 0;
|
|
||||||
while (p < source.length()) {
|
|
||||||
if (source[p] == '%') {
|
|
||||||
++p;
|
|
||||||
int ch = 0;
|
|
||||||
if (p < source.length()) {
|
|
||||||
int digit;
|
|
||||||
if (parse_hexdigit(digit, source[p])) {
|
|
||||||
ch += (digit << 4);
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if (p < source.length()) {
|
|
||||||
int digit;
|
|
||||||
if (parse_hexdigit(digit, source[p])) {
|
|
||||||
ch += digit;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
result.push_back((char)ch);
|
|
||||||
} else {
|
|
||||||
result.push_back(source[p]);
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -37,12 +37,6 @@ inline ostream &operator << (ostream &out, const wstring &str) {
|
|||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
// Some handy functions for applying and removing URL escape codes,
|
|
||||||
// which are used to pass parameters safely to p3dCert and p3dpython
|
|
||||||
// on the command line.
|
|
||||||
void url_quote(string &result, const string &source);
|
|
||||||
void url_unquote(string &result, const string &source);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user