diff options
author | Josh Micich <josh@apache.org> | 2008-05-23 03:56:31 +0000 |
---|---|---|
committer | Josh Micich <josh@apache.org> | 2008-05-23 03:56:31 +0000 |
commit | 375a18e8a3426850e0df84805ab4a40ba8f9e288 (patch) | |
tree | 67809e655d5bdce3c86f3462335339685e62d72d /src/java | |
parent | b76ec04798a541d520d6ff0707c7fe650c44643d (diff) | |
download | poi-375a18e8a3426850e0df84805ab4a40ba8f9e288.tar.gz poi-375a18e8a3426850e0df84805ab4a40ba8f9e288.zip |
Fix for 45066 - sheet encoding size mismatch problems
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@659403 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r-- | src/java/org/apache/poi/hssf/model/Sheet.java | 98 | ||||
-rw-r--r-- | src/java/org/apache/poi/hssf/record/DBCellRecord.java | 24 | ||||
-rw-r--r-- | src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java | 184 |
3 files changed, 130 insertions, 176 deletions
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 45090e85cf..871ecc100f 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -96,8 +96,8 @@ public final class Sheet implements Model { protected List condFormatting = new ArrayList(); /** Add an UncalcedRecord if not true indicating formulas have not been calculated */ - protected boolean uncalced = false; - + protected boolean _isUncalced = false; + public static final byte PANE_LOWER_RIGHT = (byte)0; public static final byte PANE_UPPER_RIGHT = (byte)1; public static final byte PANE_LOWER_LEFT = (byte)2; @@ -162,7 +162,7 @@ public final class Sheet implements Model { } } else if (rec.getSid() == UncalcedRecord.sid) { - retval.uncalced = true; + retval._isUncalced = true; } else if (rec.getSid() == DimensionsRecord.sid) { @@ -329,16 +329,8 @@ public final class Sheet implements Model { } } retval.records = records; -// if (retval.rows == null) -// { -// retval.rows = new RowRecordsAggregate(); -// } retval.checkCells(); retval.checkRows(); -// if (retval.cells == null) -// { -// retval.cells = new ValueRecordsAggregate(); -// } if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); return retval; @@ -816,17 +808,17 @@ public final class Sheet implements Model { // Once the rows have been found in the list of records, start // writing out the blocked row information. This includes the DBCell references if (record instanceof RowRecordsAggregate) { - pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length; + pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); } else if (record instanceof ValueRecordsAggregate) { //Do nothing here. The records were serialized during the RowRecordAggregate block serialization } else { - pos += record.serialize(pos, data ); // rec.length; + pos += record.serialize(pos, data ); } // If the BOF record was just serialized then add the IndexRecord if (record.getSid() == BOFRecord.sid) { // Add an optional UncalcedRecord - if (uncalced) { + if (_isUncalced) { UncalcedRecord rec = new UncalcedRecord(); pos += rec.serialize(pos, data); } @@ -837,31 +829,10 @@ public final class Sheet implements Model { pos += serializeIndexRecord(k, pos, data); } } - - //// uncomment to test record sizes //// -// System.out.println( record.getClass().getName() ); -// byte[] data2 = new byte[record.getRecordSize()]; -// record.serialize(0, data2 ); // rec.length; -// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4 -// && record instanceof RowRecordsAggregate == false -// && record instanceof ValueRecordsAggregate == false -// && record instanceof EscherAggregate == false) -// { -// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records."); -// } - -//asd: int len = record.serialize(pos + offset, data ); - - ///// DEBUG BEGIN ///// -//asd: if (len != record.getRecordSize()) -//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass()); - ///// DEBUG END ///// - -//asd: pos += len; // rec.length; - } - if (log.check( POILogger.DEBUG )) + if (log.check( POILogger.DEBUG )) { log.log(POILogger.DEBUG, "Sheet.serialize returning "); + } return pos-offset; } @@ -875,10 +846,17 @@ public final class Sheet implements Model { for (int j = BOFRecordIndex+1; j < records.size(); j++) { Record tmpRec = (( Record ) records.get(j)); - if (tmpRec instanceof RowRecordsAggregate) - break; + if (tmpRec instanceof UncalcedRecord) { + continue; + } + if (tmpRec instanceof RowRecordsAggregate) { + break; + } sheetRecSize+= tmpRec.getRecordSize(); } + if (_isUncalced) { + sheetRecSize += UncalcedRecord.getStaticRecordSize(); + } //Add the references to the DBCells in the IndexRecord (one for each block) int blockCount = rows.getRowBlockCount(); //Calculate the size of this IndexRecord @@ -2017,31 +1995,33 @@ public final class Sheet implements Model { { int retval = 0; - for ( int k = 0; k < records.size(); k++ ) - { - retval += ( (Record) records.get( k ) ).getRecordSize(); + for ( int k = 0; k < records.size(); k++) { + Record record = (Record) records.get(k); + if (record instanceof UncalcedRecord) { + // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set + continue; + } + retval += record.getRecordSize(); } - //Add space for the IndexRecord if (rows != null) { - final int blocks = rows.getRowBlockCount(); - retval += IndexRecord.getRecordSizeForBlockCount(blocks); - - //Add space for the DBCell records - //Once DBCell per block. - //8 bytes per DBCell (non variable section) - //2 bytes per row reference - retval += (8 * blocks); - for (Iterator itr = rows.getIterator(); itr.hasNext();) { - RowRecord row = (RowRecord)itr.next(); - if (cells != null && cells.rowHasCells(row.getRowNumber())) - retval += 2; + // Add space for the IndexRecord and DBCell records + final int nBlocks = rows.getRowBlockCount(); + int nRows = 0; + if (cells != null) { + for (Iterator itr = rows.getIterator(); itr.hasNext();) { + RowRecord row = (RowRecord)itr.next(); + if (cells.rowHasCells(row.getRowNumber())) { + nRows++; + } + } } + retval += IndexRecord.getRecordSizeForBlockCount(nBlocks); + retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows); } // Add space for UncalcedRecord - if (uncalced) { + if (_isUncalced) { retval += UncalcedRecord.getStaticRecordSize(); } - return retval; } @@ -2518,13 +2498,13 @@ public final class Sheet implements Model { * @return whether an uncalced record must be inserted or not at generation */ public boolean getUncalced() { - return uncalced; + return _isUncalced; } /** * @param uncalced whether an uncalced record must be inserted or not at generation */ public void setUncalced(boolean uncalced) { - this.uncalced = uncalced; + this._isUncalced = uncalced; } /** diff --git a/src/java/org/apache/poi/hssf/record/DBCellRecord.java b/src/java/org/apache/poi/hssf/record/DBCellRecord.java index caeb333a52..1da6b82c73 100644 --- a/src/java/org/apache/poi/hssf/record/DBCellRecord.java +++ b/src/java/org/apache/poi/hssf/record/DBCellRecord.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -15,7 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record; @@ -29,10 +27,7 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height * @version 2.0-pre */ - -public class DBCellRecord - extends Record -{ +public final class DBCellRecord extends Record { public final static int BLOCK_SIZE = 32; public final static short sid = 0xd7; private int field_1_row_offset; @@ -46,7 +41,6 @@ public class DBCellRecord * Constructs a DBCellRecord and sets its fields appropriately * @param in the RecordInputstream to read the record from */ - public DBCellRecord(RecordInputStream in) { super(in); @@ -78,7 +72,6 @@ public class DBCellRecord * * @param offset offset to the start of the first cell in the next DBCell block */ - public void setRowOffset(int offset) { field_1_row_offset = offset; @@ -108,7 +101,6 @@ public class DBCellRecord * * @return rowoffset to the start of the first cell in the next DBCell block */ - public int getRowOffset() { return field_1_row_offset; @@ -120,7 +112,6 @@ public class DBCellRecord * @param index of the cell offset to retrieve * @return celloffset from the celloffset array */ - public short getCellOffsetAt(int index) { return field_2_cell_offsets[ index ]; @@ -131,7 +122,6 @@ public class DBCellRecord * * @return number of cell offsets */ - public int getNumCellOffsets() { return field_2_cell_offsets.length; @@ -175,9 +165,15 @@ public class DBCellRecord return 8 + (getNumCellOffsets() * 2); } - /** Returns the size of a DBCellRecord when it needs to reference a certain number of rows*/ - public static int getRecordSizeForRows(int rows) { - return 8 + (rows * 2); + /** + * @returns the size of the group of <tt>DBCellRecord</tt>s needed to encode + * the specified number of blocks and rows + */ + public static int calculateSizeOfRecords(int nBlocks, int nRows) { + // One DBCell per block. + // 8 bytes per DBCell (non variable section) + // 2 bytes per row reference + return nBlocks * 8 + nRows * 2; } public short getSid() diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index 896ef19c14..98db9e037b 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -15,12 +15,6 @@ limitations under the License. ==================================================================== */ - -/* - * HSSFWorkbook.java - * - * Created on September 30, 2001, 3:37 PM - */ package org.apache.poi.hssf.usermodel; import org.apache.poi.POIDocument; @@ -64,7 +58,6 @@ import java.util.Stack; * @author Shawn Laubach (slaubach at apache dot org) * @version 2.0-pre */ - public class HSSFWorkbook extends POIDocument { private static final int DEBUG = POILogger.DEBUG; @@ -88,7 +81,7 @@ public class HSSFWorkbook extends POIDocument * this holds the HSSFSheet objects attached to this workbook */ - protected ArrayList sheets; + protected List _sheets; /** * this holds the HSSFName objects attached to this workbook @@ -142,7 +135,7 @@ public class HSSFWorkbook extends POIDocument { super(null, null); workbook = book; - sheets = new ArrayList( INITIAL_CAPACITY ); + _sheets = new ArrayList( INITIAL_CAPACITY ); names = new ArrayList( INITIAL_CAPACITY ); } @@ -233,7 +226,7 @@ public class HSSFWorkbook extends POIDocument this.directory = null; } - sheets = new ArrayList(INITIAL_CAPACITY); + _sheets = new ArrayList(INITIAL_CAPACITY); names = new ArrayList(INITIAL_CAPACITY); // Grab the data from the workbook stream, however @@ -263,7 +256,7 @@ public class HSSFWorkbook extends POIDocument HSSFSheet hsheet = new HSSFSheet(this, sheet); - sheets.add(hsheet); + _sheets.add(hsheet); // workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size()); } @@ -361,12 +354,12 @@ public class HSSFWorkbook extends POIDocument */ public void setSheetOrder(String sheetname, int pos ) { - sheets.add(pos,sheets.remove(getSheetIndex(sheetname))); + _sheets.add(pos,_sheets.remove(getSheetIndex(sheetname))); workbook.setSheetOrder(sheetname, pos); } private void validateSheetIndex(int index) { - int lastSheetIx = sheets.size() - 1; + int lastSheetIx = _sheets.size() - 1; if (index < 0 || index > lastSheetIx) { throw new IllegalArgumentException("Sheet index (" + index +") is out of range (0.." + lastSheetIx + ")"); @@ -380,7 +373,7 @@ public class HSSFWorkbook extends POIDocument public void setSelectedTab(int index) { validateSheetIndex(index); - int nSheets = sheets.size(); + int nSheets = _sheets.size(); for (int i=0; i<nSheets; i++) { getSheetAt(i).setSelected(i == index); } @@ -398,7 +391,7 @@ public class HSSFWorkbook extends POIDocument for (int i = 0; i < indexes.length; i++) { validateSheetIndex(indexes[i]); } - int nSheets = sheets.size(); + int nSheets = _sheets.size(); for (int i=0; i<nSheets; i++) { boolean bSelect = false; for (int j = 0; j < indexes.length; j++) { @@ -420,7 +413,7 @@ public class HSSFWorkbook extends POIDocument public void setActiveSheet(int index) { validateSheetIndex(index); - int nSheets = sheets.size(); + int nSheets = _sheets.size(); for (int i=0; i<nSheets; i++) { getSheetAt(i).setActive(i == index); } @@ -492,19 +485,15 @@ public class HSSFWorkbook extends POIDocument * set the sheet name. * Will throw IllegalArgumentException if the name is greater than 31 chars * or contains /\?*[] - * @param sheet number (0 based) + * @param sheetIx number (0 based) */ - public void setSheetName(int sheet, String name) + public void setSheetName(int sheetIx, String name) { - if (workbook.doesContainsSheetName( name, sheet )) + if (workbook.doesContainsSheetName( name, sheetIx )) { throw new IllegalArgumentException( "The workbook already contains a sheet with this name" ); - - if (sheet > (sheets.size() - 1)) - { - throw new RuntimeException("Sheet out of bounds"); } - - workbook.setSheetName( sheet, name); + validateSheetIndex(sheetIx); + workbook.setSheetName(sheetIx, name); } @@ -516,15 +505,12 @@ public class HSSFWorkbook extends POIDocument * or contains /\?*[] * @param sheet number (0 based) */ - public void setSheetName( int sheet, String name, short encoding ) + public void setSheetName(int sheetIx, String name, short encoding) { - if (workbook.doesContainsSheetName( name, sheet )) + if (workbook.doesContainsSheetName( name, sheetIx )) { throw new IllegalArgumentException( "The workbook already contains a sheet with this name" ); - - if (sheet > (sheets.size() - 1)) - { - throw new RuntimeException("Sheet out of bounds"); } + validateSheetIndex(sheetIx); switch ( encoding ) { case ENCODING_COMPRESSED_UNICODE: @@ -536,51 +522,39 @@ public class HSSFWorkbook extends POIDocument throw new RuntimeException( "Unsupported encoding" ); } - workbook.setSheetName( sheet, name, encoding ); + workbook.setSheetName( sheetIx, name, encoding ); } /** * get the sheet name - * @param sheet Number + * @param sheetIx Number * @return Sheet name */ - - public String getSheetName(int sheet) + public String getSheetName(int sheetIx) { - if (sheet > (sheets.size() - 1)) - { - throw new RuntimeException("Sheet out of bounds"); - } - return workbook.getSheetName(sheet); + validateSheetIndex(sheetIx); + return workbook.getSheetName(sheetIx); } /** * check whether a sheet is hidden - * @param sheet Number + * @param sheetIx Number * @return True if sheet is hidden */ - - public boolean isSheetHidden(int sheet) { - if (sheet > (sheets.size() - 1)) - { - throw new RuntimeException("Sheet out of bounds"); - } - return workbook.isSheetHidden(sheet); + public boolean isSheetHidden(int sheetIx) { + validateSheetIndex(sheetIx); + return workbook.isSheetHidden(sheetIx); } /** * Hide or unhide a sheet * - * @param sheetnum The sheet number + * @param sheetIx The sheet index * @param hidden True to mark the sheet as hidden, false otherwise */ - - public void setSheetHidden(int sheet, boolean hidden) { - if (sheet > (sheets.size() - 1)) - { - throw new RuntimeException("Sheet out of bounds"); - } - workbook.setSheetHidden(sheet,hidden); + public void setSheetHidden(int sheetIx, boolean hidden) { + validateSheetIndex(sheetIx); + workbook.setSheetHidden(sheetIx, hidden); } /* @@ -602,12 +576,12 @@ public class HSSFWorkbook extends POIDocument /** Returns the index of the given sheet * @param sheet the sheet to look up - * @return index of the sheet (0 based) + * @return index of the sheet (0 based). <tt>-1</tt> if not found */ public int getSheetIndex(HSSFSheet sheet) { - for(int i=0; i<sheets.size(); i++) { - if(sheets.get(i) == sheet) { + for(int i=0; i<_sheets.size(); i++) { + if(_sheets.get(i) == sheet) { return i; } } @@ -636,9 +610,9 @@ public class HSSFWorkbook extends POIDocument { HSSFSheet sheet = new HSSFSheet(this); - sheets.add(sheet); - workbook.setSheetName(sheets.size() - 1, "Sheet" + (sheets.size() - 1)); - boolean isOnlySheet = sheets.size() == 1; + _sheets.add(sheet); + workbook.setSheetName(_sheets.size() - 1, "Sheet" + (_sheets.size() - 1)); + boolean isOnlySheet = _sheets.size() == 1; sheet.setSelected(isOnlySheet); sheet.setActive(isOnlySheet); return sheet; @@ -652,13 +626,13 @@ public class HSSFWorkbook extends POIDocument public HSSFSheet cloneSheet(int sheetNum) { validateSheetIndex(sheetNum); - HSSFSheet srcSheet = (HSSFSheet) sheets.get(sheetNum); + HSSFSheet srcSheet = (HSSFSheet) _sheets.get(sheetNum); String srcName = workbook.getSheetName(sheetNum); HSSFSheet clonedSheet = srcSheet.cloneSheet(this); clonedSheet.setSelected(false); clonedSheet.setActive(false); - sheets.add(clonedSheet); + _sheets.add(clonedSheet); int i = 1; while (true) { // Try and find the next sheet name that is unique @@ -672,7 +646,7 @@ public class HSSFWorkbook extends POIDocument //If the sheet name is unique, then set it otherwise move on to the next number. if (workbook.getSheetIndex(name) == -1) { - workbook.setSheetName(sheets.size()-1, name); + workbook.setSheetName(_sheets.size()-1, name); break; } } @@ -693,14 +667,14 @@ public class HSSFWorkbook extends POIDocument public HSSFSheet createSheet(String sheetname) { - if (workbook.doesContainsSheetName( sheetname, sheets.size() )) + if (workbook.doesContainsSheetName( sheetname, _sheets.size() )) throw new IllegalArgumentException( "The workbook already contains a sheet of this name" ); HSSFSheet sheet = new HSSFSheet(this); - sheets.add(sheet); - workbook.setSheetName(sheets.size() - 1, sheetname); - boolean isOnlySheet = sheets.size() == 1; + _sheets.add(sheet); + workbook.setSheetName(_sheets.size() - 1, sheetname); + boolean isOnlySheet = _sheets.size() == 1; sheet.setSelected(isOnlySheet); sheet.setActive(isOnlySheet); return sheet; @@ -713,9 +687,14 @@ public class HSSFWorkbook extends POIDocument public int getNumberOfSheets() { - return sheets.size(); + return _sheets.size(); } + private HSSFSheet[] getSheets() { + HSSFSheet[] result = new HSSFSheet[_sheets.size()]; + _sheets.toArray(result); + return result; + } /** * Get the HSSFSheet object at the given index. * @param index of the sheet number (0-based physical & logical) @@ -724,7 +703,7 @@ public class HSSFWorkbook extends POIDocument public HSSFSheet getSheetAt(int index) { - return (HSSFSheet) sheets.get(index); + return (HSSFSheet) _sheets.get(index); } /** @@ -737,13 +716,13 @@ public class HSSFWorkbook extends POIDocument { HSSFSheet retval = null; - for (int k = 0; k < sheets.size(); k++) + for (int k = 0; k < _sheets.size(); k++) { String sheetname = workbook.getSheetName(k); if (sheetname.equalsIgnoreCase(name)) { - retval = (HSSFSheet) sheets.get(k); + retval = (HSSFSheet) _sheets.get(k); } } return retval; @@ -772,11 +751,11 @@ public class HSSFWorkbook extends POIDocument boolean wasActive = getSheetAt(index).isActive(); boolean wasSelected = getSheetAt(index).isSelected(); - sheets.remove(index); + _sheets.remove(index); workbook.removeSheet(index); // set the remaining active/selected sheet - int nSheets = sheets.size(); + int nSheets = _sheets.size(); if (nSheets < 1) { // nothing more to do if there are no sheets left return; @@ -1152,48 +1131,47 @@ public class HSSFWorkbook extends POIDocument public byte[] getBytes() { - if (log.check( POILogger.DEBUG )) + if (log.check( POILogger.DEBUG )) { log.log(DEBUG, "HSSFWorkbook.getBytes()"); + } + + HSSFSheet[] sheets = getSheets(); + int nSheets = sheets.length; // before getting the workbook size we must tell the sheets that // serialization is about to occur. - for (int k = 0; k < sheets.size(); k++) - ((HSSFSheet) sheets.get(k)).getSheet().preSerialize(); - - int wbsize = workbook.getSize(); + for (int i = 0; i < nSheets; i++) { + sheets[i].getSheet().preSerialize(); + } - // log.debug("REMOVEME: old sizing method "+workbook.serialize().length); - // ArrayList sheetbytes = new ArrayList(sheets.size()); - int totalsize = wbsize; + int totalsize = workbook.getSize(); - for (int k = 0; k < sheets.size(); k++) - { + // pre-calculate all the sheet sizes and set BOF indexes + int[] estimatedSheetSizes = new int[nSheets]; + for (int k = 0; k < nSheets; k++) { workbook.setSheetBof(k, totalsize); - totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize(); + int sheetSize = sheets[k].getSheet().getSize(); + estimatedSheetSizes[k] = sheetSize; + totalsize += sheetSize; } -/* if (totalsize < 4096) - { - totalsize = 4096; - }*/ byte[] retval = new byte[totalsize]; int pos = workbook.serialize(0, retval); - // System.arraycopy(wb, 0, retval, 0, wb.length); - for (int k = 0; k < sheets.size(); k++) - { - - // byte[] sb = (byte[])sheetbytes.get(k); - // System.arraycopy(sb, 0, retval, pos, sb.length); - int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos, - retval); - pos += len; // sb.length; + for (int k = 0; k < nSheets; k++) { + int serializedSize = sheets[k].getSheet().serialize(pos, retval); + if (serializedSize != estimatedSheetSizes[k]) { + // Wrong offset values have been passed in the call to setSheetBof() above. + // For books with more than one sheet, this discrepancy would cause excel + // to report errors and loose data while reading the workbook + throw new IllegalStateException("Actual serialized sheet size (" + serializedSize + + ") differs from pre-calculated size (" + estimatedSheetSizes[k] + + ") for sheet (" + k + ")"); + // TODO - add similar sanity check to ensure that Sheet.serializeIndexRecord() does not write mis-aligned offsets either + } + pos += serializedSize; } -/* for (int k = pos; k < totalsize; k++) - { - retval[k] = 0; - }*/ return retval; } |