gzip数据流解压

gzip数据流解压


package org.jzlib;

/*
 * GZIP library for j2me applications.
 * 
 * Copyright (c) 2004-2006 Carlos Araiz (caraiz@java4ever.com)
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

import java.io.IOException;

/**
 * Clase que permite leer ficheros GZIP.
 * 
 * @author Carlos Araiz
 * 
 * @version 1.2.0
 */
public class GzipUtil
{

//    private static final int FTEXT_MASK = 1;
//    private static final int FHCRC_MASK = 2;
//    private static final int FEXTRA_MASK = 4;
//    private static final int FNAME_MASK = 8;
//    private static final int FCOMMENT_MASK = 16;
    // Tipos de bloques.
    private static final int BTYPE_NONE = 0;
//    private static final int BTYPE_FIXED = 1;
    private static final int BTYPE_DYNAMIC = 2;
//    private static final int BTYPE_RESERVED = 3;

    private static final int MAX_BITS = 16;
    private static final int MAX_CODE_LITERALS = 287;
    private static final int MAX_CODE_DISTANCES = 31;
    private static final int MAX_CODE_LENGTHS = 18;
    private static final int EOB_CODE = 256;
    // Datos prefijados (LENGTH: 257..287 / DISTANCE: 0..29 /
    // DYNAMIC_LENGTH_ORDER: 0..18).
    private static final int LENGTH_EXTRA_BITS[] = {0, 0, 0, 0, 0, 0, 0, 0, 1,
            1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 };
    private static final int LENGTH_VALUES[] = {3, 4, 5, 6, 7, 8, 9, 10, 11,
            13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
            163, 195, 227, 258, 0, 0 };
    private static final int DISTANCE_EXTRA_BITS[] = {0, 0, 0, 0, 1, 1, 2, 2,
            3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
            13, 13 };
    private static final int DISTANCE_VALUES[] = {1, 2, 3, 4, 5, 7, 9, 13, 17,
            25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049,
            3073, 4097, 6145, 8193, 12289, 16385, 24577 };
    private static final int DYNAMIC_LENGTH_ORDER[] = {16, 17, 18, 0, 8, 7, 9,
            6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };

    /** ********************************************************************** */

    // Variables para la lectura de datos comprimidos.
    private static int gzipIndex, gzipByte, gzipBit;

    /** ********************************************************************** */
    /** ********************************************************************** */

