]> source.dussan.org Git - poi.git/commitdiff
Bugzilla 53058 - Utility for representing drawings contained in a binary Excel file...
authorYegor Kozlov <yegor@apache.org>
Wed, 2 May 2012 14:00:46 +0000 (14:00 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 2 May 2012 14:00:46 +0000 (14:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1333050 13f79535-47bb-0310-9956-ffa450edef68

29 files changed:
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/ddf/AbstractEscherOptRecord.java
src/java/org/apache/poi/ddf/EscherArrayProperty.java
src/java/org/apache/poi/ddf/EscherBSERecord.java
src/java/org/apache/poi/ddf/EscherBitmapBlip.java
src/java/org/apache/poi/ddf/EscherBlipRecord.java
src/java/org/apache/poi/ddf/EscherBlipWMFRecord.java
src/java/org/apache/poi/ddf/EscherBoolProperty.java
src/java/org/apache/poi/ddf/EscherChildAnchorRecord.java
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
src/java/org/apache/poi/ddf/EscherClientDataRecord.java
src/java/org/apache/poi/ddf/EscherComplexProperty.java
src/java/org/apache/poi/ddf/EscherContainerRecord.java
src/java/org/apache/poi/ddf/EscherDgRecord.java
src/java/org/apache/poi/ddf/EscherDggRecord.java
src/java/org/apache/poi/ddf/EscherMetafileBlip.java
src/java/org/apache/poi/ddf/EscherOptRecord.java
src/java/org/apache/poi/ddf/EscherPictBlip.java
src/java/org/apache/poi/ddf/EscherProperty.java
src/java/org/apache/poi/ddf/EscherRGBProperty.java
src/java/org/apache/poi/ddf/EscherRecord.java
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
src/java/org/apache/poi/ddf/EscherSpRecord.java
src/java/org/apache/poi/ddf/EscherSpgrRecord.java
src/java/org/apache/poi/ddf/EscherSplitMenuColorsRecord.java
src/java/org/apache/poi/ddf/EscherTextboxRecord.java
src/java/org/apache/poi/ddf/UnknownEscherRecord.java
src/java/org/apache/poi/hssf/dev/BiffDrawingToXml.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/EscherAggregate.java

index 7b085461f697127eeabc59c72ec85bff08e200e3..1eae1dcdcef292e1ec1f28e75062d3cce01596d1 100644 (file)
@@ -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>
index 5ff11dea0c67e25dcceb2afcf3182d27a79bccb3..9606fd7603f1e1f12970a1aa7267f420c7611733 100644 (file)
@@ -173,7 +173,19 @@ public abstract class AbstractEscherOptRecord extends EscherRecord
             stringBuilder.append( "    " + property.toString() + nl );
         }
 
-        return stringBuilder.toString();
-    }
-
-}
+        return stringBuilder.toString();\r
+    }\r
+\r
+    @Override\r
+    public String toXml(String tab) {\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance())))\r
+                .append(tab).append("\t").append("<Numchildren>").append(getChildRecords().size()).append("</Numchildren>\n")\r
+                .append(tab).append("\t").append("<IsContainer>").append(isContainerRecord()).append("</IsContainer>\n");\r
+        for (EscherProperty property: getEscherProperties()){\r
+            builder.append(property.toXml(tab+"\t"));\r
+        }\r
+        builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n");\r
+        return builder.toString();\r
+    }\r
+}\r
index e3ad88a071116ed5f5b048780b1304847b789eaa..6faec52321170b8a56683289b1338cde443915bb 100644 (file)
@@ -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
index 78420683a2d7690573adf5a504db3dffabd874f7..556dcdd7e2eda19567ec70c38b1d66a6a5529380 100644 (file)
@@ -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.
      */
index bec7635ebff674cca3c61284ae6f4363daf74b1f..d81eebdcc9c3ed598a691a78f43d650e5dce28fd 100644 (file)
@@ -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();
+    }
 }
index f10781f602e57be0dafa5ba0c8a11da066cd024a..b6bb8a46b09e7d8bfacc325953230f1d0a9444b6 100644 (file)
@@ -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();
+    }
 }
index 7881754af53e64aea710f5dc962989b51df1e6ce..a3659c28bfa3e8346b89a4056842de26dd646912 100644 (file)
@@ -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
      *
index cf69299f6642ef714474a48dfdfac95cf3025c06..da9499af38ffb9056d0f6080bde7aadcb4049c9d 100644 (file)
@@ -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();
+    }
 }
index 00c61c6e8e44b3022b833d50b6b520528de4126f..6aa0efde93e175b68d314470663666f483a57dd3 100644 (file)
@@ -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.
      */
index f79569ac6c531ccab8002ae645e934dc2bfd589d..fbca0fb87db7074151f662316f85661d43c58ce4 100644 (file)
@@ -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.
      */
