]> source.dussan.org Git - poi.git/commitdiff
Further CFRule12 parsing
authorNick Burch <nick@apache.org>
Mon, 13 Jul 2015 16:07:39 +0000 (16:07 +0000)
committerNick Burch <nick@apache.org>
Mon, 13 Jul 2015 16:07:39 +0000 (16:07 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1690742 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/CFRule12Record.java
src/java/org/apache/poi/hssf/record/CFRuleBase.java
src/java/org/apache/poi/hssf/record/CFRuleRecord.java

index 0b896fce85be97b664363f2e68aca2b31eaffd45..c5afb3e4e80dae10549f6143ae2fc9a90e07016c 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.ss.formula.Formula;
 import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.POILogger;
 
 /**
  * Conditional Formatting v12 Rule Record (0x087A). 
@@ -39,20 +40,46 @@ public final class CFRule12Record extends CFRuleBase {
     public static final short sid = 0x087A;
 
     private FtrHeader futureHeader;
-    private Formula formulaScale;
+    private int ext_formatting_length;
+    private byte[] ext_formatting_data;
+    private Formula formula_scale;
+    private byte ext_opts;
+    private int priority;
+    private int template_type;
+    private byte template_param_length;
+    private byte[] template_params;
+    
+    // TODO Parse these
+    private byte[] gradient_data;
+    private byte[] databar_data;
+    private byte[] filter_data;
+    private byte[] multistate_data;
 
     /** Creates new CFRuleRecord */
     private CFRule12Record(byte conditionType, byte comparisonOperation) {
         super(conditionType, comparisonOperation);
-        futureHeader = new FtrHeader();
-        futureHeader.setRecordType(sid);
-        // TODO Remaining fields
+        setDefaults();
     }
 
     private CFRule12Record(byte conditionType, byte comparisonOperation, Ptg[] formula1, Ptg[] formula2, Ptg[] formulaScale) {
         super(conditionType, comparisonOperation, formula1, formula2);
-        this.formulaScale = Formula.create(formulaScale);
-        // TODO Remaining fields
+        setDefaults();
+        this.formula_scale = Formula.create(formulaScale);
+    }
+    private void setDefaults() {
+        futureHeader = new FtrHeader();
+        futureHeader.setRecordType(sid);
+        
+        ext_formatting_length = 0;
+        ext_formatting_data = new byte[4];
+        
+        formula_scale = Formula.create(Ptg.EMPTY_PTG_ARRAY);
+        
+        ext_opts = 0;
+        priority = 0;
+        template_type = getConditionType();
+        template_param_length = 16;
+        template_params = new byte[template_param_length];
     }
 
     /**
@@ -92,7 +119,47 @@ public final class CFRule12Record extends CFRuleBase {
         int field_3_formula1_len = in.readUShort();
         int field_4_formula2_len = in.readUShort();
         
-        // TODO Handle the remainder
+        ext_formatting_length = in.readInt();
+        ext_formatting_data = new byte[0];
+        if (ext_formatting_length == 0) {
+            // 2 bytes reserved
+            in.readUShort();
+        } else {
+            int len = readFormatOptions(in);
+            if (len < ext_formatting_length) {
+                ext_formatting_data = new byte[ext_formatting_length-len];
+                in.readFully(ext_formatting_data);
+            }
+        }
+        
+        setFormula1(Formula.read(field_3_formula1_len, in));
+        setFormula2(Formula.read(field_4_formula2_len, in));
+        
+        int formula_scale_len = in.readUShort();
+        formula_scale = Formula.read(formula_scale_len, in);
+        
+        ext_opts = in.readByte();
+        priority = in.readUShort();
+        template_type = in.readUShort();
+        template_param_length = in.readByte();
+        if (template_param_length == 0 || template_param_length == 16) {
+            template_params = new byte[template_param_length];
+            in.readFully(template_params);
+        } else {
+            logger.log(POILogger.WARN, "CF Rule v12 template params length should be 0 or 16, found " + template_param_length);
+            in.readRemainder();
+        }
+        
+        byte type = getConditionType();
+        if (type == CONDITION_TYPE_COLOR_SCALE) {
+            gradient_data = in.readRemainder();
+        } else if (type == CONDITION_TYPE_DATA_BAR) {
+            databar_data = in.readRemainder();
+        } else if (type == CONDITION_TYPE_FILTER) {
+            filter_data = in.readRemainder();
+        } else if (type == CONDITION_TYPE_ICON_SET) {
+            multistate_data = in.readRemainder();
+        }
     }
 
     /**
@@ -104,10 +171,10 @@ public final class CFRule12Record extends CFRuleBase {
      * callers should check for null!
      */
     public Ptg[] getParsedExpressionScale() {
-        return formulaScale.getTokens();
+        return formula_scale.getTokens();
     }
     public void setParsedExpressionScale(Ptg[] ptgs) {
-        formulaScale = Formula.create(ptgs);
+        formula_scale = Formula.create(ptgs);
     }
 
     public short getSid() {
@@ -132,22 +199,71 @@ public final class CFRule12Record extends CFRuleBase {
         out.writeShort(formula1Len);
         out.writeShort(formula2Len);
         
-        // TODO Output the rest
+        // TODO Update ext_formatting_length
+        if (ext_formatting_length == 0) {
+            out.writeInt(0);
+            out.writeShort(0);
+        } else {
+            out.writeInt(ext_formatting_length);
+            serializeFormattingBlock(out);
+            out.write(ext_formatting_data);
+        }
+        
+        getFormula1().serializeTokens(out);
+        getFormula2().serializeTokens(out);
+        formula_scale.serializeTokens(out);
+        
+        out.writeByte(ext_opts);
+        out.writeShort(priority);
+        out.writeShort(template_type);
+        out.writeByte(template_param_length);
+        out.write(template_params);
+        
+        byte type = getConditionType();
+        if (type == CONDITION_TYPE_COLOR_SCALE) {
+            out.write(gradient_data);
+        } else if (type == CONDITION_TYPE_DATA_BAR) {
+            out.write(databar_data);
+        } else if (type == CONDITION_TYPE_FILTER) {
+            out.write(filter_data);
+        } else if (type == CONDITION_TYPE_ICON_SET) {
+            out.write(multistate_data);
+        }
     }
 
     protected int getDataSize() {
-        // TODO Calculate
-        return 0;
+        int len = FtrHeader.getDataSize() + 6;
+        if (ext_formatting_length == 0) {
+            len += 6;
+        } else {
+            len += 4 + getFormattingBlockSize() + ext_formatting_data.length;
+        }
+        len += getFormulaSize(getFormula1());
+        len += getFormulaSize(getFormula2());
+        len += 4 + getFormulaSize(formula_scale);
+        len += 6 + template_params.length;
+        
+        byte type = getConditionType();
+        if (type == CONDITION_TYPE_COLOR_SCALE) {
+            len += gradient_data.length;
+        } else if (type == CONDITION_TYPE_DATA_BAR) {
+            len += databar_data.length;
+        } else if (type == CONDITION_TYPE_FILTER) {
+            len += filter_data.length;
+        } else if (type == CONDITION_TYPE_ICON_SET) {
+            len += multistate_data.length;
+        }
+        return len;
     }
 
     public String toString() {
         StringBuffer buffer = new StringBuffer();
         buffer.append("[CFRULE12]\n");
         buffer.append("    .condition_type   =").append(getConditionType()).append("\n");
-        buffer.append("    TODO The rest!\n");
+        buffer.append("    TODO The rest!\n"); // TODO The Rest
         buffer.append("    Formula 1 =").append(Arrays.toString(getFormula1().getTokens())).append("\n");
         buffer.append("    Formula 2 =").append(Arrays.toString(getFormula2().getTokens())).append("\n");
-        buffer.append("    Formula S =").append(Arrays.toString(formulaScale.getTokens())).append("\n");
+        buffer.append("    Formula S =").append(Arrays.toString(formula_scale.getTokens())).append("\n");
         buffer.append("[/CFRULE12]\n");
         return buffer.toString();
     }
@@ -158,7 +274,7 @@ public final class CFRule12Record extends CFRuleBase {
         
         // TODO The other fields
         
-        rec.formulaScale = formulaScale.copy();
+        rec.formula_scale = formula_scale.copy();
 
         return rec;
     }
index f43b0e36a6ac81e5518b0cfc371c46aec4f3ff48..b7db3a7a09c7e18f42d63faeeaa044cd3fd44927 100644 (file)
@@ -27,6 +27,9 @@ import org.apache.poi.ss.formula.FormulaType;
 import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 /**
  * Conditional Formatting Rules. This can hold old-style rules
@@ -49,6 +52,7 @@ public abstract class CFRuleBase extends StandardRecord {
         public static final byte LE            = 8;
         private static final byte max_operator = 8;
     }
+    protected static final POILogger logger = POILogFactory.getLogger(CFRuleBase.class);
 
     private byte condition_type;
     // The only kinds that CFRuleRecord handles
@@ -91,41 +95,41 @@ public abstract class CFRuleBase extends StandardRecord {
     public static final int TEMPLATE_BELOW_OR_EQUAL_TO_AVERAGE = 0x001E;
     
     static final BitField modificationBits = bf(0x003FFFFF); // Bits: font,align,bord,patt,prot
-    static final BitField alignHor      = bf(0x00000001); // 0 = Horizontal alignment modified
-    static final BitField alignVer      = bf(0x00000002); // 0 = Vertical alignment modified
-    static final BitField alignWrap     = bf(0x00000004); // 0 = Text wrapped flag modified
-    static final BitField alignRot      = bf(0x00000008); // 0 = Text rotation modified
-    static final BitField alignJustLast = bf(0x00000010); // 0 = Justify last line flag modified
-    static final BitField alignIndent   = bf(0x00000020); // 0 = Indentation modified
-    static final BitField alignShrin    = bf(0x00000040); // 0 = Shrink to fit flag modified
-    static final BitField notUsed1      = bf(0x00000080); // Always 1
-    static final BitField protLocked    = bf(0x00000100); // 0 = Cell locked flag modified
-    static final BitField protHidden    = bf(0x00000200); // 0 = Cell hidden flag modified
-    static final BitField bordLeft      = bf(0x00000400); // 0 = Left border style and colour modified
-    static final BitField bordRight     = bf(0x00000800); // 0 = Right border style and colour modified
-    static final BitField bordTop       = bf(0x00001000); // 0 = Top border style and colour modified
-    static final BitField bordBot       = bf(0x00002000); // 0 = Bottom border style and colour modified
-    static final BitField bordTlBr      = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
-    static final BitField bordBlTr      = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
-    static final BitField pattStyle     = bf(0x00010000); // 0 = Pattern style modified
-    static final BitField pattCol       = bf(0x00020000); // 0 = Pattern colour modified
-    static final BitField pattBgCol     = bf(0x00040000); // 0 = Pattern background colour modified
-    static final BitField notUsed2      = bf(0x00380000); // Always 111
-    static final BitField undocumented  = bf(0x03C00000); // Undocumented bits
-    static final BitField fmtBlockBits  = bf(0x7C000000); // Bits: font,align,bord,patt,prot
-    static final BitField font          = bf(0x04000000); // 1 = Record contains font formatting block
-    static final BitField align         = bf(0x08000000); // 1 = Record contains alignment formatting block
-    static final BitField bord          = bf(0x10000000); // 1 = Record contains border formatting block
-    static final BitField patt          = bf(0x20000000); // 1 = Record contains pattern formatting block
-    static final BitField prot          = bf(0x40000000); // 1 = Record contains protection formatting block
-    static final BitField alignTextDir  = bf(0x80000000); // 0 = Text direction modified
+    static final BitField alignHor         = bf(0x00000001); // 0 = Horizontal alignment modified
+    static final BitField alignVer         = bf(0x00000002); // 0 = Vertical alignment modified
+    static final BitField alignWrap        = bf(0x00000004); // 0 = Text wrapped flag modified
+    static final BitField alignRot         = bf(0x00000008); // 0 = Text rotation modified
+    static final BitField alignJustLast    = bf(0x00000010); // 0 = Justify last line flag modified
+    static final BitField alignIndent      = bf(0x00000020); // 0 = Indentation modified
+    static final BitField alignShrin       = bf(0x00000040); // 0 = Shrink to fit flag modified
+    static final BitField mergeCell        = bf(0x00000080); // Normally 1, 0 = Merge Cell flag modified
+    static final BitField protLocked       = bf(0x00000100); // 0 = Cell locked flag modified
+    static final BitField protHidden       = bf(0x00000200); // 0 = Cell hidden flag modified
+    static final BitField bordLeft         = bf(0x00000400); // 0 = Left border style and colour modified
+    static final BitField bordRight        = bf(0x00000800); // 0 = Right border style and colour modified
+    static final BitField bordTop          = bf(0x00001000); // 0 = Top border style and colour modified
+    static final BitField bordBot          = bf(0x00002000); // 0 = Bottom border style and colour modified
+    static final BitField bordTlBr         = bf(0x00004000); // 0 = Top-left to bottom-right border flag modified
+    static final BitField bordBlTr         = bf(0x00008000); // 0 = Bottom-left to top-right border flag modified
+    static final BitField pattStyle        = bf(0x00010000); // 0 = Pattern style modified
+    static final BitField pattCol          = bf(0x00020000); // 0 = Pattern colour modified
+    static final BitField pattBgCol        = bf(0x00040000); // 0 = Pattern background colour modified
+    static final BitField notUsed2         = bf(0x00380000); // Always 111 (ifmt / ifnt / 1)
+    static final BitField undocumented     = bf(0x03C00000); // Undocumented bits
+    static final BitField fmtBlockBits     = bf(0x7C000000); // Bits: font,align,bord,patt,prot
+    static final BitField font             = bf(0x04000000); // 1 = Record contains font formatting block
+    static final BitField align            = bf(0x08000000); // 1 = Record contains alignment formatting block
+    static final BitField bord             = bf(0x10000000); // 1 = Record contains border formatting block
+    static final BitField patt             = bf(0x20000000); // 1 = Record contains pattern formatting block
+    static final BitField prot             = bf(0x40000000); // 1 = Record contains protection formatting block
+    static final BitField alignTextDir     = bf(0x80000000); // 0 = Text direction modified
 
     private static BitField bf(int i) {
         return BitFieldFactory.getInstance(i);
     }
 
-    protected int field_5_options; // TODO Rename me
-    protected short field_6_not_used; // TODO Rename me
+    protected int formatting_options;
+    protected short formatting_not_used; // TODO Decode this properly
 
     protected FontFormatting _fontFormatting;
     protected BorderFormatting _borderFormatting;
@@ -149,8 +153,8 @@ public abstract class CFRuleBase extends StandardRecord {
     protected CFRuleBase() {}
     
     protected int readFormatOptions(RecordInputStream in) {
-        field_5_options = in.readInt();
-        field_6_not_used = in.readShort();
+        formatting_options = in.readInt();
+        formatting_not_used = in.readShort();
 
         int len = 6;
         
@@ -261,14 +265,14 @@ public abstract class CFRuleBase extends StandardRecord {
      * @return bit mask
      */
     public int getOptions() {
-        return field_5_options;
+        return formatting_options;
     }
 
     private boolean isModified(BitField field) {
-        return !field.isSet(field_5_options);
+        return !field.isSet(formatting_options);
     }
     private void setModified(boolean modified, BitField field) {
-        field_5_options = field.setBoolean(field_5_options, !modified);
+        formatting_options = field.setBoolean(formatting_options, !modified);
     }
 
     public boolean isLeftBorderModified() {
@@ -336,10 +340,34 @@ public abstract class CFRuleBase extends StandardRecord {
     }
 
     private boolean getOptionFlag(BitField field) {
-        return field.isSet(field_5_options);
+        return field.isSet(formatting_options);
     }
     private void setOptionFlag(boolean flag, BitField field) {
-        field_5_options = field.setBoolean(field_5_options, flag);
+        formatting_options = field.setBoolean(formatting_options, flag);
+    }
+    
+    protected int getFormattingBlockSize() {
+        return
+          (containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
+          (containsBorderFormattingBlock()?8:0)+
+          (containsPatternFormattingBlock()?4:0);
+    }
+    protected void serializeFormattingBlock(LittleEndianOutput out) {
+        out.writeInt(formatting_options);
+        out.writeShort(formatting_not_used);
+
+        if (containsFontFormattingBlock()) {
+            byte[] fontFormattingRawRecord  = _fontFormatting.getRawRecord();
+            out.write(fontFormattingRawRecord);
+        }
+
+        if (containsBorderFormattingBlock()) {
+            _borderFormatting.serialize(out);
+        }
+
+        if (containsPatternFormattingBlock()) {
+            _patternFormatting.serialize(out);
+        }
     }
     
     /**
@@ -409,8 +437,8 @@ public abstract class CFRuleBase extends StandardRecord {
         rec.condition_type = condition_type;
         rec.comparison_operator = comparison_operator;
         
-        rec.field_5_options = field_5_options;
-        rec.field_6_not_used = field_6_not_used;
+        rec.formatting_options = formatting_options;
+        rec.formatting_not_used = formatting_not_used;
         if (containsFontFormattingBlock()) {
             rec._fontFormatting = (FontFormatting) _fontFormatting.clone();
         }
index f13685abb1bb1988d99367244bd89944542efe49..a00fde73116e3dd231a2f429813e8a5a7818a5d9 100644 (file)
@@ -46,12 +46,12 @@ public final class CFRuleRecord extends CFRuleBase {
     }
     private void setDefaults() {
         // Set modification flags to 1: by default options are not modified
-        field_5_options = modificationBits.setValue(field_5_options, -1);
+        formatting_options = modificationBits.setValue(formatting_options, -1);
         // Set formatting block flags to 0 (no formatting blocks)
-        field_5_options = fmtBlockBits.setValue(field_5_options, 0);
-        field_5_options = undocumented.clear(field_5_options);
+        formatting_options = fmtBlockBits.setValue(formatting_options, 0);
+        formatting_options = undocumented.clear(formatting_options);
 
-        field_6_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
+        formatting_not_used = (short)0x8002; // Excel seems to write this value, but it doesn't seem to care what it reads
         _fontFormatting = null;
         _borderFormatting = null;
         _patternFormatting = null;
@@ -106,34 +106,17 @@ public final class CFRuleRecord extends CFRuleBase {
         out.writeByte(getComparisonOperation());
         out.writeShort(formula1Len);
         out.writeShort(formula2Len);
-        out.writeInt(field_5_options);
-        out.writeShort(field_6_not_used);
-
-        if (containsFontFormattingBlock()) {
-            byte[] fontFormattingRawRecord  = _fontFormatting.getRawRecord();
-            out.write(fontFormattingRawRecord);
-        }
-
-        if (containsBorderFormattingBlock()) {
-            _borderFormatting.serialize(out);
-        }
-
-        if (containsPatternFormattingBlock()) {
-            _patternFormatting.serialize(out);
-        }
+        
+        serializeFormattingBlock(out);
 
         getFormula1().serializeTokens(out);
         getFormula2().serializeTokens(out);
     }
 
     protected int getDataSize() {
-        int i = 12 +
-                (containsFontFormattingBlock()?_fontFormatting.getRawRecord().length:0)+
-                (containsBorderFormattingBlock()?8:0)+
-                (containsPatternFormattingBlock()?4:0)+
-                getFormulaSize(getFormula1())+
-                getFormulaSize(getFormula2());
-        return i;
+        return 12 + getFormattingBlockSize() +
+               getFormulaSize(getFormula1())+
+               getFormulaSize(getFormula2());
     }
 
     public String toString() {