    /**
     * Descomprime un fichero GZIP.
     * 
     * @param gzip
     *            Array con los datos del fichero comprimido
     * 
     * @return Array con los datos descomprimidos
     */
    public static byte[] inflate(byte gzip[]) throws IOException
    {
        // Inicializa.
        gzipIndex = gzipByte = gzipBit = 0;
        // Cabecera.
        if (readBits(gzip, 16) != 0x8B1F || readBits(gzip, 8) != 8)
            throw new IOException("Invalid GZIP format");
        // Flag.
        /*int flg = */readBits(gzip, 8);
        // Fecha(4) / XFL(1) / OS(1).
        gzipIndex += 6;
        // Comprueba los flags.
//        if ((flg & FEXTRA_MASK) != 0)
//            gzipIndex += readBits(gzip, 16);
//        if ((flg & FNAME_MASK) != 0)
//            while (gzip[gzipIndex++] != 0)
//                ;
//        if ((flg & FCOMMENT_MASK) != 0)
//            while (gzip[gzipIndex++] != 0)
//                ;
//        if ((flg & FHCRC_MASK) != 0)
//            gzipIndex += 2;
        // Tama�o de los datos descomprimidos.
        int index = gzipIndex;
        gzipIndex = gzip.length - 4;
        byte uncompressed[] = new byte[readBits(gzip, 16)
                | (readBits(gzip, 16) << 16)];
        int uncompressedIndex = 0;
        gzipIndex = index;
        // Bloque con datos comprimidos.
        int bfinal = 0, btype = 0;
        do
        {
            // Lee la cabecera del bloque.
            bfinal = readBits(gzip, 1);
            btype = readBits(gzip, 2);
            // Comprueba el tipo de compresi�n.
            if (btype == BTYPE_NONE)
            {
                // Ignora los bits dentro del byte actual.
                gzipBit = 0;
                // LEN.
                int len = readBits(gzip, 16);
                // NLEN.
                /*int nlen = */readBits(gzip, 16);
                // Lee los datos.
                System.arraycopy(gzip, gzipIndex, uncompressed,
                        uncompressedIndex, len);
                gzipIndex += len;
                // Actualiza el �ndice de los datos descomprimidos.
                uncompressedIndex += len;
            }
            else
            {
                int literalTree[], distanceTree[];
                if (btype == BTYPE_DYNAMIC)
                {
                    // N�mero de datos de cada tipo.
                    int hlit = readBits(gzip, 5) + 257;
                    int hdist = readBits(gzip, 5) + 1;
                    int hclen = readBits(gzip, 4) + 4;
                    // Lee el n�mero de bits para cada c�digo de longitud.
                    byte lengthBits[] = new byte[MAX_CODE_LENGTHS + 1];
                    for (int i = 0; i < hclen; i++)
                        lengthBits[DYNAMIC_LENGTH_ORDER[i]] = (byte) readBits(
                                gzip, 3);
                    // Crea los c�digos para la longitud.
                    int lengthTree[] = createHuffmanTree(lengthBits,
                            MAX_CODE_LENGTHS);
                    // Genera los �rboles.
                    literalTree = createHuffmanTree(decodeCodeLengths(gzip,
                            lengthTree, hlit), hlit - 1);
                    distanceTree = createHuffmanTree(decodeCodeLengths(gzip,
                            lengthTree, hdist), hdist - 1);
                }
                else
                {
                    byte literalBits[] = new byte[MAX_CODE_LITERALS + 1];
                    for (int i = 0; i < 144; i++)
                        literalBits[i] = 8;
                    for (int i = 144; i < 256; i++)
                        literalBits[i] = 9;
                    for (int i = 256; i < 280; i++)
                        literalBits[i] = 7;
                    for (int i = 280; i < 288; i++)
                        literalBits[i] = 8;
                    literalTree = createHuffmanTree(literalBits,
                            MAX_CODE_LITERALS);
                    //
                    byte distanceBits[] = new byte[MAX_CODE_DISTANCES + 1];
                    for (int i = 0; i < distanceBits.length; i++)
                        distanceBits[i] = 5;
                    distanceTree = createHuffmanTree(distanceBits,
                            MAX_CODE_DISTANCES);
                }
                // Descomprime el bloque.
                int code = 0, leb = 0, deb = 0;
                while ((code = readCode(gzip, literalTree)) != EOB_CODE)
                {
                    if (code > EOB_CODE)
                    {
                        code -= 257;
                        int length = LENGTH_VALUES[code];
                        if ((leb = LENGTH_EXTRA_BITS[code]) > 0)
                            length += readBits(gzip, leb);
                        code = readCode(gzip, distanceTree);
                        int distance = DISTANCE_VALUES[code];
                        if ((deb = DISTANCE_EXTRA_BITS[code]) > 0)
                            distance += readBits(gzip, deb);
                        // Repite la informaci�n.
                        int offset = uncompressedIndex - distance;
                        while (distance < length)
                        {
                            System.arraycopy(uncompressed, offset,
                                    uncompressed, uncompressedIndex, distance);
                            uncompressedIndex += distance;
                            length -= distance;
                            distance <<= 1;
                        }
                        System.arraycopy(uncompressed, offset, uncompressed,
                                uncompressedIndex, length);
                        uncompressedIndex += length;
                    }
                    else
                        uncompressed[uncompressedIndex++] = (byte) code;
                }
            }
        }
        while (bfinal == 0);
        //
        return uncompressed;
    }

    /**
     * Lee un n�mero de bits
     * 
     * @param n
     *            N�mero de bits [0..16]
     */
    private static int readBits(byte gzip[], int n)
    {
        // Asegura que tenemos un byte.
        int data = (gzipBit == 0 ? (gzipByte = (gzip[gzipIndex++] & 0xFF))
                : (gzipByte >> gzipBit));
        // Lee hasta completar los bits.
        for (int i = (8 - gzipBit); i < n; i += 8)
        {
            gzipByte = (gzip[gzipIndex++] & 0xFF);
            data |= (gzipByte << i);
        }
        // Ajusta la posici�n actual.
        gzipBit = (gzipBit + n) & 7;
        // Devuelve el dato.
        return (data & ((1 << n) - 1));
    }

    /**
     * Lee un c�digo.
     */
    private static int readCode(byte gzip[], int tree[])
    {
        int node = tree[0];
        while (node >= 0)
        {
            // Lee un byte si es necesario.
            if (gzipBit == 0)
                gzipByte = (gzip[gzipIndex++] & 0xFF);
            // Accede al nodo correspondiente.
            node = (((gzipByte & (1 << gzipBit)) == 0) ? tree[node >> 16]
                    : tree[node & 0xFFFF]);
            // Ajusta la posici�n actual.
            gzipBit = (gzipBit + 1) & 7;
        }
        return (node & 0xFFFF);
    }

    /**
     * Decodifica la longitud de c�digos (usado en bloques comprimidos con
     * c�digos din�micos).
     */
    private static byte[] decodeCodeLengths(byte gzip[], int lengthTree[],
            int count)
    {
        byte bits[] = new byte[count];
        for (int i = 0, code = 0, last = 0; i < count;)
        {
            code = readCode(gzip, lengthTree);
            if (code >= 16)
            {
                int repeat = 0;
                if (code == 16)
                {
                    repeat = 3 + readBits(gzip, 2);
                    code = last;
                }
                else
                {
                    if (code == 17)
                        repeat = 3 + readBits(gzip, 3);
                    else
                        repeat = 11 + readBits(gzip, 7);
                    code = 0;
                }
                while (repeat-- > 0)
                    bits[i++] = (byte) code;
            }
            else
                bits[i++] = (byte) code;
            //
            last = code;
        }
        return bits;
    }

