diff --git a/src/main/java/com/threerings/getdown/data/Application.java b/src/main/java/com/threerings/getdown/data/Application.java index 9e5d373..ff20af0 100644 --- a/src/main/java/com/threerings/getdown/data/Application.java +++ b/src/main/java/com/threerings/getdown/data/Application.java @@ -503,16 +503,17 @@ public class Application { Map cdata = null; File config = _config; + ConfigUtil.ParseOpts opts = ConfigUtil.createOpts(checkPlatform); try { // if we have a configuration file, read the data from it if (config.exists()) { - cdata = ConfigUtil.parseConfig(_config, checkPlatform); + cdata = ConfigUtil.parseConfig(_config, opts); } // otherwise, try reading data from our backup config file; thanks to funny windows // bullshit, we have to do this backup file fiddling in case we got screwed while // updating getdown.txt during normal operation else if ((config = getLocalPath(CONFIG_FILE + "_old")).exists()) { - cdata = ConfigUtil.parseConfig(config, checkPlatform); + cdata = ConfigUtil.parseConfig(config, opts); } // otherwise, issue a warning that we found no getdown file else { @@ -772,7 +773,7 @@ public class Application File pairFile = getLocalPath(pairLocation); if (pairFile.exists()) { try { - List args = ConfigUtil.parsePairs(pairFile, false, false); + List args = ConfigUtil.parsePairs(pairFile, ConfigUtil.createOpts(false)); for (String[] pair : args) { if (pair[1].length() == 0) { collector.add(pair[0]); @@ -1238,7 +1239,7 @@ public class Application try { in = ConnectionUtil.open(_latest).getInputStream(); BufferedReader bin = new BufferedReader(new InputStreamReader(in)); - for (String[] pair : ConfigUtil.parsePairs(bin, false, false)) { + for (String[] pair : ConfigUtil.parsePairs(bin, ConfigUtil.createOpts(false))) { if (pair[0].equals("version")) { _targetVersion = Math.max(Long.parseLong(pair[1]), _targetVersion); if (fileVersion != -1 && _targetVersion > fileVersion) { diff --git a/src/main/java/com/threerings/getdown/data/Digest.java b/src/main/java/com/threerings/getdown/data/Digest.java index 69a14f2..41ad0be 100644 --- a/src/main/java/com/threerings/getdown/data/Digest.java +++ b/src/main/java/com/threerings/getdown/data/Digest.java @@ -113,9 +113,11 @@ public class Digest String filename = digestFile(version); StringBuilder data = new StringBuilder(); File dfile = new File(appdir, filename); + ConfigUtil.ParseOpts opts = ConfigUtil.createOpts(false); // bias = toward key: the key is the filename and could conceivably contain = signs, value // is the hex encoded hash which will not contain = - for (String[] pair : ConfigUtil.parsePairs(dfile, false, true)) { + opts.biasToKey = true; + for (String[] pair : ConfigUtil.parsePairs(dfile, opts)) { if (pair[0].equals(filename)) { _metaDigest = pair[1]; break; diff --git a/src/main/java/com/threerings/getdown/launcher/Getdown.java b/src/main/java/com/threerings/getdown/launcher/Getdown.java index 8722e40..ef08b73 100644 --- a/src/main/java/com/threerings/getdown/launcher/Getdown.java +++ b/src/main/java/com/threerings/getdown/launcher/Getdown.java @@ -313,7 +313,8 @@ public abstract class Getdown extends Thread File pfile = _app.getLocalPath("proxy.txt"); if (pfile.exists()) { try { - Map pconf = ConfigUtil.parseConfig(pfile, false); + Map pconf = + ConfigUtil.parseConfig(pfile, ConfigUtil.createOpts(false)); setProxyProperties((String)pconf.get("host"), (String)pconf.get("port")); return true; } catch (IOException ioe) { diff --git a/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java b/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java index 9c082b9..fd38511 100644 --- a/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java +++ b/src/main/java/com/threerings/getdown/launcher/GetdownAppletConfig.java @@ -366,7 +366,8 @@ public class GetdownAppletConfig boolean createGetdown = !gdfile.exists(); if (!createGetdown) { try { - Map cdata = ConfigUtil.parseConfig(gdfile, false); + Map cdata = + ConfigUtil.parseConfig(gdfile, ConfigUtil.createOpts(false)); String oappbase = StringUtil.trim((String)cdata.get(APPBASE)); createGetdown = (appbase != null && !appbase.trim().equals(oappbase)); if (createGetdown) { diff --git a/src/main/java/com/threerings/getdown/util/ConfigUtil.java b/src/main/java/com/threerings/getdown/util/ConfigUtil.java index 9b5a927..3aff1b1 100644 --- a/src/main/java/com/threerings/getdown/util/ConfigUtil.java +++ b/src/main/java/com/threerings/getdown/util/ConfigUtil.java @@ -26,6 +26,30 @@ import static com.threerings.getdown.Log.log; */ public class ConfigUtil { + /** Options that control the {@link #parsePairs} function. */ + public static class ParseOpts { + // these should be tweaked as desired by the caller + public boolean biasToKey = false; + public boolean strictComments = false; + + // these are filled in by parseConfig + public String osname = null; + public String osarch = null; + } + + /** + * Creates a parse configuration, filling in the platform filters (or not) depending on the + * value of {@code checkPlatform}. + */ + public static ParseOpts createOpts (boolean checkPlatform) { + ParseOpts opts = new ParseOpts(); + if (checkPlatform) { + opts.osname = StringUtil.deNull(System.getProperty("os.name")).toLowerCase(); + opts.osarch = StringUtil.deNull(System.getProperty("os.arch")).toLowerCase(); + } + return opts; + } + /** * Parses a configuration file containing key/value pairs. The file must be in the UTF-8 * encoding. @@ -39,25 +63,68 @@ public class ConfigUtil * @return a list of String[] instances containing the key/value pairs in the * order they were parsed from the file. */ - public static List parsePairs (File config, boolean checkPlatform, boolean biasToKey) + public static List parsePairs (File source, ParseOpts opts) throws IOException { // annoyingly FileReader does not allow encoding to be specified (uses platform default) - InputStreamReader input = new InputStreamReader(new FileInputStream(config), "UTF-8"); - return parsePairs(input, checkPlatform, biasToKey); + InputStreamReader input = new InputStreamReader(new FileInputStream(source), "UTF-8"); + return parsePairs(input, opts); } /** - * See {@link #parsePairs(File,boolean,boolean)}. + * See {@link #parsePairs(File,ParseOpts)}. */ - public static List parsePairs (Reader config, boolean checkPlatform, - boolean biasToKey) throws IOException + public static List parsePairs (Reader source, ParseOpts opts) throws IOException { - return parsePairs( - config, - checkPlatform ? StringUtil.deNull(System.getProperty("os.name")).toLowerCase() : null, - checkPlatform ? StringUtil.deNull(System.getProperty("os.arch")).toLowerCase() : null, - biasToKey); + List pairs = new ArrayList(); + for (String line : FileUtil.readLines(source)) { + // nix comments + int cidx = line.indexOf("#"); + if (opts.strictComments ? cidx == 0 : cidx != -1) { + line = line.substring(0, cidx); + } + + // trim whitespace and skip blank lines + line = line.trim(); + if (StringUtil.isBlank(line)) { + continue; + } + + // parse our key/value pair + String[] pair = new String[2]; + // if we're biasing toward key, put all the extra = in the key rather than the value + int eidx = opts.biasToKey ? line.lastIndexOf("=") : line.indexOf("="); + if (eidx != -1) { + pair[0] = line.substring(0, eidx).trim(); + pair[1] = line.substring(eidx+1).trim(); + } else { + pair[0] = line; + pair[1] = ""; + } + + // if the pair has an os qualifier, we need to process it + if (pair[1].startsWith("[")) { + int qidx = pair[1].indexOf("]"); + if (qidx == -1) { + log.warning("Bogus platform specifier", "key", pair[0], "value", pair[1]); + continue; // omit the pair entirely + } + // if we're checking qualifiers and the os doesn't match this qualifier, skip it + String quals = pair[1].substring(1, qidx); + if (opts.osname != null && !checkQualifiers(quals, opts.osname, opts.osarch)) { + log.debug("Skipping", "quals", quals, + "osname", opts.osname, "osarch", opts.osarch, + "key", pair[0], "value", pair[1]); + continue; + } + // otherwise filter out the qualifier text + pair[1] = pair[1].substring(qidx+1).trim(); + } + + pairs.add(pair); + } + + return pairs; } /** @@ -67,7 +134,7 @@ public class ConfigUtil * @return a map from keys to values, where a value will be an array of strings if more than * one key/value pair in the config file was associated with the same key. */ - public static Map parseConfig (File config, boolean checkPlatform) + public static Map parseConfig (File source, ParseOpts opts) throws IOException { Map data = new HashMap(); @@ -75,7 +142,7 @@ public class ConfigUtil // I thought that we could use HashMap and put new String[] {pair[1]} for // the null case, but it mysteriously dies on launch, so leaving it as HashMap for now - for (String[] pair : parsePairs(config, checkPlatform, false)) { + for (String[] pair : parsePairs(source, opts)) { Object value = data.get(pair[0]); if (value == null) { data.put(pair[0], pair[1]); @@ -90,6 +157,14 @@ public class ConfigUtil } } + // special magic for the getdown.txt config: if the parsed data contains 'strict_comments = + // true' then we reparse the file with strict comments (i.e. # is only assumed to start a + // comment in column 0) + if (!opts.strictComments && Boolean.parseBoolean((String)data.get("strict_comments"))) { + opts.strictComments = true; + return parseConfig(source, opts); + } + return data; } @@ -107,64 +182,9 @@ public class ConfigUtil } } - /** A helper function for {@link #parsePairs(Reader,boolean}. */ - protected static List parsePairs (Reader config, String osname, String osarch, - boolean biasToKey) - throws IOException - { - List pairs = new ArrayList(); - for (String line : FileUtil.readLines(config)) { - // nix comments - int cidx = line.indexOf("#"); - if (cidx != -1) { - line = line.substring(0, cidx); - } - - // trim whitespace and skip blank lines - line = line.trim(); - if (StringUtil.isBlank(line)) { - continue; - } - - // parse our key/value pair - String[] pair = new String[2]; - // if we're biasing toward key, put all the extra = in the key rather than the value - int eidx = biasToKey ? line.lastIndexOf("=") : line.indexOf("="); - if (eidx != -1) { - pair[0] = line.substring(0, eidx).trim(); - pair[1] = line.substring(eidx+1).trim(); - } else { - pair[0] = line; - pair[1] = ""; - } - - // if the pair has an os qualifier, we need to process it - if (pair[1].startsWith("[")) { - int qidx = pair[1].indexOf("]"); - if (qidx == -1) { - log.warning("Bogus platform specifier", "key", pair[0], "value", pair[1]); - continue; // omit the pair entirely - } - // if we're checking qualifiers and the os doesn't match this qualifier, skip it - String quals = pair[1].substring(1, qidx); - if (osname != null && !checkQualifiers(quals, osname, osarch)) { - log.debug("Skipping", "quals", quals, "osname", osname, "osarch", osarch, - "key", pair[0], "value", pair[1]); - continue; - } - // otherwise filter out the qualifier text - pair[1] = pair[1].substring(qidx+1).trim(); - } - - pairs.add(pair); - } - - return pairs; - } - /** - * A helper function for {@link #parsePairs(Reader,String,String)}. Qualifiers have the - * following form: + * A helper function for {@link #parsePairs(Reader,ParseOpts)}. Qualifiers have the following + * form: *
      * id = os[-arch]
      * ids = id | id,ids
diff --git a/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java b/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java
index 986cc3c..607bce7 100644
--- a/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java
+++ b/src/test/java/com/threerings/getdown/util/ConfigUtilTest.java
@@ -38,7 +38,8 @@ public class ConfigUtilTest
 
     @Test public void testSimplePairs () throws IOException
     {
-        List pairs = ConfigUtil.parsePairs(toReader(SIMPLE_PAIRS), true, false);
+        List pairs = ConfigUtil.parsePairs(
+            toReader(SIMPLE_PAIRS), ConfigUtil.createOpts(true));
         for (int ii = 0; ii < SIMPLE_PAIRS.length; ii++) {
             assertEquals(SIMPLE_PAIRS[ii].key, pairs.get(ii)[0]);
             assertEquals(SIMPLE_PAIRS[ii].value, pairs.get(ii)[1]);
@@ -57,7 +58,10 @@ public class ConfigUtilTest
         Pair notWin = new Pair("fifteen", "[!windows] sixteen");
         Pair[] pairs = { linux, mac, linuxAndMac, linux64, linux64s, mac64, win64, notWin };
 
-        List parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "i386", false);
+        ConfigUtil.ParseOpts opts = ConfigUtil.createOpts(false);
+        opts.osname = "linux";
+        opts.osarch = "i386";
+        List parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(exists(parsed, linuxAndMac.key));
@@ -67,7 +71,8 @@ public class ConfigUtilTest
         assertTrue(!exists(parsed, win64.key));
         assertTrue(exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "x86_64", false);
+        opts.osarch = "x86_64";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(exists(parsed, linuxAndMac.key));
@@ -77,7 +82,8 @@ public class ConfigUtilTest
         assertTrue(!exists(parsed, win64.key));
         assertTrue(exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "linux", "amd64", false);
+        opts.osarch = "amd64";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(exists(parsed, linuxAndMac.key));
@@ -87,7 +93,9 @@ public class ConfigUtilTest
         assertTrue(!exists(parsed, win64.key));
         assertTrue(exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "mac os x", "x86_64", false);
+        opts.osname = "mac os x";
+        opts.osarch = "x86_64";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(!exists(parsed, linux.key));
         assertTrue(exists(parsed, mac.key));
         assertTrue(exists(parsed, linuxAndMac.key));
@@ -97,7 +105,9 @@ public class ConfigUtilTest
         assertTrue(!exists(parsed, win64.key));
         assertTrue(exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "i386", false);
+        opts.osname = "windows";
+        opts.osarch = "i386";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(!exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(!exists(parsed, linuxAndMac.key));
@@ -107,7 +117,8 @@ public class ConfigUtilTest
         assertTrue(!exists(parsed, win64.key));
         assertTrue(!exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "x86_64", false);
+        opts.osarch = "x86_64";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(!exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(!exists(parsed, linuxAndMac.key));
@@ -117,7 +128,8 @@ public class ConfigUtilTest
         assertTrue(exists(parsed, win64.key));
         assertTrue(!exists(parsed, notWin.key));
 
-        parsed = ConfigUtil.parsePairs(toReader(pairs), "windows", "amd64", false);
+        opts.osarch = "amd64";
+        parsed = ConfigUtil.parsePairs(toReader(pairs), opts);
         assertTrue(!exists(parsed, linux.key));
         assertTrue(!exists(parsed, mac.key));
         assertTrue(!exists(parsed, linuxAndMac.key));