public Archive.ArchiveData read(HistoryLinkMap linkMap, LinkDataFactory linkFactory) throws IOException {
        DataInputStream inputStream = new DataInputStream(mStreamFactory.getInputStream());
        try {
            readHeader(inputStream);
            Set<LinkDigest> readLinks = readLinks(linkMap, linkFactory, inputStream);
            // This will fail with an IO exception if the
            // archive manifest can't be read.
            Archive.ArchiveData archiveData =
                getArchiveData(linkMap, mManifestChainHead);

            Set<LinkDigest> referencedLinks = new HashSet<LinkDigest>();
            for (Archive.RootObject obj : archiveData.mRootObjects) {
                if (!readLinks.contains(obj.mDigest)) {
                    throw new IOException("Root object not read from input stream: " + obj.mDigest);
                }
                referencedLinks.add(obj.mDigest);
            }

            for (Block block : archiveData.mBlocks) {
                for (LinkDigest digest : block.getDigests()) {
                    referencedLinks.add(digest);
                }
            }
            // Paranoid check to make sure that every link referenced
            // in the manifest was read, and no extra links were
            // included.
            if (!referencedLinks.equals(readLinks)) {
                throw new IOException("Data doesn't match manifest???");
            }

            return archiveData;
        } finally {
            if (mStreamFactory.shouldCloseInputStream()) {
                inputStream.close();
            }
        }
    }