Make a start on supporting Chunks

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@548836 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2007-06-19 19:55:30 +00:00
parent 79823fed3e
commit 0df13bee23
16 changed files with 458 additions and 20 deletions

View File

@ -19,6 +19,7 @@ package org.apache.poi.hdgf;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerFactory;
import org.apache.poi.hdgf.streams.PointerContainingStream;
@ -47,6 +48,8 @@ public class HDGFDiagram {
private Pointer trailerPointer;
private TrailerStream trailer;
private ChunkFactory chunkFactory;
private PointerFactory ptrFactory;
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
@ -71,15 +74,16 @@ public class HDGFDiagram {
docSize = LittleEndian.getUInt(_docstream, 0x1c);
// ??? 0x20 -> 0x23
// Create a Pointer Factory for the document version
// Create the Chunk+Pointer Factories for the document version
ptrFactory = new PointerFactory(version);
chunkFactory = new ChunkFactory(version);
// Grab the pointer to the trailer
trailerPointer = ptrFactory.createPointer(_docstream, 0x24);
// Now grab the trailer
trailer = (TrailerStream)
Stream.createStream(trailerPointer, _docstream, ptrFactory);
Stream.createStream(trailerPointer, _docstream, chunkFactory, ptrFactory);
// Finally, find all our streams
trailer.findChildren(_docstream);

View File

@ -0,0 +1,55 @@
/* ====================================================================
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.chunks;
/**
* Base of all chunks, which hold data, flags etc
*/
public class Chunk {
/**
* The contents of the chunk, excluding the header,
* trailer and separator
*/
private byte[] contents;
private ChunkHeader header;
/** May be null */
private ChunkTrailer trailer;
/** May be null */
private ChunkSeparator separator;
public Chunk(ChunkHeader header, ChunkTrailer trailer, ChunkSeparator separator, byte[] contents) {
this.header = header;
this.trailer = trailer;
this.separator = separator;
this.contents = contents;
}
/**
* Returns the size of the chunk, including any
* headers, trailers and separators.
*/
public int getOnDiskSize() {
int size = header.getSizeInBytes() + contents.length;
if(trailer != null) {
size += trailer.trailerData.length;
}
if(separator != null) {
size += separator.separatorData.length;
}
return size;
}
}

View File

@ -0,0 +1,67 @@
/* ====================================================================
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.chunks;
/**
* Factor class to create the appropriate chunks, which
* needs the version of the file to process the chunk header
* and trailer areas.
* Makes use of chunks_parse_cmds.tbl from vsdump to be able
* to c
*/
public class ChunkFactory {
private int version;
public ChunkFactory(int version) {
this.version = version;
}
public int getVersion() { return version; }
/**
* Creates the appropriate chunk at the given location.
* @param data
* @param offset
* @return
*/
public Chunk createChunk(byte[] data, int offset) {
// Create the header
ChunkHeader header =
ChunkHeader.createChunkHeader(version, data, offset);
// Create the trailer and separator, if required
ChunkTrailer trailer = null;
ChunkSeparator separator = null;
if(header.hasTrailer()) {
trailer = new ChunkTrailer(
data, header.getLength() + header.getSizeInBytes());
if(header.hasSeparator()) {
separator = new ChunkSeparator(
data, header.getLength() + header.getSizeInBytes() + 8);
}
}
// Now, create the chunk
byte[] contents = new byte[header.getLength()];
System.arraycopy(data, offset+header.getSizeInBytes(), contents, 0, contents.length);
Chunk chunk = new Chunk(header, trailer, separator, contents);
// Feed in the stuff from chunks_parse_cmds.tbl
// TODO
// All done
return chunk;
}
}

View File

@ -0,0 +1,83 @@
/* ====================================================================
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.chunks;
import org.apache.poi.util.LittleEndian;
/**
* A chunk header
*/
public abstract class ChunkHeader {
protected int type;
protected int id;
protected int length;
protected int unknown1;
/**
* Creates the appropriate ChunkHeader for the Chunk Header at
* the given location, for the given document version.
*/
public static ChunkHeader createChunkHeader(int documentVersion, byte[] data, int offset) {
if(documentVersion >= 6) {
ChunkHeaderV6 ch;
if(documentVersion > 6) {
ch = new ChunkHeaderV11();
} else {
ch = new ChunkHeaderV6();
}
ch.type = (int)LittleEndian.getUInt(data, offset + 0);
ch.id = (int)LittleEndian.getUInt(data, offset + 4);
ch.unknown1 = (int)LittleEndian.getUInt(data, offset + 8);
ch.length = (int)LittleEndian.getUInt(data, offset + 12);
ch.unknown2 = LittleEndian.getShort(data, offset + 16);
ch.unknown3 = (short)LittleEndian.getUnsignedByte(data, offset + 18);
return ch;
} else if(documentVersion == 5) {
throw new RuntimeException("TODO");
} else {
throw new IllegalArgumentException("Visio files with versions below 5 are not supported, yours was " + documentVersion);
}
}
public abstract int getSizeInBytes();
public abstract boolean hasTrailer();
public abstract boolean hasSeparator();
/**
* Returns the ID/IX of the chunk
*/
public int getId() {
return id;
}
/**
* Returns the length of the trunk, excluding the length
* of the header, trailer or separator.
*/
public int getLength() {
return length;
}
/**
* Returns the type of the chunk, which affects the
* mandatory information
*/
public int getType() {
return type;
}
public int getUnknown1() {
return unknown1;
}
}

View File

@ -0,0 +1,37 @@
/* ====================================================================
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.chunks;
/**
* A chunk header from v11+
*/
public class ChunkHeaderV11 extends ChunkHeaderV6 {
/**
* Does the chunk have a separator?
*/
public boolean hasSeparator() {
// If there's a trailer, there's a separator
if(hasTrailer()) { return true; }
if(unknown2 == 2 && unknown3 == 0x55) { return true; }
if(unknown2 == 2 && unknown3 == 0x54 && type == 0xaa) { return true; }
if(unknown2 == 3 && unknown3 == 0x50 && type == 0xaa) { return true; }
if(type == 0x69) { return true; }
return false;
}
}

View File

@ -0,0 +1,57 @@
/* ====================================================================
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.chunks;
/**
* A chunk header from v6
*/
public class ChunkHeaderV6 extends ChunkHeader {
protected short unknown2;
protected short unknown3;
public short getUnknown2() {
return unknown2;
}
public short getUnknown3() {
return unknown3;
}
public int getSizeInBytes() {
return 19;
}
/**
* Does the chunk have a trailer?
*/
public boolean hasTrailer() {
if(unknown1 != 0 || type == 0x71 || type == 0x70) {
return true;
}
if(type == 0x6b || type == 0x6a || type == 0x69 || type == 0x66
|| type == 0x65 || type == 0x2c) {
return true;
}
return false;
}
/**
* Does the chunk have a separator?
*/
public boolean hasSeparator() {
// V6 never has separators
return false;
}
}

View File

@ -0,0 +1,30 @@
/* ====================================================================
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.chunks;
/**
* A separator between the trailer of one chunk, and the
* header of the next one
*/
public class ChunkSeparator {
protected byte[] separatorData;
public ChunkSeparator(byte[] data, int offset) {
separatorData = new byte[4];
System.arraycopy(data, offset, separatorData, 0, 4);
}
}

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.chunks;
/**
* A trailer that follows a chunk
*/
public class ChunkTrailer {
protected byte[] trailerData;
public ChunkTrailer(byte[] data, int offset) {
trailerData = new byte[8];
System.arraycopy(data, offset, trailerData, 0, 8);
}
}

View File

@ -27,6 +27,7 @@ public class PointerFactory {
public PointerFactory(int version) {
this.version = version;
}
public int getVersion() { return version; }
public Pointer createPointer(byte[] data, int offset) {
Pointer p;

View File

@ -29,7 +29,7 @@ public class PointerV6 extends Pointer {
return (0x50 <= format && format < 0x60);
}
public boolean destinationHasChunks() {
return (0xd0 <= format && format < 0xd0);
return (0xd0 <= format && format < 0xdf);
}
public boolean destinationCompressed() {

View File

@ -0,0 +1,54 @@
/* ====================================================================
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.util.ArrayList;
import org.apache.poi.hdgf.chunks.Chunk;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
public class ChunkStream extends Stream {
private ChunkFactory chunkFactory;
/** All the Chunks we contain */
private Chunk[] chunks;
protected ChunkStream(Pointer pointer, StreamStore store, ChunkFactory chunkFactory) {
super(pointer, store);
this.chunkFactory = chunkFactory;
}
public Chunk[] getChunks() { return chunks; }
/**
* Process the contents of the stream out into chunks
*/
public void findChunks() {
ArrayList chunksA = new ArrayList();
int pos = 0;
byte[] contents = getStore().getContents();
while(pos < contents.length) {
Chunk chunk = chunkFactory.createChunk(contents, pos);
chunksA.add(chunk);
pos += chunk.getOnDiskSize();
}
chunks = (Chunk[])chunksA.toArray(new Chunk[chunksA.size()]);
}
}

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.hdgf.streams;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerFactory;
import org.apache.poi.util.LittleEndian;
@ -28,11 +29,13 @@ public class PointerContainingStream extends Stream {
private Pointer[] childPointers;
private Stream[] childStreams;
private ChunkFactory chunkFactory;
private PointerFactory pointerFactory;
private int numPointersLocalOffset;
protected PointerContainingStream(Pointer pointer, StreamStore store, PointerFactory pointerFactory) {
protected PointerContainingStream(Pointer pointer, StreamStore store, ChunkFactory chunkFactory, PointerFactory pointerFactory) {
super(pointer, store);
this.chunkFactory = chunkFactory;
this.pointerFactory = pointerFactory;
// Find the offset to the number of child pointers we have
@ -81,9 +84,15 @@ public class PointerContainingStream extends Stream {
childStreams = new Stream[childPointers.length];
for(int i=0; i<childPointers.length; i++) {
Pointer ptr = childPointers[i];
childStreams[i] = Stream.createStream(ptr, documentData, pointerFactory);
childStreams[i] = Stream.createStream(ptr, documentData, chunkFactory, pointerFactory);
// Recurse if required
// Process chunk streams into their chunks
if(childStreams[i] instanceof ChunkStream) {
ChunkStream child = (ChunkStream)childStreams[i];
// child.findChunks();
}
// Recurse into pointer containing streams
if(childStreams[i] instanceof PointerContainingStream) {
PointerContainingStream child =
(PointerContainingStream)childStreams[i];

View File

@ -18,6 +18,7 @@ package org.apache.poi.hdgf.streams;
import java.io.IOException;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerFactory;
@ -51,7 +52,7 @@ public abstract class Stream {
* @param pointer The Pointer to create a stream for
* @param documentData The raw document data
*/
public static Stream createStream(Pointer pointer, byte[] documentData, PointerFactory pointerFactory) {
public static Stream createStream(Pointer pointer, byte[] documentData, ChunkFactory chunkFactory, PointerFactory pointerFactory) {
// Create the store
StreamStore store;
if(pointer.destinationCompressed()) {
@ -71,10 +72,13 @@ public abstract class Stream {
// Figure out what sort of Stream to create, create and return it
if(pointer.getType() == 20) {
return new TrailerStream(pointer, store, pointerFactory);
return new TrailerStream(pointer, store, chunkFactory, pointerFactory);
}
else if(pointer.destinationHasPointers()) {
return new PointerContainingStream(pointer, store, pointerFactory);
return new PointerContainingStream(pointer, store, chunkFactory, pointerFactory);
}
else if(pointer.destinationHasChunks()) {
return new ChunkStream(pointer, store, chunkFactory);
}
else if(pointer.destinationHasStrings()) {
return new StringsStream(pointer, store);

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.hdgf.streams;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerFactory;
@ -26,7 +27,7 @@ import org.apache.poi.hdgf.pointers.PointerFactory;
* a special series of byte near the start of the file.
*/
public class TrailerStream extends PointerContainingStream {
protected TrailerStream(Pointer pointer, StreamStore store, PointerFactory pointerFactory) {
super(pointer, store, pointerFactory);
protected TrailerStream(Pointer pointer, StreamStore store, ChunkFactory chunkFactory, PointerFactory pointerFactory) {
super(pointer, store, chunkFactory, pointerFactory);
}
}

View File

@ -87,7 +87,7 @@ public class TestStreamBasics extends StreamTest {
// Create a fake pointer
Pointer ptr = new TestPointer(true, 0, compressedStream.length, -1, (short)-1);
// Now the stream
Stream stream = Stream.createStream(ptr, compressedStream, null);
Stream stream = Stream.createStream(ptr, compressedStream, null, null);
// Check
assertNotNull(stream.getPointer());
@ -111,7 +111,7 @@ public class TestStreamBasics extends StreamTest {
// Create a fake pointer
Pointer ptr = new TestPointer(false, 0, uncompressedStream.length, -1, (short)-1);
// Now the stream
Stream stream = Stream.createStream(ptr, uncompressedStream, null);
Stream stream = Stream.createStream(ptr, uncompressedStream, null, null);
// Check
assertNotNull(stream.getPointer());

View File

@ -18,6 +18,7 @@ package org.apache.poi.hdgf.streams;
import java.io.FileInputStream;
import org.apache.poi.hdgf.chunks.ChunkFactory;
import org.apache.poi.hdgf.pointers.Pointer;
import org.apache.poi.hdgf.pointers.PointerFactory;
import org.apache.poi.poifs.filesystem.DocumentEntry;
@ -27,12 +28,14 @@ public class TestStreamComplex extends StreamTest {
private byte[] contents;
private int trailerPointerAt = 0x24;
private int trailerDataAt = 0x8a94;
private ChunkFactory chunkFactory;
private PointerFactory ptrFactory;
protected void setUp() throws Exception {
String dirname = System.getProperty("HDGF.testdata.path");
String filename = dirname + "/Test_Visio-Some_Random_Text.vsd";
ptrFactory = new PointerFactory(6);
ptrFactory = new PointerFactory(11);
chunkFactory = new ChunkFactory(11);
FileInputStream fin = new FileInputStream(filename);
POIFSFileSystem filesystem = new POIFSFileSystem(fin);
@ -55,7 +58,7 @@ public class TestStreamComplex extends StreamTest {
assertEquals(20, trailerPtr.getType());
assertEquals(trailerDataAt, trailerPtr.getOffset());
Stream stream = Stream.createStream(trailerPtr, contents, ptrFactory);
Stream stream = Stream.createStream(trailerPtr, contents, chunkFactory, ptrFactory);
assertTrue(stream instanceof TrailerStream);
TrailerStream ts = (TrailerStream)stream;
@ -69,10 +72,14 @@ public class TestStreamComplex extends StreamTest {
assertEquals(0xff, ts.getChildPointers()[3].getType());
}
public void testChunks() {
}
public void testStrings() {
Pointer trailerPtr = ptrFactory.createPointer(contents, trailerPointerAt);
TrailerStream ts = (TrailerStream)
Stream.createStream(trailerPtr, contents, ptrFactory);
Stream.createStream(trailerPtr, contents, chunkFactory, ptrFactory);
// Should be the 1st one
Pointer stringPtr = ts.getChildPointers()[0];
@ -80,7 +87,7 @@ public class TestStreamComplex extends StreamTest {
assertFalse(stringPtr.destinationHasChunks());
assertFalse(stringPtr.destinationHasPointers());
Stream stream = Stream.createStream(stringPtr, contents, ptrFactory);
Stream stream = Stream.createStream(stringPtr, contents, chunkFactory, ptrFactory);
assertNotNull(stream);
assertTrue(stream instanceof StringsStream);
}
@ -94,7 +101,7 @@ public class TestStreamComplex extends StreamTest {
TestPointer ptr44d3 = new TestPointer(true, 0x44d3, 0x51, 0x4e, (short)0x56);
ptr44d3.hasPointers = true;
PointerContainingStream s44d3 = (PointerContainingStream)
Stream.createStream(ptr44d3, contents, ptrFactory);
Stream.createStream(ptr44d3, contents, chunkFactory, ptrFactory);
// Type: 0d Addr: 014ff644 Offset: 4312 Len: 48 Format: 54 From: 44d3
Pointer ptr4312 = s44d3.getChildPointers()[1];
@ -106,7 +113,7 @@ public class TestStreamComplex extends StreamTest {
assertFalse(ptr4312.destinationHasStrings());
PointerContainingStream s4312 = (PointerContainingStream)
Stream.createStream(ptr4312, contents, ptrFactory);
Stream.createStream(ptr4312, contents, chunkFactory, ptrFactory);
// Check it has 0x347f
// Type: 1f Addr: 01540004 Offset: 347f Len: 8e8 Format: 46 From: 4312
@ -132,7 +139,7 @@ public class TestStreamComplex extends StreamTest {
public void testTrailerContents() {
Pointer trailerPtr = ptrFactory.createPointer(contents, trailerPointerAt);
TrailerStream ts = (TrailerStream)
Stream.createStream(trailerPtr, contents, ptrFactory);
Stream.createStream(trailerPtr, contents, chunkFactory, ptrFactory);
assertNotNull(ts.getChildPointers());
assertNull(ts.getPointedToStreams());