Browse Source

per_platform flag, giving better compatibility with old p3d files

David Rose 13 years ago
parent
commit
a737ebcc90

+ 6 - 2
direct/src/p3d/AppRunner.py

@@ -104,6 +104,7 @@ class AppRunner(DirectObject):
         self.interactiveConsole = False
         self.interactiveConsole = False
         self.initialAppImport = False
         self.initialAppImport = False
         self.trueFileIO = False
         self.trueFileIO = False
+        self.respectPerPlatform = None
 
 
         self.verifyContents = self.P3DVCNone
         self.verifyContents = self.P3DVCNone
 
 
@@ -493,7 +494,7 @@ class AppRunner(DirectObject):
             hostData = InstalledHostData(host, dirnode)
             hostData = InstalledHostData(host, dirnode)
 
 
             if host:
             if host:
-                for package in host.getAllPackages():
+                for package in host.getAllPackages(includeAllPlatforms = True):
                     packageDir = package.getPackageDir()
                     packageDir = package.getPackageDir()
                     if not packageDir.exists():
                     if not packageDir.exists():
                         continue
                         continue
@@ -781,7 +782,7 @@ class AppRunner(DirectObject):
         self.deferredEvals = []
         self.deferredEvals = []
 
 
     def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl,
     def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl,
-                        verifyContents, main):
+                        verifyContents, main, respectPerPlatform):
         """ Called by the browser to set some global information about
         """ Called by the browser to set some global information about
         the instance. """
         the instance. """
 
 
@@ -807,6 +808,9 @@ class AppRunner(DirectObject):
         if main is not None:
         if main is not None:
             self.main = main
             self.main = main
 
 
+        self.respectPerPlatform = respectPerPlatform
+        #self.notify.info("respectPerPlatform = %s" % (self.respectPerPlatform))
+
         # Now that we have rootDir, we can read the config file.
         # Now that we have rootDir, we can read the config file.
         self.readConfigXml()
         self.readConfigXml()
         
         

+ 23 - 9
direct/src/p3d/HostInfo.py

@@ -28,9 +28,16 @@ class HostInfo:
         there.  At the moment, mirror folders do not download old
         there.  At the moment, mirror folders do not download old
         patch files from the server.
         patch files from the server.
 
 
-        perPlatform remains for historical reasons, but it is ignored.
-        Nowadays, all files are always unpacked into platform-specific
-        directories, even on the client. """
+        If you pass perPlatform = True, then files are unpacked into a
+        platform-specific directory, which is appropriate when you
+        might be downloading multiple platforms.  The default is
+        perPlatform = False, which means all files are unpacked into
+        the host directory directly, without an intervening
+        platform-specific directory name.  If asMirror is True, then
+        the default is perPlatform = True.
+
+        Note that perPlatform is also restricted by the individual
+        package's specification.  """
 
 
         assert appRunner or rootDir or hostDir
         assert appRunner or rootDir or hostDir
 
 
@@ -45,7 +52,9 @@ class HostInfo:
             
             
         self.hostDir = hostDir
         self.hostDir = hostDir
         self.asMirror = asMirror
         self.asMirror = asMirror
-        self.perPlatform = True
+        self.perPlatform = perPlatform
+        if perPlatform is None:
+            self.perPlatform = asMirror
 
 
         # Initially false, this is set true when the contents file is
         # Initially false, this is set true when the contents file is
         # successfully read.
         # successfully read.
@@ -372,8 +381,12 @@ class HostInfo:
                 solo = int(xpackage.Attribute('solo') or '')
                 solo = int(xpackage.Attribute('solo') or '')
             except ValueError:
             except ValueError:
                 solo = False
                 solo = False
+            try:
+                perPlatform = int(xpackage.Attribute('per_platform') or '')
+            except ValueError:
+                perPlatform = False
                 
                 
-            package = self.__makePackage(name, platform, version, solo)
+            package = self.__makePackage(name, platform, version, solo, perPlatform)
             package.descFile = FileSpec()
             package.descFile = FileSpec()
             package.descFile.loadXml(xpackage)
             package.descFile.loadXml(xpackage)
             package.setupFilenames()
             package.setupFilenames()
@@ -493,7 +506,7 @@ class HostInfo:
                 self.altHosts[keyword] = url
                 self.altHosts[keyword] = url
             xalthost = xalthost.NextSiblingElement('alt_host')
             xalthost = xalthost.NextSiblingElement('alt_host')
 
 
-    def __makePackage(self, name, platform, version, solo):
+    def __makePackage(self, name, platform, version, solo, perPlatform):
         """ Creates a new PackageInfo entry for the given name,
         """ Creates a new PackageInfo entry for the given name,
         version, and platform.  If there is already a matching
         version, and platform.  If there is already a matching
         PackageInfo, returns it. """
         PackageInfo, returns it. """
