Start to support CF12 headers for #58130

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1690494 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2015-07-12 17:58:27 +00:00
parent 8c1cb7e48a
commit c63ff25ebb
5 changed files with 129 additions and 33 deletions

View File

@ -180,6 +180,7 @@ public final class BiffViewer {
case BottomMarginRecord.sid: return new BottomMarginRecord(in); case BottomMarginRecord.sid: return new BottomMarginRecord(in);
case BoundSheetRecord.sid: return new BoundSheetRecord(in); case BoundSheetRecord.sid: return new BoundSheetRecord(in);
case CFHeaderRecord.sid: return new CFHeaderRecord(in); case CFHeaderRecord.sid: return new CFHeaderRecord(in);
case CFHeader12Record.sid: return new CFHeader12Record(in);
case CFRuleRecord.sid: return new CFRuleRecord(in); case CFRuleRecord.sid: return new CFRuleRecord(in);
case CalcCountRecord.sid: return new CalcCountRecord(in); case CalcCountRecord.sid: return new CalcCountRecord(in);
case CalcModeRecord.sid: return new CalcModeRecord(in); case CalcModeRecord.sid: return new CalcModeRecord(in);

View File

@ -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;
}
}

View File

@ -26,12 +26,13 @@ import org.apache.poi.util.LittleEndianOutput;
* Conditional Formatting Header record CFHEADER (0x01B0). * Conditional Formatting Header record CFHEADER (0x01B0).
* Used to describe a {@link CFRuleRecord}. * Used to describe a {@link CFRuleRecord}.
* @see CFHeader12Record * @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; public static final short sid = 0x01B0;
private int field_1_numcf; 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 CellRangeAddress field_3_enclosing_cell_range;
private CellRangeAddressList field_4_cell_ranges; private CellRangeAddressList field_4_cell_ranges;
@ -47,40 +48,51 @@ public final class CFHeaderRecord extends StandardRecord {
field_1_numcf = nRules; 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_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_3_enclosing_cell_range = new CellRangeAddress(in);
field_4_cell_ranges = new CellRangeAddressList(in); field_4_cell_ranges = new CellRangeAddressList(in);
} }
public int getNumberOfConditionalFormats() public int getNumberOfConditionalFormats() {
{
return field_1_numcf; return field_1_numcf;
} }
public void setNumberOfConditionalFormats(int n) public void setNumberOfConditionalFormats(int n) {
{
field_1_numcf=n; field_1_numcf=n;
} }
public boolean getNeedRecalculation() public boolean getNeedRecalculation() {
{ // Held on the 1st bit
return field_2_need_recalculation==1?true:false; 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 void setNeedRecalculation(boolean b) public int getID()
{ {
field_2_need_recalculation=b?1:0; // Remaining 15 bits of field 2
return field_2_need_recalculation_and_id>>1;
}
public void setID(int id)
{
// 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; return field_3_enclosing_cell_range;
} }
public void setEnclosingCellRange(CellRangeAddress cr) {
public void setEnclosingCellRange(CellRangeAddress cr)
{
field_3_enclosing_cell_range = cr; field_3_enclosing_cell_range = cr;
} }
@ -89,8 +101,7 @@ public final class CFHeaderRecord extends StandardRecord {
* modify the enclosing cell range accordingly. * modify the enclosing cell range accordingly.
* @param cellRanges - list of CellRange objects * @param cellRanges - list of CellRange objects
*/ */
public void setCellRanges(CellRangeAddress[] cellRanges) public void setCellRanges(CellRangeAddress[] cellRanges) {
{
if(cellRanges == null) if(cellRanges == null)
{ {
throw new IllegalArgumentException("cellRanges must not be 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(); return field_4_cell_ranges.getCellRangeAddresses();
} }
public String toString() protected String getRecordName() {
{ return "CFHEADER";
}
public String toString() {
StringBuffer buffer = new StringBuffer(); 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(" .id = ").append(Integer.toHexString(sid)).append("\n");
buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n"); buffer.append(" .numCF = ").append(getNumberOfConditionalFormats()).append("\n");
buffer.append(" .needRecalc = ").append(getNeedRecalculation()).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(i==0?"":",").append(field_4_cell_ranges.getCellRangeAddress(i).toString());
} }
buffer.append("]\n"); buffer.append("]\n");
buffer.append("[/CFHEADER]\n"); buffer.append("[/").append(getRecordName()).append("]\n");
return buffer.toString(); return buffer.toString();
} }
@ -137,9 +150,8 @@ public final class CFHeaderRecord extends StandardRecord {
} }
public void serialize(LittleEndianOutput out) { public void serialize(LittleEndianOutput out) {
out.writeShort(field_1_numcf); 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_3_enclosing_cell_range.serialize(out);
field_4_cell_ranges.serialize(out); field_4_cell_ranges.serialize(out);
} }
@ -148,11 +160,10 @@ public final class CFHeaderRecord extends StandardRecord {
return sid; return sid;
} }
public Object clone() public Object clone() {
{
CFHeaderRecord result = new CFHeaderRecord(); CFHeaderRecord result = new CFHeaderRecord();
result.field_1_numcf = field_1_numcf; 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_3_enclosing_cell_range = field_3_enclosing_cell_range;
result.field_4_cell_ranges = field_4_cell_ranges.copy(); result.field_4_cell_ranges = field_4_cell_ranges.copy();
return result; return result;

View File

@ -155,6 +155,7 @@ public final class RecordFactory {
CalcCountRecord.class, CalcCountRecord.class,
CalcModeRecord.class, CalcModeRecord.class,
CFHeaderRecord.class, CFHeaderRecord.class,
CFHeader12Record.class,
CFRuleRecord.class, CFRuleRecord.class,
ChartRecord.class, ChartRecord.class,
ChartTitleFormatRecord.class, ChartTitleFormatRecord.class,

View File

@ -32,7 +32,7 @@ public final class FtrHeader {
private short recordType; private short recordType;
/** This is a FrtFlags */ /** This is a FrtFlags */
private short grbitFrt; private short grbitFrt;
/** MUST be 8 bytes and all zero */ /** MUST be 8 bytes and all zero TODO Correct this! */
private byte[] reserved; private byte[] reserved;
public FtrHeader() { public FtrHeader() {
@ -86,4 +86,12 @@ public final class FtrHeader {
public void setReserved(byte[] reserved) { public void setReserved(byte[] reserved) {
this.reserved = reserved; this.reserved = reserved;
} }
public Object clone() {
FtrHeader result = new FtrHeader();
result.recordType = recordType;
result.grbitFrt = grbitFrt;
result.reserved = reserved;
return result;
}
} }