Browse Source

run plugin safely under a non-ASCII username

David Rose 14 years ago
parent
commit
c3936305e4

+ 30 - 3
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;
+}

+ 66 - 21
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;

+ 2 - 0
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);

+ 10 - 10
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;
   }

+ 5 - 5
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;
 

+ 18 - 2
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);

+ 19 - 6
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;
   }

+ 46 - 20
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

+ 1 - 0
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:

+ 0 - 108
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;
-    }
-  }
-}

+ 0 - 6
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