Convert HDGFDiagram to using the new pointer and stream code, and add tests for it
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@548518 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
58a5831942
commit
44288ba5e5
@ -16,10 +16,15 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hdgf;
|
package org.apache.poi.hdgf;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.poi.hdgf.pointers.Pointer;
|
||||||
|
import org.apache.poi.hdgf.pointers.PointerFactory;
|
||||||
|
import org.apache.poi.hdgf.streams.PointerContainingStream;
|
||||||
|
import org.apache.poi.hdgf.streams.Stream;
|
||||||
|
import org.apache.poi.hdgf.streams.StringsStream;
|
||||||
|
import org.apache.poi.hdgf.streams.TrailerStream;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
@ -40,8 +45,9 @@ public class HDGFDiagram {
|
|||||||
private short version;
|
private short version;
|
||||||
private long docSize;
|
private long docSize;
|
||||||
|
|
||||||
private VisioPointer trailerPointer;
|
private Pointer trailerPointer;
|
||||||
private PointerBlock trailer;
|
private TrailerStream trailer;
|
||||||
|
private PointerFactory ptrFactory;
|
||||||
|
|
||||||
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
|
public HDGFDiagram(POIFSFileSystem fs) throws IOException {
|
||||||
filesystem = fs;
|
filesystem = fs;
|
||||||
@ -65,82 +71,72 @@ public class HDGFDiagram {
|
|||||||
docSize = LittleEndian.getUInt(_docstream, 0x1c);
|
docSize = LittleEndian.getUInt(_docstream, 0x1c);
|
||||||
// ??? 0x20 -> 0x23
|
// ??? 0x20 -> 0x23
|
||||||
|
|
||||||
// Grab the pointer to the trailer
|
// Create a Pointer Factory for the document version
|
||||||
trailerPointer = VisioPointer.getPointerAt(_docstream, 0x24);
|
ptrFactory = new PointerFactory(version);
|
||||||
|
|
||||||
// And now grab the trailer
|
// Grab the pointer to the trailer
|
||||||
trailer = new CompressedPointerBlock(trailerPointer, _docstream);
|
trailerPointer = ptrFactory.createPointer(_docstream, 0x24);
|
||||||
|
|
||||||
|
// Now grab the trailer
|
||||||
|
trailer = (TrailerStream)
|
||||||
|
Stream.createStream(trailerPointer, _docstream, ptrFactory);
|
||||||
|
|
||||||
|
// Finally, find all our streams
|
||||||
|
trailer.findChildren(_docstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void debug() throws IOException {
|
/**
|
||||||
System.err.println("Trailer is at " + trailerPointer.offset);
|
* Returns the TrailerStream, which is at the root of the
|
||||||
System.err.println("Trailer has type " + trailerPointer.type);
|
* tree of Streams.
|
||||||
System.err.println("Trailer has length " + trailerPointer.length);
|
*/
|
||||||
System.err.println("Trailer has format " + trailerPointer.format);
|
public TrailerStream getTrailerStream() { return trailer; }
|
||||||
|
/**
|
||||||
|
* Returns all the top level streams, which are the streams
|
||||||
|
* pointed to by the TrailerStream.
|
||||||
|
*/
|
||||||
|
public Stream[] getTopLevelStreams() { return trailer.getPointedToStreams(); }
|
||||||
|
|
||||||
for(int i=0; i<trailer.getPointers().length; i++) {
|
|
||||||
VisioPointer ptr = trailer.getPointers()[i];
|
public void debug() throws IOException {
|
||||||
|
System.err.println("Trailer is at " + trailerPointer.getOffset());
|
||||||
|
System.err.println("Trailer has type " + trailerPointer.getType());
|
||||||
|
System.err.println("Trailer has length " + trailerPointer.getLength());
|
||||||
|
System.err.println("Trailer has format " + trailerPointer.getFormat());
|
||||||
|
|
||||||
|
for(int i=0; i<trailer.getPointedToStreams().length; i++) {
|
||||||
|
Stream stream = trailer.getPointedToStreams()[i];
|
||||||
|
Pointer ptr = stream.getPointer();
|
||||||
|
|
||||||
System.err.println("Looking at pointer " + i);
|
System.err.println("Looking at pointer " + i);
|
||||||
System.err.println("\tType is " + ptr.type + "\t\t" + Integer.toHexString(ptr.type));
|
System.err.println("\tType is " + ptr.getType() + "\t\t" + Integer.toHexString(ptr.getType()));
|
||||||
System.err.println("\tOffset is " + ptr.offset + "\t\t" + Long.toHexString(ptr.offset));
|
System.err.println("\tOffset is " + ptr.getOffset() + "\t\t" + Long.toHexString(ptr.getOffset()));
|
||||||
System.err.println("\tAddress is " + ptr.address + "\t" + Long.toHexString(ptr.address));
|
System.err.println("\tAddress is " + ptr.getAddress() + "\t" + Long.toHexString(ptr.getAddress()));
|
||||||
System.err.println("\tLength is " + ptr.length + "\t\t" + Long.toHexString(ptr.length));
|
System.err.println("\tLength is " + ptr.getLength() + "\t\t" + Long.toHexString(ptr.getLength()));
|
||||||
System.err.println("\tFormat is " + ptr.format + "\t\t" + Long.toHexString(ptr.format));
|
System.err.println("\tFormat is " + ptr.getFormat() + "\t\t" + Long.toHexString(ptr.getFormat()));
|
||||||
System.err.println("\tCompressed is " + ptr.destinationCompressed());
|
System.err.println("\tCompressed is " + ptr.destinationCompressed());
|
||||||
|
System.err.println("\tStream is " + stream.getClass());
|
||||||
|
|
||||||
if(ptr.destinationHasPointers()) {
|
if(stream instanceof PointerContainingStream) {
|
||||||
PointerBlock pb = PointerBlock.createAppropriateBlock(ptr, _docstream);
|
PointerContainingStream pcs = (PointerContainingStream)stream;
|
||||||
|
|
||||||
if(pb.getPointers() != null && pb.getPointers().length > 0) {
|
if(pcs.getPointedToStreams() != null && pcs.getPointedToStreams().length > 0) {
|
||||||
System.err.println("\tContains " + pb.getPointers().length + " other pointers");
|
System.err.println("\tContains " + pcs.getPointedToStreams().length + " other pointers/streams");
|
||||||
for(int j=0; j<pb.getPointers().length; j++) {
|
for(int j=0; j<pcs.getPointedToStreams().length; j++) {
|
||||||
VisioPointer sptr = pb.getPointers()[j];
|
Stream ss = pcs.getPointedToStreams()[j];
|
||||||
System.err.println("\t\t" + j + " - Type is " + sptr.type + "\t\t" + Integer.toHexString(sptr.type));
|
Pointer sptr = ss.getPointer();
|
||||||
System.err.println("\t\t" + j + " - Length is " + sptr.length + "\t\t" + Long.toHexString(sptr.length));
|
System.err.println("\t\t" + j + " - Type is " + sptr.getType() + "\t\t" + Integer.toHexString(sptr.getType()));
|
||||||
|
System.err.println("\t\t" + j + " - Length is " + sptr.getLength() + "\t\t" + Long.toHexString(sptr.getLength()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ptr.destinationHasStrings()) {
|
if(stream instanceof StringsStream) {
|
||||||
System.err.println("**strings**");
|
System.err.println("\t\t**strings**");
|
||||||
PointerBlock pb = PointerBlock.createAppropriateBlock(ptr, _docstream);
|
StringsStream ss = (StringsStream)stream;
|
||||||
System.err.println(pb.contents.length);
|
System.err.println("\t\t" + ss._getContentsLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Will only work on Test_Visio-Some_Random_Text.vsd !
|
|
||||||
*/
|
|
||||||
public void debugTestFile() throws Exception {
|
|
||||||
System.err.println();
|
|
||||||
|
|
||||||
VisioPointer p61ee = trailer.pointers[8];
|
|
||||||
System.err.println(p61ee.type + " " + Integer.toHexString(p61ee.type));
|
|
||||||
PointerBlock pb61ee = PointerBlock.createAppropriateBlock(p61ee, _docstream);
|
|
||||||
|
|
||||||
VisioPointer p4524 = pb61ee.pointers[4];
|
|
||||||
System.err.println(p4524.type + " " + Integer.toHexString(p4524.type));
|
|
||||||
PointerBlock pb4524 = PointerBlock.createAppropriateBlock(p4524, _docstream);
|
|
||||||
|
|
||||||
VisioPointer p44d3 = pb4524.pointers[5];
|
|
||||||
System.err.println(p44d3.type + " " + Integer.toHexString(p44d3.type));
|
|
||||||
PointerBlock pb44d3 = PointerBlock.createAppropriateBlock(p44d3, _docstream);
|
|
||||||
|
|
||||||
VisioPointer p4312 = pb44d3.pointers[1];
|
|
||||||
System.err.println(p4312.type + " " + Integer.toHexString(p4312.type));
|
|
||||||
PointerBlock pb4312 = PointerBlock.createAppropriateBlock(p4312, _docstream);
|
|
||||||
|
|
||||||
VisioPointer p347f = pb4312.pointers[0];
|
|
||||||
System.err.println();
|
|
||||||
System.err.println(p347f.type + " " + Integer.toHexString(p347f.type));
|
|
||||||
System.err.println(p347f.offset + " " + Long.toHexString(p347f.offset));
|
|
||||||
System.err.println(p347f.length + " " + Long.toHexString(p347f.length));
|
|
||||||
System.err.println("Has Strings - " + p347f.destinationHasStrings());
|
|
||||||
System.err.println("Compressed - " + p347f.destinationCompressed());
|
|
||||||
|
|
||||||
PointerBlock pb347f = PointerBlock.createAppropriateBlock(p347f, _docstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For testing only
|
* For testing only
|
||||||
@ -148,140 +144,5 @@ public class HDGFDiagram {
|
|||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
HDGFDiagram hdgf = new HDGFDiagram(new POIFSFileSystem(new FileInputStream(args[0])));
|
HDGFDiagram hdgf = new HDGFDiagram(new POIFSFileSystem(new FileInputStream(args[0])));
|
||||||
hdgf.debug();
|
hdgf.debug();
|
||||||
hdgf.debugTestFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A block containing lots of pointers to other blocks.
|
|
||||||
*/
|
|
||||||
public static class PointerBlock {
|
|
||||||
protected VisioPointer pointer;
|
|
||||||
private byte[] contents;
|
|
||||||
|
|
||||||
protected VisioPointer[] pointers;
|
|
||||||
|
|
||||||
protected PointerBlock(VisioPointer pointer) {
|
|
||||||
this.pointer = pointer;
|
|
||||||
}
|
|
||||||
protected PointerBlock(VisioPointer pointer, byte[] data) {
|
|
||||||
this(pointer);
|
|
||||||
|
|
||||||
processData(data, (int)pointer.offset, (int)pointer.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static PointerBlock createAppropriateBlock(VisioPointer pointer, byte[] data) throws IOException {
|
|
||||||
if(pointer.destinationCompressed()) {
|
|
||||||
return new CompressedPointerBlock(pointer,data);
|
|
||||||
} else {
|
|
||||||
return new PointerBlock(pointer,data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public VisioPointer[] getPointers() { return pointers; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the data up into header + contents, and processes
|
|
||||||
*/
|
|
||||||
protected void processData(byte[] data, int offset, int len) {
|
|
||||||
if(len > data.length - offset) {
|
|
||||||
len = data.length - offset;
|
|
||||||
}
|
|
||||||
if(offset < 0) { len = 0; }
|
|
||||||
|
|
||||||
contents = new byte[len];
|
|
||||||
if(len > 0)
|
|
||||||
System.arraycopy(data, offset, contents, 0, contents.length);
|
|
||||||
|
|
||||||
// If we're of type 20, we have child pointers
|
|
||||||
if(len > 0 && (pointer.type == 20 || pointer.destinationHasPointers())) {
|
|
||||||
// Grab the offset to the number of pointers
|
|
||||||
int nPointersAt = (int)LittleEndian.getUInt(contents, 0);
|
|
||||||
int numPointers = (int)LittleEndian.getUInt(contents, nPointersAt);
|
|
||||||
int unknownA = (int)LittleEndian.getUInt(contents, nPointersAt+4);
|
|
||||||
|
|
||||||
pointers = new VisioPointer[numPointers];
|
|
||||||
int pos = nPointersAt + 8;
|
|
||||||
for(int i=0; i<numPointers; i++) {
|
|
||||||
pointers[i] = VisioPointer.getPointerAt(contents, pos);
|
|
||||||
pos += 18;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have strings, try to make sense of them
|
|
||||||
if(len > 0 && (pointer.destinationHasStrings())) {
|
|
||||||
for(int i=0; i<64; i+=1) {
|
|
||||||
short s = LittleEndian.getShort(contents, i);
|
|
||||||
long l = LittleEndian.getUInt(contents, i);
|
|
||||||
System.err.println(i + "\t" + s + "\t" + Integer.toHexString(s));
|
|
||||||
System.err.println(i + "\t" + l + "\t" + Long.toHexString(l));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A block containing lots of pointers to other blocks, that
|
|
||||||
* is itself compressed
|
|
||||||
*/
|
|
||||||
public static class CompressedPointerBlock extends PointerBlock {
|
|
||||||
protected byte[] compressedContents;
|
|
||||||
private byte[] blockHeader = new byte[4];
|
|
||||||
|
|
||||||
protected CompressedPointerBlock(VisioPointer pointer, byte[] data) throws IOException {
|
|
||||||
super(pointer);
|
|
||||||
|
|
||||||
compressedContents = new byte[(int)pointer.length];
|
|
||||||
System.arraycopy(data, (int)pointer.offset, compressedContents, 0, compressedContents.length);
|
|
||||||
|
|
||||||
// Decompress
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(compressedContents);
|
|
||||||
|
|
||||||
// TIFFLZWDecoder lzw = new TIFFLZWDecoder();
|
|
||||||
// byte[] out = new byte[4096];
|
|
||||||
// contents = lzw.decode(compressedContents, out);
|
|
||||||
|
|
||||||
LZW4HDGF lzw = new LZW4HDGF();
|
|
||||||
byte[] decomp = lzw.decode(bais);
|
|
||||||
System.arraycopy(decomp, 0, blockHeader, 0, 4);
|
|
||||||
processData(decomp, 4, decomp.length-4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A visio pointer, for visio versions 6+
|
|
||||||
*/
|
|
||||||
public static class VisioPointer {
|
|
||||||
private int type;
|
|
||||||
private long address;
|
|
||||||
private long offset;
|
|
||||||
private long length;
|
|
||||||
private short format;
|
|
||||||
|
|
||||||
public boolean destinationHasStrings() {
|
|
||||||
return (0x40 <= format && format < 0x50);
|
|
||||||
}
|
|
||||||
public boolean destinationHasPointers() {
|
|
||||||
if(format == 0x1d || format == 0x1e) return true;
|
|
||||||
return (0x50 <= format && format < 0x60);
|
|
||||||
}
|
|
||||||
public boolean destinationHasChunks() {
|
|
||||||
return (0xd0 <= format && format < 0xd0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean destinationCompressed() {
|
|
||||||
// Apparently, it's the second least significant bit
|
|
||||||
return (format & 2) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VisioPointer getPointerAt(byte[] data, int offset) {
|
|
||||||
VisioPointer p = new VisioPointer();
|
|
||||||
p.type = LittleEndian.getInt(data, offset+0);
|
|
||||||
p.address = LittleEndian.getUInt(data, offset+4);
|
|
||||||
p.offset = LittleEndian.getUInt(data, offset+8);
|
|
||||||
p.length = LittleEndian.getUInt(data, offset+12);
|
|
||||||
p.format = LittleEndian.getShort(data, offset+16);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ public abstract class Stream {
|
|||||||
|
|
||||||
public Pointer getPointer() { return pointer; }
|
public Pointer getPointer() { return pointer; }
|
||||||
protected StreamStore getStore() { return store; }
|
protected StreamStore getStore() { return store; }
|
||||||
|
public int _getContentsLength() { return store.getContents().length; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Stream, having already used the pointer
|
* Creates a new Stream, having already used the pointer
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
import org.apache.poi.hdgf.streams.PointerContainingStream;
|
||||||
|
import org.apache.poi.hdgf.streams.TrailerStream;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class TestHDGFCore extends TestCase {
|
||||||
|
POIFSFileSystem fs;
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
String dirname = System.getProperty("HDGF.testdata.path");
|
||||||
|
String filename = dirname + "/Test_Visio-Some_Random_Text.vsd";
|
||||||
|
fs = new POIFSFileSystem(new FileInputStream(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
new HDGFDiagram(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTrailer() throws Exception {
|
||||||
|
HDGFDiagram hdgf = new HDGFDiagram(fs);
|
||||||
|
assertNotNull(hdgf);
|
||||||
|
assertNotNull(hdgf.getTrailerStream());
|
||||||
|
|
||||||
|
// Check it has what we'd expect
|
||||||
|
TrailerStream trailer = hdgf.getTrailerStream();
|
||||||
|
assertEquals(0x8a94, trailer.getPointer().getOffset());
|
||||||
|
|
||||||
|
assertNotNull(trailer.getPointedToStreams());
|
||||||
|
assertEquals(20, trailer.getPointedToStreams().length);
|
||||||
|
|
||||||
|
assertEquals(20, hdgf.getTopLevelStreams().length);
|
||||||
|
|
||||||
|
// 9th one should have children
|
||||||
|
assertNotNull(trailer.getPointedToStreams()[8]);
|
||||||
|
assertNotNull(trailer.getPointedToStreams()[8].getPointer());
|
||||||
|
PointerContainingStream ps8 = (PointerContainingStream)
|
||||||
|
trailer.getPointedToStreams()[8];
|
||||||
|
assertNotNull(ps8.getPointedToStreams());
|
||||||
|
assertEquals(8, ps8.getPointedToStreams().length);
|
||||||
|
}
|
||||||
|
}
|
@ -18,8 +18,6 @@ package org.apache.poi.hdgf.streams;
|
|||||||
|
|
||||||
import org.apache.poi.hdgf.pointers.Pointer;
|
import org.apache.poi.hdgf.pointers.Pointer;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
public class TestStreamBasics extends StreamTest {
|
public class TestStreamBasics extends StreamTest {
|
||||||
/** The header from when compressedStream is decompressed */
|
/** The header from when compressedStream is decompressed */
|
||||||
public static final byte[] compressedStreamDCHeader = new byte[] {
|
public static final byte[] compressedStreamDCHeader = new byte[] {
|
||||||
|
@ -18,8 +18,6 @@ package org.apache.poi.hdgf.streams;
|
|||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import org.apache.poi.hdgf.pointers.Pointer;
|
import org.apache.poi.hdgf.pointers.Pointer;
|
||||||
import org.apache.poi.hdgf.pointers.PointerFactory;
|
import org.apache.poi.hdgf.pointers.PointerFactory;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
|
Loading…
Reference in New Issue
Block a user