Initial HDGF support for streams, plus tests

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@548476 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2007-06-18 20:24:39 +00:00
parent 407d10ffd1
commit ca88624f6f
5 changed files with 313 additions and 0 deletions

View File

@ -0,0 +1,62 @@
/**
*
*/
package org.apache.poi.hdgf.streams;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.poi.hdgf.LZW4HDGF;
class CompressedStreamStore extends StreamStore {
/** The raw, compressed contents */
private byte[] compressedContents;
/**
* We're not sure what this is, but it comes before the
* real contents in the de-compressed data
*/
private byte[] blockHeader = new byte[4];
protected byte[] _getCompressedContents() { return compressedContents; }
protected byte[] _getBlockHeader() { return blockHeader; }
/**
* Creates a new compressed StreamStore, which will handle
* the decompression.
*/
protected CompressedStreamStore(byte[] data, int offset, int length) throws IOException {
this(decompress(data,offset,length));
compressedContents = new byte[length];
System.arraycopy(data, offset, compressedContents, 0, length);
}
/**
* Handles passing the de-compressed data onto our superclass.
*/
private CompressedStreamStore(byte[][] decompressedData) {
super(decompressedData[1], 0, decompressedData[1].length);
blockHeader = decompressedData[0];
}
/**
* Decompresses the given data, returning it as header + contents
*/
public static byte[][] decompress(byte[] data, int offset, int length) throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(data, offset, length);
// Decompress
LZW4HDGF lzw = new LZW4HDGF();
byte[] decompressed = lzw.decode(bais);
// Split into header and contents
byte[][] ret = new byte[2][];
ret[0] = new byte[4];
ret[1] = new byte[decompressed.length - 4];
System.arraycopy(decompressed, 0, ret[0], 0, 4);
System.arraycopy(decompressed, 4, ret[1], 0, ret[1].length);
// All done
return ret;
}
}

View File

@ -0,0 +1,75 @@
/* ====================================================================
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.hdgf.streams;
import java.io.IOException;
import org.apache.poi.hdgf.pointers.Pointer;
/**
* Base of all Streams within a HDGF document.
* Streams are what hold the data (the metadata of a stream
* is held in the pointer that points to the stream).
* A stream may be stored compressed or un-compressed on the
* disk, but that doesn't appear to change their use.
*/
public abstract class Stream {
private Pointer pointer;
private StreamStore store;
public Pointer getPointer() { return pointer; }
protected StreamStore getStore() { return store; }
/**
* Creates a new Stream, having already used the pointer
* to build a store
*/
protected Stream(Pointer pointer, StreamStore store) {
this.pointer = pointer;
this.store = store;
}
/**
* Uses the pointer to locate a Stream within the document
* data, and creates it.
* @param pointer The Pointer to create a stream for
* @param documentData The raw document data
*/
public static Stream createStream(Pointer pointer, byte[] documentData) {
// Create the store
StreamStore store;
if(pointer.destinationCompressed()) {
try {
store = new CompressedStreamStore(
documentData, pointer.getOffset(), pointer.getLength()
);
} catch(IOException e) {
// Should never occur
throw new IllegalStateException(e);
}
} else {
store = new StreamStore(
documentData, pointer.getOffset(), pointer.getLength()
);
}
// Figure out what sort of Stream to create, and create it
// Give up and return a generic one
return new UnknownStream(pointer, store);
}
}

View File

@ -0,0 +1,20 @@
package org.apache.poi.hdgf.streams;
/**
* Holds the representation of the stream on-disk, and
* handles de-compressing it as required.
* In future, may also handle writing it back out again
*/
class StreamStore {
private byte[] contents;
/**
* Creates a new, non compressed Stream Store
*/
protected StreamStore(byte[] data, int offset, int length) {
contents = new byte[length];
System.arraycopy(data, offset, contents, 0, length);
}
protected byte[] getContents() { return contents; }
}

View File

@ -0,0 +1,29 @@
/* ====================================================================
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.hdgf.streams;
import org.apache.poi.hdgf.pointers.Pointer;
/**
* A placeholder for a stream where we don't known anything
* about how to process / handle it
*/
public class UnknownStream extends Stream {
protected UnknownStream(Pointer pointer, StreamStore store) {
super(pointer, store);
}
}

View File

@ -0,0 +1,127 @@
package org.apache.poi.hdgf.streams;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerV6;
import junit.framework.TestCase;
public class TestStreamBasics extends TestCase {
/** The header from when compressedStream is decompressed */
public static final byte[] compressedStreamDCHeader = new byte[] {
-60, 2, 0, 0
};
public static final byte[] compressedStream = new byte[] {
123, -60, 2, -21, -16, 1, 0, 0, -72, -13, -16, 78, -32, -5, 1,
0, 3, -21, -16, 10, 5, 4, -21, -16, 21, 9, -21, -16, 103, -21,
-16, 34, -36, -1, 52, 15, 70, 15, 120, 88, 15, -7, -2, -28, -9,
-123, 21, 0, 44, -122, 1, -4, 104, 15, -24, -13, 40, -98, 32,
78, 102, -67, -1, -2, -30, 64, 40, -67, -113, -73, 116, -98,
-85, 2, 66, 123, 9, 109, -85, 2, -89, 14, -56, -69, -83, -79,
-34, -3, 120, 110, 75, -9, -10, 20, -6, -25, -12, 22, -21, -16,
-12, -81, 67, 1, -128, -70, -21, -16, 84, -21, -16, 70, 0, 23,
-21, -16, 76, 47, -40, 79, 1, -44, -21, -16, 32, 3, 18, 12, 17,
-43, -68, 17, 16, -8, 21, 22, -1, -21, -16, -84, -1, -35, 79,
-9, -10, 96, 0, 46, -21, -16, 44, -39, -41, 79, 1, 119, -13,
-16, -106, -13, -16, 84, 0, 125, 26, -21, -16, 68, -38, 79, 1,
17, 10, 0, -97, 50, 10, 0, 0, -42, -108, 15, 118, 31, 0, -3, 29,
-21, -16, -100, -25, 79, 1, -18, 97, -36, 76, 16, -21, -16, 86,
0, 36, -5, 1, -5, 79, 63, 1, -124, 98, 0, 0, 28, 3, 20, -34, -3,
125, 33, -21, -16, 100, -4, 79, 1, -92, -91, 16, -22, 24, 19, 41,
-21, -16, -44, -59, 16, 108, 100, 0, -21, 0, 71, -105, 18, 39, 85,
17, -3, 79, 1, 95, -108, 113, 0, 0, 104, 3, 18, 49, 49, 17, -1, 64,
85, 1, 0, 114, 0, 0, -93, -36, -21, -16, 100, 31, 0, 0, -40, -21,
-16, -92, 66, 127, 85, 1, 98, 119, 0, 0, -48, 79, 18, -3, 50, -17,
1, 67, 85, 1, 81, -127, 0, -41, 0, 14, 6, 4, 17, 63, -63, 17, 68,
85, -65, 1, 30, -120, 0, 0, 42, 79, 18, 68, 126, -21, -16, -76, 69,
85, 1, 102, -119, 72, 37, 0, 97, 33 };
public static final byte[] uncompressedStream = new byte[] {
0, 1, 0, 0, -72, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0,
0, 9, 0, 0, 0, 103, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-123, 21, 0, 44, -123, 21, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, -98, 32, 78, 102, -67,
-2, -30, 64, 40, -67, -113, -73, 116, -67, -2, -30, 64, 40, 66,
123, 9, 109, -67, -2, -30, 64, 40, -98, 32, 78, 102, -67, -2, -30,
64, 40, -67, -113, -73, 116, -67, -2, -30, 64, -56, -83, -79, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 110, 75, 1, 0, 0, 0,
0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, -12, -81, 67,
1, -128, 0, 0, 0, 84, 0, 0, 0, 70, 0, 23, 0, 0, 0, 76, -40, 79, 1,
-44, 0, 0, 0, 32, 0, 0, 0, 84, 0, 23, 0, 0, 0, -68, -40, 79, 1, -8,
0, 0, 0, 32, 0, 0, 0, 84, 0, -1, 0, 0, 0, -84, -1, 79, 1, 0, 0, 0,
0, 0, 0, 0, 0, 96, 0, 46, 0, 0, 0, 44, -39, 79, 1, 119, 1, 0, 0,
-106, 1, 0, 0, 84, 0, 26, 0, 0, 0, 68, -38, 79, 1, 17, 3, 0, 0,
50, 10, 0, 0, -42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29, 0, 0, 0, -100, -25, 79, 1, -18, 97, 0, 0, -106, 0, 0, 0, 86, 0,
36, 0, 0, 0, -12, -5, 79, 1, -124, 98, 0, 0, 28, 0, 0, 0, 84, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 100,
-4, 79, 1, -92, 98, 0, 0, 32, 0, 0, 0, 84, 0, 41, 0, 0, 0, -44, -4,
79, 1, 108, 100, 0, 0, 71, 0, 0, 0, 86, 0, 39, 0, 0, 0, 68, -3, 79,
1, -108, 113, 0, 0, 104, 0, 0, 0, 84, 0, 49, 0, 0, 0, -84, 64, 85,
1, 0, 114, 0, 0, -93, 0, 0, 0, -42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, -40, 0, 0, 0, -92, 66, 85, 1, 98, 119,
0, 0, -48, 1, 0, 0, 84, 0, 50, 0, 0, 0, 20, 67, 85, 1, 81, -127,
0, 0, 14, 6, 0, 0, 84, 0, 63, 0, 0, 0, 100, 68, 85, 1, 30, -120,
0, 0, 42, 1, 0, 0, 84, 0, 68, 0, 0, 0, -76, 69, 85, 1, 102, -119,
0, 0, 42, 1, 0, 0, 84, 0, 0, 0, 0, 0
};
public void testCompressedStream() {
// Create a fake pointer
Pointer ptr = new TestPointer(true, 0, compressedStream.length, -1, (short)-1);
// Now the stream
Stream stream = Stream.createStream(ptr, compressedStream);
// Check
assertNotNull(stream.getPointer());
assertNotNull(stream.getStore());
assertTrue(stream.getStore() instanceof StreamStore);
assertTrue(stream.getStore() instanceof CompressedStreamStore);
assertTrue(stream instanceof UnknownStream);
// Check the stream store
CompressedStreamStore ss = (CompressedStreamStore)stream.getStore();
assertEquals(4, ss._getBlockHeader().length);
assertEquals(compressedStream.length, ss._getCompressedContents().length);
assertEquals(uncompressedStream.length, ss.getContents().length);
for(int i=0; i<uncompressedStream.length; i++) {
assertEquals(uncompressedStream[i], ss.getContents()[i]);
}
}
public void testUncompressedStream() {
// Create a fake pointer
Pointer ptr = new TestPointer(false, 0, uncompressedStream.length, -1, (short)-1);
// Now the stream
Stream stream = Stream.createStream(ptr, uncompressedStream);
// Check
assertNotNull(stream.getPointer());
assertNotNull(stream.getStore());
assertTrue(stream.getStore() instanceof StreamStore);
assertFalse(stream.getStore() instanceof CompressedStreamStore);
assertTrue(stream instanceof UnknownStream);
}
public static class TestPointer extends Pointer {
private boolean compressed;
public TestPointer(boolean compressed, int offset, int length, int type, short format) {
this.compressed = compressed;
this.offset = offset;
this.length = length;
this.type = type;
this.format = format;
}
public boolean destinationCompressed() { return compressed; }
public boolean destinationHasChunks() { return false; }
public boolean destinationHasPointers() { return false; }
public boolean destinationHasStrings() { return false; }
public int getSizeInBytes() { return -1; }
}
}