@@ -507,7 +520,8 @@ class HostInfo:
         package = platforms.get(platform, None)
         package = platforms.get(platform, None)
         if not package:
         if not package:
             package = PackageInfo(self, name, version, platform = platform,
             package = PackageInfo(self, name, version, platform = platform,
-                                  solo = solo, asMirror = self.asMirror)
+                                  solo = solo, asMirror = self.asMirror,
+                                  perPlatform = perPlatform)
             platforms[platform] = package
             platforms[platform] = package
 
 
         return package
         return package
@@ -560,7 +574,7 @@ class HostInfo:
 
 
         return packages
         return packages
 
 
-    def getAllPackages(self):
+    def getAllPackages(self, includeAllPlatforms = False):
         """ Returns a list of all available packages provided by this
         """ Returns a list of all available packages provided by this
         host. """
         host. """
 
 
@@ -569,7 +583,7 @@ class HostInfo:
         items = self.packages.items()
         items = self.packages.items()
         items.sort()
         items.sort()
         for key, platforms in items:
         for key, platforms in items:
-            if self.perPlatform:
+            if self.perPlatform or includeAllPlatforms:
                 # If we maintain a different answer per platform,
                 # If we maintain a different answer per platform,
                 # return all of them.
                 # return all of them.
                 pitems = platforms.items()
                 pitems = platforms.items()

+ 25 - 6
direct/src/p3d/PackageInfo.py

@@ -78,13 +78,14 @@ class PackageInfo:
             return min(float(self.bytesDone) / float(self.bytesNeeded), 1)
             return min(float(self.bytesDone) / float(self.bytesNeeded), 1)
     
     
     def __init__(self, host, packageName, packageVersion, platform = None,
     def __init__(self, host, packageName, packageVersion, platform = None,
-                 solo = False, asMirror = False):
+                 solo = False, asMirror = False, perPlatform = False):
         self.host = host
         self.host = host
         self.packageName = packageName
         self.packageName = packageName
         self.packageVersion = packageVersion
         self.packageVersion = packageVersion
         self.platform = platform
         self.platform = platform
         self.solo = solo
         self.solo = solo
         self.asMirror = asMirror
         self.asMirror = asMirror
+        self.perPlatform = perPlatform
 
 
         # This will be active while we are in the middle of a download
         # This will be active while we are in the middle of a download
         # cycle.
         # cycle.
@@ -144,12 +145,23 @@ class PackageInfo:
                 self.packageDir = Filename(self.packageDir, self.packageVersion)
                 self.packageDir = Filename(self.packageDir, self.packageVersion)
 
 
             if self.host.perPlatform:
             if self.host.perPlatform:
-                # The server directory contains the platform name,
-                # though the client directory normally doesn't (unless
-                # perPlatform is set true).
+                # If we're running on a special host that wants us to
+                # include the platform, we include it.
+                includePlatform = True
+            elif self.perPlatform and self.host.appRunner.respectPerPlatform:
+                # Otherwise, if our package spec wants us to include
+                # the platform (and our plugin knows about this), then
+                # we also include it.
+                includePlatform = True
+            else:
+                # Otherwise, we must be running legacy code
+                # somewhere--either an old package or an old
+                # plugin--and we therefore shouldn't include the
+                # platform in the directory hierarchy.
+                includePlatform = False
                 
                 
-                if self.platform:
-                    self.packageDir = Filename(self.packageDir, self.platform)
+            if includePlatform and self.platform:
+                self.packageDir = Filename(self.packageDir, self.platform)
 
 
         return self.packageDir
         return self.packageDir
 
 
@@ -346,6 +358,13 @@ class PackageInfo:
         except ValueError:
         except ValueError:
             self.patchVersion = None
             self.patchVersion = None
 
 
+        try:
+            perPlatform = int(xpackage.Attribute('per_platform') or '')
+        except ValueError:
+            perPlatform = False
+        if perPlatform != self.perPlatform:
+            self.notify.warning("per_platform disagreement on package %s" % (self.packageName))
+
         self.displayName = None
         self.displayName = None
         xconfig = xpackage.FirstChildElement('config')
         xconfig = xpackage.FirstChildElement('config')
         if xconfig:
         if xconfig:

+ 4 - 0
direct/src/p3d/PackageMerger.py

@@ -41,6 +41,8 @@ class PackageMerger:
             self.version = xpackage.Attribute('version')
             self.version = xpackage.Attribute('version')
             solo = xpackage.Attribute('solo')
             solo = xpackage.Attribute('solo')
             self.solo = int(solo or '0')
             self.solo = int(solo or '0')
+            perPlatform = xpackage.Attribute('per_platform')
+            self.perPlatform = int(perPlatform or '0')
 
 
             self.descFile = FileSpec()
             self.descFile = FileSpec()
             self.descFile.loadXml(xpackage)
             self.descFile.loadXml(xpackage)
