Package org.toubassi.femtozip.models

Source Code of org.toubassi.femtozip.models.FemtoZipCompressionModel

/**
*   Copyright 2011 Garrick Toubassi
*
*   Licensed under the Apache License, Version 2.0 (the "License");
*   you may not use this file except in compliance with the License.
*   You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*   Unless required by applicable law or agreed to in writing, software
*   distributed under the License is distributed on an "AS IS" BASIS,
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*   See the License for the specific language governing permissions and
*   limitations under the License.
*/
package org.toubassi.femtozip.models;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.toubassi.femtozip.CompressionModel;
import org.toubassi.femtozip.DocumentList;
import org.toubassi.femtozip.coding.huffman.FrequencyHuffmanModel;
import org.toubassi.femtozip.coding.huffman.HuffmanDecoder;
import org.toubassi.femtozip.coding.huffman.HuffmanEncoder;
import org.toubassi.femtozip.substring.SubstringPacker;
import org.toubassi.femtozip.substring.SubstringUnpacker;

public class FemtoZipCompressionModel extends CompressionModel {
   
    private FemtoZipHuffmanModel codeModel;
   
    public void load(DataInputStream in) throws IOException {
        super.load(in);
        codeModel = new FemtoZipHuffmanModel(in);
    }

    public void save(DataOutputStream out) throws IOException {
        super.save(out);
        codeModel.save(out);
    }
   
    public void build(DocumentList documents) throws IOException {
        buildDictionaryIfUnspecified(documents);
        codeModel = ((ModelBuilder)buildEncodingModel(documents)).createModel();
    }
   
    protected SubstringPacker.Consumer createModelBuilder() {
        return new ModelBuilder();
    }
   
    public void compress(byte[] data, OutputStream out) throws IOException {
        getSubstringPacker().pack(data, this, new HuffmanEncoder(codeModel.createModel(), out));
    }
   
    public void encodeLiteral(int aByte, Object context) {
        try {
            HuffmanEncoder encoder = (HuffmanEncoder)context;
            encoder.encodeSymbol(aByte);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void encodeSubstring(int offset, int length, Object context) {
        try {
            HuffmanEncoder encoder = (HuffmanEncoder)context;
            if (length < 1 || length > 255) {
                throw new IllegalArgumentException("Length " + length + " out of range [1,255]");
            }
            encoder.encodeSymbol(256 + length);
           
            offset = -offset;
            if (offset < 1 || offset > (2<<15)-1) {
                throw new IllegalArgumentException("Offset " + offset + " out of range [1, 65535]");
            }
            encoder.encodeSymbol(offset & 0xf);
            encoder.encodeSymbol((offset >> 4) & 0xf);
            encoder.encodeSymbol((offset >> 8) & 0xf);
            encoder.encodeSymbol((offset >> 12) & 0xf);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
   
    public void endEncoding(Object context) {
        try {
            HuffmanEncoder encoder = (HuffmanEncoder)context;
            encoder.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
   
    public byte[] decompress(byte[] compressedBytes) {
        try {
            ByteArrayInputStream bytesIn = new ByteArrayInputStream(compressedBytes);
            HuffmanDecoder decoder = new HuffmanDecoder(codeModel.createModel(), bytesIn);
            SubstringUnpacker unpacker = new SubstringUnpacker(dictionary);
       
            int nextSymbol;
            while ((nextSymbol = decoder.decodeSymbol()) != -1) {
                if (nextSymbol > 255) {
                    int length = nextSymbol - 256;
                    int offset = decoder.decodeSymbol() | (decoder.decodeSymbol() << 4) | (decoder.decodeSymbol() << 8) | (decoder.decodeSymbol() << 12);
                    offset = -offset;
                    unpacker.encodeSubstring(offset, length, null);
                }
                else {
                    unpacker.encodeLiteral(nextSymbol, null);
                }
            }
            unpacker.endEncoding(null);
            return unpacker.getUnpackedBytes();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }   
   
   
    private class ModelBuilder implements SubstringPacker.Consumer {
        private int[] literalLengthHistogram = new int[256 + 256 + 1]; // 256 for each unique literal byte, 256 for all possible length, plus 1 for EOF
        private int[] offsetHistogramNibble0 = new int[16];
        private int[] offsetHistogramNibble1 = new int[16];
        private int[] offsetHistogramNibble2 = new int[16];
        private int[] offsetHistogramNibble3 = new int[16];
       
        public void encodeLiteral(int aByte, Object context) {
            literalLengthHistogram[aByte]++;
        }
       
        public void endEncoding(Object context) {
            literalLengthHistogram[literalLengthHistogram.length - 1]++;
        }

        public void encodeSubstring(int offset, int length, Object context) {
           
            if (length < 1 || length > 255) {
                throw new IllegalArgumentException("Length " + length + " out of range [1,255]");
            }
            literalLengthHistogram[256 + length]++;
           
            offset = -offset;
            if (length < 1 || offset > (2<<15)-1) {
                throw new IllegalArgumentException("Length " + length + " out of range [1, 65535]");
            }
            offsetHistogramNibble0[offset & 0xf]++;
            offsetHistogramNibble1[(offset >> 4) & 0xf]++;
            offsetHistogramNibble2[(offset >> 8) & 0xf]++;
            offsetHistogramNibble3[(offset >> 12) & 0xf]++;
        }

        public FemtoZipHuffmanModel createModel() {
            return new FemtoZipHuffmanModel(
                    new FrequencyHuffmanModel(literalLengthHistogram, false),
                    new FrequencyHuffmanModel(offsetHistogramNibble0, false),
                    new FrequencyHuffmanModel(offsetHistogramNibble1, false),
                    new FrequencyHuffmanModel(offsetHistogramNibble2, false),
                    new FrequencyHuffmanModel(offsetHistogramNibble3, false));
        }
    }
}
TOP

Related Classes of org.toubassi.femtozip.models.FemtoZipCompressionModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.