diff --git a/direct/src/plugin/make_contents.py b/direct/src/plugin/make_contents.py
index 05187c0e56..cfb7408e3f 100755
--- a/direct/src/plugin/make_contents.py
+++ b/direct/src/plugin/make_contents.py
@@ -53,9 +53,11 @@ class ContentsMaker:
f = open(contentsFilePathname.toOsSpecific(), 'w')
print >> f, ''
print >> f, ''
+ print >> f, ''
for packageName, packageVersion, packagePlatform, file in self.packages:
- print >> f, '' % (
+ print >> f, ' ' % (
packageName, packageVersion, packagePlatform or '', file.getParams())
+ print >> f, ''
f.close()
def scanDirectory(self):
diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx
index a70c11d77d..f1ad123a69 100644
--- a/direct/src/plugin_npapi/ppInstance.cxx
+++ b/direct/src/plugin_npapi/ppInstance.cxx
@@ -703,18 +703,21 @@ read_contents_file(const string &filename) {
return false;
}
- TiXmlElement *xpackage = doc.FirstChildElement("package");
- while (xpackage != NULL) {
- const char *name = xpackage->Attribute("name");
- if (name != NULL && strcmp(name, "coreapi") == 0) {
- const char *platform = xpackage->Attribute("platform");
- if (platform != NULL && strcmp(platform, P3D_PLUGIN_PLATFORM) == 0) {
- get_core_api(xpackage);
- return true;
+ TiXmlElement *xcontents = doc.FirstChildElement("contents");
+ if (xcontents != NULL) {
+ TiXmlElement *xpackage = xcontents->FirstChildElement("package");
+ while (xpackage != NULL) {
+ const char *name = xpackage->Attribute("name");
+ if (name != NULL && strcmp(name, "coreapi") == 0) {
+ const char *platform = xpackage->Attribute("platform");
+ if (platform != NULL && strcmp(platform, P3D_PLUGIN_PLATFORM) == 0) {
+ get_core_api(xpackage);
+ return true;
+ }
}
- }
- xpackage = xpackage->NextSiblingElement("package");
+ xpackage = xpackage->NextSiblingElement("package");
+ }
}
// Couldn't find the coreapi package description.
diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx
index 1b1dcad7a2..ade258eecd 100644
--- a/direct/src/plugin_standalone/panda3d.cxx
+++ b/direct/src/plugin_standalone/panda3d.cxx
@@ -15,7 +15,10 @@
#include "panda3d.h"
#include "httpClient.h"
#include "load_plugin.h"
+#include "find_root_dir.h"
+#include "p3d_plugin_config.h"
+#include
#ifdef _WIN32
#include
#endif
@@ -36,6 +39,7 @@
////////////////////////////////////////////////////////////////////
Panda3D::
Panda3D() {
+ _root_dir = find_root_dir();
}
////////////////////////////////////////////////////////////////////
@@ -48,9 +52,12 @@ int Panda3D::
run(int argc, char *argv[]) {
extern char *optarg;
extern int optind;
- const char *optstr = "p:l:t:s:o:h";
+ const char *optstr = "u:p:fl:t:s:o:h";
+
+ string root_url = P3D_PLUGIN_DOWNLOAD;
+ string this_platform = P3D_PLUGIN_PLATFORM;
+ bool force_download = false;
- Filename p3d_plugin_filename;
Filename output_filename;
P3D_window_type window_type = P3D_WT_toplevel;
int win_x = 0, win_y = 0;
@@ -60,8 +67,19 @@ run(int argc, char *argv[]) {
while (flag != EOF) {
switch (flag) {
+ case 'u':
+ root_url = optarg;
+ if (!root_url.empty() && root_url[root_url.length() - 1] != '/') {
+ root_url += '/';
+ }
+ break;
+
case 'p':
- p3d_plugin_filename = Filename::from_os_specific(optarg);
+ this_platform = optarg;
+ break;
+
+ case 'f':
+ force_download = true;
break;
case 'l':
@@ -114,7 +132,7 @@ run(int argc, char *argv[]) {
return 1;
}
- if (!load_plugin(p3d_plugin_filename.to_os_specific())) {
+ if (!get_plugin(root_url, this_platform, force_download)) {
cerr << "Unable to load Panda3D plugin.\n";
return 1;
}
@@ -257,66 +275,132 @@ run(int argc, char *argv[]) {
}
////////////////////////////////////////////////////////////////////
-// Function: Panda3D::feed_file
+// Function: Panda3D::get_plugin
// Access: Private
-// Description: Opens the named file (extracted from a file:// URL)
-// and feeds its contents to the plugin.
+// Description: Downloads the contents.xml file from the named URL
+// and attempts to use it to load the core API. Returns
+// true on success, false on failure.
////////////////////////////////////////////////////////////////////
-void Panda3D::
-feed_file(P3D_instance *inst, int unique_id, string filename) {
-#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.empty()) {
- if (filename[0] == '/' || filename[0] == '\\') {
- Filename fname = Filename::from_os_specific(filename.substr(1));
- if (fname.is_local()) {
- // Put the slash back on.
- fname = string("/") + fname.get_fullpath();
- }
- filename = fname.to_os_specific();
- }
+bool Panda3D::
+get_plugin(const string &root_url, const string &this_platform, bool force_download) {
+ // First, look for the existing contents.xml file.
+ Filename contents = Filename(Filename::from_os_specific(_root_dir), "contents.xml");
+ if (!force_download && read_contents_file(contents, root_url, this_platform)) {
+ // Got the file, and it's good.
+ return true;
}
-#endif // _WIN32
- 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
- (inst, unique_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;
+ // Couldn't read it, so go get it.
+ string url = root_url;
+ url += "contents.xml";
+ cerr << "Getting URL " << root_url << "\n";
+
+ HTTPClient *http = HTTPClient::get_global_ptr();
+ PT(HTTPChannel) channel = http->get_document(url);
+ Ramfile rf;
+ if (!channel->download_to_file(contents)) {
+ cerr << "Unable to download " << url << "\n";
+ return false;
}
- P3D_result_code result = P3D_RC_done;
- if (file.fail() && !file.eof()) {
- // Got an error while reading.
- result = P3D_RC_generic_error;
+ return read_contents_file(contents, root_url, this_platform);
+}
+
+////////////////////////////////////////////////////////////////////
+// Function: Panda3D::read_contents_file
+// Access: Private
+// Description: Attempts to open and read the contents.xml file on
+// disk, and uses that data to load the plugin, if
+// possible. Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool Panda3D::
+read_contents_file(Filename contents, const string &root_url,
+ const string &this_platform) {
+ ifstream in;
+ contents.set_text();
+ if (!contents.open_read(in)) {
+ cerr << "Couldn't read " << contents.to_os_specific() << "\n";
+ return false;
}
- P3D_instance_feed_url_stream
- (inst, unique_id, result, 0, total_count, NULL, 0);
+ TiXmlDocument doc;
+ in >> doc;
+
+ TiXmlElement *xcontents = doc.FirstChildElement("contents");
+ if (xcontents != NULL) {
+ TiXmlElement *xpackage = xcontents->FirstChildElement("package");
+ while (xpackage != NULL) {
+ const char *name = xpackage->Attribute("name");
+ if (name != NULL && strcmp(name, "coreapi") == 0) {
+ const char *xplatform = xpackage->Attribute("platform");
+ if (xplatform != NULL && strcmp(xplatform, this_platform.c_str()) == 0) {
+ return get_core_api(root_url, xpackage);
+ }
+ }
+
+ xpackage = xpackage->NextSiblingElement("package");
+ }
+ }
+
+ // Couldn't find the coreapi package description.
+ cerr << "No coreapi package defined in contents file for "
+ << this_platform << "\n";
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////
+// Function: Panda3D::get_core_api
+// Access: Private
+// Description: Checks the core API DLL file against the
+// specification in the contents file, and downloads it
+// if necessary.
+////////////////////////////////////////////////////////////////////
+bool Panda3D::
+get_core_api(const string &root_url, TiXmlElement *xpackage) {
+ _core_api_dll.load_xml(xpackage);
+
+ if (!_core_api_dll.quick_verify(_root_dir)) {
+ // The DLL file needs to be downloaded. Go get it.
+ string url = root_url;
+ url += _core_api_dll.get_filename();
+
+ Filename pathname = Filename::from_os_specific(_core_api_dll.get_pathname(_root_dir));
+ HTTPClient *http = HTTPClient::get_global_ptr();
+ PT(HTTPChannel) channel = http->get_document(url);
+ if (!channel->download_to_file(pathname)) {
+ cerr << "Unable to download " << url << "\n";
+ return false;
+ }
+
+ if (!_core_api_dll.quick_verify(_root_dir)) {
+ cerr << "Mismatched download for " << url << "\n";
+ return false;
+ }
+ }
+
+ // Now we've got the DLL. Load it.
+ string pathname = _core_api_dll.get_pathname(_root_dir);
+
+#ifdef P3D_PLUGIN_P3D_PLUGIN
+ // This is a convenience macro for development. If defined and
+ // nonempty, it indicates the name of the plugin DLL that we will
+ // actually run, even after downloading a possibly different
+ // (presumably older) version. Its purpose is to simplify iteration
+ // on the plugin DLL.
+ string override_filename = P3D_PLUGIN_P3D_PLUGIN;
+ if (!override_filename.empty()) {
+ pathname = override_filename;
+ }
+#endif // P3D_PLUGIN_P3D_PLUGIN
+
+ if (!load_plugin(pathname)) {
+ cerr << "Unable to launch core API in " << pathname << "\n" << flush;
+ return false;
+ }
+
+ // Successfully loaded.
+ return true;
}
////////////////////////////////////////////////////////////////////
@@ -370,18 +454,9 @@ handle_request(P3D_request *request) {
{
int unique_id = request->_request._get_url._unique_id;
const string &url = request->_request._get_url._url;
- if (url.substr(0, 7) == "file://") {
- // A special case: if the url begins with "file://", just open
- // the named file and feed it directly to the plugin.
- feed_file(request->_instance, unique_id, url.substr(7));
-
- } else {
- // Otherwise, assume it's a legitimate URL and pass it down to
- // Panda's HTTPClient to read it.
- URLGetter *getter = new URLGetter
- (request->_instance, unique_id, URLSpec(url), "");
- _url_getters.insert(getter);
- }
+ URLGetter *getter = new URLGetter
+ (request->_instance, unique_id, URLSpec(url), "");
+ _url_getters.insert(getter);
handled = true;
}
break;
@@ -570,11 +645,6 @@ usage() {
<< "Options:\n\n"
- << " -p " << get_plugin_basename() << "\n"
- << " Specify the full path to the particular Panda plugin DLL to\n"
- << " run. Normally, this will be found by searching in the usual\n"
- << " places.\n\n"
-
<< " -l output.log\n"
<< " Specify the name of the file to receive the log output of the\n"
<< " plugin process(es). The default is to send this output to the\n"
@@ -589,7 +659,20 @@ usage() {
<< " -o x,y\n"
<< " Specify the position (origin) of the graphic window on the\n"
- << " screen, or on the parent window.\n\n";
+ << " screen, or on the parent window.\n\n"
+
+ << " -f\n"
+ << " Force a HTTP contact to the Panda3D download server, to check\n"
+ << " if a new version is available. Normally, this is done only\n"
+ << " if contents.xml cannot be read.\n\n"
+
+ << " -u url\n"
+ << " Specify the URL of the Panda3D download server. The default is\n"
+ << " " << P3D_PLUGIN_DOWNLOAD << "\n\n"
+
+ << " -p platform\n"
+ << " Specify the platform to masquerade as. The default is "
+ << P3D_PLUGIN_PLATFORM << "\n\n";
}
////////////////////////////////////////////////////////////////////
diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h
index c43d66872d..119ed632fe 100755
--- a/direct/src/plugin_standalone/panda3d.h
+++ b/direct/src/plugin_standalone/panda3d.h
@@ -27,6 +27,7 @@
#include "p3d_plugin.h"
#include "httpChannel.h"
#include "ramfile.h"
+#include "fileSpec.h"
#include "pset.h"
////////////////////////////////////////////////////////////////////
@@ -41,7 +42,11 @@ public:
int run(int argc, char *argv[]);
private:
- void feed_file(P3D_instance *inst, int unique_id, string filename);
+ bool get_plugin(const string &root_url, const string &this_platform,
+ bool force_download);
+ bool read_contents_file(Filename contents, const string &root_url,
+ const string &this_platform);
+ bool get_core_api(const string &root_url, TiXmlElement *xpackage);
void run_getters();
void handle_request(P3D_request *request);
void make_parent_window(P3D_window_handle &parent_window,
@@ -58,6 +63,9 @@ private:
bool parse_int_pair(char *arg, int &x, int &y);
private:
+ string _root_dir;
+ FileSpec _core_api_dll;
+
typedef pset Instances;
Instances _instances;