index a94a022f0aa3e77a907ebe8deac1f1dbfe5d675c..4c78e6760e10234c7bb0014cdd1741cc40de8606 100644 (file)
@@ -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.
      */
index fa822f7f49f30c386cf49849c709338812e76604..d3db3469a48f950eb67eb00591dcce7d09e97328 100644 (file)
@@ -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();
+    }
 }
index 70232eb1d80da692b15c97de3df7338e28e0e1a1..bed9619d11e2abd6d3b668db9936415a0474a5a4 100644 (file)
@@ -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 )
index 2f251f17d10c1f9faadfa001a49e1c2d45733521..a4447dc016174fc29c0da97a65c1abf7e51fd74a 100644 (file)
@@ -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();
     }
 
     /**
index c5e4551d4dd6c5c584657c68db4754d96d71e5c7..7e8d07cb86d148a204941c9e9fefbab58bb474c6 100644 (file)
@@ -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;
     }
index d9a13476151f8bc331fab5ea60334f2179a5989f..37f405469436516ed0406f341577fbdeee3abe33 100644 (file)
@@ -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)));\r
+    }\r
+\r
+    @Override\r
+    public String toXml(String tab) {\r
+        String extraData = "";\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance())))\r
+                .append(tab).append("\t").append("<UID>0x").append(HexDump.toHex( field_1_UID ) + '\n' +\r
+                                (field_2_UID == null ? "" : ("  UID2: 0x" + HexDump.toHex( field_2_UID ) + '\n'))).append("</UID>\n")\r
+                .append(tab).append("\t").append("<UncompressedSize>0x").append(HexDump.toHex( field_2_cb )).append("</UncompressedSize>\n")\r
+                .append(tab).append("\t").append("<Bounds>").append(getBounds()).append("</Bounds>\n")\r
+                .append(tab).append("\t").append("<SizeInEMU>").append(getSizeEMU()).append("</SizeInEMU>\n")\r
+                .append(tab).append("\t").append("<CompressedSize>0x").append(HexDump.toHex( field_5_cbSave )).append("</CompressedSize>\n")\r
+                .append(tab).append("\t").append("<Compression>0x").append(HexDump.toHex( field_6_fCompression )).append("</Compression>\n")\r
+                .append(tab).append("\t").append("<Filter>0x").append(HexDump.toHex( field_7_fFilter )).append("</Filter>\n")\r
+                .append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n")\r
+                .append(tab).append("\t").append("<RemainingData>0x").append(HexDump.toHex(remainingData, 32)).append("</RemainingData>\n");\r
+        builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n");\r
+        return builder.toString();\r
+    }\r
+\r
+    /**\r
+     * Return the blip signature\r
+     *\r
      * @return the blip signature
      */
     public short getSignature() {
index e83b324adfcf1783d3db02920bd2e76d511a506b..39c20b5b3b619742e15b7330acf866e299147cde 100644 (file)
@@ -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();
+    }
 }
index 9b93b08b9d796fd3892a38e47eac4d8dcc5aed54..c450d4f18c50c688510b31a3ea8bfdc3130663b2 100644 (file)
@@ -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' +\r
+                "  Extra Data:" + '\n' + extraData;\r
+    }\r
+\r
+    @Override\r
+    public String toXml(String tab) {\r
+        String extraData = "";\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance())))\r
+                .append(tab).append("\t").append("<UID>0x").append(HexDump.toHex( field_1_UID )).append("</UID>\n")\r
+                .append(tab).append("\t").append("<UncompressedSize>0x").append(HexDump.toHex( field_2_cb )).append("</UncompressedSize>\n")\r
+                .append(tab).append("\t").append("<Bounds>").append(getBounds()).append("</Bounds>\n")\r
+                .append(tab).append("\t").append("<SizeInEMU>").append(getSizeEMU()).append("</SizeInEMU>\n")\r
+                .append(tab).append("\t").append("<CompressedSize>0x").append(HexDump.toHex( field_5_cbSave )).append("</CompressedSize>\n")\r
+                .append(tab).append("\t").append("<Compression>0x").append(HexDump.toHex( field_6_fCompression )).append("</Compression>\n")\r
+                .append(tab).append("\t").append("<Filter>0x").append(HexDump.toHex( field_7_fFilter )).append("</Filter>\n")\r
+                .append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n");\r
+        builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n");\r
+        return builder.toString();\r
+    }\r
+}\r
index e06fff1bfcb9f0540b55f82929fae6b6d08b7b41..0d4efce975a2d8f633169120a16b086d5457c29e 100644 (file)
@@ -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.
index 2e1ef02618b6dab97902e54975952a8da93ded04..5d23addfb5773a6beccba8600d91579f18637b47 100644 (file)
@@ -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();
+    }
 }
