diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index eedeb59cc4..c1ddf335c9 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -72,8 +72,15 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, v = ""; } + // Make the token lowercase, since HTML is case-insensitive but + // we're not. + string keyword; + for (const char *p = argn[i]; *p; ++p) { + keyword += tolower(*p); + } + P3D_token token; - token._keyword = strdup(argn[i]); + token._keyword = strdup(keyword.c_str()); token._value = strdup(v); _tokens.push_back(token); } @@ -1238,6 +1245,24 @@ read_contents_file(const string &contents_filename, bool fresh_download) { return false; } + // Check the coreapi_set_ver token. If it is given, it specifies a + // minimum Core API version number we expect to find. If we didn't + // find that number, perhaps our contents.xml is out of date. + string coreapi_set_ver = lookup_token("coreapi_set_ver"); + if (!coreapi_set_ver.empty()) { + nout << "Instance asked for Core API set_ver " << coreapi_set_ver + << ", we found " << _coreapi_set_ver << "\n"; + // But don't bother if we just freshly downloaded it. + if (!fresh_download) { + if (compare_seq(coreapi_set_ver, _coreapi_set_ver) > 0) { + // The requested set_ver value is higher than the one we have on + // file; our contents.xml file must be out of date after all. + nout << "expiring contents.xml\n"; + _contents_expiration = 0; + } + } + } + // Success. Now save the file in its proper place. string standard_filename = _root_dir + "/contents.xml"; @@ -1809,6 +1834,88 @@ copy_file(const string &from_filename, const string &to_filename) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::lookup_token +// Access: Private +// Description: Returns the value associated with the first +// appearance of the named token, or empty string if the +// token does not appear. +//////////////////////////////////////////////////////////////////// +string PPInstance:: +lookup_token(const string &keyword) const { + Tokens::const_iterator ti; + for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { + if (keyword == (*ti)._keyword) { + return (*ti)._value; + } + } + + return string(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::compare_seq +// Access: Private, Static +// Description: Compares the two dotted-integer sequence values +// numerically. Returns -1 if seq_a sorts first, 1 if +// seq_b sorts first, 0 if they are equivalent. +//////////////////////////////////////////////////////////////////// +int PPInstance:: +compare_seq(const string &seq_a, const string &seq_b) { + const char *num_a = seq_a.c_str(); + const char *num_b = seq_b.c_str(); + int comp = compare_seq_int(num_a, num_b); + while (comp == 0) { + if (*num_a != '.') { + if (*num_b != '.') { + // Both strings ran out together. + return 0; + } + // a ran out first. + return -1; + } else if (*num_b != '.') { + // b ran out first. + return 1; + } + + // Increment past the dot. + ++num_a; + ++num_b; + comp = compare_seq(num_a, num_b); + } + + return comp; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::compare_seq_int +// Access: Private, Static +// Description: Numerically compares the formatted integer value at +// num_a with num_b. Increments both num_a and num_b to +// the next character following the valid integer. +//////////////////////////////////////////////////////////////////// +int PPInstance:: +compare_seq_int(const char *&num_a, const char *&num_b) { + long int a; + char *next_a; + long int b; + char *next_b; + + a = strtol((char *)num_a, &next_a, 10); + b = strtol((char *)num_b, &next_b, 10); + + num_a = next_a; + num_b = next_b; + + if (a < b) { + return -1; + } else if (b < a) { + return 1; + } else { + return 0; + } +} + //////////////////////////////////////////////////////////////////// // Function: PPInstance::set_failed // Access: Private @@ -1824,23 +1931,8 @@ set_failed() { nout << "Plugin failed.\n"; stop_outstanding_streams(); - string expression; // Look for the "onpluginfail" token. - Tokens::iterator ti; - for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { - if ((*ti)._keyword != NULL && (*ti)._value != NULL) { - // Make the token lowercase, since HTML is case-insensitive but - // we're not. - string keyword; - for (const char *p = (*ti)._keyword; *p; ++p) { - keyword += tolower(*p); - } - if (keyword == "onpluginfail") { - expression = (*ti)._value; - break; - } - } - } + string expression = lookup_token("onpluginfail"); if (!expression.empty()) { // Now attempt to evaluate the expression. diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index b29322103f..02329d1ecf 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -94,6 +94,10 @@ private: void cleanup_window(); bool copy_file(const string &from_filename, const string &to_filename); + string lookup_token(const string &keyword) const; + static int compare_seq(const string &seq_a, const string &seq_b); + static int compare_seq_int(const char *&num_a, const char *&num_b); + void set_failed(); static void handle_request_loop(); diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 72a2c13432..091f8631dd 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -536,6 +536,24 @@ read_contents_file(const Filename &contents_filename, bool fresh_download) { return false; } + // Check the coreapi_set_ver token. If it is given, it specifies a + // minimum Core API version number we expect to find. If we didn't + // find that number, perhaps our contents.xml is out of date. + string coreapi_set_ver = lookup_token("coreapi_set_ver"); + if (!coreapi_set_ver.empty()) { + nout << "Instance asked for Core API set_ver " << coreapi_set_ver + << ", we found " << _coreapi_set_ver << "\n"; + // But don't bother if we just freshly downloaded it. + if (!fresh_download) { + if (compare_seq(coreapi_set_ver, _coreapi_set_ver) > 0) { + // The requested set_ver value is higher than the one we have on + // file; our contents.xml file must be out of date after all. + nout << "expiring contents.xml\n"; + _contents_expiration = 0; + } + } + } + // Success. Now copy the file into place. Filename standard_filename = Filename(Filename::from_os_specific(_root_dir), "contents.xml"); if (fresh_download) { diff --git a/direct/src/plugin_standalone/panda3dBase.cxx b/direct/src/plugin_standalone/panda3dBase.cxx index 71f1d7bf51..33a6e750a8 100644 --- a/direct/src/plugin_standalone/panda3dBase.cxx +++ b/direct/src/plugin_standalone/panda3dBase.cxx @@ -434,19 +434,21 @@ delete_instance(P3D_instance *inst) { // on failure. //////////////////////////////////////////////////////////////////// bool Panda3DBase:: -parse_token(char *arg) { - char *equals = strchr(arg, '='); +parse_token(const char *arg) { + const char *equals = strchr(arg, '='); if (equals == NULL) { return false; } - // Directly munge the C string to truncate it at the equals sign. - // Classic C tricks. - *equals = '\0'; + // By convention, the keyword is always lowercase. + string keyword; + for (const char *p = arg; p < equals; ++p) { + keyword += tolower(*p); + } + P3D_token token; - token._keyword = strdup(arg); + token._keyword = strdup(keyword.c_str()); token._value = strdup(equals + 1); - *equals = '='; _tokens.push_back(token); @@ -460,7 +462,7 @@ parse_token(char *arg) { // Returns true on success, false on failure. //////////////////////////////////////////////////////////////////// bool Panda3DBase:: -parse_int_pair(char *arg, int &x, int &y) { +parse_int_pair(const char *arg, int &x, int &y) { char *endptr; x = strtol(arg, &endptr, 10); if (*endptr == ',') { @@ -474,6 +476,88 @@ parse_int_pair(char *arg, int &x, int &y) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: Panda3DBase::lookup_token +// Access: Protected +// Description: Returns the value associated with the first +// appearance of the named token, or empty string if the +// token does not appear. +//////////////////////////////////////////////////////////////////// +string Panda3DBase:: +lookup_token(const string &keyword) const { + Tokens::const_iterator ti; + for (ti = _tokens.begin(); ti != _tokens.end(); ++ti) { + if (keyword == (*ti)._keyword) { + return (*ti)._value; + } + } + + return string(); +} + +//////////////////////////////////////////////////////////////////// +// Function: Panda3DBase::compare_seq +// Access: Protected, Static +// Description: Compares the two dotted-integer sequence values +// numerically. Returns -1 if seq_a sorts first, 1 if +// seq_b sorts first, 0 if they are equivalent. +//////////////////////////////////////////////////////////////////// +int Panda3DBase:: +compare_seq(const string &seq_a, const string &seq_b) { + const char *num_a = seq_a.c_str(); + const char *num_b = seq_b.c_str(); + int comp = compare_seq_int(num_a, num_b); + while (comp == 0) { + if (*num_a != '.') { + if (*num_b != '.') { + // Both strings ran out together. + return 0; + } + // a ran out first. + return -1; + } else if (*num_b != '.') { + // b ran out first. + return 1; + } + + // Increment past the dot. + ++num_a; + ++num_b; + comp = compare_seq(num_a, num_b); + } + + return comp; +} + +//////////////////////////////////////////////////////////////////// +// Function: Panda3DBase::compare_seq_int +// Access: Protected, Static +// Description: Numerically compares the formatted integer value at +// num_a with num_b. Increments both num_a and num_b to +// the next character following the valid integer. +//////////////////////////////////////////////////////////////////// +int Panda3DBase:: +compare_seq_int(const char *&num_a, const char *&num_b) { + long int a; + char *next_a; + long int b; + char *next_b; + + a = strtol((char *)num_a, &next_a, 10); + b = strtol((char *)num_b, &next_b, 10); + + num_a = next_a; + num_b = next_b; + + if (a < b) { + return -1; + } else if (b < a) { + return 1; + } else { + return 0; + } +} + //////////////////////////////////////////////////////////////////// // Function: Panda3DBase::is_url // Access: Protected, Static diff --git a/direct/src/plugin_standalone/panda3dBase.h b/direct/src/plugin_standalone/panda3dBase.h index 6f42c6d68e..fba5bdd8a9 100755 --- a/direct/src/plugin_standalone/panda3dBase.h +++ b/direct/src/plugin_standalone/panda3dBase.h @@ -53,8 +53,11 @@ protected: char **args, int num_args, const int &p3d_offset = 0); void delete_instance(P3D_instance *instance); - bool parse_token(char *arg); - bool parse_int_pair(char *arg, int &x, int &y); + bool parse_token(const char *arg); + bool parse_int_pair(const char *arg, int &x, int &y); + string lookup_token(const string &keyword) const; + static int compare_seq(const string &seq_a, const string &seq_b); + static int compare_seq_int(const char *&num_a, const char *&num_b); static bool is_url(const string ¶m); void report_downloading_package(P3D_instance *instance);