    /**
     * Crea el �rbol para los c�digos Huffman.
     */
    private static int[] createHuffmanTree(byte bits[], int maxCode)
    {
        // N�mero de c�digos por cada longitud de c�digo.
        int bl_count[] = new int[MAX_BITS + 1];
        for (int i = 0; i < bits.length; i++)
            bl_count[bits[i]]++;
        // M�nimo valor num�rico del c�digo para cada longitud de c�digo.
        int code = 0;
        bl_count[0] = 0;
        int next_code[] = new int[MAX_BITS + 1];
        for (int i = 1; i <= MAX_BITS; i++)
            next_code[i] = code = (code + bl_count[i - 1]) << 1;
        // Genera el �rbol.
        // Bit 31 => Nodo (0) o c�digo (1).
        // (Nodo) bit 16..30 => �ndice del nodo de la izquierda (0 si no tiene).
        // (Nodo) bit 0..15 => �ndice del nodo de la derecha (0 si no tiene).
        // (C�digo) bit 0..15
        int tree[] = new int[(maxCode << 1) + MAX_BITS];
        int treeInsert = 1;
        for (int i = 0; i <= maxCode; i++)
        {
            int len = bits[i];
            if (len != 0)
            {
                code = next_code[len]++;
                // Lo mete en en �rbol.
                int node = 0;
                for (int bit = len - 1; bit >= 0; bit--)
                {
                    int value = code & (1 << bit);
                    // Inserta a la izquierda.
                    if (value == 0)
                    {
                        int left = tree[node] >> 16;
                        if (left == 0)
                        {
                            tree[node] |= (treeInsert << 16);
                            node = treeInsert++;
                        }
                        else
                            node = left;
                    }
                    // Inserta a la derecha.
                    else
                    {
                        int right = tree[node] & 0xFFFF;
                        if (right == 0)
                        {
                            tree[node] |= treeInsert;
                            node = treeInsert++;
                        }
                        else
                            node = right;
                    }
                }
                // Inserta el c�digo.
                tree[node] = 0x80000000 | i;
            }
        }
        return tree;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
  作为信息时代象征的Internet的广泛使用是毋庸置疑的,作为Internet的终极用户,您可能经常有这种抱怨,我的机器够快的,但使用Internet时总觉得慢,作为ISP又抱怨用户不愿意掏钱买更好的线路,作为ICP又觉得没有太好的软件可以让数据的流量变小,这种受带宽限制的Internet着实让很多人伤心,何不制作一个数据缩程序,将数据缩一下,让他变得快些呢,Web Server和IE提供了部分这样的功能,也就是将网页的内容进行缩,但这仅仅是部分功能。   对于象地理信息系统,图书查询系统,ERP系统等的,Internet要传输的数据量相当大,而象图形数据、XML数据、文本数据其缩率是相当高的,甚至可以缩到百分之几,正是由于这个要求,我制作了这么两个软件:一是传输流/文件的缩软件,另一个是基于HTTP的缩传输软件,这两个软件花费了我很多心血(尽管里面还有一些BUG),但我准备把他作为免费软件,来庆贺我的生日,如果你想使用或想得到源码请发邮件给我。   第一个软件,传输流/文件的缩,利用Internet中惯常使用的gzip, deflate算法,可以和sun java的GZipInputStream和GZipOutputStream互操作   第二个软件,基于HTTP的缩传输软件,可完全和IE的VBScript和JScript无缝融合   更详细信息请看使用文档Help.doc   例子文件包含这么几个: readme.doc 本文件 help.doc 帮助文档 GZCore.dll gzip,deflate缩/程序,使用前必须注册 GZUtil.dll GZCore.dll的缓冲区处理封装,用于Web的流处理,使用前必须注册 GZip4Web.dll 基于Web的缩文件/流的传送,使用前必须注册 Test.zip 第一个产品的例子, C++代码工程 Temp.asp 第一个产品的例子, 直接用缩程序发送GZip流 SvrRecv.asp 第二个产品的例子,用于服务端处理接受的缩流 SvrSend.asp 第二个产品的例子,用于服务端处理发送的缩流 default.asp 第二个产品的例子,用于客户端处理处理接受文件,GZip流   如果您有好的建议或BUG汇报,请邮件给我,我先表示感谢。   重要说明,此软件不允许使用于商业用途,否则会受到牵连。   另注,由于本软件使用带来的任何损失,软件制作者概不负责。    Ashley Wang ashleywang@21cn.com 2001.12.24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值