diff --git a/src/java/com/threerings/getdown/data/Application.java b/src/java/com/threerings/getdown/data/Application.java index e421536..f56c3e0 100644 --- a/src/java/com/threerings/getdown/data/Application.java +++ b/src/java/com/threerings/getdown/data/Application.java @@ -121,7 +121,7 @@ public class Application public Resource getConfigResource () { try { - return createResource(CONFIG_FILE); + return createResource(CONFIG_FILE, false); } catch (Exception e) { throw new RuntimeException("Invalid appbase '" + _vappbase + "'."); } @@ -162,7 +162,7 @@ public class Application String pfile = "patch" + _version + ".dat"; try { URL remote = new URL(createVAppBase(_targetVersion), pfile); - return new Resource(pfile, remote, getLocalPath(pfile)); + return new Resource(pfile, remote, getLocalPath(pfile), false); } catch (Exception e) { Log.warning("Failed to create patch resource path [pfile=" + pfile + ", appbase=" + _appbase + ", tvers=" + _targetVersion + @@ -259,7 +259,7 @@ public class Application } for (int ii = 0; ii < codes.length; ii++) { try { - _codes.add(createResource(codes[ii])); + _codes.add(createResource(codes[ii], false)); } catch (Exception e) { Log.warning("Invalid code resource '" + codes[ii] + "'." + e); } @@ -269,8 +269,16 @@ public class Application String[] rsrcs = ConfigUtil.getMultiValue(cdata, "resource"); if (rsrcs != null) { for (int ii = 0; ii < rsrcs.length; ii++) { + String rsrc = rsrcs[ii]; try { - _resources.add(createResource(rsrcs[ii])); + boolean unpack = false; + int uidx; + if ((uidx = rsrc.indexOf("[u]")) != -1) { + unpack = true; + rsrc = rsrc.substring(0, uidx).trim() + + rsrc.substring(uidx+3).trim(); + } + _resources.add(createResource(rsrc, unpack)); } catch (Exception e) { Log.warning("Invalid resource '" + rsrcs[ii] + "'. " + e); } @@ -629,9 +637,13 @@ public class Application try { if (_digest.validateResource(rsrc, mpobs)) { - // make a note that this file is kosher - rsrc.markAsValid(); - continue; + // unpack this resource if appropriate + if (!rsrc.shouldUnpack() || rsrc.unpack()) { + // finally note that this resource is kosher + rsrc.markAsValid(); + continue; + } + Log.info("Failure unpacking resource [rsrc=" + rsrc + "]."); } } catch (Exception e) { @@ -737,10 +749,11 @@ public class Application } /** Helper function for creating {@link Resource} instances. */ - protected Resource createResource (String path) + protected Resource createResource (String path, boolean unpack) throws MalformedURLException { - return new Resource(path, getRemoteURL(path), getLocalPath(path)); + return new Resource( + path, getRemoteURL(path), getLocalPath(path), unpack); } /** Used to parse rectangle specifications from the config file. */ diff --git a/src/java/com/threerings/getdown/data/Resource.java b/src/java/com/threerings/getdown/data/Resource.java index 16bd663..536ff29 100644 --- a/src/java/com/threerings/getdown/data/Resource.java +++ b/src/java/com/threerings/getdown/data/Resource.java @@ -19,6 +19,7 @@ import java.util.jar.JarFile; import com.samskivert.io.StreamUtil; import com.samskivert.util.CollectionUtil; +import com.samskivert.util.FileUtil; import com.samskivert.util.SortableArrayList; import com.samskivert.util.StringUtil; @@ -33,12 +34,13 @@ public class Resource /** * Creates a resource with the supplied remote URL and local path. */ - public Resource (String path, URL remote, File local) + public Resource (String path, URL remote, File local, boolean unpack) { _path = path; _remote = remote; _local = local; _marker = new File(_local.getPath() + "v"); + _unpack = unpack; } /** @@ -65,6 +67,15 @@ public class Resource return _remote; } + /** + * Returns true if this resource should be unpacked as a part of the + * validation process. + */ + public boolean shouldUnpack () + { + return _unpack; + } + /** * Computes the MD5 hash of this resource's underlying file. * Note: This is both CPU and I/O intensive. @@ -113,6 +124,27 @@ public class Resource } } + /** + * Unpacks this resource file into the directory that contains it. Returns + * false if an error occurs while unpacking it. + */ + public boolean unpack () + { + // sanity check + if (!_local.getPath().endsWith(".jar")) { + Log.warning("Requested to unpack non-jar file '" + _local + "'."); + return false; + } + try { + return FileUtil.unpackJar( + new JarFile(_local), _local.getParentFile()); + } catch (IOException ioe) { + Log.warning("Failed to create JarFile from '" + + _local + "': " + ioe); + return false; + } + } + /** * Wipes this resource file along with any "validated" marker file * that may be associated with it. @@ -237,6 +269,7 @@ public class Resource protected String _path; protected URL _remote; protected File _local, _marker; + protected boolean _unpack; /** Used to sort the entries in a jar file. */ protected static final Comparator ENTRY_COMP = new Comparator() {