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:
Nick Burch 2007-06-21 21:24:25 +00:00
parent 2a0276c665
commit d04f8956c5
4 changed files with 203 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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