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
- decompress(byte src[], int src_off, int src_len, byte dst[], int dst_off, int dst_len)
- decompress(byte[] compressed, int sequenceLen)
- decompress(byte[] in, int len)
- decompress_action(byte[] source)
- decompressHuffman(byte[] message, int length)