From 795c8c0fc587187e19603dbf8cf8d8fe2badd902 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 8 Jul 2009 18:14:25 +0000 Subject: [PATCH] fix some startup issues --- direct/src/plugin_npapi/ppInstance.cxx | 209 ++++++++++++++++++++----- direct/src/plugin_npapi/ppInstance.h | 8 + direct/src/plugin_npapi/startup.cxx | 10 +- 3 files changed, 182 insertions(+), 45 deletions(-) diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 12ce218491..1f2e6a6ec8 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/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); } } diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index 414beaed07..56e356bdde 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -22,6 +22,7 @@ #include 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); diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 442c99853a..425e1946f3 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/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);