All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xbib.io.compress.xz.index.IndexHash Maven / Gradle / Ivy


package org.xbib.io.compress.xz.index;

import org.xbib.io.compress.xz.CorruptedInputException;
import org.xbib.io.compress.xz.XZIOException;
import org.xbib.io.compress.xz.common.DecoderUtil;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.CheckedInputStream;

public class IndexHash extends IndexBase {
    private org.xbib.io.compress.xz.check.Check hash;

    public IndexHash() {
        super(new CorruptedInputException());

        try {
            hash = new org.xbib.io.compress.xz.check.SHA256();
        } catch (java.security.NoSuchAlgorithmException e) {
            hash = new org.xbib.io.compress.xz.check.CRC32();
        }
    }

    public void add(long unpaddedSize, long uncompressedSize)
            throws XZIOException {
        super.add(unpaddedSize, uncompressedSize);

        ByteBuffer buf = ByteBuffer.allocate(2 * 8);
        buf.putLong(unpaddedSize);
        buf.putLong(uncompressedSize);
        hash.update(buf.array());
    }

    public void validate(InputStream in) throws IOException {
        // Index Indicator (0x00) has already been read by BlockInputStream
        // so add 0x00 to the CRC32 here.
        java.util.zip.CRC32 crc32 = new java.util.zip.CRC32();
        crc32.update('\0');
        CheckedInputStream inChecked = new CheckedInputStream(in, crc32);

        // Get and validate the Number of Records field.
        long storedRecordCount = DecoderUtil.decodeVLI(inChecked);
        if (storedRecordCount != recordCount) {
            throw new CorruptedInputException("XZ Index is corrupt");
        }

        // Decode and hash the Index field and compare it to
        // the hash value calculated from the decoded Blocks.
        IndexHash stored = new IndexHash();
        for (long i = 0; i < recordCount; ++i) {
            long unpaddedSize = DecoderUtil.decodeVLI(inChecked);
            long uncompressedSize = DecoderUtil.decodeVLI(inChecked);

            try {
                stored.add(unpaddedSize, uncompressedSize);
            } catch (XZIOException e) {
                throw new CorruptedInputException("XZ Index is corrupt");
            }

            if (stored.blocksSum > blocksSum
                    || stored.uncompressedSum > uncompressedSum
                    || stored.indexListSize > indexListSize) {
                throw new CorruptedInputException("XZ Index is corrupt");
            }
        }

        if (stored.blocksSum != blocksSum
                || stored.uncompressedSum != uncompressedSum
                || stored.indexListSize != indexListSize
                || !Arrays.equals(stored.hash.finish(), hash.finish())) {
            throw new CorruptedInputException("XZ Index is corrupt");
        }

        // Index Padding
        DataInputStream inData = new DataInputStream(inChecked);
        for (int i = getIndexPaddingSize(); i > 0; --i) {
            if (inData.readUnsignedByte() != 0x00) {
                throw new CorruptedInputException("XZ Index is corrupt");
            }
        }

        // CRC32
        long value = crc32.getValue();
        for (int i = 0; i < 4; ++i) {
            if (((value >>> (i * 8)) & 0xFF) != inData.readUnsignedByte()) {
                throw new CorruptedInputException("XZ Index is corrupt");
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy