mirror of https://github.com/apache/poi.git
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
aa1b5c9dd4
commit
84726d7ca1
|
@ -16,7 +16,10 @@
|
|||
==================================================================== */
|
||||
package org.apache.poi.hdgf.chunks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.poi.hdgf.chunks.ChunkFactory.CommandDefinition;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* Base of all chunks, which hold data, flags etc
|
||||
|
@ -34,6 +37,12 @@ public class Chunk {
|
|||
private ChunkSeparator separator;
|
||||
/** The possible different commands we can hold */
|
||||
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) {
|
||||
this.header = header;
|
||||
|
@ -63,6 +72,15 @@ public class Chunk {
|
|||
public CommandDefinition[] getCommandDefinitions() {
|
||||
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
|
||||
|
@ -78,4 +96,156 @@ public class Chunk {
|
|||
}
|
||||
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
|
||||
CommandDefinition[] defs = (CommandDefinition[])
|
||||
chunkCommandDefinitions.get(new Integer(header.getType()));
|
||||
if(defs == null) defs = new CommandDefinition[0];
|
||||
chunk.commandDefinitions = defs;
|
||||
|
||||
// Now get the chunk to process its commands
|
||||
chunk.processCommands();
|
||||
|
||||
// All done
|
||||
return chunk;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ package org.apache.poi.hdgf.dev;
|
|||
import java.io.FileInputStream;
|
||||
|
||||
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.streams.ChunkStream;
|
||||
import org.apache.poi.hdgf.streams.PointerContainingStream;
|
||||
import org.apache.poi.hdgf.streams.Stream;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
|
@ -54,6 +57,9 @@ public class VSDDumper {
|
|||
for(int i=0; i<indent; i++) {
|
||||
ind += " ";
|
||||
}
|
||||
String ind2 = ind + " ";
|
||||
String ind3 = ind2 + " ";
|
||||
|
||||
|
||||
Pointer ptr = stream.getPointer();
|
||||
System.out.println(ind + "Stream at\t" + ptr.getOffset() +
|
||||
|
@ -86,5 +92,23 @@ public class VSDDumper {
|
|||
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, 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,
|
||||
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,
|
||||
-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(0x46, chunk.getHeader().getType());
|
||||
|
||||
// Should have two different chunk commands, a
|
||||
// Should have two virtual chunk commands, a
|
||||
// 10 (page sheet) and an 18
|
||||
assertEquals(2, chunk.commandDefinitions.length);
|
||||
assertEquals(0, chunk.getCommands().length);
|
||||
|
||||
assertEquals(10, chunk.commandDefinitions[0].getType());
|
||||
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(0x68, chunk.getHeader().getType());
|
||||
|
||||
// Should have two different chunk commands, a
|
||||
// Should have two virtual chunk commands, a
|
||||
// 10 (Unknown) and an 18
|
||||
assertEquals(2, chunk.commandDefinitions.length);
|
||||
assertEquals(0, chunk.getCommands().length);
|
||||
|
||||
assertEquals(10, chunk.commandDefinitions[0].getType());
|
||||
assertEquals(0, chunk.commandDefinitions[0].getOffset());
|
||||
|
|
Loading…
Reference in New Issue