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:
Nick Burch 2007-06-18 22:44:56 +00:00
parent 58a5831942
commit 44288ba5e5
5 changed files with 121 additions and 201 deletions

View File

@ -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;
}
} }
} }

View File

@ -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

View File

@ -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);
}
}

View File

@ -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[] {

View File

@ -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;