Make a start on processing the commands within the chunks, and their values. Includes some tests
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@549616 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2a0276c665
commit
d04f8956c5
@ -16,7 +16,10 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hdgf.chunks;
|
package org.apache.poi.hdgf.chunks;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.apache.poi.hdgf.chunks.ChunkFactory.CommandDefinition;
|
import org.apache.poi.hdgf.chunks.ChunkFactory.CommandDefinition;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base of all chunks, which hold data, flags etc
|
* Base of all chunks, which hold data, flags etc
|
||||||
@ -34,6 +37,12 @@ public class Chunk {
|
|||||||
private ChunkSeparator separator;
|
private ChunkSeparator separator;
|
||||||
/** The possible different commands we can hold */
|
/** The possible different commands we can hold */
|
||||||
protected CommandDefinition[] commandDefinitions;
|
protected CommandDefinition[] commandDefinitions;
|
||||||
|
/** The command+value pairs we hold */
|
||||||
|
private Command[] commands;
|
||||||
|
/** The blocks (if any) we hold */
|
||||||
|
//private Block[] blocks
|
||||||
|
/** The name of the chunk, as found from the commandDefinitions */
|
||||||
|
private String name;
|
||||||
|
|
||||||
public Chunk(ChunkHeader header, ChunkTrailer trailer, ChunkSeparator separator, byte[] contents) {
|
public Chunk(ChunkHeader header, ChunkTrailer trailer, ChunkSeparator separator, byte[] contents) {
|
||||||
this.header = header;
|
this.header = header;
|
||||||
@ -63,6 +72,15 @@ public class Chunk {
|
|||||||
public CommandDefinition[] getCommandDefinitions() {
|
public CommandDefinition[] getCommandDefinitions() {
|
||||||
return commandDefinitions;
|
return commandDefinitions;
|
||||||
}
|
}
|
||||||
|
public Command[] getCommands() {
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the name of the chunk, as found from the CommandDefinitions
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of the chunk, including any
|
* Returns the size of the chunk, including any
|
||||||
@ -78,4 +96,156 @@ public class Chunk {
|
|||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses our CommandDefinitions to process the commands
|
||||||
|
* our chunk type has, and figure out the
|
||||||
|
* values for them.
|
||||||
|
*/
|
||||||
|
protected void processCommands() {
|
||||||
|
if(commandDefinitions == null) {
|
||||||
|
throw new IllegalStateException("You must supply the command definitions before calling processCommands!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over the definitions, building the commands
|
||||||
|
// and getting their values
|
||||||
|
ArrayList commands = new ArrayList();
|
||||||
|
for(int i=0; i<commandDefinitions.length; i++) {
|
||||||
|
int type = commandDefinitions[i].getType();
|
||||||
|
int offset = commandDefinitions[i].getOffset();
|
||||||
|
|
||||||
|
// Handle virtual commands
|
||||||
|
if(type == 10) {
|
||||||
|
name = commandDefinitions[i].getName();
|
||||||
|
continue;
|
||||||
|
} else if(type == 18) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build the appropriate command for the type
|
||||||
|
Command command;
|
||||||
|
if(type == 11 || type == 21) {
|
||||||
|
command = new BlockOffsetCommand(commandDefinitions[i]);
|
||||||
|
} else {
|
||||||
|
command = new Command(commandDefinitions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bizarely, many of the offsets are from the start of the
|
||||||
|
// header, not from the start of the chunk body
|
||||||
|
switch(type) {
|
||||||
|
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
||||||
|
case 11: case 21:
|
||||||
|
case 12: case 16: case 17: case 18: case 28: case 29:
|
||||||
|
// Offset is from start of chunk
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Offset is from start of header!
|
||||||
|
if(offset >= 19) {
|
||||||
|
offset -= 19;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we seem to have enough data
|
||||||
|
if(offset >= contents.length) {
|
||||||
|
System.err.println("Command offset " + offset + " past end of data at " + contents.length);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process
|
||||||
|
switch(type) {
|
||||||
|
// Types 0->7 = a flat at bit 0->7
|
||||||
|
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
|
||||||
|
int val = contents[offset] & (1<<type);
|
||||||
|
command.value = new Boolean( (val > 0) );
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
command.value = new Byte( contents[offset] );
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
command.value = new Double(
|
||||||
|
LittleEndian.getDouble(contents, offset)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
command.value = new Short(
|
||||||
|
LittleEndian.getShort(contents, offset)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
command.value = new Integer(
|
||||||
|
LittleEndian.getInt(contents, offset)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Types 11 and 21 hold the offset to the blocks
|
||||||
|
case 11: case 21:
|
||||||
|
if(offset < contents.length - 3) {
|
||||||
|
int bOffset = (int)LittleEndian.getUInt(contents, offset);
|
||||||
|
BlockOffsetCommand bcmd = (BlockOffsetCommand)command;
|
||||||
|
bcmd.setOffset(bOffset);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//System.err.println("Warning - Command of type " + type + " not processed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to the array
|
||||||
|
commands.add(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the commands we liked the look of
|
||||||
|
this.commands = (Command[])commands.toArray(
|
||||||
|
new Command[commands.size()] );
|
||||||
|
|
||||||
|
// Now build up the blocks, if we had a command that tells
|
||||||
|
// us where a block is
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A command in the visio file. In order to make things fun,
|
||||||
|
* all the chunk actually stores is the value of the command.
|
||||||
|
* You have to have your own lookup table to figure out what
|
||||||
|
* the commands are based on the chunk type.
|
||||||
|
*/
|
||||||
|
public static class Command {
|
||||||
|
protected Object value;
|
||||||
|
private CommandDefinition definition;
|
||||||
|
|
||||||
|
private Command(CommandDefinition definition, Object value) {
|
||||||
|
this.definition = definition;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
private Command(CommandDefinition definition) {
|
||||||
|
this(definition, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandDefinition getDefinition() { return definition; }
|
||||||
|
public Object getValue() { return value; }
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* A special kind of command that is an artificat of how we
|
||||||
|
* process CommandDefinitions, and so doesn't actually exist
|
||||||
|
* in the chunk
|
||||||
|
*/
|
||||||
|
// public static class VirtualCommand extends Command {
|
||||||
|
// private VirtualCommand(CommandDefinition definition) {
|
||||||
|
// super(definition);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
/**
|
||||||
|
* A special kind of command that holds the offset to
|
||||||
|
* a block
|
||||||
|
*/
|
||||||
|
public static class BlockOffsetCommand extends Command {
|
||||||
|
private int offset;
|
||||||
|
private BlockOffsetCommand(CommandDefinition definition) {
|
||||||
|
super(definition, null);
|
||||||
|
}
|
||||||
|
private void setOffset(int offset) {
|
||||||
|
this.offset = offset;
|
||||||
|
value = new Integer(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,8 +152,12 @@ public class ChunkFactory {
|
|||||||
// Feed in the stuff from chunks_parse_cmds.tbl
|
// Feed in the stuff from chunks_parse_cmds.tbl
|
||||||
CommandDefinition[] defs = (CommandDefinition[])
|
CommandDefinition[] defs = (CommandDefinition[])
|
||||||
chunkCommandDefinitions.get(new Integer(header.getType()));
|
chunkCommandDefinitions.get(new Integer(header.getType()));
|
||||||
|
if(defs == null) defs = new CommandDefinition[0];
|
||||||
chunk.commandDefinitions = defs;
|
chunk.commandDefinitions = defs;
|
||||||
|
|
||||||
|
// Now get the chunk to process its commands
|
||||||
|
chunk.processCommands();
|
||||||
|
|
||||||
// All done
|
// All done
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,10 @@ package org.apache.poi.hdgf.dev;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
import org.apache.poi.hdgf.HDGFDiagram;
|
import org.apache.poi.hdgf.HDGFDiagram;
|
||||||
|
import org.apache.poi.hdgf.chunks.Chunk;
|
||||||
|
import org.apache.poi.hdgf.chunks.Chunk.Command;
|
||||||
import org.apache.poi.hdgf.pointers.Pointer;
|
import org.apache.poi.hdgf.pointers.Pointer;
|
||||||
|
import org.apache.poi.hdgf.streams.ChunkStream;
|
||||||
import org.apache.poi.hdgf.streams.PointerContainingStream;
|
import org.apache.poi.hdgf.streams.PointerContainingStream;
|
||||||
import org.apache.poi.hdgf.streams.Stream;
|
import org.apache.poi.hdgf.streams.Stream;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
@ -54,6 +57,9 @@ public class VSDDumper {
|
|||||||
for(int i=0; i<indent; i++) {
|
for(int i=0; i<indent; i++) {
|
||||||
ind += " ";
|
ind += " ";
|
||||||
}
|
}
|
||||||
|
String ind2 = ind + " ";
|
||||||
|
String ind3 = ind2 + " ";
|
||||||
|
|
||||||
|
|
||||||
Pointer ptr = stream.getPointer();
|
Pointer ptr = stream.getPointer();
|
||||||
System.out.println(ind + "Stream at\t" + ptr.getOffset() +
|
System.out.println(ind + "Stream at\t" + ptr.getOffset() +
|
||||||
@ -86,5 +92,23 @@ public class VSDDumper {
|
|||||||
dumpStream(pcs.getPointedToStreams()[i], (indent+1));
|
dumpStream(pcs.getPointedToStreams()[i], (indent+1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(stream instanceof ChunkStream) {
|
||||||
|
ChunkStream cs = (ChunkStream)stream;
|
||||||
|
System.out.println(ind + " Has " + cs.getChunks().length +
|
||||||
|
" chunks:");
|
||||||
|
|
||||||
|
for(int i=0; i<cs.getChunks().length; i++) {
|
||||||
|
Chunk chunk = cs.getChunks()[i];
|
||||||
|
System.out.println(ind2 + "" + chunk.getName());
|
||||||
|
System.out.println(ind2 + " Holds " + chunk.getCommands().length + " commands");
|
||||||
|
for(int j=0; j<chunk.getCommands().length; j++) {
|
||||||
|
Command command = chunk.getCommands()[j];
|
||||||
|
System.out.println(ind3 + "" +
|
||||||
|
command.getDefinition().getName() +
|
||||||
|
" " + command.getValue()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public static final byte[] data_a = new byte[] { 70, 0, 0, 0,
|
|||||||
0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 1, 0, 84, 24, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
-125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 2, 0, 85, 5, 0, 0,
|
-125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 2, 0, 85, 5, 0, 0,
|
||||||
0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
};
|
};
|
||||||
public static final byte[] data_b = new byte[] { 70, 0, 0, 0,
|
public static final byte[] data_b = new byte[] { 70, 0, 0, 0,
|
||||||
-1, -1, -1, -1, 3, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0,
|
-1, -1, -1, -1, 3, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0,
|
||||||
@ -137,9 +137,10 @@ public static final byte[] data_b = new byte[] { 70, 0, 0, 0,
|
|||||||
assertEquals(70, chunk.getHeader().getType());
|
assertEquals(70, chunk.getHeader().getType());
|
||||||
assertEquals(0x46, chunk.getHeader().getType());
|
assertEquals(0x46, chunk.getHeader().getType());
|
||||||
|
|
||||||
// Should have two different chunk commands, a
|
// Should have two virtual chunk commands, a
|
||||||
// 10 (page sheet) and an 18
|
// 10 (page sheet) and an 18
|
||||||
assertEquals(2, chunk.commandDefinitions.length);
|
assertEquals(2, chunk.commandDefinitions.length);
|
||||||
|
assertEquals(0, chunk.getCommands().length);
|
||||||
|
|
||||||
assertEquals(10, chunk.commandDefinitions[0].getType());
|
assertEquals(10, chunk.commandDefinitions[0].getType());
|
||||||
assertEquals(0, chunk.commandDefinitions[0].getOffset());
|
assertEquals(0, chunk.commandDefinitions[0].getOffset());
|
||||||
@ -171,9 +172,10 @@ public static final byte[] data_b = new byte[] { 70, 0, 0, 0,
|
|||||||
assertEquals(104, chunk.getHeader().getType());
|
assertEquals(104, chunk.getHeader().getType());
|
||||||
assertEquals(0x68, chunk.getHeader().getType());
|
assertEquals(0x68, chunk.getHeader().getType());
|
||||||
|
|
||||||
// Should have two different chunk commands, a
|
// Should have two virtual chunk commands, a
|
||||||
// 10 (Unknown) and an 18
|
// 10 (Unknown) and an 18
|
||||||
assertEquals(2, chunk.commandDefinitions.length);
|
assertEquals(2, chunk.commandDefinitions.length);
|
||||||
|
assertEquals(0, chunk.getCommands().length);
|
||||||
|
|
||||||
assertEquals(10, chunk.commandDefinitions[0].getType());
|
assertEquals(10, chunk.commandDefinitions[0].getType());
|
||||||
assertEquals(0, chunk.commandDefinitions[0].getOffset());
|
assertEquals(0, chunk.commandDefinitions[0].getOffset());
|
||||||
|
Loading…
Reference in New Issue
Block a user