@@ -71,6 +73,8 @@ class PackageMerger:
                 xpackage.SetAttribute('version', self.version)
                 xpackage.SetAttribute('version', self.version)
             if self.solo:
             if self.solo:
                 xpackage.SetAttribute('solo', '1')
                 xpackage.SetAttribute('solo', '1')
+            if self.perPlatform:
+                xpackage.SetAttribute('per_platform', '1')
 
 
             self.descFile.storeXml(xpackage)
             self.descFile.storeXml(xpackage)
             self.packageSeq.storeXml(xpackage, 'seq')
             self.packageSeq.storeXml(xpackage, 'seq')

+ 18 - 3
direct/src/p3d/Packager.py

@@ -187,12 +187,13 @@ class Packager:
             objects uniquely per package. """
             objects uniquely per package. """
             return (self.packageName, self.platform, self.version)
             return (self.packageName, self.platform, self.version)
 
 
-        def fromFile(self, packageName, platform, version, solo,
+        def fromFile(self, packageName, platform, version, solo, perPlatform,
                      installDir, descFilename, importDescFilename):
                      installDir, descFilename, importDescFilename):
             self.packageName = packageName
             self.packageName = packageName
             self.platform = platform
             self.platform = platform
             self.version = version
             self.version = version
             self.solo = solo
             self.solo = solo
+            self.perPlatform = perPlatform
 
 
             self.descFile = FileSpec()
             self.descFile = FileSpec()
             self.descFile.fromFile(installDir, descFilename)
             self.descFile.fromFile(installDir, descFilename)
@@ -208,6 +209,8 @@ class Packager:
             self.version = xpackage.Attribute('version')
             self.version = xpackage.Attribute('version')
             solo = xpackage.Attribute('solo')
             solo = xpackage.Attribute('solo')
             self.solo = int(solo or '0')
             self.solo = int(solo or '0')
+            perPlatform = xpackage.Attribute('per_platform')
+            self.perPlatform = int(perPlatform or '0')
 
 
             self.packageSeq = SeqValue()
             self.packageSeq = SeqValue()
             self.packageSeq.loadXml(xpackage, 'seq')
             self.packageSeq.loadXml(xpackage, 'seq')
@@ -235,6 +238,8 @@ class Packager:
                 xpackage.SetAttribute('version', self.version)
                 xpackage.SetAttribute('version', self.version)
             if self.solo:
             if self.solo:
                 xpackage.SetAttribute('solo', '1')
                 xpackage.SetAttribute('solo', '1')
+            if self.perPlatform:
+                xpackage.SetAttribute('per_platform', '1')
 
 
             self.packageSeq.storeXml(xpackage, 'seq')
             self.packageSeq.storeXml(xpackage, 'seq')
             self.packageSetVer.storeXml(xpackage, 'set_ver')
             self.packageSetVer.storeXml(xpackage, 'set_ver')
@@ -322,6 +327,9 @@ class Packager:
             # platform-specific.
             # platform-specific.
             self.platform = None
             self.platform = None
 
 
+            # This is always true on modern packages.
+            self.perPlatform = True
+
             # The arch string, though, is pre-loaded from the system
             # The arch string, though, is pre-loaded from the system
             # arch string, so we can sensibly call otool.
             # arch string, so we can sensibly call otool.
             self.arch = self.packager.arch
             self.arch = self.packager.arch
@@ -722,6 +730,7 @@ class Packager:
             else:
             else:
                 self.readDescFile()
                 self.readDescFile()
                 self.packageSeq += 1
                 self.packageSeq += 1
+                self.perPlatform = True  # always true on modern packages.
                 self.compressMultifile()
                 self.compressMultifile()
                 self.writeDescFile()
                 self.writeDescFile()
                 self.writeImportDescFile()
                 self.writeImportDescFile()
@@ -734,7 +743,7 @@ class Packager:
                 # Replace or add the entry in the contents.
                 # Replace or add the entry in the contents.
                 pe = Packager.PackageEntry()
                 pe = Packager.PackageEntry()
                 pe.fromFile(self.packageName, self.platform, self.version,
                 pe.fromFile(self.packageName, self.platform, self.version,
-                            False, self.packager.installDir,
+                            False, self.perPlatform, self.packager.installDir,
                             self.packageDesc, self.packageImportDesc)
                             self.packageDesc, self.packageImportDesc)
                 pe.packageSeq = self.packageSeq
                 pe.packageSeq = self.packageSeq
                 pe.packageSetVer = self.packageSetVer
                 pe.packageSetVer = self.packageSetVer
@@ -753,6 +762,7 @@ class Packager:
             kinds of similar "solo" packages as well. """
             kinds of similar "solo" packages as well. """
 
 
             self.considerPlatform()
             self.considerPlatform()
+            self.perPlatform = False  # Not true on "solo" packages.
 
 
             packageDir = self.packageName
             packageDir = self.packageName
             if self.platform:
             if self.platform:
