From: Josh Micich Date: Thu, 11 Sep 2008 23:18:50 +0000 (+0000) Subject: Fix for bug 45639 - cleaned up index logic inside ColumnInfoRecordsAggregate X-Git-Tag: REL_3_2_FINAL~67 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f736644496248f93b487ba004af07670c31d5f12;p=poi.git Fix for bug 45639 - cleaned up index logic inside ColumnInfoRecordsAggregate git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@694534 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 95cab0e781..02d75184a9 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate Fixed special cases of INDEX function (single column/single row, errors) 45761 - Support for Very Hidden excel sheets in HSSF 45738 - Initial HWPF support for Office Art Shapes diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index e7fb447da7..dab203e98d 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45639 - Fixed AIOOBE due to bad index logic in ColumnInfoRecordsAggregate Fixed special cases of INDEX function (single column/single row, errors) 45761 - Support for Very Hidden excel sheets in HSSF 45738 - Initial HWPF support for Office Art Shapes diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 388f1a6ee4..8bbc30435a 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -1055,7 +1055,7 @@ public final class Sheet implements Model { ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); if (ci != null) { - return ci.getColumnWidth(); + return (short)ci.getColumnWidth(); } //default column width is measured in characters //multiply @@ -1079,8 +1079,8 @@ public final class Sheet implements Model { public short getXFIndexForColAt(short columnIndex) { ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); if (ci != null) { - return ci.getXFIndex(); - } + return (short)ci.getXFIndex(); + } return 0xF; } @@ -1138,8 +1138,7 @@ public final class Sheet implements Model { * @param indent if true the group will be indented by one level, * if false indenting will be removed by one level. */ - public void groupColumnRange(short fromColumn, short toColumn, boolean indent) - { + public void groupColumnRange(int fromColumn, int toColumn, boolean indent) { // Set the level for each column _columnInfos.groupColumnRange( fromColumn, toColumn, indent); @@ -1709,17 +1708,13 @@ public final class Sheet implements Model { } - public void setColumnGroupCollapsed( short columnNumber, boolean collapsed ) - { - if (collapsed) - { - _columnInfos.collapseColumn( columnNumber ); - } - else - { - _columnInfos.expandColumn( columnNumber ); - } - } + public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) { + if (collapsed) { + _columnInfos.collapseColumn(columnNumber); + } else { + _columnInfos.expandColumn(columnNumber); + } + } /** * protect a spreadsheet with a password (not encypted, just sets protect diff --git a/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java b/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java index b77dca3e17..32aef3a6c3 100644 --- a/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java +++ b/src/java/org/apache/poi/hssf/record/ColumnInfoRecord.java @@ -17,6 +17,7 @@ package org.apache.poi.hssf.record; +import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; @@ -30,19 +31,24 @@ import org.apache.poi.util.BitFieldFactory; */ public final class ColumnInfoRecord extends Record { public static final short sid = 0x7d; - private short field_1_first_col; - private short field_2_last_col; - private short field_3_col_width; - private short field_4_xf_index; - private short field_5_options; + private int field_1_first_col; + private int field_2_last_col; + private int field_3_col_width; + private int field_4_xf_index; + private int field_5_options; private static final BitField hidden = BitFieldFactory.getInstance(0x01); private static final BitField outlevel = BitFieldFactory.getInstance(0x0700); private static final BitField collapsed = BitFieldFactory.getInstance(0x1000); // Excel seems write values 2, 10, and 260, even though spec says "must be zero" private short field_6_reserved; - public ColumnInfoRecord() - { + /** + * Creates a column info record with default width and format + */ + public ColumnInfoRecord() { + setColumnWidth(2275); + field_5_options = 2; + field_4_xf_index = 0x0f; field_6_reserved = 2; // seems to be the most common value } @@ -90,7 +96,7 @@ public final class ColumnInfoRecord extends Record { * @param fc - the first column index (0-based) */ - public void setFirstColumn(short fc) + public void setFirstColumn(int fc) { field_1_first_col = fc; } @@ -100,7 +106,7 @@ public final class ColumnInfoRecord extends Record { * @param lc - the last column index (0-based) */ - public void setLastColumn(short lc) + public void setLastColumn(int lc) { field_2_last_col = lc; } @@ -110,7 +116,7 @@ public final class ColumnInfoRecord extends Record { * @param cw - column width */ - public void setColumnWidth(short cw) + public void setColumnWidth(int cw) { field_3_col_width = cw; } @@ -121,20 +127,11 @@ public final class ColumnInfoRecord extends Record { * @see org.apache.poi.hssf.record.ExtendedFormatRecord */ - public void setXFIndex(short xfi) + public void setXFIndex(int xfi) { field_4_xf_index = xfi; } - /** - * set the options bitfield - use the bitsetters instead - * @param options - the bitfield raw value - */ - - public void setOptions(short options) - { - field_5_options = options; - } // start options bitfield @@ -146,7 +143,7 @@ public final class ColumnInfoRecord extends Record { public void setHidden(boolean ishidden) { - field_5_options = hidden.setShortBoolean(field_5_options, ishidden); + field_5_options = hidden.setBoolean(field_5_options, ishidden); } /** @@ -155,9 +152,9 @@ public final class ColumnInfoRecord extends Record { * @param olevel -outline level for the cells */ - public void setOutlineLevel(short olevel) + public void setOutlineLevel(int olevel) { - field_5_options = outlevel.setShortValue(field_5_options, olevel); + field_5_options = outlevel.setValue(field_5_options, olevel); } /** @@ -168,7 +165,7 @@ public final class ColumnInfoRecord extends Record { public void setCollapsed(boolean iscollapsed) { - field_5_options = collapsed.setShortBoolean(field_5_options, + field_5_options = collapsed.setBoolean(field_5_options, iscollapsed); } @@ -179,7 +176,7 @@ public final class ColumnInfoRecord extends Record { * @return the first column index (0-based) */ - public short getFirstColumn() + public int getFirstColumn() { return field_1_first_col; } @@ -189,7 +186,7 @@ public final class ColumnInfoRecord extends Record { * @return the last column index (0-based) */ - public short getLastColumn() + public int getLastColumn() { return field_2_last_col; } @@ -199,7 +196,7 @@ public final class ColumnInfoRecord extends Record { * @return column width */ - public short getColumnWidth() + public int getColumnWidth() { return field_3_col_width; } @@ -210,21 +207,18 @@ public final class ColumnInfoRecord extends Record { * @see org.apache.poi.hssf.record.ExtendedFormatRecord */ - public short getXFIndex() + public int getXFIndex() { return field_4_xf_index; } - /** - * get the options bitfield - use the bitsetters instead - * @return the bitfield raw value - */ - - public short getOptions() - { + public int getOptions() { return field_5_options; } - + public void setOptions(int field_5_options) { + this.field_5_options = field_5_options; + } + // start options bitfield /** @@ -244,9 +238,9 @@ public final class ColumnInfoRecord extends Record { * @return outline level for the cells */ - public short getOutlineLevel() + public int getOutlineLevel() { - return outlevel.getShortValue(field_5_options); + return outlevel.getValue(field_5_options); } /** @@ -261,6 +255,31 @@ public final class ColumnInfoRecord extends Record { } // end options bitfield + + public boolean containsColumn(int columnIndex) { + return field_1_first_col <= columnIndex && columnIndex <= field_2_last_col; + } + public boolean isAdjacentBefore(ColumnInfoRecord other) { + return field_2_last_col == other.field_1_first_col - 1; + } + + /** + * @return true if the format, options and column width match + */ + public boolean formatMatches(ColumnInfoRecord other) { + if (field_4_xf_index != other.field_4_xf_index) { + return false; + } + if (field_5_options != other.field_5_options) { + return false; + } + if (field_3_col_width != other.field_3_col_width) { + return false; + } + return true; + } + + public short getSid() { return sid; @@ -269,13 +288,13 @@ public final class ColumnInfoRecord extends Record { public int serialize(int offset, byte [] data) { LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 12); - LittleEndian.putShort(data, 4 + offset, getFirstColumn()); - LittleEndian.putShort(data, 6 + offset, getLastColumn()); - LittleEndian.putShort(data, 8 + offset, getColumnWidth()); - LittleEndian.putShort(data, 10 + offset, getXFIndex()); - LittleEndian.putShort(data, 12 + offset, getOptions()); - LittleEndian.putShort(data, 14 + offset, field_6_reserved); + LittleEndian.putUShort(data, 2 + offset, 12); + LittleEndian.putUShort(data, 4 + offset, getFirstColumn()); + LittleEndian.putUShort(data, 6 + offset, getLastColumn()); + LittleEndian.putUShort(data, 8 + offset, getColumnWidth()); + LittleEndian.putUShort(data, 10 + offset, getXFIndex()); + LittleEndian.putUShort(data, 12 + offset, field_5_options); + LittleEndian.putUShort(data, 14 + offset, field_6_reserved); return getRecordSize(); } @@ -286,24 +305,19 @@ public final class ColumnInfoRecord extends Record { public String toString() { - StringBuffer buffer = new StringBuffer(); - - buffer.append("[COLINFO]\n"); - buffer.append("colfirst = ").append(getFirstColumn()) - .append("\n"); - buffer.append("collast = ").append(getLastColumn()) - .append("\n"); - buffer.append("colwidth = ").append(getColumnWidth()) - .append("\n"); - buffer.append("xfindex = ").append(getXFIndex()).append("\n"); - buffer.append("options = ").append(getOptions()).append("\n"); - buffer.append(" hidden = ").append(getHidden()).append("\n"); - buffer.append(" olevel = ").append(getOutlineLevel()) - .append("\n"); - buffer.append(" collapsed = ").append(getCollapsed()) - .append("\n"); - buffer.append("[/COLINFO]\n"); - return buffer.toString(); + StringBuffer sb = new StringBuffer(); + + sb.append("[COLINFO]\n"); + sb.append(" colfirst = ").append(getFirstColumn()).append("\n"); + sb.append(" collast = ").append(getLastColumn()).append("\n"); + sb.append(" colwidth = ").append(getColumnWidth()).append("\n"); + sb.append(" xfindex = ").append(getXFIndex()).append("\n"); + sb.append(" options = ").append(HexDump.shortToHex(field_5_options)).append("\n"); + sb.append(" hidden = ").append(getHidden()).append("\n"); + sb.append(" olevel = ").append(getOutlineLevel()).append("\n"); + sb.append(" collapsed= ").append(getCollapsed()).append("\n"); + sb.append("[/COLINFO]\n"); + return sb.toString(); } public Object clone() { diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java index b24d8c5b45..0f405bd111 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java @@ -18,18 +18,35 @@ package org.apache.poi.hssf.record.aggregates; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.record.ColumnInfoRecord; -import org.apache.poi.hssf.record.Record; /** * @author Glen Stampoultzis - * @version $Id$ */ public final class ColumnInfoRecordsAggregate extends RecordAggregate { + /** + * List of {@link ColumnInfoRecord}s assumed to be in order + */ private final List records; + + + private static final class CIRComparator implements Comparator { + public static final Comparator instance = new CIRComparator(); + private CIRComparator() { + // enforce singleton + } + public int compare(Object a, Object b) { + return compareColInfos((ColumnInfoRecord)a, (ColumnInfoRecord)b); + } + public static int compareColInfos(ColumnInfoRecord a, ColumnInfoRecord b) { + return a.getFirstColumn()-b.getFirstColumn(); + } + } /** * Creates an empty aggregate @@ -37,486 +54,470 @@ public final class ColumnInfoRecordsAggregate extends RecordAggregate { public ColumnInfoRecordsAggregate() { records = new ArrayList(); } - public ColumnInfoRecordsAggregate(RecordStream rs) { - this(); - - while(rs.peekNextClass() == ColumnInfoRecord.class) { - records.add(rs.getNext()); - } - if (records.size() < 1) { - throw new RuntimeException("No column info records found"); - } - } - - /** - * Performs a deep clone of the record - */ - public Object clone() - { - ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate(); - for (int k = 0; k < records.size(); k++) - { - ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k); - ci=(ColumnInfoRecord) ci.clone(); - rec.insertColumn( ci ); - } - return rec; - } - - /** - * Inserts a column into the aggregate (at the end of the list). - */ - public void insertColumn( ColumnInfoRecord col ) - { - records.add( col ); - } - - /** - * Inserts a column into the aggregate (at the position specified - * by idx. - */ - public void insertColumn( int idx, ColumnInfoRecord col ) - { - records.add( idx, col ); - } - - public int getNumColumns( ) - { - return records.size(); - } - - public void visitContainedRecords(RecordVisitor rv) { - int nItems = records.size(); - if (nItems < 1) { - return; - } - for(int i=0; i