From 014d371a5faeeba599fc208f947d4dbd6ac39252 Mon Sep 17 00:00:00 2001
From: Javen O'Neal Returns the last name in the document path's name sequence.
+ * If the document path's name sequence is empty, then the empty string is returned. Returns a string representation of the path. Components are
- * separated by the platform-specific file separator.
- * If the end of file is reached before any bytes are read, returns -1. If + *
Same as the normal {@link InputStream#read(byte[], int, int)}, but tries to ensure + * that the entire len number of bytes is read.
+ * + *If the end of file is reached before any bytes are read, returns -1. If * the end of the file is reached after some bytes are read, returns the - * number of bytes read. If the end of the file isn't reached before len - * bytes have been read, will return len bytes. + * number of bytes read. If the end of the file isn't reached before len + * bytes have been read, will return len bytes.
+ * + * @param in the stream from which the data is read. + * @param b the buffer into which the data is read. + * @param off the start offset in array b at which the data is written. + * @param len the maximum number of bytes to read. */ public static int readFully(InputStream in, byte[] b, int off, int len) throws IOException { int total = 0; diff --git a/src/java/org/apache/poi/util/RLEDecompressingInputStream.java b/src/java/org/apache/poi/util/RLEDecompressingInputStream.java index 0090ebb3f..b8a858702 100644 --- a/src/java/org/apache/poi/util/RLEDecompressingInputStream.java +++ b/src/java/org/apache/poi/util/RLEDecompressingInputStream.java @@ -19,6 +19,8 @@ package org.apache.poi.util; import java.io.IOException; import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; /** * Wrapper of InputStream which provides Run Length Encoding (RLE) @@ -270,4 +272,18 @@ public class RLEDecompressingInputStream extends InputStream { } return (b0 & 0xFF) | ((b1 & 0xFF) << 8) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 24); } + + public static final byte[] decompress(byte[] compressed) throws IOException { + return decompress(compressed, 0, compressed.length); + } + + public static final byte[] decompress(byte[] compressed, int offset, int length) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream instream = new ByteArrayInputStream(compressed, offset, length); + InputStream stream = new RLEDecompressingInputStream(instream); + IOUtils.copy(stream, out); + stream.close(); + out.close(); + return out.toByteArray(); + } } diff --git a/src/testcases/org/apache/poi/util/TestRLEDecompressingInputStream.java b/src/testcases/org/apache/poi/util/TestRLEDecompressingInputStream.java new file mode 100644 index 000000000..6693ab2d4 --- /dev/null +++ b/src/testcases/org/apache/poi/util/TestRLEDecompressingInputStream.java @@ -0,0 +1,166 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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.apache.poi.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Test; + +public class TestRLEDecompressingInputStream { + + /** + * Section 3.2.1 No Compression Example + * + * The following string illustrates an ASCII text string with a set of characters that cannot be compressed + * by the compression algorithm specified in section 2.4.1. + * + * abcdefghijklmnopqrstuv. + * + * This example is provided to demonstrate the results of compressing and decompressing the string + * using an interoperable implementation of the algorithm specified in section 2.4.1. + * + * The following hex array represents the compressed byte array of the example string as compressed by + * the compression algorithm. + * + * 01 19 B0 00 61 62 63 64 65 66 67 68 00 69 6A 6B 6C + * 6D 6E 6F 70 00 71 72 73 74 75 76 2E + * + * The following hex array represents the decompressed byte array of the example string as + * decompressed by the decompression algorithm. + * + * 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 + * 72 73 74 75 76 2E + * + */ + @Test + public void noCompressionExample() { + final byte[] compressed = { + 0x01, 0x19, (byte)0xB0, 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x00, 0x69, 0x6A, 0x6B, 0x6C, + 0x6D, 0x6E, 0x6F, 0x70, 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x2E + }; + final String expected = "abcdefghijklmnopqrstuv."; + checkRLEDecompression(expected, compressed); + } + + /** + * Section 3.2.2 Normal Compression Example + * + * The following string illustrates an ASCII text string with a typical set of characters that can be + * compressed by the compression algorithm. + * + * #aaabcdefaaaaghijaaaaaklaaamnopqaaaaaaaaaaaarstuvwxyzaaa + * + * This example is provided to demonstrate the results of compressing and decompressing the example + * string using an interoperable implementation of the algorithm specified in section 2.4.1. + * + * The following hex array represents the compressed byte array of the example string as compressed by + * the compression algorithm: + * + * 01 2F B0 00 23 61 61 61 62 63 64 65 82 66 00 70 + * 61 67 68 69 6A 01 38 08 61 6B 6C 00 30 6D 6E 6F + * 70 06 71 02 70 04 10 72 73 74 75 76 10 77 78 79 + * 7A 00 3C + * + * The following hex array represents the decompressed byte array of the example string as + * decompressed by the decompression algorithm: + * + * 23 61 61 61 62 63 64 65 66 61 61 61 61 67 68 69 + * 6a 61 61 61 61 61 6B 6C 61 61 61 6D 6E 6F 70 71 + * 61 61 61 61 61 61 61 61 61 61 61 61 72 73 74 75 + * 76 77 78 79 7A 61 61 61 + */ + @Test + public void normalCompressionExample() { + final byte[] compressed = { + 0x01, 0x2F, (byte)0xB0, 0x00, 0x23, 0x61, 0x61, 0x61, 0x62, 0x63, 0x64, 0x65, (byte)0x82, 0x66, 0x00, 0x70, + 0x61, 0x67, 0x68, 0x69, 0x6A, 0x01, 0x38, 0x08, 0x61, 0x6B, 0x6C, 0x00, 0x30, 0x6D, 0x6E, 0x6F, + 0x70, 0x06, 0x71, 0x02, 0x70, 0x04, 0x10, 0x72, 0x73, 0x74, 0x75, 0x76, 0x10, 0x77, 0x78, 0x79, + 0x7A, 0x00, 0x3C + }; + final String expected = "#aaabcdefaaaaghijaaaaaklaaamnopqaaaaaaaaaaaarstuvwxyzaaa"; + checkRLEDecompression(expected, compressed); + } + + /** + * Section 3.2.3 Maximum Compression Example + * + * The following string illustrates an ASCII text string with a typical set of characters that can be + * compressed by the compression algorithm. + * + * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + * + * This example is provided to demonstrate the results of compressing and decompressing the example + * string using an interoperable implementation of the algorithm specified in section 2.4.1. + * + * The following hex array represents the compressed byte array of the example string as compressed by + * the compression algorithm: + * + * 01 03 B0 02 61 45 00 + * + * The following hex array represents the decompressed byte array of the example string as + * decompressed by the decompression algorithm: + * + * 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 + * 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 + * 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 + * 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 + * 61 61 61 61 61 61 61 61 61 + */ + @Test + public void maximumCompressionExample() { + final byte[] compressed = { + 0x01, 0x03, (byte)0xB0, 0x02, 0x61, 0x45, 0x00 + }; + final String expected = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + checkRLEDecompression(expected, compressed); + } + + @Test + public void decompress() throws IOException { + final byte[] compressed = { + 0x01, 0x03, (byte)0xB0, 0x02, 0x61, 0x45, 0x00 + }; + final byte[] expanded = RLEDecompressingInputStream.decompress(compressed); + final byte[] expected = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".getBytes(); + assertArrayEquals(expected, expanded); + } + + private static void checkRLEDecompression(String expected, byte[] runLengthEncodedData) { + InputStream compressedStream = new ByteArrayInputStream(runLengthEncodedData); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + InputStream stream = new RLEDecompressingInputStream(compressedStream); + try { + IOUtils.copy(stream, out); + } finally { + out.close(); + stream.close(); + } + } catch (final IOException e) { + throw new RuntimeException(e); + } + + assertEquals(expected, out.toString()); + } +}