2002-01-30 21:22:28 -05:00
|
|
|
|
|
|
|
/* ====================================================================
|
2004-04-09 09:05:39 -04:00
|
|
|
Copyright 2002-2004 Apache Software Foundation
|
|
|
|
|
|
|
|
Licensed 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.
|
|
|
|
==================================================================== */
|
2004-08-23 04:52:54 -04:00
|
|
|
|
2002-01-30 21:22:28 -05:00
|
|
|
|
|
|
|
package org.apache.poi.hssf.record.aggregates;
|
|
|
|
|
2002-08-21 07:56:49 -04:00
|
|
|
import org.apache.poi.hssf.record.*;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
|
|
|
|
2004-10-06 23:37:16 -04:00
|
|
|
|
2002-01-30 21:22:28 -05:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Aggregate value records together. Things are easier to handle that way.
|
|
|
|
*
|
2004-08-23 04:52:54 -04:00
|
|
|
* @author andy
|
2002-02-10 23:23:11 -05:00
|
|
|
* @author Glen Stampoultzis (glens at apache.org)
|
2002-09-04 20:26:28 -04:00
|
|
|
* @author Jason Height (jheight at chariot dot net dot au)
|
2002-01-30 21:22:28 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
public class ValueRecordsAggregate
|
|
|
|
extends Record
|
|
|
|
{
|
|
|
|
public final static short sid = -1000;
|
2004-08-23 04:52:54 -04:00
|
|
|
int firstcell = -1;
|
|
|
|
int lastcell = -1;
|
2006-01-03 02:24:01 -05:00
|
|
|
CellValueRecordInterface[][] records;
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/** Creates a new instance of ValueRecordsAggregate */
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public ValueRecordsAggregate()
|
|
|
|
{
|
2006-01-03 02:24:01 -05:00
|
|
|
records = new CellValueRecordInterface[30][]; // We start with 30 Rows.
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
2006-01-03 02:24:01 -05:00
|
|
|
public void insertCell(CellValueRecordInterface cell) {
|
|
|
|
short column = cell.getColumn();
|
|
|
|
int row = cell.getRow();
|
|
|
|
if (row >= records.length) {
|
|
|
|
CellValueRecordInterface[][] oldRecords = records;
|
|
|
|
int newSize = oldRecords.length * 2;
|
|
|
|
if(newSize<row+1) newSize=row+1;
|
|
|
|
records = new CellValueRecordInterface[newSize][];
|
|
|
|
System.arraycopy(oldRecords, 0, records, 0, oldRecords.length);
|
|
|
|
}
|
|
|
|
CellValueRecordInterface[] rowCells = records[row];
|
|
|
|
if (rowCells == null) {
|
|
|
|
int newSize = column + 1;
|
|
|
|
if(newSize<10) newSize=10;
|
|
|
|
rowCells = new CellValueRecordInterface[newSize];
|
|
|
|
records[row] = rowCells;
|
|
|
|
}
|
|
|
|
if (column >= rowCells.length) {
|
|
|
|
CellValueRecordInterface[] oldRowCells = rowCells;
|
|
|
|
int newSize = oldRowCells.length * 2;
|
|
|
|
if(newSize<column+1) newSize=column+1;
|
|
|
|
// if(newSize>257) newSize=257; // activate?
|
|
|
|
rowCells = new CellValueRecordInterface[newSize];
|
|
|
|
System.arraycopy(oldRowCells, 0, rowCells, 0, oldRowCells.length);
|
|
|
|
records[row] = rowCells;
|
|
|
|
}
|
|
|
|
rowCells[column] = cell;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2006-01-03 02:24:01 -05:00
|
|
|
if ((column < firstcell) || (firstcell == -1)) {
|
|
|
|
firstcell = column;
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
2006-01-03 02:24:01 -05:00
|
|
|
if ((column > lastcell) || (lastcell == -1)) {
|
|
|
|
lastcell = column;
|
|
|
|
}
|
|
|
|
}
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public void removeCell(CellValueRecordInterface cell)
|
|
|
|
{
|
2006-01-03 02:24:01 -05:00
|
|
|
if (cell != null) {
|
|
|
|
short column = cell.getColumn();
|
|
|
|
int row = cell.getRow();
|
|
|
|
if(row>=records.length) return;
|
|
|
|
CellValueRecordInterface[] rowCells=records[row];
|
|
|
|
if(rowCells==null) return;
|
|
|
|
if(column>=rowCells.length) return;
|
|
|
|
rowCells[column]=null;
|
|
|
|
}
|
2002-01-30 21:22:28 -05:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public int getPhysicalNumberOfCells()
|
|
|
|
{
|
2006-01-03 02:24:01 -05:00
|
|
|
int count=0;
|
|
|
|
for(int r=0;r<records.length;r++) {
|
|
|
|
CellValueRecordInterface[] rowCells=records[r];
|
|
|
|
if (rowCells != null)
|
|
|
|
for(short c=0;c<rowCells.length;c++) {
|
|
|
|
if(rowCells[c]!=null) count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
2003-09-17 22:10:50 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public int getFirstCellNum()
|
2004-04-18 09:02:48 -04:00
|
|
|
{
|
2004-08-23 04:52:54 -04:00
|
|
|
return firstcell;
|
2003-09-17 22:10:50 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public int getLastCellNum()
|
2003-09-17 22:10:50 -04:00
|
|
|
{
|
2004-08-23 04:52:54 -04:00
|
|
|
return lastcell;
|
2003-09-17 22:10:50 -04:00
|
|
|
}
|
|
|
|
|
2002-01-30 21:22:28 -05:00
|
|
|
public int construct(int offset, List records)
|
|
|
|
{
|
2004-08-23 04:52:54 -04:00
|
|
|
int k = 0;
|
2002-01-30 21:22:28 -05:00
|
|
|
|
2002-08-21 07:56:49 -04:00
|
|
|
FormulaRecordAggregate lastFormulaAggregate = null;
|
2006-07-27 10:15:11 -04:00
|
|
|
|
|
|
|
List sharedFormulas = new java.util.ArrayList();
|
2002-08-21 07:56:49 -04:00
|
|
|
|
2002-01-30 21:22:28 -05:00
|
|
|
for (k = offset; k < records.size(); k++)
|
|
|
|
{
|
|
|
|
Record rec = ( Record ) records.get(k);
|
|
|
|
|
2002-08-21 07:56:49 -04:00
|
|
|
if (rec instanceof StringRecord == false && !rec.isInValueSection() && !(rec instanceof UnknownRecord))
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
|
|
|
break;
|
2006-07-27 10:15:11 -04:00
|
|
|
} else if (rec instanceof SharedFormulaRecord) {
|
|
|
|
sharedFormulas.add(rec);
|
|
|
|
} else if (rec instanceof FormulaRecord)
|
2002-08-21 07:56:49 -04:00
|
|
|
{
|
2006-07-25 10:30:34 -04:00
|
|
|
FormulaRecord formula = (FormulaRecord)rec;
|
|
|
|
if (formula.isSharedFormula()) {
|
2006-07-27 10:15:11 -04:00
|
|
|
Record nextRecord = (Record) records.get(k + 1);
|
|
|
|
if (nextRecord instanceof SharedFormulaRecord) {
|
|
|
|
sharedFormulas.add(nextRecord);
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
//traverse the list of shared formulas in reverse order, and try to find the correct one
|
|
|
|
//for us
|
|
|
|
boolean found = false;
|
|
|
|
for (int i=sharedFormulas.size()-1;i>=0;i--) {
|
|
|
|
SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
|
|
|
|
if (shrd.isFormulaInShared(formula)) {
|
|
|
|
shrd.convertSharedFormulaRecord(formula);
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
throw new RecordFormatException("Could not find appropriate shared formula");
|
|
|
|
/*
|
|
|
|
|
2006-07-25 10:30:34 -04:00
|
|
|
if ((lastSharedFormula != null) && (lastSharedFormula.isFormulaInShared(formula))) {
|
|
|
|
//Convert this Formula Record from a shared formula to a real formula
|
|
|
|
lastSharedFormula.convertSharedFormulaRecord(formula);
|
2006-07-27 10:15:11 -04:00
|
|
|
} else {
|
2006-07-25 10:30:34 -04:00
|
|
|
if (nextRecord instanceof SharedFormulaRecord) {
|
2006-07-27 10:15:11 -04:00
|
|
|
//Handle the SharedFormulaRecord and move on.
|
2006-07-25 10:30:34 -04:00
|
|
|
k++;
|
|
|
|
lastSharedFormula = (SharedFormulaRecord) nextRecord;
|
|
|
|
|
|
|
|
//Convert this Formula Record from a shared formula to a real formula
|
|
|
|
lastSharedFormula.convertSharedFormulaRecord(formula);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw new RuntimeException(
|
|
|
|
"Shared formula bit set but next record is not a Shared Formula??");
|
2006-07-27 10:15:11 -04:00
|
|
|
}*/
|
2006-07-25 10:30:34 -04:00
|
|
|
}
|
|
|
|
|
2006-07-27 10:15:11 -04:00
|
|
|
lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
|
|
|
|
insertCell( lastFormulaAggregate );
|
2002-08-21 07:56:49 -04:00
|
|
|
}
|
|
|
|
else if (rec instanceof StringRecord)
|
|
|
|
{
|
|
|
|
lastFormulaAggregate.setStringRecord((StringRecord)rec);
|
2004-08-23 04:52:54 -04:00
|
|
|
}
|
2002-08-21 07:56:49 -04:00
|
|
|
else if (rec.isValue())
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
|
|
|
insertCell(( CellValueRecordInterface ) rec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/**
|
|
|
|
* called by the class that is responsible for writing this sucker.
|
|
|
|
* Subclasses should implement this so that their data is passed back in a
|
|
|
|
* byte array.
|
|
|
|
*
|
|
|
|
* @param offset to begin writing at
|
|
|
|
* @param data byte array containing instance data
|
|
|
|
* @return number of bytes written
|
|
|
|
*/
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public int serialize(int offset, byte [] data)
|
2004-04-18 09:02:48 -04:00
|
|
|
{
|
2004-10-06 23:37:16 -04:00
|
|
|
throw new RuntimeException("This method shouldnt be called. ValueRecordsAggregate.serializeCellRow() should be called from RowRecordsAggregate.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Tallies a count of the size of the cell records
|
|
|
|
* that are attached to the rows in the range specified.
|
|
|
|
*/
|
|
|
|
public int getRowCellBlockSize(int startRow, int endRow) {
|
2006-01-03 02:24:01 -05:00
|
|
|
MyIterator itr = new MyIterator(startRow, endRow);
|
2004-10-06 23:37:16 -04:00
|
|
|
int size = 0;
|
|
|
|
while (itr.hasNext()) {
|
|
|
|
CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
|
|
|
|
int row = cell.getRow();
|
|
|
|
if (row > endRow)
|
|
|
|
break;
|
|
|
|
if ((row >=startRow) && (row <= endRow))
|
|
|
|
size += ((Record)cell).getRecordSize();
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns true if the row has cells attached to it */
|
|
|
|
public boolean rowHasCells(int row) {
|
2006-01-05 02:29:36 -05:00
|
|
|
if (row > records.length)
|
|
|
|
return false;
|
2006-01-03 02:24:01 -05:00
|
|
|
CellValueRecordInterface[] rowCells=records[row];
|
|
|
|
if(rowCells==null) return false;
|
|
|
|
for(int col=0;col<rowCells.length;col++) {
|
|
|
|
if(rowCells[col]!=null) return true;
|
|
|
|
}
|
|
|
|
return false;
|
2004-10-06 23:37:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Serializes the cells that are allocated to a certain row range*/
|
|
|
|
public int serializeCellRow(final int row, int offset, byte [] data)
|
|
|
|
{
|
2006-01-03 02:24:01 -05:00
|
|
|
MyIterator itr = new MyIterator(row, row);
|
2004-08-23 04:52:54 -04:00
|
|
|
int pos = offset;
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
while (itr.hasNext())
|
2004-04-18 09:02:48 -04:00
|
|
|
{
|
2004-10-06 23:37:16 -04:00
|
|
|
CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
|
|
|
|
if (cell.getRow() != row)
|
|
|
|
break;
|
|
|
|
pos += (( Record ) cell).serialize(pos, data);
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
2004-08-23 04:52:54 -04:00
|
|
|
return pos - offset;
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
2004-10-06 23:37:16 -04:00
|
|
|
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/**
|
|
|
|
* called by the constructor, should set class level fields. Should throw
|
|
|
|
* runtime exception for bad/icomplete data.
|
|
|
|
*
|
|
|
|
* @param data raw data
|
|
|
|
* @param size size of data
|
|
|
|
* @param offset of the record's data (provided a big array of the file)
|
|
|
|
*/
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2005-08-18 03:06:44 -04:00
|
|
|
protected void fillFields(RecordInputStream in)
|
2002-01-30 21:22:28 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2004-04-18 09:02:48 -04:00
|
|
|
/**
|
2004-08-23 04:52:54 -04:00
|
|
|
* called by constructor, should throw runtime exception in the event of a
|
|
|
|
* record passed with a differing ID.
|
2004-04-18 09:02:48 -04:00
|
|
|
*
|
2004-08-23 04:52:54 -04:00
|
|
|
* @param id alleged id for this record
|
2004-04-18 09:02:48 -04:00
|
|
|
*/
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
protected void validateSid(short id)
|
|
|
|
{
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/**
|
|
|
|
* return the non static version of the id for this record.
|
|
|
|
*/
|
2003-07-18 22:48:17 -04:00
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public short getSid()
|
|
|
|
{
|
|
|
|
return sid;
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public int getRecordSize() {
|
|
|
|
|
|
|
|
int size = 0;
|
2006-01-03 02:24:01 -05:00
|
|
|
Iterator irecs = this.getIterator();
|
2004-08-23 04:52:54 -04:00
|
|
|
|
|
|
|
while (irecs.hasNext()) {
|
|
|
|
size += (( Record ) irecs.next()).getRecordSize();
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
return size;
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
public Iterator getIterator()
|
|
|
|
{
|
2006-01-03 02:24:01 -05:00
|
|
|
return new MyIterator();
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
|
|
|
|
2004-08-23 04:52:54 -04:00
|
|
|
/** Performs a deep clone of the record*/
|
|
|
|
public Object clone() {
|
|
|
|
ValueRecordsAggregate rec = new ValueRecordsAggregate();
|
|
|
|
for (Iterator valIter = getIterator(); valIter.hasNext();) {
|
|
|
|
CellValueRecordInterface val = (CellValueRecordInterface)((CellValueRecordInterface)valIter.next()).clone();
|
|
|
|
rec.insertCell(val);
|
|
|
|
}
|
|
|
|
return rec;
|
2003-07-18 22:48:17 -04:00
|
|
|
}
|
2006-01-03 02:24:01 -05:00
|
|
|
|
|
|
|
public class MyIterator implements Iterator {
|
|
|
|
short nextColumn=-1;
|
|
|
|
int nextRow,lastRow;
|
|
|
|
|
|
|
|
public MyIterator()
|
|
|
|
{
|
|
|
|
this.nextRow=0;
|
|
|
|
this.lastRow=records.length-1;
|
|
|
|
findNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
public MyIterator(int firstRow,int lastRow)
|
|
|
|
{
|
|
|
|
this.nextRow=firstRow;
|
|
|
|
this.lastRow=lastRow;
|
|
|
|
findNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasNext() {
|
|
|
|
return nextRow<=lastRow;
|
|
|
|
}
|
|
|
|
public Object next() {
|
|
|
|
Object o=records[nextRow][nextColumn];
|
|
|
|
findNext();
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
public void remove() {
|
|
|
|
throw new UnsupportedOperationException("gibt's noch nicht");
|
|
|
|
}
|
|
|
|
|
|
|
|
private void findNext() {
|
|
|
|
nextColumn++;
|
|
|
|
for(;nextRow<=lastRow;nextRow++) {
|
|
|
|
CellValueRecordInterface[] rowCells=records[nextRow];
|
|
|
|
if(rowCells==null) { // This row is empty
|
|
|
|
nextColumn=0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for(;nextColumn<rowCells.length;nextColumn++) {
|
|
|
|
if(rowCells[nextColumn]!=null) return;
|
|
|
|
}
|
|
|
|
nextColumn=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2004-10-06 23:37:16 -04:00
|
|
|
}
|