git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1333050 13f79535-47bb-0310-9956-ffa450edef68tags/3.10-beta1
@@ -34,6 +34,7 @@ | |||
<changes> | |||
<release version="3.9-beta1" date="2012-??-??"> | |||
<action dev="poi-developers" type="add">53058 - Utility for representing drawings contained in a binary Excel file as a XML tree</action> | |||
<action dev="poi-developers" type="add">53165 - HWPF support for fetching the description (alt text) of a picture</action> | |||
<action dev="poi-developers" type="fix">48528 - support negative arguments to the DATE() function</action> | |||
<action dev="poi-developers" type="fix">53092 - allow specifying of a TimeZone to DateUtil.getJavaDate(), for when it is known that a file comes from a different (known) timezone to the current machine</action> |
@@ -173,7 +173,19 @@ public abstract class AbstractEscherOptRecord extends EscherRecord | |||
stringBuilder.append( " " + property.toString() + nl ); | |||
} | |||
return stringBuilder.toString(); | |||
} | |||
} | |||
return stringBuilder.toString(); | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<Numchildren>").append(getChildRecords().size()).append("</Numchildren>\n") | |||
.append(tab).append("\t").append("<IsContainer>").append(isContainerRecord()).append("</IsContainer>\n"); | |||
for (EscherProperty property: getEscherProperties()){ | |||
builder.append(property.toXml(tab+"\t")); | |||
} | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -135,6 +135,18 @@ public final class EscherArrayProperty extends EscherComplexProperty { | |||
+ ", data: " + '\n' + results.toString(); | |||
} | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"0x").append(HexDump.toHex(getId())) | |||
.append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\">\n"); | |||
for (int i = 0; i < getNumberOfElementsInArray(); i++) { | |||
builder.append("\t").append(tab).append("<Element>").append(HexDump.toHex(getElement(i))).append("</Element>\n"); | |||
} | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* We have this method because the way in which arrays in escher works | |||
* is screwed for seemly arbitary reasons. While most properties are |
@@ -330,6 +330,25 @@ public final class EscherBSERecord extends EscherRecord { | |||
" Extra Data:" + '\n' + extraData; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<BlipTypeWin32>").append(field_1_blipTypeWin32).append("</BlipTypeWin32>\n") | |||
.append(tab).append("\t").append("<BlipTypeMacOS>").append(field_2_blipTypeMacOS).append("</BlipTypeMacOS>\n") | |||
.append(tab).append("\t").append("<SUID>").append(field_3_uid == null ? "" : HexDump.toHex(field_3_uid)).append("</SUID>\n") | |||
.append(tab).append("\t").append("<Tag>").append(field_4_tag).append("</Tag>\n") | |||
.append(tab).append("\t").append("<Size>").append(field_5_size).append("</Size>\n") | |||
.append(tab).append("\t").append("<Ref>").append(field_6_ref).append("</Ref>\n") | |||
.append(tab).append("\t").append("<Offset>").append(field_7_offset).append("</Offset>\n") | |||
.append(tab).append("\t").append("<Usage>").append(field_8_usage).append("</Usage>\n") | |||
.append(tab).append("\t").append("<Name>").append(field_9_name).append("</Name>\n") | |||
.append(tab).append("\t").append("<Unused2>").append(field_10_unused2).append("</Unused2>\n") | |||
.append(tab).append("\t").append("<Unused3>").append(field_11_unused3).append("</Unused3>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Retrieve the string representation given a blip id. | |||
*/ |
@@ -114,4 +114,26 @@ public class EscherBitmapBlip extends EscherBlipRecord { | |||
" Marker: 0x" + HexDump.toHex( field_2_marker ) + nl + | |||
" Extra Data:" + nl + extraData; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData; | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
try | |||
{ | |||
HexDump.dump( this.field_pictureData, 0, b, 0 ); | |||
extraData = b.toString(); | |||
} | |||
catch ( Exception e ) | |||
{ | |||
extraData = e.toString(); | |||
} | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<UID>0x").append(HexDump.toHex(field_1_UID)).append("</UID>\n") | |||
.append(tab).append("\t").append("<Marker>0x").append(HexDump.toHex(field_2_marker)).append("</Marker>\n") | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -81,4 +81,14 @@ public class EscherBlipRecord extends EscherRecord { // TODO - instantiable supe | |||
" Instance: 0x" + HexDump.toHex( getInstance() ) + '\n' + | |||
" Extra Data:" + '\n' + extraData; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData = HexDump.toHex(field_pictureData, 32); | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -350,6 +350,37 @@ public class EscherBlipWMFRecord | |||
" Data:" + nl + extraData; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData; | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
try | |||
{ | |||
HexDump.dump( this.field_12_data, 0, b, 0 ); | |||
extraData = b.toString(); | |||
} | |||
catch ( Exception e ) | |||
{ | |||
extraData = e.toString(); | |||
} | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<SecondaryUID>0x").append(HexDump.toHex(field_1_secondaryUID)).append("</SecondaryUID>\n") | |||
.append(tab).append("\t").append("<CacheOfSize>").append(field_2_cacheOfSize).append("</CacheOfSize>\n") | |||
.append(tab).append("\t").append("<BoundaryTop>").append(field_3_boundaryTop).append("</BoundaryTop>\n") | |||
.append(tab).append("\t").append("<BoundaryLeft>").append(field_4_boundaryLeft).append("</BoundaryLeft>\n") | |||
.append(tab).append("\t").append("<BoundaryWidth>").append(field_5_boundaryWidth).append("</BoundaryWidth>\n") | |||
.append(tab).append("\t").append("<BoundaryHeight>").append(field_6_boundaryHeight).append("</BoundaryHeight>\n") | |||
.append(tab).append("\t").append("<X>").append(field_7_width).append("</X>\n") | |||
.append(tab).append("\t").append("<Y>").append(field_8_height).append("</Y>\n") | |||
.append(tab).append("\t").append("<CacheOfSavedSize>").append(field_9_cacheOfSavedSize).append("</CacheOfSavedSize>\n") | |||
.append(tab).append("\t").append("<CompressionFlag>").append(field_10_compressionFlag).append("</CompressionFlag>\n") | |||
.append(tab).append("\t").append("<Filter>").append(field_11_filter).append("</Filter>\n") | |||
.append(tab).append("\t").append("<Data>").append(extraData).append("</Data>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Compress the contents of the provided array | |||
* |
@@ -18,6 +18,8 @@ | |||
package org.apache.poi.ddf; | |||
import org.apache.poi.util.HexDump; | |||
/** | |||
* Represents a boolean property. The actual utility of this property is in doubt because many | |||
* of the properties marked as boolean seem to actually contain special values. In other words | |||
@@ -65,4 +67,11 @@ public class EscherBoolProperty | |||
// + ", value: " + (getValue() != 0); | |||
// } | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"0x").append(HexDump.toHex(getId())) | |||
.append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\" value=\"").append(isTrue()).append("\"").append("/>\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -97,6 +97,18 @@ public class EscherChildAnchorRecord | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<X1>").append(field_1_dx1).append("</X1>\n") | |||
.append(tab).append("\t").append("<Y1>").append(field_2_dy1).append("</Y1>\n") | |||
.append(tab).append("\t").append("<X2>").append(field_3_dx2).append("</X2>\n") | |||
.append(tab).append("\t").append("<Y2>").append(field_4_dy2).append("</Y2>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Retrieves offset within the parent coordinate space for the top left point. | |||
*/ |
@@ -160,6 +160,38 @@ public class EscherClientAnchorRecord | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData; | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
try | |||
{ | |||
HexDump.dump(this.remainingData, 0, b, 0); | |||
extraData = b.toString(); | |||
} | |||
catch ( Exception e ) | |||
{ | |||
extraData = "error\n"; | |||
} | |||
if (extraData.contains("No Data")){ | |||
extraData = "No Data"; | |||
} | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<Flag>").append(field_1_flag).append("</Flag>\n") | |||
.append(tab).append("\t").append("<Col1>").append(field_2_col1).append("</Col1>\n") | |||
.append(tab).append("\t").append("<DX1>").append(field_3_dx1).append("</DX1>\n") | |||
.append(tab).append("\t").append("<Row1>").append(field_4_row1).append("</Row1>\n") | |||
.append(tab).append("\t").append("<DY1>").append(field_5_dy1).append("</DY1>\n") | |||
.append(tab).append("\t").append("<Col2>").append(field_6_col2).append("</Col2>\n") | |||
.append(tab).append("\t").append("<DX2>").append(field_7_dx2).append("</DX2>\n") | |||
.append(tab).append("\t").append("<Row2>").append(field_8_row2).append("</Row2>\n") | |||
.append(tab).append("\t").append("<DY2>").append(field_9_dy2).append("</DY2>\n") | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells. | |||
*/ |
@@ -99,6 +99,30 @@ public class EscherClientDataRecord | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData; | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
try | |||
{ | |||
HexDump.dump(this.remainingData, 0, b, 0); | |||
extraData = b.toString(); | |||
} | |||
catch ( Exception e ) | |||
{ | |||
extraData = "error"; | |||
} | |||
if (extraData.contains("No Data")){ | |||
extraData = "No Data"; | |||
} | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), | |||
HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Any data recording this record. | |||
*/ |
@@ -134,4 +134,14 @@ public class EscherComplexProperty extends EscherProperty { | |||
+ ", data: " + System.getProperty("line.separator") + dataStr; | |||
} | |||
public String toXml(String tab){ | |||
String dataStr = HexDump.toHex( _complexData, 32); | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"0x").append(HexDump.toHex(getId())) | |||
.append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\">\n"); | |||
builder.append("\t").append(tab).append(dataStr); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -255,6 +255,23 @@ public final class EscherContainerRecord extends EscherRecord { | |||
+ children.toString(); | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<RecordName>").append(getRecordName()).append("</RecordName>\n") | |||
.append(tab).append("\t").append("<IsContainer>").append(isContainerRecord()).append("</IsContainer>\n") | |||
.append(tab).append("\t").append("<Numchildren>").append(HexDump.toHex(_childRecords.size())).append("</Numchildren>\n"); | |||
for ( Iterator<EscherRecord> iterator = _childRecords.iterator(); iterator | |||
.hasNext(); ) | |||
{ | |||
EscherRecord record = iterator.next(); | |||
builder.append(record.toXml(tab+"\t")); | |||
} | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
public <T extends EscherRecord> T getChildById( short recordId ) | |||
{ | |||
for ( EscherRecord childRecord : _childRecords ) |
@@ -92,7 +92,16 @@ public class EscherDgRecord | |||
" Instance: 0x" + HexDump.toHex(getInstance()) + '\n' + | |||
" NumShapes: " + field_1_numShapes + '\n' + | |||
" LastMSOSPID: " + field_2_lastMSOSPID + '\n'; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<NumShapes>").append(field_1_numShapes).append("</NumShapes>\n") | |||
.append(tab).append("\t").append("<LastMSOSPID>").append(field_2_lastMSOSPID).append("</LastMSOSPID>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** |
@@ -142,6 +142,18 @@ public final class EscherDggRecord extends EscherRecord { | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<ShapeIdMax>").append(field_1_shapeIdMax).append("</ShapeIdMax>\n") | |||
.append(tab).append("\t").append("<NumIdClusters>").append(getNumIdClusters()).append("</NumIdClusters>\n") | |||
.append(tab).append("\t").append("<NumShapesSaved>").append(field_3_numShapesSaved).append("</NumShapesSaved>\n") | |||
.append(tab).append("\t").append("<DrawingsSaved>").append(field_4_drawingsSaved).append("</DrawingsSaved>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
public int getShapeIdMax() { | |||
return field_1_shapeIdMax; | |||
} |
@@ -259,12 +259,31 @@ public final class EscherMetafileBlip extends EscherBlipRecord { | |||
" Filter: " + HexDump.toHex( field_7_fFilter ) + '\n' + | |||
" Extra Data:" + '\n' + extraData + | |||
(remainingData == null ? null : ("\n" + | |||
" Remaining Data: " + HexDump.toHex(remainingData, 32))); | |||
} | |||
/** | |||
* Return the blip signature | |||
* | |||
" Remaining Data: " + HexDump.toHex(remainingData, 32))); | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData = ""; | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<UID>0x").append(HexDump.toHex( field_1_UID ) + '\n' + | |||
(field_2_UID == null ? "" : (" UID2: 0x" + HexDump.toHex( field_2_UID ) + '\n'))).append("</UID>\n") | |||
.append(tab).append("\t").append("<UncompressedSize>0x").append(HexDump.toHex( field_2_cb )).append("</UncompressedSize>\n") | |||
.append(tab).append("\t").append("<Bounds>").append(getBounds()).append("</Bounds>\n") | |||
.append(tab).append("\t").append("<SizeInEMU>").append(getSizeEMU()).append("</SizeInEMU>\n") | |||
.append(tab).append("\t").append("<CompressedSize>0x").append(HexDump.toHex( field_5_cbSave )).append("</CompressedSize>\n") | |||
.append(tab).append("\t").append("<Compression>0x").append(HexDump.toHex( field_6_fCompression )).append("</Compression>\n") | |||
.append(tab).append("\t").append("<Filter>0x").append(HexDump.toHex( field_7_fFilter )).append("</Filter>\n") | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n") | |||
.append(tab).append("\t").append("<RemainingData>0x").append(HexDump.toHex(remainingData, 32)).append("</RemainingData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Return the blip signature | |||
* | |||
* @return the blip signature | |||
*/ | |||
public short getSignature() { |
@@ -16,6 +16,7 @@ | |||
==================================================================== */ | |||
package org.apache.poi.ddf; | |||
import org.apache.poi.util.HexDump; | |||
import org.apache.poi.util.Internal; | |||
/** | |||
@@ -71,4 +72,15 @@ public class EscherOptRecord extends AbstractEscherOptRecord | |||
super.setVersion( value ); | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))); | |||
for (EscherProperty property: getEscherProperties()){ | |||
builder.append(property.toXml(tab+"\t")); | |||
} | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -210,7 +210,24 @@ public final class EscherPictBlip extends EscherBlipRecord { | |||
" Size in EMU: " + getSizeEMU() + '\n' + | |||
" Compressed Size: " + HexDump.toHex( field_5_cbSave ) + '\n' + | |||
" Compression: " + HexDump.toHex( field_6_fCompression ) + '\n' + | |||
" Filter: " + HexDump.toHex( field_7_fFilter ) + '\n' + | |||
" Extra Data:" + '\n' + extraData; | |||
} | |||
} | |||
" Filter: " + HexDump.toHex( field_7_fFilter ) + '\n' + | |||
" Extra Data:" + '\n' + extraData; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String extraData = ""; | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<UID>0x").append(HexDump.toHex( field_1_UID )).append("</UID>\n") | |||
.append(tab).append("\t").append("<UncompressedSize>0x").append(HexDump.toHex( field_2_cb )).append("</UncompressedSize>\n") | |||
.append(tab).append("\t").append("<Bounds>").append(getBounds()).append("</Bounds>\n") | |||
.append(tab).append("\t").append("<SizeInEMU>").append(getSizeEMU()).append("</SizeInEMU>\n") | |||
.append(tab).append("\t").append("<CompressedSize>0x").append(HexDump.toHex( field_5_cbSave )).append("</CompressedSize>\n") | |||
.append(tab).append("\t").append("<Compression>0x").append(HexDump.toHex( field_6_fCompression )).append("</Compression>\n") | |||
.append(tab).append("\t").append("<Filter>0x").append(HexDump.toHex( field_7_fFilter )).append("</Filter>\n") | |||
.append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -72,6 +72,13 @@ public abstract class EscherProperty { | |||
public int getPropertySize() { | |||
return 6; | |||
} | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"").append(getId()).append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\"/>\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Escher properties consist of a simple fixed length part and a complex variable length part. |
@@ -17,6 +17,8 @@ | |||
package org.apache.poi.ddf; | |||
import org.apache.poi.util.HexDump; | |||
/** | |||
* A color property. | |||
* | |||
@@ -51,4 +53,11 @@ public class EscherRGBProperty | |||
return (byte) ( (propertyValue >> 16) & 0xFF ); | |||
} | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"0x").append(HexDump.toHex(getId())) | |||
.append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\" value=\"0x").append(HexDump.toHex(propertyValue)).append("\"/>\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -22,10 +22,7 @@ import java.io.PrintWriter; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.apache.poi.util.BitField; | |||
import org.apache.poi.util.BitFieldFactory; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.util.LittleEndian; | |||
import org.apache.poi.util.*; | |||
/** | |||
* The base abstract record from which all escher records are defined. Subclasses will need | |||
@@ -297,4 +294,28 @@ public abstract class EscherRecord { | |||
{ | |||
_options = fVersion.setShortValue( _options, value ); | |||
} | |||
/** | |||
* @param tab - each children must be a right of his parent | |||
* @return | |||
*/ | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(">\n") | |||
.append(tab).append("\t").append("<RecordId>0x").append(HexDump.toHex(_recordId)).append("</RecordId>\n") | |||
.append(tab).append("\t").append("<Options>").append(_options).append("</Options>\n") | |||
.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
protected String formatXmlRecordHeader(String className, String recordId, String version, String instance){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append("<").append(className).append(" recordId=\"0x").append(recordId).append("\" version=\"0x") | |||
.append(version).append("\" instance=\"0x").append(instance).append("\">\n"); | |||
return builder.toString(); | |||
} | |||
public String toXml(){ | |||
return toXml(""); | |||
} | |||
} |
@@ -118,4 +118,12 @@ public class EscherSimpleProperty extends EscherProperty | |||
+ ", value: " + propertyValue + " (0x" + HexDump.toHex(propertyValue) + ")"; | |||
} | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getClass().getSimpleName()).append(" id=\"0x").append(HexDump.toHex(getId())) | |||
.append("\" name=\"").append(getName()).append("\" blipId=\"") | |||
.append(isBlipId()).append("\" complex=\"").append(isComplex()).append("\" value=\"").append("0x") | |||
.append(HexDump.toHex(propertyValue)).append("\"/>\n"); | |||
return builder.toString(); | |||
} | |||
} |
@@ -115,6 +115,17 @@ public class EscherSpRecord | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<ShapeType>").append(HexDump.toHex(getShapeType())).append("</ShapeType>\n") | |||
.append(tab).append("\t").append("<ShapeId>").append(field_1_shapeId).append("</ShapeId>\n") | |||
.append(tab).append("\t").append("<Flags>").append(decodeFlags(field_2_flags) + " (0x" + HexDump.toHex(field_2_flags) + ")").append("</Flags>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Converts the shape flags into a more descriptive name. | |||
*/ |
@@ -97,6 +97,18 @@ public class EscherSpgrRecord | |||
" RectHeight: " + field_4_rectY2 + '\n'; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<RectX>").append(field_1_rectX1).append("</RectX>\n") | |||
.append(tab).append("\t").append("<RectY>").append(field_2_rectY1).append("</RectY>\n") | |||
.append(tab).append("\t").append("<RectWidth>").append(field_3_rectX2).append("</RectWidth>\n") | |||
.append(tab).append("\t").append("<RectHeight>").append(field_4_rectY2).append("</RectHeight>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* The starting top-left coordinate of child records. | |||
*/ |
@@ -99,6 +99,18 @@ public class EscherSplitMenuColorsRecord | |||
""; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<Color1>0x").append(HexDump.toHex(field_1_color1)).append("</Color1>\n") | |||
.append(tab).append("\t").append("<Color2>0x").append(HexDump.toHex(field_2_color2)).append("</Color2>\n") | |||
.append(tab).append("\t").append("<Color3>0x").append(HexDump.toHex(field_3_color3)).append("</Color3>\n") | |||
.append(tab).append("\t").append("<Color4>0x").append(HexDump.toHex(field_4_color4)).append("</Color4>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
public int getColor1() | |||
{ | |||
return field_1_color1; |
@@ -139,6 +139,28 @@ public class EscherTextboxRecord extends EscherRecord | |||
theDumpHex; | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String theDumpHex = ""; | |||
try | |||
{ | |||
if (thedata.length != 0) | |||
{ | |||
theDumpHex += HexDump.dump(thedata, 0, 0); | |||
} | |||
} | |||
catch ( Exception e ) | |||
{ | |||
theDumpHex = "Error!!"; | |||
} | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<IsContainer>").append(isContainerRecord()).append("</IsContainer>\n") | |||
.append(tab).append("\t").append("<Numchildren>").append(getChildRecords().size()).append("</Numchildren>\n") | |||
.append(tab).append("\t").append("<ExtraData>").append(theDumpHex).append("</ExtraData>\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
} | |||
@@ -18,6 +18,7 @@ | |||
package org.apache.poi.ddf; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import org.apache.poi.util.HexDump; | |||
@@ -143,6 +144,24 @@ public final class UnknownEscherRecord extends EscherRecord { | |||
children.toString(); | |||
} | |||
@Override | |||
public String toXml(String tab) { | |||
String theDumpHex = HexDump.toHex(thedata, 32); | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance()))) | |||
.append(tab).append("\t").append("<IsContainer>").append(isContainerRecord()).append("</IsContainer>\n") | |||
.append(tab).append("\t").append("<Numchildren>").append(HexDump.toHex(_childRecords.size())).append("</Numchildren>\n"); | |||
for ( Iterator<EscherRecord> iterator = _childRecords.iterator(); iterator | |||
.hasNext(); ) | |||
{ | |||
EscherRecord record = iterator.next(); | |||
builder.append(record.toXml(tab+"\t")); | |||
} | |||
builder.append(theDumpHex).append("\n"); | |||
builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
public void addChildRecord(EscherRecord childRecord) { | |||
getChildRecords().add( childRecord ); | |||
} |
@@ -0,0 +1,192 @@ | |||
/* | |||
* ==================================================================== | |||
* 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.hssf.dev; | |||
import org.apache.poi.ddf.EscherRecord; | |||
import org.apache.poi.hssf.model.InternalWorkbook; | |||
import org.apache.poi.hssf.record.*; | |||
import org.apache.poi.hssf.usermodel.HSSFPatriarch; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | |||
import java.io.*; | |||
import java.lang.reflect.Field; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Utility for representing drawings contained in a binary Excel file as a XML tree | |||
* | |||
* @author Evgeniy Berlog | |||
* date: 10.04.12 | |||
*/ | |||
public class BiffDrawingToXml { | |||
private static final String SHEET_NAME_PARAM = "-sheet-name"; | |||
private static final String SHEET_INDEXES_PARAM = "-sheet-indexes"; | |||
private static final String EXCLUDE_WORKBOOK_RECORDS = "-exclude-workbook"; | |||
private static int getAttributeIndex(String attribute, String[] params) { | |||
for (int i = 0; i < params.length; i++) { | |||
String param = params[i]; | |||
if (attribute.equals(param)) { | |||
return i; | |||
} | |||
} | |||
return -1; | |||
} | |||
private static boolean isExcludeWorkbookRecords(String[] params) { | |||
return -1 != getAttributeIndex(EXCLUDE_WORKBOOK_RECORDS, params); | |||
} | |||
private static List<Integer> getIndexesByName(String[] params, HSSFWorkbook workbook) { | |||
List<Integer> list = new ArrayList<Integer>(); | |||
int pos = getAttributeIndex(SHEET_NAME_PARAM, params); | |||
if (-1 != pos) { | |||
if (pos >= params.length) { | |||
throw new IllegalArgumentException("sheet name param value was not specified"); | |||
} | |||
String sheetName = params[pos + 1]; | |||
int sheetPos = workbook.getSheetIndex(sheetName); | |||
if (-1 == sheetPos){ | |||
throw new IllegalArgumentException("specified sheet name has not been found in xls file"); | |||
} | |||
list.add(sheetPos); | |||
} | |||
return list; | |||
} | |||
private static List<Integer> getIndexesByIdArray(String[] params) { | |||
List<Integer> list = new ArrayList<Integer>(); | |||
int pos = getAttributeIndex(SHEET_INDEXES_PARAM, params); | |||
if (-1 != pos) { | |||
if (pos >= params.length) { | |||
throw new IllegalArgumentException("sheet list value was not specified"); | |||
} | |||
String sheetParam = params[pos + 1]; | |||
String[] sheets = sheetParam.split(","); | |||
for (String sheet : sheets) { | |||
list.add(Integer.parseInt(sheet)); | |||
} | |||
} | |||
return list; | |||
} | |||
private static List<Integer> getSheetsIndexes(String[] params, HSSFWorkbook workbook) { | |||
List<Integer> list = new ArrayList<Integer>(); | |||
list.addAll(getIndexesByIdArray(params)); | |||
list.addAll(getIndexesByName(params, workbook)); | |||
if (0 == list.size()) { | |||
int size = workbook.getNumberOfSheets(); | |||
for (int i = 0; i < size; i++) { | |||
list.add(i); | |||
} | |||
} | |||
return list; | |||
} | |||
private static String getInputFileName(String[] params) { | |||
return params[params.length - 1]; | |||
} | |||
private static String getOutputFileName(String input) { | |||
if (input.contains("xls")) { | |||
return input.replace(".xls", ".xml"); | |||
} | |||
return input + ".xml"; | |||
} | |||
public static void main(String[] params) throws IOException { | |||
if (0 == params.length) { | |||
System.out.println("Usage: BiffDrawingToXml [options] inputWorkbook"); | |||
System.out.println("Options:"); | |||
System.out.println(" -exclude-workbook exclude workbook-level records"); | |||
System.out.println(" -sheet-indexes <indexes> output sheets with specified indexes"); | |||
System.out.println(" -sheet-namek <names> output sheets with specified name"); | |||
return; | |||
} | |||
String input = getInputFileName(params); | |||
FileInputStream inp = new FileInputStream(input); | |||
String output = getOutputFileName(input); | |||
FileOutputStream outputStream = new FileOutputStream(output); | |||
writeToFile(outputStream, inp, isExcludeWorkbookRecords(params), params); | |||
inp.close(); | |||
outputStream.close(); | |||
} | |||
public static void writeToFile(FileOutputStream fos, InputStream xlsWorkbook, boolean excludeWorkbookRecords, String[] params) throws IOException { | |||
POIFSFileSystem fs = new POIFSFileSystem(xlsWorkbook); | |||
HSSFWorkbook workbook = new HSSFWorkbook(fs); | |||
InternalWorkbook internalWorkbook = getInternalWorkbook(workbook); | |||
DrawingGroupRecord r = (DrawingGroupRecord) internalWorkbook.findFirstRecordBySid(DrawingGroupRecord.sid); | |||
r.decode(); | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append("<workbook>\n"); | |||
String tab = "\t"; | |||
if (!excludeWorkbookRecords) { | |||
List<EscherRecord> escherRecords = r.getEscherRecords(); | |||
for (EscherRecord record : escherRecords) { | |||
builder.append(record.toXml(tab)); | |||
} | |||
} | |||
List<Integer> sheets = getSheetsIndexes(params, workbook); | |||
for (Integer i : sheets) { | |||
HSSFPatriarch p = workbook.getSheetAt(i).getDrawingPatriarch(); | |||
if(p != null ) { | |||
builder.append(tab).append("<sheet").append(i).append(">\n"); | |||
builder.append(getHSSFPatriarchBoundAggregate(p).toXml(tab + "\t")); | |||
builder.append(tab).append("</sheet").append(i).append(">\n"); | |||
} | |||
} | |||
builder.append("</workbook>\n"); | |||
fos.write(builder.toString().getBytes()); | |||
fos.close(); | |||
} | |||
private static EscherAggregate getHSSFPatriarchBoundAggregate(HSSFPatriarch patriarch) { | |||
Field boundAggregateField = null; | |||
try { | |||
boundAggregateField = patriarch.getClass().getDeclaredField("_boundAggregate"); | |||
boundAggregateField.setAccessible(true); | |||
return (EscherAggregate) boundAggregateField.get(patriarch); | |||
} catch (NoSuchFieldException e) { | |||
e.printStackTrace(); | |||
} catch (IllegalAccessException e) { | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
private static InternalWorkbook getInternalWorkbook(HSSFWorkbook workbook) { | |||
Field internalSheetField = null; | |||
try { | |||
internalSheetField = workbook.getClass().getDeclaredField("workbook"); | |||
internalSheetField.setAccessible(true); | |||
return (InternalWorkbook) internalSheetField.get(workbook); | |||
} catch (NoSuchFieldException e) { | |||
e.printStackTrace(); | |||
} catch (IllegalAccessException e) { | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
} |
@@ -329,6 +329,18 @@ public final class EscherAggregate extends AbstractEscherHolderRecord { | |||
return result.toString(); | |||
} | |||
public String toXml(String tab){ | |||
StringBuilder builder = new StringBuilder(); | |||
builder.append(tab).append("<").append(getRecordName()).append(">\n"); | |||
for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) | |||
{ | |||
EscherRecord escherRecord = (EscherRecord) iterator.next(); | |||
builder.append( escherRecord.toXml(tab+"\t") ); | |||
} | |||
builder.append(tab).append("</").append(getRecordName()).append(">\n"); | |||
return builder.toString(); | |||
} | |||
/** | |||
* Collapses the drawing records into an aggregate. |