Skip to content
Snippets Groups Projects
CacheFileHeader.java 6.03 KiB
Newer Older
  • Learn to ignore specific revisions
  • package azgracompress.cache;
    
    
    import azgracompress.data.V2i;
    
    import azgracompress.data.V3i;
    import azgracompress.fileformat.QuantizationType;
    
    import azgracompress.utilities.Utils;
    
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    
    public class CacheFileHeader {
        public static final String QCMP_CACHE_MAGIC_VALUE = "QCMPCACHE";
        private String magicValue;
        private QuantizationType quantizationType;
    
        private int codebookSize;
    
        private int trainFileNameSize;
        private String trainFileName;
    
        private int vectorSizeX;
        private int vectorSizeY;
        private int vectorSizeZ;
    
    
        public void setQuantizationType(final QuantizationType quantizationType) {
    
            this.quantizationType = quantizationType;
        }
    
    
        public void setCodebookSize(final int codebookSize) {
    
            this.codebookSize = codebookSize;
        }
    
    
    
        public void setTrainFileName(final String trainFileName) {
    
            this.trainFileName = trainFileName;
            this.trainFileNameSize = this.trainFileName.length();
        }
    
    
        public void setVectorSizeX(final int vectorSizeX) {
    
            this.vectorSizeX = vectorSizeX;
        }
    
    
        public void setVectorSizeY(final int vectorSizeY) {
    
            this.vectorSizeY = vectorSizeY;
        }
    
    
        public void setVectorSizeZ(final int vectorSizeZ) {
    
            this.vectorSizeZ = vectorSizeZ;
        }
    
        public QuantizationType getQuantizationType() {
            return quantizationType;
        }
    
        public int getCodebookSize() {
            return codebookSize;
        }
    
    
        public int getBitsPerCodebookIndex() {
            return (int) Utils.log2(codebookSize);
        }
    
    
        public int getTrainFileNameSize() {
            return trainFileNameSize;
        }
    
        public String getTrainFileName() {
            return trainFileName;
        }
    
        public int getVectorSizeX() {
            return vectorSizeX;
        }
    
        public int getVectorSizeY() {
            return vectorSizeY;
        }
    
        public int getVectorSizeZ() {
            return vectorSizeZ;
        }
    
        public V3i getVectorDim() {
            return new V3i(vectorSizeX, vectorSizeY, vectorSizeZ);
        }
    
        /**
         * Write QCMP cache file header to stream.
         *
         * @param outputStream Data output stream.
         * @throws IOException when fails to write the header to stream.
         */
    
        public void writeToStream(final DataOutputStream outputStream) throws IOException {
    
            outputStream.writeBytes(QCMP_CACHE_MAGIC_VALUE);
            outputStream.writeByte(quantizationType.getValue());
            outputStream.writeShort(codebookSize);
    
            outputStream.writeShort(trainFileName.length());
            outputStream.writeBytes(trainFileName);
    
            outputStream.writeShort(vectorSizeX);
            outputStream.writeShort(vectorSizeY);
            outputStream.writeShort(vectorSizeZ);
        }
    
    
        public long getExpectedFileSize() {
            long expectedFileSize = 20 + trainFileNameSize; // Base header size
            expectedFileSize += (codebookSize * 8);         // Frequency values
            switch (quantizationType) {
                case Scalar:
                    expectedFileSize += (codebookSize * 2); // Scalar quantization values
                    break;
                case Vector1D:
                case Vector2D:
                case Vector3D:
                    expectedFileSize += ((vectorSizeX * vectorSizeY * vectorSizeZ) * codebookSize * 2); // Quantization vectors
                    break;
                case Invalid:
                    return -1;
            }
            return expectedFileSize;
        }
    
    
        /**
         * Read header from the stream.
         *
         * @param inputStream Data input stream.
         */
    
        public void readFromStream(final DataInputStream inputStream) throws IOException {
    
            final int MIN_AVAIL = 9;
            if (inputStream.available() < MIN_AVAIL) {
                throw new IOException("Invalid file. File too small.");
            }
    
    
            final byte[] magicBuffer = new byte[QCMP_CACHE_MAGIC_VALUE.length()];
    
            int toRead = QCMP_CACHE_MAGIC_VALUE.length();
            while (toRead > 0) {
                final int read = inputStream.read(magicBuffer, QCMP_CACHE_MAGIC_VALUE.length() - toRead, toRead);
                if (read < 0) {
                    throw new IOException("Invalid file type. Unable to read magic value");
                }
                toRead -= read;
    
            magicValue = new String(magicBuffer);
            if (!magicValue.equals(QCMP_CACHE_MAGIC_VALUE)) {
                throw new IOException("Invalid file type. Wrong magic value.");
            }
            quantizationType = QuantizationType.fromByte(inputStream.readByte());
            codebookSize = inputStream.readUnsignedShort();
    
            trainFileNameSize = inputStream.readUnsignedShort();
    
            final byte[] fileNameBuffer = new byte[trainFileNameSize];
    
    
            toRead = trainFileNameSize;
            while (toRead > 0) {
                toRead -= inputStream.read(fileNameBuffer, trainFileNameSize - toRead, toRead);
            }
    
    
    
            trainFileName = new String(fileNameBuffer);
    
            vectorSizeX = inputStream.readUnsignedShort();
            vectorSizeY = inputStream.readUnsignedShort();
            vectorSizeZ = inputStream.readUnsignedShort();
        }
    
        public void setVectorDims(final V3i v3i) {
            this.vectorSizeX = v3i.getX();
            this.vectorSizeY = v3i.getY();
            this.vectorSizeZ = v3i.getZ();
        }
    
        public void report(final StringBuilder sb) {
            sb.append("Magic: ").append(magicValue).append('\n');
    
            sb.append("CodebookType: ");
            switch (quantizationType) {
                case Scalar:
                    sb.append("Scalar\n");
                    break;
                case Vector1D:
    
                    sb.append(String.format("Vector1D [%sx1]\n", vectorSizeX));
    
                    break;
                case Vector2D:
    
                    sb.append(String.format("Vector2D %s\n", new V2i(vectorSizeX, vectorSizeY).toString()));
                    break;
                case Vector3D:
                    sb.append(String.format("Vector3D %s\n", new V3i(vectorSizeX, vectorSizeY, vectorSizeZ).toString()));
    
                    break;
            }
            sb.append("CodebookSize: ").append(codebookSize).append('\n');
            sb.append("TrainFile: ").append(trainFileName).append('\n');
        }
    }