@@ -798,7 +808,7 @@ class Packager:
             # Replace or add the entry in the contents.
             # Replace or add the entry in the contents.
             pe = Packager.PackageEntry()
             pe = Packager.PackageEntry()
             pe.fromFile(self.packageName, self.platform, self.version,
             pe.fromFile(self.packageName, self.platform, self.version,
-                        True, self.packager.installDir,
+                        True, self.perPlatform, self.packager.installDir,
                         Filename(packageDir, file.newName), None)
                         Filename(packageDir, file.newName), None)
             peOrig = self.packager.contents.get(pe.getKey(), None)
             peOrig = self.packager.contents.get(pe.getKey(), None)
             if peOrig:
             if peOrig:
@@ -1509,6 +1519,9 @@ class Packager:
             if not xpackage:
             if not xpackage:
                 return
                 return
 
 
+            perPlatform = xpackage.Attribute('per_platform')
+            self.perPlatform = int(perPlatform or '0')
+
             self.packageSeq.loadXml(xpackage, 'seq')
             self.packageSeq.loadXml(xpackage, 'seq')
             self.packageSetVer.loadXml(xpackage, 'set_ver')
             self.packageSetVer.loadXml(xpackage, 'set_ver')
 
 
@@ -1554,6 +1567,8 @@ class Packager:
                 xpackage.SetAttribute('platform', self.platform)
                 xpackage.SetAttribute('platform', self.platform)
             if self.version:
             if self.version:
                 xpackage.SetAttribute('version', self.version)
                 xpackage.SetAttribute('version', self.version)
+            if self.perPlatform:
+                xpackage.SetAttribute('per_platform', '1')
 
 
             if self.patchVersion:
             if self.patchVersion:
                 xpackage.SetAttribute('last_patch_version', self.patchVersion)
                 xpackage.SetAttribute('last_patch_version', self.patchVersion)

+ 3 - 1
direct/src/plugin/Sources.pp

@@ -70,6 +70,7 @@
     p3dX11SplashWindow.h p3dX11SplashWindow.I \
     p3dX11SplashWindow.h p3dX11SplashWindow.I \
     p3dWindowParams.h p3dWindowParams.I \
     p3dWindowParams.h p3dWindowParams.I \
     plugin_get_x11.h \
     plugin_get_x11.h \
+    xml_helpers.h \
     run_p3dpython.h
     run_p3dpython.h
 
 
 #define COREAPI_INCLUDED_SOURCES \
 #define COREAPI_INCLUDED_SOURCES \
@@ -104,7 +105,8 @@
     p3dUndefinedObject.cxx \
     p3dUndefinedObject.cxx \
     p3dWinSplashWindow.cxx \
     p3dWinSplashWindow.cxx \
     p3dX11SplashWindow.cxx \
     p3dX11SplashWindow.cxx \
-    p3dWindowParams.cxx
+    p3dWindowParams.cxx \
+    xml_helpers.cxx
 
 
 #begin lib_target
 #begin lib_target
 
 

+ 22 - 12
direct/src/plugin/p3dFileParams.cxx

@@ -89,26 +89,36 @@ set_p3d_url(const string &p3d_url) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DFileParams::set_tokens
 //     Function: P3DFileParams::set_tokens
 //       Access: Public
 //       Access: Public
-//  Description: Specifies the tokens associated with the instance.
+//  Description: Replaces all the tokens associated with the instance.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DFileParams::
 void P3DFileParams::
 set_tokens(const P3D_token tokens[], size_t num_tokens) {
 set_tokens(const P3D_token tokens[], size_t num_tokens) {
   _tokens.clear();
   _tokens.clear();
 
 
   for (size_t i = 0; i < num_tokens; ++i) {
   for (size_t i = 0; i < num_tokens; ++i) {
-    Token token;
-    if (tokens[i]._keyword != NULL) {
-      // Make the token lowercase, since HTML is case-insensitive but
-      // we're not.
-      for (const char *p = tokens[i]._keyword; *p; ++p) {
-        token._keyword += tolower(*p);
-      }
-    }
-    if (tokens[i]._value != NULL) {
-      token._value = tokens[i]._value;
+    set_token(tokens[i]._keyword, tokens[i]._value);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DFileParams::set_token
+//       Access: Public
+//  Description: Sets an individual token value.
+////////////////////////////////////////////////////////////////////
+void P3DFileParams::
+set_token(const char *keyword, const char *value) {
+  Token token;
+  if (keyword != NULL) {
+    // Make the token lowercase, since HTML is case-insensitive but
+    // we're not.
+    for (const char *p = keyword; *p; ++p) {
+      token._keyword += tolower(*p);
     }
     }
-    _tokens.push_back(token);
   }
   }
+  if (value != NULL) {
+    token._value = value;
+  }
+  _tokens.push_back(token);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
direct/src/plugin/p3dFileParams.h

@@ -34,6 +34,7 @@ public:
   void set_p3d_offset(const int &p3d_offset);
   void set_p3d_offset(const int &p3d_offset);
   void set_p3d_url(const string &p3d_url);
   void set_p3d_url(const string &p3d_url);
   void set_tokens(const P3D_token tokens[], size_t num_tokens);
   void set_tokens(const P3D_token tokens[], size_t num_tokens);
+  void set_token(const char *keyword, const char *value);
   void set_args(int argc, const char *argv[]);
   void set_args(int argc, const char *argv[]);
 
 
   inline const string &get_p3d_filename() const;
   inline const string &get_p3d_filename() const;

+ 16 - 41
direct/src/plugin/p3dHost.cxx

@@ -17,6 +17,7 @@
 #include "p3dPackage.h"
 #include "p3dPackage.h"
 #include "mkdir_complete.h"
 #include "mkdir_complete.h"
 #include "wstring_encode.h"
 #include "wstring_encode.h"
+#include "xml_helpers.h"
 #include "openssl/md5.h"
 #include "openssl/md5.h"
 
 
 #include <algorithm>
 #include <algorithm>
@@ -445,12 +446,15 @@ get_package(const string &package_name, const string &package_version,
 //     Function: P3DHost::choose_suitable_platform
 //     Function: P3DHost::choose_suitable_platform
 //       Access: Public
 //       Access: Public
 //  Description: Chooses the most appropriate platform for the
 //  Description: Chooses the most appropriate platform for the
-//               indicated package (presumably the "panda3d" package),
-//               based on what this hardware supports and what is
-//               actually available.
+//               indicated package based on what this hardware
+//               supports and what is actually available.  Also fills
+//               in per_platform, which is a boolean value indicating
+//               whether the directory structure contains the platform
+//               directory or not.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool P3DHost::
 bool P3DHost::
 choose_suitable_platform(string &selected_platform,
 choose_suitable_platform(string &selected_platform,
+                         bool &per_platform,
                          const string &package_name,
                          const string &package_name,
                          const string &package_version,
                          const string &package_version,
                          const string &package_platform) {
                          const string &package_platform) {
@@ -482,6 +486,7 @@ choose_suitable_platform(string &selected_platform,
             package_version == version) {
             package_version == version) {
           // Here's the matching package definition.
           // Here's the matching package definition.
           selected_platform = platform;
           selected_platform = platform;
+          per_platform = parse_bool_attrib(xpackage, "per_platform", false);
           return true;
           return true;
         }
         }
         
         
@@ -490,7 +495,7 @@ choose_suitable_platform(string &selected_platform,
     }
     }
   }
   }
 
 
-  // Now, we look for an exact match for the current platform.
+  // Now, we look for an exact match for the expected platform.
   xpackage = _xcontents->FirstChildElement("package");
   xpackage = _xcontents->FirstChildElement("package");
   while (xpackage != NULL) {
   while (xpackage != NULL) {
     const char *name = xpackage->Attribute("name");
     const char *name = xpackage->Attribute("name");
@@ -505,13 +510,15 @@ choose_suitable_platform(string &selected_platform,
         package_version == version) {
         package_version == version) {
       // Here's the matching package definition.
       // Here's the matching package definition.
       selected_platform = platform;
       selected_platform = platform;
+      per_platform = parse_bool_attrib(xpackage, "per_platform", false);
       return true;
       return true;
     }
     }
 
 
     xpackage = xpackage->NextSiblingElement("package");
     xpackage = xpackage->NextSiblingElement("package");
   }
   }
 
 
-  // Look again, this time looking for a non-platform-specific version.
+  // Look one more time, this time looking for a non-platform-specific
+  // version.
   xpackage = _xcontents->FirstChildElement("package");
   xpackage = _xcontents->FirstChildElement("package");
   while (xpackage != NULL) {
   while (xpackage != NULL) {
     const char *name = xpackage->Attribute("name");
     const char *name = xpackage->Attribute("name");
@@ -528,6 +535,7 @@ choose_suitable_platform(string &selected_platform,
         *platform == '\0' &&
         *platform == '\0' &&
         package_version == version) {
         package_version == version) {
       selected_platform = platform;
       selected_platform = platform;
+      per_platform = parse_bool_attrib(xpackage, "per_platform", false);
       return true;
       return true;
     }
     }
 
 
@@ -561,8 +569,9 @@ get_package_desc_file(FileSpec &desc_file,              // out
 
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
 
 
-  // Scan the contents data for the indicated package.  First, we look
-  // for a platform-specific version.
+  // Scan the contents data for the indicated package.  We expect to
+  // match the platform precisely, because we previously called
+  // choose_suitable_platform().
   TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
   TiXmlElement *xpackage = _xcontents->FirstChildElement("package");
   while (xpackage != NULL) {
   while (xpackage != NULL) {
     const char *name = xpackage->Attribute("name");
     const char *name = xpackage->Attribute("name");
@@ -593,40 +602,6 @@ get_package_desc_file(FileSpec &desc_file,              // out
     xpackage = xpackage->NextSiblingElement("package");
     xpackage = xpackage->NextSiblingElement("package");
   }
   }
 
 
-  // Look again, this time looking for a non-platform-specific version.
-  xpackage = _xcontents->FirstChildElement("package");
-  while (xpackage != NULL) {
-    const char *name = xpackage->Attribute("name");
-    const char *platform = xpackage->Attribute("platform");
-    const char *version = xpackage->Attribute("version");
-    const char *seq = xpackage->Attribute("seq");
-    const char *solo = xpackage->Attribute("solo");
-    if (platform == NULL) {
-      platform = "";
-    }
-    if (version == NULL) {
-      version = "";
-    }
-    if (seq == NULL) {
-      seq = "";
-    }
-    if (name != NULL &&
-        package_name == name && 
-        *platform == '\0' &&
-        package_version == version) {
-      // Here's the matching package definition.
-      desc_file.load_xml(xpackage);
-      package_seq = seq;
-      package_solo = false;
-      if (solo != NULL) {
-        package_solo = (atoi(solo) != 0);
-      }
-      return true;
-    }
-
-    xpackage = xpackage->NextSiblingElement("package");
-  }
-
   // Couldn't find the named package.
   // Couldn't find the named package.
   return false;
   return false;
 }
 }

+ 1 - 0
direct/src/plugin/p3dHost.h

@@ -58,6 +58,7 @@ public:
                           const string &package_seq,
                           const string &package_seq,
                           const string &alt_host = "");
                           const string &alt_host = "");
   bool choose_suitable_platform(string &selected_platform,
   bool choose_suitable_platform(string &selected_platform,
+                                bool &per_platform,
                                 const string &package_name,
                                 const string &package_name,
                                 const string &package_version,
                                 const string &package_version,
                                 const string &package_platform);
                                 const string &package_platform);

+ 5 - 0
direct/src/plugin/p3dInstance.cxx

@@ -1366,10 +1366,15 @@ make_xml() {
   xinstance->SetAttribute("log_directory", inst_mgr->get_log_directory());
   xinstance->SetAttribute("log_directory", inst_mgr->get_log_directory());
   xinstance->SetAttribute("verify_contents", (int)inst_mgr->get_verify_contents());
   xinstance->SetAttribute("verify_contents", (int)inst_mgr->get_verify_contents());
 
 
+  // Tell the Panda process that it was started by a plugin that knows
+  // about the new per_platform flag.
+  xinstance->SetAttribute("respect_per_platform", 1);
+
   if (!inst_mgr->get_super_mirror().empty()) {
   if (!inst_mgr->get_super_mirror().empty()) {
     xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror());
     xinstance->SetAttribute("super_mirror", inst_mgr->get_super_mirror());
   }
   }
 
 
+
   TiXmlElement *xfparams = _fparams.make_xml();
   TiXmlElement *xfparams = _fparams.make_xml();
   xinstance->LinkEndChild(xfparams);
   xinstance->LinkEndChild(xfparams);
 
 

+ 6 - 0
direct/src/plugin/p3dInstanceManager.cxx

@@ -300,6 +300,12 @@ initialize(int api_version, const string &contents_filename,
     }
     }
   }
   }
 
 
