Java Byte Array Decompress decompressRTF(byte[] src)

Here you can find the source of decompressRTF(byte[] src)

Description

Decompresses compressed-RTF data.

License

Open Source License

Parameter

Parameter Description
src the compressed-RTF data bytes

Exception

Parameter Description
IllegalArgumentException if src does not contain valid compressed-RTF bytes.

Return

an array containing the decompressed bytes.

Declaration

public static byte[] decompressRTF(byte[] src) 

Method Source Code

//package com.java2s;
/*/*from w  ww.  j av  a  2 s .c  o  m*/
 *  (c) copyright 2003-2007 Amichai Rothman
 *
 *  This file is part of the Java TNEF package.
 *
 *  The Java TNEF package is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  The Java TNEF package 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

public class Main {
    /** The lookup table used in the CRC32 calculation */
    static int[] CRC32_TABLE;
    /**
     * Prebuffered bytes used in RTF-compressed format (found them in
     * RTFLIB32.LIB)
     * */
    static byte[] COMPRESSED_RTF_PREBUF;

    /**
     * Decompresses compressed-RTF data.
     * 
     * @param src
     *            the compressed-RTF data bytes
     * @return an array containing the decompressed bytes.
     * @throws IllegalArgumentException
     *             if src does not contain valid compressed-RTF bytes.
     */
    public static byte[] decompressRTF(byte[] src) {
        byte[] dst; // destination for uncompressed bytes
        int in = 0; // current position in src array
        int out = 0; // current position in dst array

        // get header fields (as defined in RTFLIB.H)
        if (src == null || src.length < 16) {
            throw new IllegalArgumentException(
                    "Invalid compressed-RTF header");
        }

        int compressedSize = (int) getU32(src, in);
        in += 4;
        int uncompressedSize = (int) getU32(src, in);
        in += 4;
        int magic = (int) getU32(src, in);
        in += 4;
        int crc32 = (int) getU32(src, in);
        in += 4;

        if (compressedSize != src.length - 4) {// check size excluding the size
            // field itself
            throw new IllegalArgumentException(
                    "compressed-RTF data size mismatch");
        }

        if (crc32 != calculateCRC32(src, 16, src.length - 16)) {
            throw new IllegalArgumentException(
                    "compressed-RTF CRC32 failed");
        }

        // process the data
        if (magic == 0x414c454d) { // magic number that identifies the stream as
            // a uncompressed stream
            dst = new byte[uncompressedSize];
            System.arraycopy(src, in, dst, out, uncompressedSize); // just copy
            // it as it
            // is
        } else if (magic == 0x75465a4c) { // magic number that identifies the
            // stream as a compressed stream
            dst = new byte[COMPRESSED_RTF_PREBUF.length + uncompressedSize];
            System.arraycopy(COMPRESSED_RTF_PREBUF, 0, dst, 0,
                    COMPRESSED_RTF_PREBUF.length);
            out = COMPRESSED_RTF_PREBUF.length;
            int flagCount = 0;
            int flags = 0;
            while (out < dst.length) {
                // each flag byte flags 8 literals/references, 1 per bit
                flags = (flagCount++ % 8 == 0) ? getU8(src, in++)
                        : flags >> 1;
                if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0
                    // for literal
                    int offset = getU8(src, in++);
                    int length = getU8(src, in++);
                    offset = (offset << 4) | (length >>> 4); // the offset
                    // relative to
                    // block start
                    length = (length & 0xF) + 2; // the number of bytes to copy
                    // the decompression buffer is supposed to wrap around back
                    // to the beginning when the end is reached. we save the
                    // need for such a buffer by pointing straight into the data
                    // buffer, and simulating this behaviour by modifying the
                    // pointers appropriately.
                    offset = (out / 4096) * 4096 + offset;
                    if (offset >= out) {// take from previous block
                        offset -= 4096;
                    }
                    // note: can't use System.arraycopy, because the referenced
                    // bytes can cross through the current out position.
                    int end = offset + length;
                    while (offset < end) {
                        dst[out++] = dst[offset++];
                    }
                } else { // literal
                    dst[out++] = src[in++];
                }
            }
            // copy it back without the prebuffered data
            src = dst;
            dst = new byte[uncompressedSize];
            System.arraycopy(src, COMPRESSED_RTF_PREBUF.length, dst, 0,
                    uncompressedSize);
        } else { // unknown magic number
            throw new IllegalArgumentException(
                    "Unknown compression type (magic number " + magic + ")");
        }
        return dst;
    }

    /**
     * Returns an unsigned 32-bit value from little-endian ordered bytes.
     * 
     * @param b1
     *            first byte value
     * @param b2
     *            second byte value
     * @param b3
     *            third byte value
     * @param b4
     *            fourth byte value
     * @return an unsigned 32-bit value as a long.
     */
    public static long getU32(int b1, int b2, int b3, int b4) {
        return ((b1 & 0xFF) | ((b2 & 0xFF) << 8) | ((b3 & 0xFF) << 16) | ((b4 & 0xFF) << 24)) & 0x00000000FFFFFFFFL;
    }

    /**
     * Returns an unsigned 32-bit value from little-endian ordered bytes.
     * 
     * @param buf
     *            a byte array from which byte values are taken
     * @param offset
     *            the offset within buf from which byte values are taken
     * @return an unsigned 32-bit value as a long.
     */
    public static long getU32(byte[] buf, int offset) {
        return ((buf[offset] & 0xFF) | ((buf[offset + 1] & 0xFF) << 8)
                | ((buf[offset + 2] & 0xFF) << 16) | ((buf[offset + 3] & 0xFF) << 24)) & 0x00000000FFFFFFFFL;
    }

    /**
     * Calculates the CRC32 of the given bytes. The CRC32 calculation is similar
     * to the standard one as demonstrated in RFC 1952, but with the inversion
     * (before and after the calculation) ommited.
     * 
     * @param buf
     *            the byte array to calculate CRC32 on
     * @param off
     *            the offset within buf at which the CRC32 calculation will
     *            start
     * @param len
     *            the number of bytes on which to calculate the CRC32
     * @return the CRC32 value.
     */
    static public int calculateCRC32(byte[] buf, int off, int len) {
        int c = 0;
        int end = off + len;
        for (int i = off; i < end; i++) {
            c = CRC32_TABLE[(c ^ buf[i]) & 0xFF] ^ (c >>> 8);
        }
        return c;
    }

    /**
     * Returns an unsigned 8-bit value from a byte array.
     * 
     * @param buf
     *            a byte array from which byte value is taken
     * @param offset
     *            the offset within buf from which byte value is taken
     * @return an unsigned 8-bit value as an int.
     */
    public static int getU8(byte[] buf, int offset) {
        return buf[offset] & 0xFF;
    }
}

Related

  1. decompress(byte src[], int src_off, int src_len, byte dst[], int dst_off, int dst_len)
  2. decompress(byte[] compressed, int sequenceLen)
  3. decompress(byte[] in, int len)
  4. decompress_action(byte[] source)
  5. decompressHuffman(byte[] message, int length)