/** * Convert the MVD file format data into an MVD object * * @param bytes a byte array of the decompressed file contents * @return a finished MVD * @throws and exception if it is not a valid MVD */ private static MVD parse(byte[] bytes) throws Exception { MVD mvd = null; // point after magic int p = MVD_MAGIC.length; // mask type - redundant int maskType = readInt(bytes, p); p += 4; int groupTableOffset = readInt(bytes, p); p += 4; int versionTableOffset = readInt(bytes, p); p += 4; int pairsTableOffset = readInt(bytes, p); p += 4; int dataTableOffset = readInt(bytes, p); p += 4; short strLen = readShort(bytes, p); String description = readUtf8String(bytes, p); p += strLen + 2; strLen = readShort(bytes, p); String encoding = readUtf8String(bytes, p); mvd = new MVD(description, encoding); // mvd.setMask( Mask.values()[maskType] ); p = groupTableOffset; readGroupTable(bytes, p, mvd); p = versionTableOffset; readVersionTable(bytes, p, mvd); p = pairsTableOffset; readPairsTable(bytes, p, dataTableOffset, mvd); int i = 0; try { for (i = 0; i < mvd.pairs.size(); i++) { Pair z = mvd.pairs.get(i); z.verify(); } } catch (Exception e) { System.out.println("Index:" + i + " " + e.getMessage()); } return mvd; }
/** * Read the pairs table for an MVD from a byte array * * @param data the byte array containing the version definitions * @param p the start offset of the versions within data * @param dataTableOffset offset within data of the pairs data * @param mvd an mvd to add the version definitions to */ private static void readPairsTable(byte[] data, int p, int dataTableOffset, MVD mvd) throws Exception { // record any pairs declaring themselves as parents HashMap<Integer, Pair> parents = new HashMap<Integer, Pair>(); HashMap<Integer, LinkedList<Pair>> orphans = new HashMap<Integer, LinkedList<Pair>>(); int nPairs = readInt(data, p); p += 4; if (nPairs < 0) throw new MVDException("Invalid number of pairs: " + nPairs); for (int i = 0; i < nPairs; i++) { byte[] copy; Pair pair; BitSet versions = readVersionSet(mvd.versionSetSize, data, p); p += mvd.versionSetSize; int offset = readInt(data, p); p += 4; int len = readInt(data, p); int flag = len & Pair.TRANSPOSE_MASK; // clear top two bits len &= Pair.INVERSE_MASK; p += 4; if (flag == Pair.PARENT_FLAG) { // read special parent id field int pId = readInt(data, p); p += 4; // transpose parent copy = copyData(len, dataTableOffset + offset, data); pair = new Pair(versions, toChars(copy, mvd.encoding)); Integer key = new Integer(pId); // check for orphans of this parent LinkedList<Pair> children = orphans.get(key); if (children != null) { ListIterator<Pair> iter = children.listIterator(); // match them up with this parent while (iter.hasNext()) { Pair child = iter.next(); child.setParent(pair); pair.addChild(child); } // now they're not orphans any more orphans.remove(key); } // always do this in case more children turn up parents.put(key, pair); } else if (flag == Pair.CHILD_FLAG) { // read special parent id field int pId = readInt(data, p); p += 4; // transpose child Integer key = new Integer(pId); Pair parent = parents.get(key); if (parent == null) { LinkedList<Pair> children = orphans.get(key); if (children == null) { children = new LinkedList<Pair>(); orphans.put(key, children); } pair = new Pair(versions, null); children.add(pair); } else // parent available { pair = new Pair(versions, null); pair.setParent(parent); parent.addChild(pair); } } else { // no transposition copy = copyData(len, dataTableOffset + offset, data); pair = new Pair(versions, toChars(copy, mvd.encoding)); } mvd.addPair(pair); } }