Browse Source

fix some startup issues

David Rose 16 years ago
parent
commit
795c8c0fc5

+ 167 - 42
direct/src/plugin_npapi/ppInstance.cxx

@@ -52,14 +52,6 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
   _started_instance_data = false;
   _got_instance_data = false;
   _got_window = false;
-
-  if (!is_plugin_loaded()) {
-    // Go download the contents file, so we can download the core DLL.
-    string url = P3D_PLUGIN_DOWNLOAD;
-    url += "contents.xml";
-    PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_contents_file);
-    browser->geturlnotify(_npp_instance, url.c_str(), NULL, req);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -99,6 +91,27 @@ PPInstance::
   _tokens.clear();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::begin
+//       Access: Public
+//  Description: Begins the initial download of the core API.  This
+//               should be called after constructing the PPInstance.
+//               It is a separate method than the constructor, because
+//               it initiates some callbacks that might rely on the
+//               object having been fully constructed and its pointer
+//               stored.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+begin() {
+  if (!is_plugin_loaded()) {
+    // Go download the contents file, so we can download the core DLL.
+    string url = P3D_PLUGIN_DOWNLOAD;
+    url += "contents.xml";
+    PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_contents_file);
+    start_download(url, req);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::set_window
 //       Access: Public
@@ -172,7 +185,7 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
   switch (req->_rtype) {
   case PPDownloadRequest::RT_contents_file:
     // This is the initial contents.xml file.  We'll just download
-    // this directoy to a file, since it is small and this is easy.
+    // this directly to a file, since it is small and this is easy.
     *stype = NP_ASFILEONLY;
     return NPERR_NO_ERROR;
 
@@ -290,6 +303,13 @@ url_notify(const char *url, NPReason reason, void *notifyData) {
       req->_notified_done = true;
     }
     break;
+
+  case PPDownloadRequest::RT_contents_file:
+    if (reason != NPRES_DONE) {
+      logfile << "Failure downloading " << url << "\n";
+      // TODO: fail
+    }
+    break;
     
   default:
     break;
@@ -345,34 +365,7 @@ stream_as_file(NPStream *stream, const char *fname) {
 #endif  // __APPLE__
 
   PPDownloadRequest *req = (PPDownloadRequest *)(stream->notifyData);
-  switch (req->_rtype) {
-  case PPDownloadRequest::RT_contents_file:
-    // Now we have the contents.xml file.  Read this to get the
-    // filename and md5 hash of our core API DLL.
-    if (!read_contents_file(filename)) {
-      logfile << "Unable to read contents file\n";
-      // TODO: fail
-    }
-    break;
-
-  case PPDownloadRequest::RT_core_dll:
-    // This is the core API DLL (or dylib or whatever).  Now that
-    // we've downloaded it, we can load it.
-    downloaded_plugin(filename);
-    break;
-
-  case PPDownloadRequest::RT_instance_data:
-    // This is the instance data, e.g. the p3d filename.  Now we can
-    // launch the instance.
-    _got_instance_data = true;
-    _p3d_filename = filename;
-    create_instance();
-    break;
-
-  default:
-    // Don't know what this is.
-    logfile << "Unexpected stream_as_file, type " << (int)req->_rtype << "\n";
-  }
+  downloaded_file(req, filename);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -402,8 +395,7 @@ handle_request(P3D_request *request) {
       PPDownloadRequest *req = 
         new PPDownloadRequest(PPDownloadRequest::RT_user, 
                               request->_request._get_url._unique_id);
-      browser->geturlnotify(_npp_instance, request->_request._get_url._url,
-                            NULL, req);
+      start_download(request->_request._get_url._url, req);
     }
     break;
 
@@ -486,7 +478,7 @@ get_panda_script_object() {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::p3dobj_to_variant
-//       Access: Private
+//       Access: Public
 //  Description: Converts the indicated P3D_object to the equivalent
 //               NPVariant, and stores it in result.
 ////////////////////////////////////////////////////////////////////
@@ -533,7 +525,7 @@ p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::variant_to_p3dobj
-//       Access: Private
+//       Access: Public
 //  Description: Converts the indicated NPVariant to the equivalent
 //               P3D_object, and returns it (newly-allocated).  The
 //               caller is responsible for freeing the returned object
@@ -562,6 +554,23 @@ variant_to_p3dobj(const NPVariant *variant) {
   return P3D_new_none_object();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::start_download
+//       Access: Private
+//  Description: Initiates a download request.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+start_download(const string &url, PPDownloadRequest *req) {
+  if (url.substr(0, 7) == "file://") {
+    // If we're "downloading" a file URL, just go read the file directly.
+    downloaded_file(req, get_filename_from_url(url));
+    delete req;
+  } else {
+    // Otherwise, ask the browser to download it.
+    browser->geturlnotify(_npp_instance, url.c_str(), NULL, req);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::read_contents_file
 //       Access: Private
@@ -591,6 +600,122 @@ read_contents_file(const string &filename) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::get_filename_from_url
+//       Access: Private, Static
+//  Description: Returns the actual filename referenced by a file://
+//               url.
+////////////////////////////////////////////////////////////////////
+string PPInstance::
+get_filename_from_url(const string &url) {
+  string filename = url.substr(7);
+
+#ifdef _WIN32 
+  // On Windows, we have to munge the filename specially, because it's
+  // been URL-munged.  It might begin with a leading slash as well as
+  // a drive letter.  Clean up that nonsense.
+  if (filename.length() >= 3 && 
+      (filename[0] == '/' || filename[0] == '\\') &&
+      isalpha(filename[1]) && filename[2] == ':') {
+    filename = filename.substr(1);
+  }
+#endif  // _WIN32
+
+  return filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::downloaded_file
+//       Access: Private
+//  Description: Called to receive the fully-downloaded contents of a
+//               URL.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+downloaded_file(PPDownloadRequest *req, const string &filename) {
+  switch (req->_rtype) {
+  case PPDownloadRequest::RT_contents_file:
+    // Now we have the contents.xml file.  Read this to get the
+    // filename and md5 hash of our core API DLL.
+    if (!read_contents_file(filename)) {
+      logfile << "Unable to read contents file\n";
+      // TODO: fail
+    }
+    break;
+
+  case PPDownloadRequest::RT_core_dll:
+    // This is the core API DLL (or dylib or whatever).  Now that
+    // we've downloaded it, we can load it.
+    downloaded_plugin(filename);
+    break;
+
+  case PPDownloadRequest::RT_instance_data:
+    // This is the instance data, e.g. the p3d filename.  Now we can
+    // launch the instance.
+    _got_instance_data = true;
+    _p3d_filename = filename;
+    create_instance();
+    break;
+
+  case PPDownloadRequest::RT_user:
+    // Normally, RT_user requests won't come here, unless we
+    // short-circuited the browser by "downloading" a file:// url.  In
+    // any case, we'll now open the file and feed it to the user.
+    feed_file(req, filename);
+    break;
+
+  default:
+    // Don't know what this is.
+    logfile << "Unexpected downloaded file, type " << (int)req->_rtype << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::feed_file
+//       Access: Private
+//  Description: Opens the named file (extracted from a file:// URL)
+//               and feeds its contents to the plugin.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+feed_file(PPDownloadRequest *req, const string &filename) {
+  ifstream file(filename.c_str(), ios::in | ios::binary);
+
+  // First, seek to the end to get the file size.
+  file.seekg(0, ios::end);
+  size_t file_size = file.tellg();
+
+  // Then return to the beginning to read the data.
+  file.seekg(0, ios::beg);
+
+  static const size_t buffer_size = 4096;
+  char buffer[buffer_size];
+
+  file.read(buffer, buffer_size);
+  size_t count = file.gcount();
+  size_t total_count = 0;
+  while (count != 0) {
+    bool download_ok = P3D_instance_feed_url_stream
+      (_p3d_inst, req->_user_id, P3D_RC_in_progress,
+       0, file_size, (const unsigned char *)buffer, count);
+
+    if (!download_ok) {
+      // Never mind.
+      return;
+    }
+    file.read(buffer, buffer_size);
+    count = file.gcount();
+    total_count += count;
+  }
+  
+  P3D_result_code result = P3D_RC_done;
+  if (file.fail() && !file.eof()) {
+    // Got an error while reading.
+    result = P3D_RC_generic_error;
+  }
+
+  P3D_instance_feed_url_stream
+    (_p3d_inst, req->_user_id, result, 0, total_count, NULL, 0);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::get_core_api
 //       Access: Private
@@ -614,7 +739,7 @@ get_core_api(TiXmlElement *xpackage) {
     url += _core_api_dll.get_filename();
     
     PPDownloadRequest *req = new PPDownloadRequest(PPDownloadRequest::RT_core_dll);
-    browser->geturlnotify(_npp_instance, url.c_str(), NULL, req);
+    start_download(url, req);
   }
 }
 

+ 8 - 0
direct/src/plugin_npapi/ppInstance.h

@@ -22,6 +22,7 @@
 #include <vector>
 
 class PPPandaObject;
+class PPDownloadRequest;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PPInstance
@@ -36,6 +37,8 @@ public:
              int16 argc, char *argn[], char *argv[], NPSavedData *saved);
   ~PPInstance();
 
+  void begin();
+
   inline NPP get_npp_instance() const;
 
   inline const NPWindow *get_window() const;
@@ -56,6 +59,11 @@ public:
   P3D_object *variant_to_p3dobj(const NPVariant *variant);
 
 private:
+  void start_download(const string &url, PPDownloadRequest *req);
+  void downloaded_file(PPDownloadRequest *req, const string &filename);
+  static string get_filename_from_url(const string &url);
+  void feed_file(PPDownloadRequest *req, const string &filename);
+
   bool read_contents_file(const string &filename);
   void get_core_api(TiXmlElement *xpackage);
   void downloaded_plugin(const string &filename);

+ 7 - 3
direct/src/plugin_npapi/startup.cxx

@@ -201,8 +201,9 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
         int16 argc, char *argn[], char *argv[], NPSavedData *saved) {
   logfile << "new instance\n" << flush;
 
-  instance->pdata = new PPInstance(pluginType, instance, mode,
-                                   argc, argn, argv, saved);
+  PPInstance *inst = new PPInstance(pluginType, instance, mode,
+                                    argc, argn, argv, saved);
+  instance->pdata = inst;
 
   // To experiment with a "windowless" plugin, which really means we
   // create our own window without an intervening window, try this.
@@ -210,6 +211,10 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
   // surely it can be solved.
   //  browser->setvalue(instance, NPPVpluginWindowBool, (void *)false);
 
+  // Now that we have stored the pointer, we can call begin(), which
+  // starts to initiate downloads.
+  inst->begin();
+
   return NPERR_NO_ERROR;
 }
 
@@ -331,7 +336,6 @@ NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) {
           << ", " << stream->end 
           << ", notifyData = " << stream->notifyData
           << "\n" << flush;
-  logfile << "filename: " << fname << "\n" << flush;
 
   PPInstance *inst = (PPInstance *)(instance->pdata);
   assert(inst != NULL);