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;
private Pointer trailerPointer;
private TrailerStream trailer;
+
+ private ChunkFactory chunkFactory;
private PointerFactory ptrFactory;
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
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);
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
public PointerFactory(int version) {
this.version = version;
}
+ public int getVersion() { return version; }
public Pointer createPointer(byte[] data, int offset) {
Pointer p;
return (0x50 <= format && format < 0x60);
}
public boolean destinationHasChunks() {
- return (0xd0 <= format && format < 0xd0);
+ return (0xd0 <= format && format < 0xdf);
}
public boolean destinationCompressed() {
--- /dev/null
+/* ====================================================================
+ 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()]);
+ }
+}
==================================================================== */
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;
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
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];
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;
* @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()) {
// 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);
==================================================================== */
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;
* 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);
}
}
// 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());
// 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());
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;
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);
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;
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];
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);
}
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];
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
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());