index 0eb5a31d49f81db8b694a83a971605580ce2aa5f..cad6be171dbd09a32c832227b584ba0186434715 100644 (file)
@@ -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("");
+    }
 }
index a1adae84d608e7a362023c4c24418e77e354c3f4..78fb6420342a633329ffcd309235d798536b0dcd 100644 (file)
@@ -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();
+    }
 }
index cd51c91929dfd3a2b67f121de1f2394fddb46263..11a893f466bc6d4dcda680acd015cd4b0f2b8e9e 100644 (file)
@@ -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.
      */
index 43197322df0a54dbfec8c12ffc8165ede7770404..de279a5a50dd4e070823c0bbecf7a9a7416ff372 100644 (file)
@@ -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.
      */
index 2f85ef24add90473a6316573812c026aa37adbff..443c003784d070834cfe7dfbc5b5fb76981f5a73 100644 (file)
@@ -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;
index 5e726d523ee2bbadbf9c9966f3fdff9b7190ad58..12a0dcccd88a05d6d9f2d12b280e9dde09cfacdb 100644 (file)
@@ -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();
+    }
 }
 
 
index 563ef6d6e45acf62909dd2d2b5287dab54600c77..e60703ae3af8156833eb4f46c8e9e83f861145fc 100644 (file)
@@ -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 );
     }
