sclass LineCompReader { new LS literals; new LPair pairs; new LinkedHashMap> versions; // takes .filecomp (text) or .filecomp.gz (gzipped) *(File f) { temp BufferedReader reader = rawByteReader_possiblyGZipped(f); load(reader); } *(BufferedReader reader) { load(reader); } void load(BufferedReader reader) ctex { S s = reader.readLine(); new Matches m; if (!startsWith(s, "LINECOMP ", m)) fail("Not a LINECOMP file"); int nLiterals = parseInt(m.rest()); for i to nLiterals: literals.add(assertNotNull(reader.readLine())); while licensed { s = reader.readLine(); if (s == null || contains(s, "=")) break; pairs.add(assertNotNull(listToPair(parseInts(splitAtSpace(s))))); } while (contains(s, "=")) { int i = indexOf(s, '='); versions.put(takeFirst(s, i), parseInts(splitAtSpace(substring(s, i+1)))); s = reader.readLine(); } } Set versions() { ret keys(versions); } S getText(S version) { ret textForVersion(version); } S textForVersion(S version) { L encoded = versions.get(version); if (encoded == null) null; new LS buf; for (int idx : encoded) decode(idx, buf); ret myFromLines(buf); } S myFromLines(LS l) { ret fromLines_rtrim(l); } void decode(int idx, LS buf) { if (idx < l(literals)) buf.add(literals.get(idx)); else { Pair p = pairs.get(idx-l(literals)); decode(p.a, buf); decode(p.b, buf); } } }