diff --git a/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java b/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java index b4ceb8dca..14c988ac8 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/HDGFDiagram.java @@ -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); diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java new file mode 100644 index 000000000..94bc65a67 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/Chunk.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java new file mode 100644 index 000000000..166a5e006 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkFactory.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java new file mode 100644 index 000000000..86603a4b9 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeader.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java new file mode 100644 index 000000000..a81a20f56 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV11.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java new file mode 100644 index 000000000..e8061563a --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkHeaderV6.java @@ -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; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkSeparator.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkSeparator.java new file mode 100644 index 000000000..7098f17ea --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkSeparator.java @@ -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); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkTrailer.java b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkTrailer.java new file mode 100644 index 000000000..a610b49b1 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/chunks/ChunkTrailer.java @@ -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); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerFactory.java b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerFactory.java index ad36da08d..58e863907 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerFactory.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerFactory.java @@ -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; diff --git a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV6.java b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV6.java index e94beed0a..5f6ab18cf 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV6.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/pointers/PointerV6.java @@ -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() { diff --git a/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java new file mode 100644 index 000000000..dcb231078 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hdgf/streams/ChunkStream.java @@ -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()]); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hdgf/streams/PointerContainingStream.java b/src/scratchpad/src/org/apache/poi/hdgf/streams/PointerContainingStream.java index fc1442a57..949cc58f8 100644 --- a/src/scratchpad/src/org/apache/poi/hdgf/streams/PointerContainingStream.java +++ b/src/scratchpad/src/org/apache/poi/hdgf/streams/PointerContainingStream.java @@ -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