mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -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
|
||||
// on the user's machine.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
find_root_dir() {
|
||||
static string
|
||||
find_root_dir_actual() {
|
||||
string root = find_root_dir_default();
|
||||
|
||||
// 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.
|
||||
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
|
||||
|
||||
// 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();
|
||||
|
||||
// These are the enviroment variables we forward from the current
|
||||
// environment, if they are set.
|
||||
const char *keep[] = {
|
||||
"TMP", "TEMP", "HOME", "USER",
|
||||
#ifdef _WIN32
|
||||
"SYSTEMROOT", "USERPROFILE", "COMSPEC",
|
||||
#endif
|
||||
#ifdef HAVE_X11
|
||||
"DISPLAY", "XAUTHORITY",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||
char *value = getenv(keep[ki]);
|
||||
if (value != NULL) {
|
||||
@ -201,6 +223,7 @@ start_p3dcert() {
|
||||
_env += '\0';
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// Define some new environment variables.
|
||||
_env += "PATH=";
|
||||
@ -219,6 +242,9 @@ start_p3dcert() {
|
||||
_env += root_dir;
|
||||
_env += '\0';
|
||||
|
||||
nout << "Setting environment:\n";
|
||||
write_env();
|
||||
|
||||
nout << "Attempting to start p3dcert from " << _p3dcert_exe << "\n";
|
||||
|
||||
bool started_p3dcert = false;
|
||||
@ -268,6 +294,27 @@ join_wait_thread() {
|
||||
_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
|
||||
// Access: Private
|
||||
@ -332,7 +379,7 @@ win_create_process() {
|
||||
// Make sure we see an error dialog if there is a missing DLL.
|
||||
SetErrorMode(0);
|
||||
|
||||
STARTUPINFOW startup_info;
|
||||
STARTUPINFO startup_info;
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
|
||||
@ -340,34 +387,32 @@ win_create_process() {
|
||||
startup_info.wShowWindow = SW_SHOW;
|
||||
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
|
||||
|
||||
const wchar_t *start_dir_cstr;
|
||||
wstring start_dir_w;
|
||||
string_to_wstring(start_dir_w, _start_dir);
|
||||
start_dir_cstr = start_dir_w.c_str();
|
||||
const char *start_dir_cstr = _start_dir.c_str();
|
||||
|
||||
// Construct the command-line string, containing the quoted
|
||||
// command-line arguments.
|
||||
ostringstream stream;
|
||||
stream << "\"" << _p3dcert_exe << "\" \""
|
||||
<< _cert_filename->get_filename() << "\" \""
|
||||
<< _cert_dir << "\"";
|
||||
<< _cert_filename->get_filename() << "\" \"" << _cert_dir << "\"";
|
||||
|
||||
// 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
|
||||
// non-const char array that it can modify.
|
||||
wstring command_line_str;
|
||||
string_to_wstring(command_line_str, stream.str());
|
||||
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);
|
||||
string command_line_str = stream.str();
|
||||
char *command_line = new char[command_line_str.size() + 1];
|
||||
memcpy(command_line, command_line_str.c_str(), command_line_str.size() + 1);
|
||||
|
||||
wstring p3dcert_exe_w;
|
||||
string_to_wstring(p3dcert_exe_w, _p3dcert_exe);
|
||||
nout << "Command line: " << command_line_str << "\n";
|
||||
|
||||
// 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;
|
||||
BOOL result = CreateProcessW
|
||||
(p3dcert_exe_w.c_str(), command_line, NULL, NULL, TRUE, 0,
|
||||
(void *)_env.c_str(), start_dir_cstr,
|
||||
&startup_info, &process_info);
|
||||
BOOL result = CreateProcess
|
||||
(_p3dcert_exe.c_str(), command_line, NULL, NULL, TRUE,
|
||||
0, (void *)_env.c_str(),
|
||||
start_dir_cstr, &startup_info, &process_info);
|
||||
bool started_program = (result != 0);
|
||||
|
||||
delete[] command_line;
|
||||
|
@ -44,6 +44,8 @@ private:
|
||||
void spawn_wait_thread();
|
||||
void join_wait_thread();
|
||||
|
||||
void write_env() const;
|
||||
|
||||
private:
|
||||
// These methods run only within the read thread.
|
||||
THREAD_CALLBACK_DECLARATION(P3DAuthSession, wt_thread_run);
|
||||
|
@ -124,8 +124,9 @@ OnInitCmdLine(wxCmdLineParser &parser) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool P3DCertApp::
|
||||
OnCmdLineParsed(wxCmdLineParser &parser) {
|
||||
_cert_filename = parser.GetParam(0);
|
||||
_cert_dir = parser.GetParam(1);
|
||||
_cert_filename = (const char *)parser.GetParam(0).mb_str();
|
||||
_cert_dir = (const char *)parser.GetParam(1).mb_str();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -144,7 +145,7 @@ END_EVENT_TABLE()
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
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
|
||||
// doesn't come to the foreground on OSX, and might be lost behind
|
||||
// the browser window.
|
||||
@ -232,8 +233,7 @@ approve_cert() {
|
||||
assert(_cert != NULL);
|
||||
|
||||
// Make sure the directory exists.
|
||||
string cert_dir_str = (const char *)_cert_dir.mb_str();
|
||||
mkdir_complete(cert_dir_str, cerr);
|
||||
mkdir_complete(_cert_dir, cerr);
|
||||
|
||||
// Look for an unused filename.
|
||||
int i = 1;
|
||||
@ -288,24 +288,24 @@ approve_cert() {
|
||||
// passed on the command line into _cert and _stack.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AuthDialog::
|
||||
read_cert_file(const wxString &cert_filename) {
|
||||
read_cert_file(const string &cert_filename) {
|
||||
FILE *fp = NULL;
|
||||
#ifdef _WIN32
|
||||
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");
|
||||
}
|
||||
#else // _WIN32
|
||||
fp = fopen(cert_filename.mb_str(), "r");
|
||||
fp = fopen(cert_filename.c_str(), "r");
|
||||
#endif // _WIN32
|
||||
|
||||
if (fp == NULL) {
|
||||
cerr << "Couldn't read " << cert_filename.mb_str() << "\n";
|
||||
cerr << "Couldn't read " << cert_filename << "\n";
|
||||
return;
|
||||
}
|
||||
_cert = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ public:
|
||||
virtual bool OnCmdLineParsed(wxCmdLineParser &parser);
|
||||
|
||||
private:
|
||||
wxString _cert_filename;
|
||||
wxString _cert_dir;
|
||||
string _cert_filename;
|
||||
string _cert_dir;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -67,7 +67,7 @@ private:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class AuthDialog : public wxDialog {
|
||||
public:
|
||||
AuthDialog(const wxString &cert_filename, const wxString &cert_dir);
|
||||
AuthDialog(const string &cert_filename, const string &cert_dir);
|
||||
virtual ~AuthDialog();
|
||||
|
||||
void run_clicked(wxCommandEvent &event);
|
||||
@ -77,7 +77,7 @@ public:
|
||||
void approve_cert();
|
||||
|
||||
private:
|
||||
void read_cert_file(const wxString &cert_filename);
|
||||
void read_cert_file(const string &cert_filename);
|
||||
void get_friendly_name();
|
||||
void verify_cert();
|
||||
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
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
wxString _cert_dir;
|
||||
string _cert_dir;
|
||||
X509 *_cert;
|
||||
STACK_OF(X509) *_stack;
|
||||
|
||||
|
@ -839,7 +839,15 @@ find_cert(X509 *cert) {
|
||||
for (si = contents.begin(); si != contents.end(); ++si) {
|
||||
string filename = this_cert_dir + "/" + (*si);
|
||||
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) {
|
||||
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||
fclose(fp);
|
||||
@ -882,7 +890,15 @@ read_certlist(P3DPackage *package) {
|
||||
if (suffix == ".pem" || suffix == ".crt") {
|
||||
string filename = package->get_package_dir() + "/" + basename;
|
||||
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) {
|
||||
x509 = PEM_read_X509(fp, NULL, NULL, (void *)"");
|
||||
fclose(fp);
|
||||
|
@ -156,16 +156,16 @@ run_python() {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Of course it's already resident, so use that version.
|
||||
string basename = Filename::dso_filename("libpandaexpress.so").to_os_specific();
|
||||
HMODULE h = GetModuleHandle(basename.c_str());
|
||||
wstring basename = Filename::dso_filename("libpandaexpress.so").to_os_specific_w();
|
||||
HMODULE h = GetModuleHandleW(basename.c_str());
|
||||
|
||||
if (h == NULL) {
|
||||
nout << "Can't find libpandaexpress in memory.\n";
|
||||
} else {
|
||||
static const int buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
GetModuleFileName(h, buffer, buffer_size);
|
||||
libpandaexpress = Filename::from_os_specific(buffer);
|
||||
wchar_t buffer[buffer_size];
|
||||
GetModuleFileNameW(h, buffer, buffer_size);
|
||||
libpandaexpress = Filename::from_os_specific_w(buffer);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
@ -179,7 +179,7 @@ run_python() {
|
||||
libpandaexpress.set_type(Filename::T_general);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (!libpandaexpress.exists()) {
|
||||
nout << "Can't find " << libpandaexpress << "\n";
|
||||
return false;
|
||||
@ -188,15 +188,22 @@ run_python() {
|
||||
// We need the "imp" built-in module for that.
|
||||
PyObject *imp_module = PyImport_ImportModule("imp");
|
||||
if (imp_module == NULL) {
|
||||
nout << "Failed to import module imp\n";
|
||||
PyErr_Print();
|
||||
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();
|
||||
PyObject *result = PyObject_CallMethod
|
||||
(imp_module, (char *)"load_dynamic", (char *)"ss",
|
||||
"libpandaexpress", os_specific.c_str());
|
||||
if (result == NULL) {
|
||||
nout << "Failed to import libpandaexpress as a module\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -208,6 +215,7 @@ run_python() {
|
||||
// available to import as well.
|
||||
PyObject *vfsimporter = PyImport_ImportModule("_vfsimporter");
|
||||
if (vfsimporter == NULL) {
|
||||
nout << "Failed to import _vfsimporter\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -216,6 +224,7 @@ run_python() {
|
||||
// And now we can import the VFSImporter module that was so defined.
|
||||
PyObject *vfsimporter_module = PyImport_ImportModule("VFSImporter");
|
||||
if (vfsimporter_module == NULL) {
|
||||
nout << "Failed to import VFSImporter\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -223,6 +232,7 @@ run_python() {
|
||||
// And register the VFSImporter.
|
||||
result = PyObject_CallMethod(vfsimporter_module, (char *)"register", (char *)"");
|
||||
if (result == NULL) {
|
||||
nout << "Failed to call VFSImporter.register()\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -248,6 +258,7 @@ run_python() {
|
||||
// And finally, we can import the startup module.
|
||||
PyObject *app_runner_module = PyImport_ImportModule("direct.p3d.AppRunner");
|
||||
if (app_runner_module == NULL) {
|
||||
nout << "Failed to import direct.p3d.AppRunner\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -255,6 +266,7 @@ run_python() {
|
||||
// Get the pointers to the objects needed within the module.
|
||||
PyObject *app_runner_class = PyObject_GetAttrString(app_runner_module, "AppRunner");
|
||||
if (app_runner_class == NULL) {
|
||||
nout << "Failed to get AppRunner class\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
@ -262,6 +274,7 @@ run_python() {
|
||||
// Construct an instance of AppRunner.
|
||||
_runner = PyObject_CallFunction(app_runner_class, (char *)"");
|
||||
if (_runner == NULL) {
|
||||
nout << "Failed to construct AppRunner instance\n";
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
|
@ -795,21 +795,14 @@ start_p3dpython(P3DInstance *inst) {
|
||||
// This allows the caller's on-disk Python files to shadow the
|
||||
// similar-named files in the p3d file, allowing easy iteration on
|
||||
// the code in the p3d file.
|
||||
const char *pypath = getenv("PYTHONPATH");
|
||||
if (pypath != (char *)NULL) {
|
||||
python_path = pypath;
|
||||
if (get_env(python_path, "PYTHONPATH")) {
|
||||
replace_slashes(python_path);
|
||||
python_path += sep;
|
||||
python_path += search_path;
|
||||
}
|
||||
|
||||
// We also preserve PRC_PATH.
|
||||
const char *prcpath = getenv("PRC_PATH");
|
||||
if (prcpath == NULL) {
|
||||
prcpath = getenv("PANDA_PRC_PATH");
|
||||
}
|
||||
if (prcpath != (char *)NULL) {
|
||||
prc_path = prcpath;
|
||||
if (get_env(prc_path, "PRC_PATH") || get_env(prc_path, "PANDA_PRC_PATH")) {
|
||||
replace_slashes(prc_path);
|
||||
prc_path += sep;
|
||||
prc_path += search_path;
|
||||
@ -891,8 +884,8 @@ start_p3dpython(P3DInstance *inst) {
|
||||
NULL
|
||||
};
|
||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||
char *value = getenv(keep[ki]);
|
||||
if (value != NULL) {
|
||||
string value;
|
||||
if (get_env(value, keep[ki])) {
|
||||
_env += keep[ki];
|
||||
_env += "=";
|
||||
_env += value;
|
||||
@ -950,18 +943,18 @@ start_p3dpython(P3DInstance *inst) {
|
||||
// definitions, even if keep_user_env is not set. This is necessary
|
||||
// for os.system() and such to work as expected within the embedded
|
||||
// app. It's also necessary for webbrowser on Linux.
|
||||
char *orig_path = getenv("PATH");
|
||||
if (orig_path != NULL) {
|
||||
string orig_path;
|
||||
if (get_env(orig_path, "PATH")) {
|
||||
sys_path += sep;
|
||||
sys_path += orig_path;
|
||||
}
|
||||
char *orig_ld_path = getenv("LD_LIBRARY_PATH");
|
||||
if (orig_ld_path != NULL) {
|
||||
string orig_ld_path;
|
||||
if (get_env(orig_ld_path, "LD_LIBRARY_PATH")) {
|
||||
ld_path += sep;
|
||||
ld_path += orig_ld_path;
|
||||
}
|
||||
char *orig_dyld_path = getenv("DYLD_LIBRARY_PATH");
|
||||
if (orig_dyld_path != NULL) {
|
||||
string orig_dyld_path;
|
||||
if (get_env(orig_dyld_path, "DYLD_LIBRARY_PATH")) {
|
||||
dyld_path += sep;
|
||||
dyld_path += orig_dyld_path;
|
||||
}
|
||||
@ -1541,14 +1534,18 @@ win_create_process() {
|
||||
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);
|
||||
|
||||
nout << "Command line: " << command_line_str << "\n";
|
||||
|
||||
wstring p3dpython_exe_w;
|
||||
string_to_wstring(p3dpython_exe_w, _p3dpython_exe);
|
||||
wstring env_w;
|
||||
string_to_wstring(env_w, _env);
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
BOOL result = CreateProcessW
|
||||
(p3dpython_exe_w.c_str(), command_line, NULL, NULL, TRUE, 0,
|
||||
(void *)_env.c_str(), start_dir_cstr,
|
||||
&startup_info, &process_info);
|
||||
(p3dpython_exe_w.c_str(), command_line, NULL, NULL, TRUE,
|
||||
CREATE_UNICODE_ENVIRONMENT, (void *)env_w.c_str(),
|
||||
start_dir_cstr, &startup_info, &process_info);
|
||||
bool started_program = (result != 0);
|
||||
|
||||
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
|
||||
// Access: Private
|
||||
|
@ -90,6 +90,7 @@ private:
|
||||
THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run);
|
||||
void p3dpython_thread_run();
|
||||
|
||||
static bool get_env(string &value, const string &varname);
|
||||
void write_env() const;
|
||||
|
||||
private:
|
||||
|
@ -72,111 +72,3 @@ string_to_wstring(wstring &result, const string &source) {
|
||||
return success;
|
||||
}
|
||||
#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
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user