diff --git a/src/java/org/apache/poi/hssf/dev/BiffDrawingToXml.java b/src/java/org/apache/poi/hssf/dev/BiffDrawingToXml.java
new file mode 100644 (file)
index 0000000..b20670c
--- /dev/null
@@ -0,0 +1,192 @@
+/*\r
+ *  ====================================================================\r
+ *    Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *    contributor license agreements.  See the NOTICE file distributed with\r
+ *    this work for additional information regarding copyright ownership.\r
+ *    The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *    (the "License"); you may not use this file except in compliance with\r
+ *    the License.  You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ * ====================================================================\r
+ */\r
+\r
+package org.apache.poi.hssf.dev;\r
+\r
+import org.apache.poi.ddf.EscherRecord;\r
+import org.apache.poi.hssf.model.InternalWorkbook;\r
+import org.apache.poi.hssf.record.*;\r
+import org.apache.poi.hssf.usermodel.HSSFPatriarch;\r
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;\r
+\r
+import java.io.*;\r
+import java.lang.reflect.Field;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * Utility for representing drawings contained in a binary Excel file as a XML tree\r
+ *\r
+ * @author Evgeniy Berlog\r
+ * date: 10.04.12\r
+ */\r
+public class BiffDrawingToXml {\r
+\r
+    private static final String SHEET_NAME_PARAM = "-sheet-name";\r
+    private static final String SHEET_INDEXES_PARAM = "-sheet-indexes";\r
+    private static final String EXCLUDE_WORKBOOK_RECORDS = "-exclude-workbook";\r
+\r
+    private static int getAttributeIndex(String attribute, String[] params) {\r
+        for (int i = 0; i < params.length; i++) {\r
+            String param = params[i];\r
+            if (attribute.equals(param)) {\r
+                return i;\r
+            }\r
+        }\r
+        return -1;\r
+    }\r
+\r
+    private static boolean isExcludeWorkbookRecords(String[] params) {\r
+        return -1 != getAttributeIndex(EXCLUDE_WORKBOOK_RECORDS, params);\r
+    }\r
+\r
+    private static List<Integer> getIndexesByName(String[] params, HSSFWorkbook workbook) {\r
+        List<Integer> list = new ArrayList<Integer>();\r
+        int pos = getAttributeIndex(SHEET_NAME_PARAM, params);\r
+        if (-1 != pos) {\r
+            if (pos >= params.length) {\r
+                throw new IllegalArgumentException("sheet name param value was not specified");\r
+            }\r
+            String sheetName = params[pos + 1];\r
+            int sheetPos = workbook.getSheetIndex(sheetName);\r
+            if (-1 == sheetPos){\r
+                throw new IllegalArgumentException("specified sheet name has not been found in xls file");\r
+            }\r
+            list.add(sheetPos);\r
+        }\r
+        return list;\r
+    }\r
+\r
+    private static List<Integer> getIndexesByIdArray(String[] params) {\r
+        List<Integer> list = new ArrayList<Integer>();\r
+        int pos = getAttributeIndex(SHEET_INDEXES_PARAM, params);\r
+        if (-1 != pos) {\r
+            if (pos >= params.length) {\r
+                throw new IllegalArgumentException("sheet list value was not specified");\r
+            }\r
+            String sheetParam = params[pos + 1];\r
+            String[] sheets = sheetParam.split(",");\r
+            for (String sheet : sheets) {\r
+                list.add(Integer.parseInt(sheet));\r
+            }\r
+        }\r
+        return list;\r
+    }\r
+\r
+    private static List<Integer> getSheetsIndexes(String[] params, HSSFWorkbook workbook) {\r
+        List<Integer> list = new ArrayList<Integer>();\r
+        list.addAll(getIndexesByIdArray(params));\r
+        list.addAll(getIndexesByName(params, workbook));\r
+        if (0 == list.size()) {\r
+            int size = workbook.getNumberOfSheets();\r
+            for (int i = 0; i < size; i++) {\r
+                list.add(i);\r
+            }\r
+        }\r
+        return list;\r
+    }\r
+\r
+    private static String getInputFileName(String[] params) {\r
+        return params[params.length - 1];\r
+    }\r
+\r
+    private static String getOutputFileName(String input) {\r
+        if (input.contains("xls")) {\r
+            return input.replace(".xls", ".xml");\r
+        }\r
+        return input + ".xml";\r
+    }\r
+\r
+    public static void main(String[] params) throws IOException {\r
+        if (0 == params.length) {\r
+            System.out.println("Usage: BiffDrawingToXml [options] inputWorkbook");\r
+            System.out.println("Options:");\r
+            System.out.println("  -exclude-workbook            exclude workbook-level records");\r
+            System.out.println("  -sheet-indexes   <indexes>   output sheets with specified indexes");\r
+            System.out.println("  -sheet-namek  <names>        output sheets with specified name");\r
+            return;\r
+        }\r
+        String input = getInputFileName(params);\r
+        FileInputStream inp = new FileInputStream(input);\r
+        String output = getOutputFileName(input);\r
+        FileOutputStream outputStream = new FileOutputStream(output);\r
+        writeToFile(outputStream, inp, isExcludeWorkbookRecords(params), params);\r
+        inp.close();\r
+        outputStream.close();\r
+    }\r
+\r
+    public static void writeToFile(FileOutputStream fos, InputStream xlsWorkbook, boolean excludeWorkbookRecords, String[] params) throws IOException {\r
+        POIFSFileSystem fs = new POIFSFileSystem(xlsWorkbook);\r
+        HSSFWorkbook workbook = new HSSFWorkbook(fs);\r
+        InternalWorkbook internalWorkbook = getInternalWorkbook(workbook);\r
+        DrawingGroupRecord r = (DrawingGroupRecord) internalWorkbook.findFirstRecordBySid(DrawingGroupRecord.sid);\r
+        r.decode();\r
+\r
+        StringBuilder builder = new StringBuilder();\r
+        builder.append("<workbook>\n");\r
+        String tab = "\t";\r
+        if (!excludeWorkbookRecords) {\r
+            List<EscherRecord> escherRecords = r.getEscherRecords();\r
+            for (EscherRecord record : escherRecords) {\r
+                builder.append(record.toXml(tab));\r
+            }\r
+        }\r
+        List<Integer> sheets = getSheetsIndexes(params, workbook);\r
+        for (Integer i : sheets) {\r
+            HSSFPatriarch p = workbook.getSheetAt(i).getDrawingPatriarch();\r
+            if(p != null ) {\r
+                builder.append(tab).append("<sheet").append(i).append(">\n");\r
+                builder.append(getHSSFPatriarchBoundAggregate(p).toXml(tab + "\t"));\r
+                builder.append(tab).append("</sheet").append(i).append(">\n");\r
+            }\r
+        }\r
+        builder.append("</workbook>\n");\r
+        fos.write(builder.toString().getBytes());\r
+        fos.close();\r
+    }\r
+\r
+    private static EscherAggregate getHSSFPatriarchBoundAggregate(HSSFPatriarch patriarch) {\r
+        Field boundAggregateField = null;\r
+        try {\r
+            boundAggregateField = patriarch.getClass().getDeclaredField("_boundAggregate");\r
+            boundAggregateField.setAccessible(true);\r
+            return (EscherAggregate) boundAggregateField.get(patriarch);\r
+        } catch (NoSuchFieldException e) {\r
+            e.printStackTrace();\r
+        } catch (IllegalAccessException e) {\r
+            e.printStackTrace();\r
+        }\r
+        return null;\r
+    }\r
+\r
+    private static InternalWorkbook getInternalWorkbook(HSSFWorkbook workbook) {\r
+        Field internalSheetField = null;\r
+        try {\r
+            internalSheetField = workbook.getClass().getDeclaredField("workbook");\r
+            internalSheetField.setAccessible(true);\r
+            return (InternalWorkbook) internalSheetField.get(workbook);\r
+        } catch (NoSuchFieldException e) {\r
+            e.printStackTrace();\r
+        } catch (IllegalAccessException e) {\r
+            e.printStackTrace();\r
+        }\r
+        return null;\r
+    }\r
+}\r
index abd67e72cb4046f6e9b1b7ccdea2d06baca12080..6cbec15016916096d732b21a1ff2aff408fdb9a2 100644 (file)
@@ -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.