+  nout << "Supported platforms:";
+  for (size_t pi = 0; pi < _supported_platforms.size(); ++pi) {
+    nout << " " << _supported_platforms[pi];
+  }
+  nout << "\n";
+
   return true;
   return true;
 }
 }
 
 

+ 3 - 3
direct/src/plugin/p3dMainObject.cxx

@@ -674,7 +674,7 @@ read_log_file(const string &log_pathname,
     log.seekg(0, ios::beg);
     log.seekg(0, ios::beg);
     log.read(buffer, full_bytes);
     log.read(buffer, full_bytes);
     streamsize read_bytes = log.gcount();
     streamsize read_bytes = log.gcount();
-    assert(read_bytes < buffer_bytes);
+    assert(read_bytes < (streamsize)buffer_bytes);
     buffer[read_bytes] = '\0';
     buffer[read_bytes] = '\0';
     log_data << "== PandaLog-" << "Full Start";
     log_data << "== PandaLog-" << "Full Start";
     log_data << " " << "(" << log_leafname << ")" << "\n";
     log_data << " " << "(" << log_leafname << ")" << "\n";
@@ -688,7 +688,7 @@ read_log_file(const string &log_pathname,
     log.seekg(0, ios::beg);
     log.seekg(0, ios::beg);
     log.read(buffer, head_bytes);
     log.read(buffer, head_bytes);
     streamsize read_bytes = log.gcount();
     streamsize read_bytes = log.gcount();
-    assert(read_bytes < buffer_bytes);
+    assert(read_bytes < (streamsize)buffer_bytes);
     buffer[read_bytes] = '\0';
     buffer[read_bytes] = '\0';
     log_data << "== PandaLog-" << "Head Start";
     log_data << "== PandaLog-" << "Head Start";
     log_data << " " << "(" << log_leafname << ")" << "\n";
     log_data << " " << "(" << log_leafname << ")" << "\n";
@@ -708,7 +708,7 @@ read_log_file(const string &log_pathname,
     log.seekg(file_size - tail_bytes, ios::beg);
     log.seekg(file_size - tail_bytes, ios::beg);
     log.read(buffer, tail_bytes);
     log.read(buffer, tail_bytes);
     streamsize read_bytes = log.gcount();
     streamsize read_bytes = log.gcount();
-    assert(read_bytes < buffer_bytes);
+    assert(read_bytes < (streamsize)buffer_bytes);
     buffer[read_bytes] = '\0';
     buffer[read_bytes] = '\0';
     log_data << "== PandaLog-" << "Tail Start";
     log_data << "== PandaLog-" << "Tail Start";
     log_data << " " << "(" << log_leafname << ")" << "\n";
     log_data << " " << "(" << log_leafname << ")" << "\n";

+ 38 - 9
direct/src/plugin/p3dPackage.cxx

@@ -52,10 +52,8 @@ P3DPackage(P3DHost *host, const string &package_name,
   _package_platform(package_platform),
   _package_platform(package_platform),
   _alt_host(alt_host)
   _alt_host(alt_host)
 {
 {
-  _package_fullname = _package_name;
-  if (!_package_version.empty()) {
-    _package_fullname += string(".") + _package_version;
-  }
+  set_fullname();
+  _per_platform = false;
   _patch_version = 0;
   _patch_version = 0;
 
 
   // This is set true if the package is a "solo", i.e. a single
   // This is set true if the package is a "solo", i.e. a single
@@ -638,24 +636,28 @@ host_got_contents_file() {
   // provided.
   // provided.
   assert(_alt_host.empty());
   assert(_alt_host.empty());
   string new_platform;
   string new_platform;
-  if (_host->choose_suitable_platform(new_platform, _package_name, _package_version, _package_platform)) {
+  if (_host->choose_suitable_platform(new_platform, _per_platform,
+                                      _package_name, _package_version, _package_platform)) {
     if (new_platform != _package_platform) {
     if (new_platform != _package_platform) {
       nout << "Migrating " << get_package_name() << " from platform \""
       nout << "Migrating " << get_package_name() << " from platform \""
            << _package_platform << "\" to platform \"" 
            << _package_platform << "\" to platform \"" 
            << new_platform << "\"\n";
            << new_platform << "\"\n";
       _package_platform = new_platform;
       _package_platform = new_platform;
+      set_fullname();
     }
     }
   } else {
   } else {
     nout << "Couldn't find a platform for " << get_package_name() << ".\n";
     nout << "Couldn't find a platform for " << get_package_name() << ".\n";
   }
   }
 
 
+  nout << "_per_platform for " << get_package_name() << " = " << _per_platform << "\n";
+
   // Now that we have a valid host and platform, we can define the
   // Now that we have a valid host and platform, we can define the
   // _package_dir.
   // _package_dir.
   _package_dir = _host->get_host_dir() + string("/") + _package_name;
   _package_dir = _host->get_host_dir() + string("/") + _package_name;
   if (!_package_version.empty()) {
   if (!_package_version.empty()) {
     _package_dir += string("/") + _package_version;
     _package_dir += string("/") + _package_version;
   }
   }
-  if (!_package_platform.empty()) {
+  if (_per_platform && !_package_platform.empty()) {
     _package_dir += string("/") + _package_platform;
     _package_dir += string("/") + _package_platform;
   }
   }
 
 
@@ -686,7 +688,7 @@ download_desc_file() {
                                     _package_name, _package_version,
                                     _package_name, _package_version,
                                     _package_platform)) {
                                     _package_platform)) {
     nout << "Couldn't find package " << _package_fullname
     nout << "Couldn't find package " << _package_fullname
-         << "/" << _package_platform << " in contents file.\n";
+         << " in contents file.\n";
     redownload_contents_file(NULL);
     redownload_contents_file(NULL);
     return;
     return;
   }
   }
@@ -702,8 +704,8 @@ download_desc_file() {
   }
   }
 
 
   // The desc file might have a different path on the host server than
   // The desc file might have a different path on the host server than
-  // it has locally, because we strip out the platform directory
-  // locally.
+  // it has locally, because we might strip out the platform directory
+  // locally (according to _per_platform).
   FileSpec local_desc_file = _desc_file;
   FileSpec local_desc_file = _desc_file;
   local_desc_file.set_filename(_desc_file_basename);
   local_desc_file.set_filename(_desc_file_basename);
   _desc_file_pathname = local_desc_file.get_pathname(_package_dir);
   _desc_file_pathname = local_desc_file.get_pathname(_package_dir);
@@ -791,6 +793,16 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
     report_done(false);
     report_done(false);
     return;
     return;
   }
   }
+
+  bool per_platform = parse_bool_attrib(xpackage, "per_platform", false);
+  if (per_platform != _per_platform) {
+    nout << "Warning! per_platform disagreement for " << get_package_name()
+         << "!\n";
+    // We don't do anything with this warning--the original value for
+    // _per_platform we got from the contents.xml file has to apply,
+    // because we're already committed to the _package_dir we're
+    // using.
+  }
   
   
   xpackage->Attribute("patch_version", &_patch_version);
   xpackage->Attribute("patch_version", &_patch_version);
   
   
@@ -1458,6 +1470,23 @@ instance_terminating(P3DInstance *instance) {
   return true;
   return true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DPackage::set_fullname
+//       Access: Private
+//  Description: Assigns _package_fullname to the appropriate
+//               combination of name, version, and platform.
+////////////////////////////////////////////////////////////////////
+void P3DPackage::
+set_fullname() {
+  _package_fullname = _package_name;
+  if (!_package_version.empty()) {
+    _package_fullname += string(".") + _package_version;
+  }
+  if (!_package_platform.empty()) {
+    _package_fullname += string(".") + _package_platform;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DPackage::Download::Constructor
 //     Function: P3DPackage::Download::Constructor
 //       Access: Public
 //       Access: Public

+ 2 - 0
direct/src/plugin/p3dPackage.h

@@ -241,6 +241,7 @@ private:
 
 
   bool is_extractable(FileSpec &file, const string &filename) const;
   bool is_extractable(FileSpec &file, const string &filename) const;
   bool instance_terminating(P3DInstance *instance);
   bool instance_terminating(P3DInstance *instance);
+  void set_fullname();
 
 
 public:
 public:
   class RequiredPackage {
   class RequiredPackage {
@@ -264,6 +265,7 @@ private:
   string _package_name;
   string _package_name;
   string _package_version;
   string _package_version;
   string _package_platform;
   string _package_platform;
+  bool _per_platform;
   int _patch_version;
   int _patch_version;
   string _alt_host;
   string _alt_host;
   bool _package_solo;
   bool _package_solo;

+ 5 - 2
direct/src/plugin/p3dPythonRun.cxx

@@ -1252,9 +1252,12 @@ set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance) {
     Py_INCREF(main);
     Py_INCREF(main);
   }
   }
 
 
+  int respect_per_platform = 0;
+  xinstance->Attribute("respect_per_platform", &respect_per_platform);
+
   PyObject *result = PyObject_CallMethod
   PyObject *result = PyObject_CallMethod
-    (_runner, (char *)"setInstanceInfo", (char *)"sssiO", root_dir, 
-     log_directory, super_mirror, verify_contents, main);
+    (_runner, (char *)"setInstanceInfo", (char *)"sssiOi", root_dir, 
+     log_directory, super_mirror, verify_contents, main, respect_per_platform);
   Py_DECREF(main);
   Py_DECREF(main);
 
 
   if (result == NULL) {
   if (result == NULL) {

+ 1 - 0
direct/src/plugin/p3d_plugin_composite1.cxx

@@ -30,3 +30,4 @@
 #include "p3dWinSplashWindow.cxx"
 #include "p3dWinSplashWindow.cxx"
 #include "p3dX11SplashWindow.cxx"
 #include "p3dX11SplashWindow.cxx"
 #include "p3dWindowParams.cxx"
 #include "p3dWindowParams.cxx"
+#include "xml_helpers.cxx"

+ 43 - 0
direct/src/plugin/xml_helpers.cxx

@@ -0,0 +1,43 @@
+// Filename: xml_helpers.cxx
+// Created by:  drose (28Sep12)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "p3d_plugin_common.h"
+#include "xml_helpers.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: parse_bool_attrib
+//  Description: Examines the indicated attrib from the XML attrib and
+//               returns its true or false value.  Returns
+//               default_value if the attrib is not present or is
+//               empty.
+////////////////////////////////////////////////////////////////////
+bool
+parse_bool_attrib(TiXmlElement *xelem, const string &attrib,
+                  bool default_value) {
+  const char *value = xelem->Attribute(attrib.c_str());
+  if (value == NULL || *value == '\0') {
+    return default_value;
+  }
+
+  char *endptr;
+  int result = strtol(value, &endptr, 10);
+  if (*endptr == '\0') {
+    // A valid integer.
+    return (result != 0);
+  }
+
+  // An invalid integer.
+  return default_value;
+}

+ 24 - 0
direct/src/plugin/xml_helpers.h

@@ -0,0 +1,24 @@
+// Filename: xml_helpers.h
+// Created by:  drose (28Sep12)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef XML_HELPERS_H
+#define XML_HELPERS_H
+
+#include "get_tinyxml.h"
+
+bool parse_bool_attrib(TiXmlElement *xelem, const string &attrib,
+                       bool default_value);
+
+#endif
+