From c3936305e497b442d0c5a7cd6b58ce829a693c1c Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 30 Aug 2011 22:45:58 +0000 Subject: [PATCH] run plugin safely under a non-ASCII username --- direct/src/plugin/find_root_dir.cxx | 33 ++++++- direct/src/plugin/p3dAuthSession.cxx | 87 +++++++++++++----- direct/src/plugin/p3dAuthSession.h | 2 + direct/src/plugin/p3dCert_wx.cxx | 20 ++--- direct/src/plugin/p3dCert_wx.h | 10 +-- direct/src/plugin/p3dInstanceManager.cxx | 20 ++++- direct/src/plugin/p3dPythonRun.cxx | 25 ++++-- direct/src/plugin/p3dSession.cxx | 66 +++++++++----- direct/src/plugin/p3dSession.h | 1 + direct/src/plugin/wstring_encode.cxx | 108 ----------------------- direct/src/plugin/wstring_encode.h | 6 -- 11 files changed, 197 insertions(+), 181 deletions(-) diff --git a/direct/src/plugin/find_root_dir.cxx b/direct/src/plugin/find_root_dir.cxx index a0756e7d5f..f2750ca91c 100755 --- a/direct/src/plugin/find_root_dir.cxx +++ b/direct/src/plugin/find_root_dir.cxx @@ -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; +} diff --git a/direct/src/plugin/p3dAuthSession.cxx b/direct/src/plugin/p3dAuthSession.cxx index df0372efa7..cc457260fb 100644 --- a/direct/src/plugin/p3dAuthSession.cxx +++ b/direct/src/plugin/p3dAuthSession.cxx @@ -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; diff --git a/direct/src/plugin/p3dAuthSession.h b/direct/src/plugin/p3dAuthSession.h index 3859947e6e..bc0efda82d 100644 --- a/direct/src/plugin/p3dAuthSession.h +++ b/direct/src/plugin/p3dAuthSession.h @@ -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); diff --git a/direct/src/plugin/p3dCert_wx.cxx b/direct/src/plugin/p3dCert_wx.cxx index c765ef5514..8111adc13d 100644 --- a/direct/src/plugin/p3dCert_wx.cxx +++ b/direct/src/plugin/p3dCert_wx.cxx @@ -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; } diff --git a/direct/src/plugin/p3dCert_wx.h b/direct/src/plugin/p3dCert_wx.h index 6ae79304d5..af3800e04c 100644 --- a/direct/src/plugin/p3dCert_wx.h +++ b/direct/src/plugin/p3dCert_wx.h @@ -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; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 97c2c456d0..cb14c359e4 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -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); diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 8c271e1252..6443aa7ba1 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -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; } diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index c5b639236e..b541411749 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -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 diff --git a/direct/src/plugin/p3dSession.h b/direct/src/plugin/p3dSession.h index 8dfed6c33c..09c779b740 100644 --- a/direct/src/plugin/p3dSession.h +++ b/direct/src/plugin/p3dSession.h @@ -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: diff --git a/direct/src/plugin/wstring_encode.cxx b/direct/src/plugin/wstring_encode.cxx index 5b14f91ed4..082f2bf1f0 100755 --- a/direct/src/plugin/wstring_encode.cxx +++ b/direct/src/plugin/wstring_encode.cxx @@ -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; - } - } -} diff --git a/direct/src/plugin/wstring_encode.h b/direct/src/plugin/wstring_encode.h index 11aac6e04a..5d9fca9fc3 100755 --- a/direct/src/plugin/wstring_encode.h +++ b/direct/src/plugin/wstring_encode.h @@ -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