public static FreenetTopKey fromBytes(InputStream rawBytes) throws IOException {
        DataInputStream inputStream = new DataInputStream(rawBytes);
        try {
            byte[] versionBytes = new byte[HEADER.length];
            inputStream.readFully(versionBytes);
            if (!Arrays.equals(HEADER, versionBytes)) {
                throw new IOException("Version mismatch or bad data.");
            }

            List<Archive.RootObject> rootObjects = new ArrayList<Archive.RootObject>();
            int rootObjectCount = inputStream.readShort();
            while (rootObjectCount > 0) {
                LinkDigest digest = BinaryLinkRep.readLinkDigest(inputStream);
                int kind = inputStream.readInt();
                rootObjects.add(new Archive.RootObject(digest, kind));
                rootObjectCount--;
            }

            List<BlockDescription> blockDescriptions = new ArrayList<BlockDescription>();
            int blockDescriptionCount = inputStream.readShort();
            while (blockDescriptionCount > 0) {
                long blockLength = inputStream.readLong();
                List<byte[]> blockChks = new ArrayList<byte[]>();
                int blockChkCount = inputStream.readShort();
                while (blockChkCount > 0) {
                    byte[] chkBytes = new byte[BINARY_CHK_LENGTH];
                    inputStream.readFully(chkBytes);
                    blockChks.add(chkBytes);
                    blockChkCount--;
                }
                if (blockChks.size() < 1) {
                    throw new IOException("Block description must have at least one CHK.");
                }
                blockDescriptions.add(new BlockDescription(blockLength, blockChks));
                blockDescriptionCount--;
            }
            if (blockDescriptions.size() < 1) {
                throw new IOException("Must have at least one block description.");
            }
            return new FreenetTopKey(new String(versionBytes, "ascii"),
                                     Collections.unmodifiableList(rootObjects),
                                     Collections.unmodifiableList(blockDescriptions));
        } finally {
            //rawBytes.close(); DCI: Don't close the stream passed to you by AllData!
        }
    }