From 239998a88cd9dea778345af9ea02c29d28749be4 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sun, 12 Jul 2015 17:58:27 +0000 Subject: [PATCH] Start to support CF12 headers for #58130 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1690494 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/hssf/dev/BiffViewer.java | 1 + .../poi/hssf/record/CFHeader12Record.java | 75 +++++++++++++++++++ .../poi/hssf/record/CFHeaderRecord.java | 71 ++++++++++-------- .../apache/poi/hssf/record/RecordFactory.java | 3 +- .../poi/hssf/record/common/FtrHeader.java | 10 ++- 5 files changed, 128 insertions(+), 32 deletions(-) create mode 100644 src/java/org/apache/poi/hssf/record/CFHeader12Record.java diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index 42d851de76..a14339a66d 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -180,6 +180,7 @@ public final class BiffViewer { case BottomMarginRecord.sid: return new BottomMarginRecord(in); case BoundSheetRecord.sid: return new BoundSheetRecord(in); case CFHeaderRecord.sid: return new CFHeaderRecord(in); + case CFHeader12Record.sid: return new CFHeader12Record(in); case CFRuleRecord.sid: return new CFRuleRecord(in); case CalcCountRecord.sid: return new CalcCountRecord(in); case CalcModeRecord.sid: return new CalcModeRecord(in); diff --git a/src/java/org/apache/poi/hssf/record/CFHeader12Record.java b/src/java/org/apache/poi/hssf/record/CFHeader12Record.java new file mode 100644 index 0000000000..4b0345ed13 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/CFHeader12Record.java @@ -0,0 +1,75 @@ +/* ==================================================================== + 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.record; + +import org.apache.poi.hssf.record.common.FtrHeader; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.util.LittleEndianOutput; + +/** + * Conditional Formatting Header v12 record CFHEADER12 (0x0879), + * for conditional formattings introduced in Excel 2007 and newer. + */ +public final class CFHeader12Record extends CFHeaderRecord { + public static final short sid = 0x0879; + + private FtrHeader futureHeader; + + /** Creates new CFHeaderRecord */ + public CFHeader12Record() { + super(); + futureHeader = new FtrHeader(); + futureHeader.setRecordType(sid); + } + public CFHeader12Record(CellRangeAddress[] regions, int nRules) { + super(regions, nRules); + futureHeader = new FtrHeader(); + futureHeader.setRecordType(sid); + } + + public CFHeader12Record(RecordInputStream in) + { + futureHeader = new FtrHeader(in); + read(in); + } + + @Override + protected String getRecordName() { + return "CFHEADER12"; + } + + protected int getDataSize() { + return FtrHeader.getDataSize() + super.getDataSize(); + } + + public void serialize(LittleEndianOutput out) { + futureHeader.serialize(out); + super.serialize(out); + } + + public short getSid() { + return sid; + } + + public Object clone() { + CFHeader12Record result = new CFHeader12Record(); + result.futureHeader = (FtrHeader)futureHeader.clone(); + // TODO Clone the rest via the base + return result; + } +} diff --git a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java index bfdd4b0579..55dd98d50a 100644 --- a/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java +++ b/src/java/org/apache/poi/hssf/record/CFHeaderRecord.java @@ -26,12 +26,13 @@ import org.apache.poi.util.LittleEndianOutput; * Conditional Formatting Header record CFHEADER (0x01B0). * Used to describe a {@link CFRuleRecord}. * @see CFHeader12Record + * TODO Move most of the logic into a base class */ -public final class CFHeaderRecord extends StandardRecord { +public class CFHeaderRecord extends StandardRecord { public static final short sid = 0x01B0; private int field_1_numcf; - private int field_2_need_recalculation; + private int field_2_need_recalculation_and_id; private CellRangeAddress field_3_enclosing_cell_range; private CellRangeAddressList field_4_cell_ranges; @@ -47,40 +48,51 @@ public final class CFHeaderRecord extends StandardRecord { field_1_numcf = nRules; } - public CFHeaderRecord(RecordInputStream in) - { + public CFHeaderRecord(RecordInputStream in) { + read(in); + } + protected void read(RecordInputStream in) { field_1_numcf = in.readShort(); - field_2_need_recalculation = in.readShort(); + field_2_need_recalculation_and_id = in.readShort(); field_3_enclosing_cell_range = new CellRangeAddress(in); field_4_cell_ranges = new CellRangeAddressList(in); } - public int getNumberOfConditionalFormats() - { + public int getNumberOfConditionalFormats() { return field_1_numcf; } - public void setNumberOfConditionalFormats(int n) - { + public void setNumberOfConditionalFormats(int n) { field_1_numcf=n; } - public boolean getNeedRecalculation() + public boolean getNeedRecalculation() { + // Held on the 1st bit + return field_2_need_recalculation_and_id % 2 == 1; + } + public void setNeedRecalculation(boolean b) { + // held on the first bit + if (b == getNeedRecalculation()) return; + if (b) field_2_need_recalculation_and_id++; + else field_2_need_recalculation_and_id--; + } + + public int getID() { - return field_2_need_recalculation==1?true:false; + // Remaining 15 bits of field 2 + return field_2_need_recalculation_and_id>>1; } - - public void setNeedRecalculation(boolean b) + public void setID(int id) { - field_2_need_recalculation=b?1:0; + // Remaining 15 bits of field 2 + boolean needsRecalc = getNeedRecalculation(); + field_2_need_recalculation_and_id = (id<<1); + if (needsRecalc) field_2_need_recalculation_and_id++; } - public CellRangeAddress getEnclosingCellRange() - { + public CellRangeAddress getEnclosingCellRange() { return field_3_enclosing_cell_range; } - - public void setEnclosingCellRange(CellRangeAddress cr) - { + public void setEnclosingCellRange(CellRangeAddress cr) { field_3_enclosing_cell_range = cr; } @@ -89,8 +101,7 @@ public final class CFHeaderRecord extends StandardRecord { * modify the enclosing cell range accordingly. * @param cellRanges - list of CellRange objects */ - public void setCellRanges(CellRangeAddress[] cellRanges) - { + public void setCellRanges(CellRangeAddress[] cellRanges) { if(cellRanges == null) { throw new IllegalArgumentException("cellRanges must not be null"); @@ -111,11 +122,13 @@ public final class CFHeaderRecord extends StandardRecord { return field_4_cell_ranges.getCellRangeAddresses(); } - public String toString() - { + protected String getRecordName() { + return "CFHEADER"; + } + public String toString() { StringBuffer buffer = new StringBuffer(); - buffer.append("[CFHEADER]\n"); + buffer.append("[").append(getRecordName()).append("]\n"); buffer.append(" .id = ").append(Integer.toHexString(sid)).append("\n"); buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n"); buffer.append(" .needRecalc = ").append(getNeedRecalculation()).append("\n"); @@ -126,7 +139,7 @@ public final class CFHeaderRecord extends StandardRecord { buffer.append(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString()); } buffer.append("]\n"); - buffer.append("[/CFHEADER]\n"); + buffer.append("[/").append(getRecordName()).append("]\n"); return buffer.toString(); } @@ -137,9 +150,8 @@ public final class CFHeaderRecord extends StandardRecord { } public void serialize(LittleEndianOutput out) { - out.writeShort(field_1_numcf); - out.writeShort(field_2_need_recalculation); + out.writeShort(field_2_need_recalculation_and_id); field_3_enclosing_cell_range.serialize(out); field_4_cell_ranges.serialize(out); } @@ -148,11 +160,10 @@ public final class CFHeaderRecord extends StandardRecord { return sid; } - public Object clone() - { + public Object clone() { CFHeaderRecord result = new CFHeaderRecord(); result.field_1_numcf = field_1_numcf; - result.field_2_need_recalculation = field_2_need_recalculation; + result.field_2_need_recalculation_and_id = field_2_need_recalculation_and_id; result.field_3_enclosing_cell_range = field_3_enclosing_cell_range; result.field_4_cell_ranges = field_4_cell_ranges.copy(); return result; diff --git a/src/java/org/apache/poi/hssf/record/RecordFactory.java b/src/java/org/apache/poi/hssf/record/RecordFactory.java index 3a1f7acca3..83622e1fb5 100644 --- a/src/java/org/apache/poi/hssf/record/RecordFactory.java +++ b/src/java/org/apache/poi/hssf/record/RecordFactory.java @@ -155,6 +155,7 @@ public final class RecordFactory { CalcCountRecord.class, CalcModeRecord.class, CFHeaderRecord.class, + CFHeader12Record.class, CFRuleRecord.class, ChartRecord.class, ChartTitleFormatRecord.class, @@ -166,7 +167,7 @@ public final class RecordFactory { CRNRecord.class, DateWindow1904Record.class, DBCellRecord.class, - DConRefRecord.class, + DConRefRecord.class, DefaultColWidthRecord.class, DefaultRowHeightRecord.class, DeltaRecord.class, diff --git a/src/java/org/apache/poi/hssf/record/common/FtrHeader.java b/src/java/org/apache/poi/hssf/record/common/FtrHeader.java index dc2d4e26e9..b240e8112f 100644 --- a/src/java/org/apache/poi/hssf/record/common/FtrHeader.java +++ b/src/java/org/apache/poi/hssf/record/common/FtrHeader.java @@ -32,7 +32,7 @@ public final class FtrHeader { private short recordType; /** This is a FrtFlags */ private short grbitFrt; - /** MUST be 8 bytes and all zero */ + /** MUST be 8 bytes and all zero TODO Correct this! */ private byte[] reserved; public FtrHeader() { @@ -86,4 +86,12 @@ public final class FtrHeader { public void setReserved(byte[] reserved) { this.reserved = reserved; } + + public Object clone() { + FtrHeader result = new FtrHeader(); + result.recordType = recordType; + result.grbitFrt = grbitFrt; + result.reserved = reserved; + return result; + } } \ No newline at end of file -- 2.39.5