first commit

This commit is contained in:
2025-07-28 13:56:49 +05:30
commit e9eb805edb
3438 changed files with 520990 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
public class BOFRecord extends RecordData {
private static Logger logger = Logger.getLogger(BOFRecord.class);
private static final int Biff8 = 1536;
private static final int Biff7 = 1280;
private static final int WorkbookGlobals = 5;
private static final int Worksheet = 16;
private static final int Chart = 32;
private static final int MacroSheet = 64;
private int version;
private int substreamType;
BOFRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.version = IntegerHelper.getInt(data[0], data[1]);
this.substreamType = IntegerHelper.getInt(data[2], data[3]);
}
public boolean isBiff8() {
return (this.version == 1536);
}
public boolean isBiff7() {
return (this.version == 1280);
}
boolean isWorkbookGlobals() {
return (this.substreamType == 5);
}
public boolean isWorksheet() {
return (this.substreamType == 16);
}
public boolean isMacroSheet() {
return (this.substreamType == 64);
}
public boolean isChart() {
return (this.substreamType == 32);
}
int getLength() {
return getRecord().getLength();
}
}

View File

@@ -0,0 +1,60 @@
package jxl.read.biff;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
public abstract class BaseSharedFormulaRecord extends CellValue implements FormulaData {
private String formulaString;
private int filePos;
private byte[] tokens;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
public BaseSharedFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si, int pos) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.filePos = pos;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
FormulaParser fp = new FormulaParser(this.tokens, this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
void setTokens(byte[] t) {
this.tokens = t;
}
protected final byte[] getTokens() {
return this.tokens;
}
protected final ExternalSheet getExternalSheet() {
return this.externalSheet;
}
protected final WorkbookMethods getNameTable() {
return this.nameTable;
}
public Record getRecord() {
return super.getRecord();
}
final int getFilePos() {
return this.filePos;
}
}

View File

@@ -0,0 +1,33 @@
package jxl.read.biff;
import jxl.JXLException;
public class BiffException extends JXLException {
private static class BiffMessage {
public String message;
BiffMessage(String m) {
this.message = m;
}
}
static final BiffMessage unrecognizedBiffVersion = new BiffMessage("Unrecognized biff version");
static final BiffMessage expectedGlobals = new BiffMessage("Expected globals");
static final BiffMessage excelFileTooBig = new BiffMessage("Warning: not all of the excel file could be read");
static final BiffMessage excelFileNotFound = new BiffMessage("The input file was not found");
static final BiffMessage unrecognizedOLEFile = new BiffMessage("Unable to recognize OLE stream");
static final BiffMessage streamNotFound = new BiffMessage("Compound file does not contain the specified stream");
static final BiffMessage passwordProtected = new BiffMessage("The workbook is password protected");
static final BiffMessage corruptFileFormat = new BiffMessage("The file format is corrupt");
public BiffException(BiffMessage m) {
super(m.message);
}
}

View File

@@ -0,0 +1,18 @@
package jxl.read.biff;
import jxl.CellType;
import jxl.biff.FormattingRecords;
public class BlankCell extends CellValue {
BlankCell(Record t, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
}
public String getContents() {
return "";
}
public CellType getType() {
return CellType.EMPTY;
}
}

View File

@@ -0,0 +1,65 @@
package jxl.read.biff;
import common.Assert;
import jxl.BooleanCell;
import jxl.BooleanFormulaCell;
import jxl.CellType;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
class BooleanFormulaRecord extends CellValue implements BooleanCell, FormulaData, BooleanFormulaCell {
private boolean value;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private String formulaString;
private byte[] data;
public BooleanFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.value = false;
this.data = getRecord().getData();
Assert.verify((this.data[6] != 2));
this.value = (this.data[8] == 1);
}
public boolean getValue() {
return this.value;
}
public String getContents() {
return (new Boolean(this.value)).toString();
}
public CellType getType() {
return CellType.BOOLEAN_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
byte[] d = new byte[this.data.length - 6];
System.arraycopy(this.data, 6, d, 0, this.data.length - 6);
return d;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
byte[] tokens = new byte[this.data.length - 22];
System.arraycopy(this.data, 22, tokens, 0, tokens.length);
FormulaParser fp = new FormulaParser(tokens, this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
}

View File

@@ -0,0 +1,43 @@
package jxl.read.biff;
import common.Assert;
import jxl.BooleanCell;
import jxl.CellType;
import jxl.biff.FormattingRecords;
class BooleanRecord extends CellValue implements BooleanCell {
private boolean error;
private boolean value;
public BooleanRecord(Record t, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
this.error = false;
this.value = false;
byte[] data = getRecord().getData();
this.error = (data[7] == 1);
if (!this.error)
this.value = (data[6] == 1);
}
public boolean isError() {
return this.error;
}
public boolean getValue() {
return this.value;
}
public String getContents() {
Assert.verify(!isError());
return (new Boolean(this.value)).toString();
}
public CellType getType() {
return CellType.BOOLEAN;
}
public Record getRecord() {
return super.getRecord();
}
}

View File

@@ -0,0 +1,9 @@
package jxl.read.biff;
import jxl.biff.Type;
class BottomMarginRecord extends MarginRecord {
BottomMarginRecord(Record r) {
super(Type.BOTTOMMARGIN, r);
}
}

View File

@@ -0,0 +1,73 @@
package jxl.read.biff;
import java.io.UnsupportedEncodingException;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class BoundsheetRecord extends RecordData {
private int offset;
private byte typeFlag;
private byte visibilityFlag;
private int length;
private String name;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
public BoundsheetRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.offset = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
this.typeFlag = data[5];
this.visibilityFlag = data[4];
this.length = data[6];
if (data[7] == 0) {
byte[] bytes = new byte[this.length];
System.arraycopy(data, 8, bytes, 0, this.length);
this.name = new String(bytes);
} else {
byte[] bytes = new byte[this.length * 2];
System.arraycopy(data, 8, bytes, 0, this.length * 2);
try {
this.name = new String(bytes, "UnicodeLittle");
} catch (UnsupportedEncodingException e) {
this.name = "Error";
}
}
}
public BoundsheetRecord(Record t, Biff7 biff7) {
super(t);
byte[] data = getRecord().getData();
this.offset = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
this.typeFlag = data[5];
this.visibilityFlag = data[4];
this.length = data[6];
byte[] bytes = new byte[this.length];
System.arraycopy(data, 7, bytes, 0, this.length);
this.name = new String(bytes);
}
public String getName() {
return this.name;
}
public boolean isHidden() {
return (this.visibilityFlag != 0);
}
public boolean isSheet() {
return (this.typeFlag == 0);
}
public boolean isChart() {
return (this.typeFlag == 2);
}
}

View File

@@ -0,0 +1,16 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.RecordData;
public class ButtonPropertySetRecord extends RecordData {
private static Logger logger = Logger.getLogger(ButtonPropertySetRecord.class);
ButtonPropertySetRecord(Record t) {
super(t);
}
public byte[] getData() {
return getRecord().getData();
}
}

View File

@@ -0,0 +1,22 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class CalcModeRecord extends RecordData {
private static Logger logger = Logger.getLogger(CalcModeRecord.class);
private boolean automatic;
public CalcModeRecord(Record t) {
super(t);
byte[] data = t.getData();
int mode = IntegerHelper.getInt(data[0], data[1]);
this.automatic = (mode == 1);
}
public boolean isAutomatic() {
return this.automatic;
}
}

View File

@@ -0,0 +1,9 @@
package jxl.read.biff;
import jxl.CellFeatures;
interface CellFeaturesAccessor {
void setCellFeatures(CellFeatures paramCellFeatures);
CellFeatures getCellFeatures();
}

View File

@@ -0,0 +1,85 @@
package jxl.read.biff;
import common.Logger;
import jxl.Cell;
import jxl.CellFeatures;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.XFRecord;
import jxl.format.CellFormat;
public abstract class CellValue extends RecordData implements Cell, CellFeaturesAccessor {
private static Logger logger = Logger.getLogger(CellValue.class);
private int row;
private int column;
private int xfIndex;
private FormattingRecords formattingRecords;
private boolean initialized;
private XFRecord format;
private SheetImpl sheet;
private CellFeatures features;
protected CellValue(Record t, FormattingRecords fr, SheetImpl si) {
super(t);
byte[] data = getRecord().getData();
this.row = IntegerHelper.getInt(data[0], data[1]);
this.column = IntegerHelper.getInt(data[2], data[3]);
this.xfIndex = IntegerHelper.getInt(data[4], data[5]);
this.sheet = si;
this.formattingRecords = fr;
this.initialized = false;
}
public final int getRow() {
return this.row;
}
public final int getColumn() {
return this.column;
}
public final int getXFIndex() {
return this.xfIndex;
}
public CellFormat getCellFormat() {
if (!this.initialized) {
this.format = this.formattingRecords.getXFRecord(this.xfIndex);
this.initialized = true;
}
return (CellFormat)this.format;
}
public boolean isHidden() {
ColumnInfoRecord cir = this.sheet.getColumnInfo(this.column);
if (cir != null && (cir.getWidth() == 0 || cir.getHidden()))
return true;
RowRecord rr = this.sheet.getRowInfo(this.row);
if (rr != null && (rr.getRowHeight() == 0 || rr.isCollapsed()))
return true;
return false;
}
protected SheetImpl getSheet() {
return this.sheet;
}
public CellFeatures getCellFeatures() {
return this.features;
}
public void setCellFeatures(CellFeatures cf) {
if (this.features != null)
logger.warn("current cell features not null - overwriting");
this.features = cf;
}
}

View File

@@ -0,0 +1,18 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class CentreRecord extends RecordData {
private boolean centre;
public CentreRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.centre = (IntegerHelper.getInt(data[0], data[1]) != 0);
}
public boolean isCentre() {
return this.centre;
}
}

View File

@@ -0,0 +1,21 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class CodepageRecord extends RecordData {
private static Logger logger = Logger.getLogger(CodepageRecord.class);
private int characterSet;
public CodepageRecord(Record t) {
super(t);
byte[] data = t.getData();
this.characterSet = IntegerHelper.getInt(data[0], data[1]);
}
public int getCharacterSet() {
return this.characterSet;
}
}

View File

@@ -0,0 +1,50 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.Type;
public class ColumnInfoRecord extends RecordData {
private byte[] data;
private int startColumn;
private int endColumn;
private int xfIndex;
private int width;
private boolean hidden;
ColumnInfoRecord(Record t) {
super(Type.COLINFO);
this.data = t.getData();
this.startColumn = IntegerHelper.getInt(this.data[0], this.data[1]);
this.endColumn = IntegerHelper.getInt(this.data[2], this.data[3]);
this.width = IntegerHelper.getInt(this.data[4], this.data[5]);
this.xfIndex = IntegerHelper.getInt(this.data[6], this.data[7]);
int options = IntegerHelper.getInt(this.data[8], this.data[9]);
this.hidden = ((options & 0x1) != 0);
}
public int getStartColumn() {
return this.startColumn;
}
public int getEndColumn() {
return this.endColumn;
}
public int getXFIndex() {
return this.xfIndex;
}
public int getWidth() {
return this.width;
}
public boolean getHidden() {
return this.hidden;
}
}

View File

@@ -0,0 +1,266 @@
package jxl.read.biff;
import common.Logger;
import java.util.ArrayList;
import java.util.Iterator;
import jxl.WorkbookSettings;
import jxl.biff.BaseCompoundFile;
import jxl.biff.IntegerHelper;
public final class CompoundFile extends BaseCompoundFile {
private static Logger logger = Logger.getLogger(CompoundFile.class);
private byte[] data;
private int numBigBlockDepotBlocks;
private int sbdStartBlock;
private int rootStartBlock;
private int extensionBlock;
private int numExtensionBlocks;
private byte[] rootEntry;
private int[] bigBlockChain;
private int[] smallBlockChain;
private int[] bigBlockDepotBlocks;
private ArrayList propertySets;
private WorkbookSettings settings;
private BaseCompoundFile.PropertyStorage rootEntryPropertyStorage;
public CompoundFile(byte[] d, WorkbookSettings ws) throws BiffException {
this.data = d;
this.settings = ws;
for (int i = 0; i < IDENTIFIER.length; i++) {
if (this.data[i] != IDENTIFIER[i])
throw new BiffException(BiffException.unrecognizedOLEFile);
}
this.propertySets = new ArrayList();
this.numBigBlockDepotBlocks = IntegerHelper.getInt(this.data[44], this.data[45], this.data[46], this.data[47]);
this.sbdStartBlock = IntegerHelper.getInt(this.data[60], this.data[61], this.data[62], this.data[63]);
this.rootStartBlock = IntegerHelper.getInt(this.data[48], this.data[49], this.data[50], this.data[51]);
this.extensionBlock = IntegerHelper.getInt(this.data[68], this.data[69], this.data[70], this.data[71]);
this.numExtensionBlocks = IntegerHelper.getInt(this.data[72], this.data[73], this.data[74], this.data[75]);
this.bigBlockDepotBlocks = new int[this.numBigBlockDepotBlocks];
int pos = 76;
int bbdBlocks = this.numBigBlockDepotBlocks;
if (this.numExtensionBlocks != 0)
bbdBlocks = 109;
for (int k = 0; k < bbdBlocks; k++) {
this.bigBlockDepotBlocks[k] = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
pos += 4;
}
for (int j = 0; j < this.numExtensionBlocks; j++) {
pos = (this.extensionBlock + 1) * 512;
int blocksToRead = Math.min(this.numBigBlockDepotBlocks - bbdBlocks, 127);
for (int m = bbdBlocks; m < bbdBlocks + blocksToRead; m++) {
this.bigBlockDepotBlocks[m] = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
pos += 4;
}
bbdBlocks += blocksToRead;
if (bbdBlocks < this.numBigBlockDepotBlocks)
this.extensionBlock = IntegerHelper.getInt(d[pos], d[pos + 1], d[pos + 2], d[pos + 3]);
}
readBigBlockDepot();
readSmallBlockDepot();
this.rootEntry = readData(this.rootStartBlock);
readPropertySets();
}
private void readBigBlockDepot() {
int pos = 0;
int index = 0;
this.bigBlockChain = new int[this.numBigBlockDepotBlocks * 512 / 4];
for (int i = 0; i < this.numBigBlockDepotBlocks; i++) {
pos = (this.bigBlockDepotBlocks[i] + 1) * 512;
for (int j = 0; j < 128; j++) {
this.bigBlockChain[index] = IntegerHelper.getInt(this.data[pos], this.data[pos + 1], this.data[pos + 2], this.data[pos + 3]);
pos += 4;
index++;
}
}
}
private void readSmallBlockDepot() {
int pos = 0;
int index = 0;
int sbdBlock = this.sbdStartBlock;
this.smallBlockChain = new int[0];
if (sbdBlock == -1) {
logger.warn("invalid small block depot number");
return;
}
while (sbdBlock != -2) {
int[] oldChain = this.smallBlockChain;
this.smallBlockChain = new int[this.smallBlockChain.length + 128];
System.arraycopy(oldChain, 0, this.smallBlockChain, 0, oldChain.length);
pos = (sbdBlock + 1) * 512;
for (int j = 0; j < 128; j++) {
this.smallBlockChain[index] = IntegerHelper.getInt(this.data[pos], this.data[pos + 1], this.data[pos + 2], this.data[pos + 3]);
pos += 4;
index++;
}
sbdBlock = this.bigBlockChain[sbdBlock];
}
}
private void readPropertySets() {
int offset = 0;
byte[] d = null;
while (offset < this.rootEntry.length) {
d = new byte[128];
System.arraycopy(this.rootEntry, offset, d, 0, d.length);
BaseCompoundFile.PropertyStorage ps = new BaseCompoundFile.PropertyStorage(this, d);
if (ps.name == null || ps.name.length() == 0)
if (ps.type == 5) {
ps.name = "Root Entry";
logger.warn("Property storage name for " + ps.type + " is empty - setting to " + "Root Entry");
} else if (ps.size != 0) {
logger.warn("Property storage type " + ps.type + " is non-empty and has no associated name");
}
this.propertySets.add(ps);
if (ps.name.equalsIgnoreCase("Root Entry"))
this.rootEntryPropertyStorage = ps;
offset += 128;
}
if (this.rootEntryPropertyStorage == null)
this.rootEntryPropertyStorage = this.propertySets.get(0);
}
public byte[] getStream(String streamName) throws BiffException {
BaseCompoundFile.PropertyStorage ps = findPropertyStorage(streamName, this.rootEntryPropertyStorage);
if (ps == null)
ps = getPropertyStorage(streamName);
if (ps.size >= 4096 || streamName.equalsIgnoreCase("Root Entry"))
return getBigBlockStream(ps);
return getSmallBlockStream(ps);
}
public byte[] getStream(int psIndex) throws BiffException {
BaseCompoundFile.PropertyStorage ps = getPropertyStorage(psIndex);
if (ps.size >= 4096 || ps.name.equalsIgnoreCase("Root Entry"))
return getBigBlockStream(ps);
return getSmallBlockStream(ps);
}
public BaseCompoundFile.PropertyStorage findPropertyStorage(String name) {
return findPropertyStorage(name, this.rootEntryPropertyStorage);
}
private BaseCompoundFile.PropertyStorage findPropertyStorage(String name, BaseCompoundFile.PropertyStorage base) {
if (base.child == -1)
return null;
BaseCompoundFile.PropertyStorage child = getPropertyStorage(base.child);
if (child.name.equalsIgnoreCase(name))
return child;
BaseCompoundFile.PropertyStorage prev = child;
while (prev.previous != -1) {
prev = getPropertyStorage(prev.previous);
if (prev.name.equalsIgnoreCase(name))
return prev;
}
BaseCompoundFile.PropertyStorage next = child;
while (next.next != -1) {
next = getPropertyStorage(next.next);
if (next.name.equalsIgnoreCase(name))
return next;
}
return findPropertyStorage(name, child);
}
private BaseCompoundFile.PropertyStorage getPropertyStorage(String name) throws BiffException {
Iterator i = this.propertySets.iterator();
boolean found = false;
boolean multiple = false;
BaseCompoundFile.PropertyStorage ps = null;
while (i.hasNext()) {
BaseCompoundFile.PropertyStorage ps2 = i.next();
if (ps2.name.equalsIgnoreCase(name)) {
multiple = (found == true);
found = true;
ps = ps2;
}
}
if (multiple)
logger.warn("found multiple copies of property set " + name);
if (!found)
throw new BiffException(BiffException.streamNotFound);
return ps;
}
private BaseCompoundFile.PropertyStorage getPropertyStorage(int index) {
return this.propertySets.get(index);
}
private byte[] getBigBlockStream(BaseCompoundFile.PropertyStorage ps) {
int numBlocks = ps.size / 512;
if (ps.size % 512 != 0)
numBlocks++;
byte[] streamData = new byte[numBlocks * 512];
int block = ps.startBlock;
int count = 0;
int pos = 0;
while (block != -2 && count < numBlocks) {
pos = (block + 1) * 512;
System.arraycopy(this.data, pos, streamData, count * 512, 512);
count++;
block = this.bigBlockChain[block];
}
if (block != -2 && count == numBlocks)
logger.warn("Property storage size inconsistent with block chain.");
return streamData;
}
private byte[] getSmallBlockStream(BaseCompoundFile.PropertyStorage ps) throws BiffException {
byte[] rootdata = readData(this.rootEntryPropertyStorage.startBlock);
byte[] sbdata = new byte[0];
int block = ps.startBlock;
int pos = 0;
while (block != -2) {
byte[] olddata = sbdata;
sbdata = new byte[olddata.length + 64];
System.arraycopy(olddata, 0, sbdata, 0, olddata.length);
pos = block * 64;
System.arraycopy(rootdata, pos, sbdata, olddata.length, 64);
block = this.smallBlockChain[block];
if (block == -1) {
logger.warn("Incorrect terminator for small block stream " + ps.name);
block = -2;
}
}
return sbdata;
}
private byte[] readData(int bl) throws BiffException {
int block = bl;
int pos = 0;
byte[] entry = new byte[0];
while (block != -2) {
byte[] oldEntry = entry;
entry = new byte[oldEntry.length + 512];
System.arraycopy(oldEntry, 0, entry, 0, oldEntry.length);
pos = (block + 1) * 512;
System.arraycopy(this.data, pos, entry, oldEntry.length, 512);
if (this.bigBlockChain[block] == block)
throw new BiffException(BiffException.corruptFileFormat);
block = this.bigBlockChain[block];
}
return entry;
}
public int getNumberOfPropertySets() {
return this.propertySets.size();
}
public BaseCompoundFile.PropertyStorage getPropertySet(int index) {
return getPropertyStorage(index);
}
}

View File

@@ -0,0 +1,28 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
public class CountryRecord extends RecordData {
private static Logger logger = Logger.getLogger(CountryRecord.class);
private int language;
private int regionalSettings;
public CountryRecord(Record t) {
super(t);
byte[] data = t.getData();
this.language = IntegerHelper.getInt(data[0], data[1]);
this.regionalSettings = IntegerHelper.getInt(data[2], data[3]);
}
public int getLanguageCode() {
return this.language;
}
public int getRegionalSettingsCode() {
return this.regionalSettings;
}
}

View File

@@ -0,0 +1,31 @@
package jxl.read.biff;
import common.Assert;
public class DataValidation {
private DataValidityListRecord validityList;
private DataValiditySettingsRecord[] validitySettings;
private int pos;
DataValidation(DataValidityListRecord dvlr) {
this.validityList = dvlr;
this.validitySettings = new DataValiditySettingsRecord[this.validityList.getNumberOfSettings()];
this.pos = 0;
}
void add(DataValiditySettingsRecord dvsr) {
Assert.verify((this.pos < this.validitySettings.length));
this.validitySettings[this.pos] = dvsr;
this.pos++;
}
public DataValidityListRecord getDataValidityList() {
return this.validityList;
}
public DataValiditySettingsRecord[] getDataValiditySettings() {
return this.validitySettings;
}
}

View File

@@ -0,0 +1,22 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
public class DataValidityListRecord extends RecordData {
private int numSettings;
DataValidityListRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.numSettings = IntegerHelper.getInt(data[14], data[15], data[16], data[17]);
}
int getNumberOfSettings() {
return this.numSettings;
}
public byte[] getData() {
return getRecord().getData();
}
}

View File

@@ -0,0 +1,13 @@
package jxl.read.biff;
import jxl.biff.RecordData;
public class DataValiditySettingsRecord extends RecordData {
DataValiditySettingsRecord(Record t) {
super(t);
}
public byte[] getData() {
return getRecord().getData();
}
}

View File

@@ -0,0 +1,59 @@
package jxl.read.biff;
import java.text.NumberFormat;
import jxl.Cell;
import jxl.CellType;
import jxl.DateCell;
import jxl.DateFormulaCell;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
class DateFormulaRecord extends DateRecord implements DateCell, FormulaData, DateFormulaCell {
private String formulaString;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private byte[] data;
public DateFormulaRecord(NumberFormulaRecord t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, boolean nf, SheetImpl si) throws FormulaException {
super(t, t.getXFIndex(), fr, nf, si);
this.externalSheet = es;
this.nameTable = nt;
this.data = t.getFormulaData();
}
public CellType getType() {
return CellType.DATE_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
return this.data;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
byte[] tokens = new byte[this.data.length - 16];
System.arraycopy(this.data, 16, tokens, 0, tokens.length);
FormulaParser fp = new FormulaParser(tokens, (Cell)this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
public double getValue() {
return 0.0D;
}
public NumberFormat getNumberFormat() {
return null;
}
}

View File

@@ -0,0 +1,144 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import jxl.CellFeatures;
import jxl.CellType;
import jxl.DateCell;
import jxl.NumberCell;
import jxl.biff.FormattingRecords;
import jxl.format.CellFormat;
class DateRecord implements DateCell, CellFeaturesAccessor {
private static Logger logger = Logger.getLogger(DateRecord.class);
private Date date;
private int row;
private int column;
private boolean time;
private DateFormat format;
private CellFormat cellFormat;
private int xfIndex;
private FormattingRecords formattingRecords;
private SheetImpl sheet;
private CellFeatures features;
private boolean initialized;
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy");
private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
private static final int nonLeapDay = 61;
private static final TimeZone gmtZone = TimeZone.getTimeZone("GMT");
private static final int utcOffsetDays = 25569;
private static final int utcOffsetDays1904 = 24107;
private static final long secondsInADay = 86400L;
private static final long msInASecond = 1000L;
private static final long msInADay = 86400000L;
public DateRecord(NumberCell num, int xfi, FormattingRecords fr, boolean nf, SheetImpl si) {
this.row = num.getRow();
this.column = num.getColumn();
this.xfIndex = xfi;
this.formattingRecords = fr;
this.sheet = si;
this.initialized = false;
this.format = this.formattingRecords.getDateFormat(this.xfIndex);
double numValue = num.getValue();
if (Math.abs(numValue) < 1.0D) {
if (this.format == null)
this.format = timeFormat;
this.time = true;
} else {
if (this.format == null)
this.format = dateFormat;
this.time = false;
}
if (!nf && !this.time && numValue < 61.0D)
numValue++;
this.format.setTimeZone(gmtZone);
int offsetDays = nf ? 24107 : 25569;
double utcDays = numValue - offsetDays;
long utcValue = Math.round(utcDays * 86400.0D) * 1000L;
this.date = new Date(utcValue);
}
public final int getRow() {
return this.row;
}
public final int getColumn() {
return this.column;
}
public Date getDate() {
return this.date;
}
public String getContents() {
return this.format.format(this.date);
}
public CellType getType() {
return CellType.DATE;
}
public boolean isTime() {
return this.time;
}
public DateFormat getDateFormat() {
Assert.verify((this.format != null));
return this.format;
}
public CellFormat getCellFormat() {
if (!this.initialized) {
this.cellFormat = (CellFormat)this.formattingRecords.getXFRecord(this.xfIndex);
this.initialized = true;
}
return this.cellFormat;
}
public boolean isHidden() {
ColumnInfoRecord cir = this.sheet.getColumnInfo(this.column);
if (cir != null && cir.getWidth() == 0)
return true;
RowRecord rr = this.sheet.getRowInfo(this.row);
if (rr != null && (rr.getRowHeight() == 0 || rr.isCollapsed()))
return true;
return false;
}
protected final SheetImpl getSheet() {
return this.sheet;
}
public CellFeatures getCellFeatures() {
return this.features;
}
public void setCellFeatures(CellFeatures cf) {
this.features = cf;
}
}

View File

@@ -0,0 +1,18 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class DefaultColumnWidthRecord extends RecordData {
private int width;
public DefaultColumnWidthRecord(Record t) {
super(t);
byte[] data = t.getData();
this.width = IntegerHelper.getInt(data[0], data[1]);
}
public int getWidth() {
return this.width;
}
}

View File

@@ -0,0 +1,19 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class DefaultRowHeightRecord extends RecordData {
private int height;
public DefaultRowHeightRecord(Record t) {
super(t);
byte[] data = t.getData();
if (data.length > 2)
this.height = IntegerHelper.getInt(data[2], data[3]);
}
public int getHeight() {
return this.height;
}
}

View File

@@ -0,0 +1,53 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class DimensionRecord extends RecordData {
private static Logger logger = Logger.getLogger(DimensionRecord.class);
private int numRows;
private int numCols;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
public DimensionRecord(Record t) {
super(t);
byte[] data = t.getData();
if (data.length == 10) {
read10ByteData(data);
} else {
read14ByteData(data);
}
}
public DimensionRecord(Record t, Biff7 biff7) {
super(t);
byte[] data = t.getData();
read10ByteData(data);
}
private void read10ByteData(byte[] data) {
this.numRows = IntegerHelper.getInt(data[2], data[3]);
this.numCols = IntegerHelper.getInt(data[6], data[7]);
}
private void read14ByteData(byte[] data) {
this.numRows = IntegerHelper.getInt(data[4], data[5], data[6], data[7]);
this.numCols = IntegerHelper.getInt(data[10], data[11]);
}
public int getNumberOfRows() {
return this.numRows;
}
public int getNumberOfColumns() {
return this.numCols;
}
}

View File

@@ -0,0 +1,69 @@
package jxl.read.biff;
import common.Assert;
import jxl.CellType;
import jxl.ErrorCell;
import jxl.ErrorFormulaCell;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaErrorCode;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
class ErrorFormulaRecord extends CellValue implements ErrorCell, FormulaData, ErrorFormulaCell {
private int errorCode;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private String formulaString;
private byte[] data;
private FormulaErrorCode error;
public ErrorFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.data = getRecord().getData();
Assert.verify((this.data[6] == 2));
this.errorCode = this.data[8];
}
public int getErrorCode() {
return this.errorCode;
}
public String getContents() {
if (this.error == null)
this.error = FormulaErrorCode.getErrorCode(this.errorCode);
return (this.error != FormulaErrorCode.UNKNOWN) ? this.error.getDescription() : ("ERROR " + this.errorCode);
}
public CellType getType() {
return CellType.FORMULA_ERROR;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
byte[] d = new byte[this.data.length - 6];
System.arraycopy(this.data, 6, d, 0, this.data.length - 6);
return d;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
byte[] tokens = new byte[this.data.length - 22];
System.arraycopy(this.data, 22, tokens, 0, tokens.length);
FormulaParser fp = new FormulaParser(tokens, this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
}

View File

@@ -0,0 +1,27 @@
package jxl.read.biff;
import jxl.CellType;
import jxl.ErrorCell;
import jxl.biff.FormattingRecords;
class ErrorRecord extends CellValue implements ErrorCell {
private int errorCode;
public ErrorRecord(Record t, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.errorCode = data[6];
}
public int getErrorCode() {
return this.errorCode;
}
public String getContents() {
return "ERROR " + this.errorCode;
}
public CellType getType() {
return CellType.ERROR;
}
}

View File

@@ -0,0 +1,77 @@
package jxl.read.biff;
import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
public class ExternalSheetRecord extends RecordData {
private static Logger logger = Logger.getLogger(ExternalSheetRecord.class);
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
private XTI[] xtiArray;
private static class XTI {
int supbookIndex;
int firstTab;
int lastTab;
XTI(int s, int f, int l) {
this.supbookIndex = s;
this.firstTab = f;
this.lastTab = l;
}
}
ExternalSheetRecord(Record t, WorkbookSettings ws) {
super(t);
byte[] data = getRecord().getData();
int numxtis = IntegerHelper.getInt(data[0], data[1]);
if (data.length < numxtis * 6 + 2) {
this.xtiArray = new XTI[0];
logger.warn("Could not process external sheets. Formulas may be compromised.");
return;
}
this.xtiArray = new XTI[numxtis];
int pos = 2;
for (int i = 0; i < numxtis; i++) {
int s = IntegerHelper.getInt(data[pos], data[pos + 1]);
int f = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
int l = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
this.xtiArray[i] = new XTI(s, f, l);
pos += 6;
}
}
ExternalSheetRecord(Record t, WorkbookSettings settings, Biff7 dummy) {
super(t);
logger.warn("External sheet record for Biff 7 not supported");
}
public int getNumRecords() {
return (this.xtiArray != null) ? this.xtiArray.length : 0;
}
public int getSupbookIndex(int index) {
return (this.xtiArray[index]).supbookIndex;
}
public int getFirstTabIndex(int index) {
return (this.xtiArray[index]).firstTab;
}
public int getLastTabIndex(int index) {
return (this.xtiArray[index]).lastTab;
}
public byte[] getData() {
return getRecord().getData();
}
}

View File

@@ -0,0 +1,134 @@
package jxl.read.biff;
import common.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import jxl.WorkbookSettings;
import jxl.biff.BaseCompoundFile;
import jxl.biff.IntegerHelper;
import jxl.biff.Type;
public class File {
private static Logger logger = Logger.getLogger(File.class);
private byte[] data;
private int filePos;
private int oldPos;
private int initialFileSize;
private int arrayGrowSize;
private CompoundFile compoundFile;
private WorkbookSettings workbookSettings;
public File(InputStream is, WorkbookSettings ws) throws IOException, BiffException {
this.workbookSettings = ws;
this.initialFileSize = this.workbookSettings.getInitialFileSize();
this.arrayGrowSize = this.workbookSettings.getArrayGrowSize();
byte[] d = new byte[this.initialFileSize];
int bytesRead = is.read(d);
int pos = bytesRead;
if (Thread.currentThread().isInterrupted())
throw new InterruptedIOException();
while (bytesRead != -1) {
if (pos >= d.length) {
byte[] newArray = new byte[d.length + this.arrayGrowSize];
System.arraycopy(d, 0, newArray, 0, d.length);
d = newArray;
}
bytesRead = is.read(d, pos, d.length - pos);
pos += bytesRead;
if (Thread.currentThread().isInterrupted())
throw new InterruptedIOException();
}
bytesRead = pos + 1;
if (bytesRead == 0)
throw new BiffException(BiffException.excelFileNotFound);
CompoundFile cf = new CompoundFile(d, ws);
try {
this.data = cf.getStream("workbook");
} catch (BiffException e) {
this.data = cf.getStream("book");
}
if (!this.workbookSettings.getPropertySetsDisabled() && cf.getNumberOfPropertySets() > BaseCompoundFile.STANDARD_PROPERTY_SETS.length)
this.compoundFile = cf;
cf = null;
if (!this.workbookSettings.getGCDisabled())
System.gc();
}
public File(byte[] d) {
this.data = d;
}
Record next() {
Record r = new Record(this.data, this.filePos, this);
return r;
}
Record peek() {
int tempPos = this.filePos;
Record r = new Record(this.data, this.filePos, this);
this.filePos = tempPos;
return r;
}
public void skip(int bytes) {
this.filePos += bytes;
}
public byte[] read(int pos, int length) {
byte[] ret = new byte[length];
try {
System.arraycopy(this.data, pos, ret, 0, length);
} catch (ArrayIndexOutOfBoundsException e) {
logger.error("Array index out of bounds at position " + pos + " record length " + length);
throw e;
}
return ret;
}
public int getPos() {
return this.filePos;
}
public void setPos(int p) {
this.oldPos = this.filePos;
this.filePos = p;
}
public void restorePos() {
this.filePos = this.oldPos;
}
private void moveToFirstBof() {
boolean bofFound = false;
while (!bofFound) {
int code = IntegerHelper.getInt(this.data[this.filePos], this.data[this.filePos + 1]);
if (code == Type.BOF.value) {
bofFound = true;
continue;
}
skip(128);
}
}
public void close() {}
public void clear() {
this.data = null;
}
public boolean hasNext() {
return (this.filePos < this.data.length - 4);
}
CompoundFile getCompoundFile() {
return this.compoundFile;
}
}

View File

@@ -0,0 +1,43 @@
package jxl.read.biff;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;
public class FooterRecord extends RecordData {
private String footer;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
FooterRecord(Record t, WorkbookSettings ws) {
super(t);
byte[] data = getRecord().getData();
if (data.length == 0)
return;
int chars = IntegerHelper.getInt(data[0], data[1]);
boolean unicode = (data[2] == 1);
if (unicode) {
this.footer = StringHelper.getUnicodeString(data, chars, 3);
} else {
this.footer = StringHelper.getString(data, chars, 3, ws);
}
}
FooterRecord(Record t, WorkbookSettings ws, Biff7 dummy) {
super(t);
byte[] data = getRecord().getData();
if (data.length == 0)
return;
int chars = data[0];
this.footer = StringHelper.getString(data, chars, 1, ws);
}
String getFooter() {
return this.footer;
}
}

View File

@@ -0,0 +1,91 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import jxl.CellType;
import jxl.WorkbookSettings;
import jxl.biff.DoubleHelper;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
class FormulaRecord extends CellValue {
private static Logger logger = Logger.getLogger(FormulaRecord.class);
private CellValue formula;
private boolean shared;
private static class IgnoreSharedFormula {
private IgnoreSharedFormula() {}
}
public static final IgnoreSharedFormula ignoreSharedFormula = new IgnoreSharedFormula();
public FormulaRecord(Record t, File excelFile, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si, WorkbookSettings ws) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.shared = false;
int grbit = IntegerHelper.getInt(data[14], data[15]);
if ((grbit & 0x8) != 0) {
this.shared = true;
if (data[6] == 0 && data[12] == -1 && data[13] == -1) {
this.formula = new SharedStringFormulaRecord(t, excelFile, fr, es, nt, si, ws);
} else if (data[6] == 2 && data[12] == -1 && data[13] == -1) {
int errorCode = data[8];
this.formula = new SharedErrorFormulaRecord(t, excelFile, errorCode, fr, es, nt, si);
} else {
double value = DoubleHelper.getIEEEDouble(data, 6);
SharedNumberFormulaRecord snfr = new SharedNumberFormulaRecord(t, excelFile, value, fr, es, nt, si);
snfr.setNumberFormat(fr.getNumberFormat(getXFIndex()));
this.formula = snfr;
}
return;
}
if (data[6] == 0 && data[12] == -1 && data[13] == -1) {
this.formula = new StringFormulaRecord(t, excelFile, fr, es, nt, si, ws);
} else if (data[6] == 1 && data[12] == -1 && data[13] == -1) {
this.formula = new BooleanFormulaRecord(t, fr, es, nt, si);
} else if (data[6] == 2 && data[12] == -1 && data[13] == -1) {
this.formula = new ErrorFormulaRecord(t, fr, es, nt, si);
} else if (data[6] == 3 && data[12] == -1 && data[13] == -1) {
this.formula = new StringFormulaRecord(t, fr, es, nt, si);
} else {
this.formula = new NumberFormulaRecord(t, fr, es, nt, si);
}
}
public FormulaRecord(Record t, File excelFile, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, IgnoreSharedFormula i, SheetImpl si, WorkbookSettings ws) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.shared = false;
if (data[6] == 0 && data[12] == -1 && data[13] == -1) {
this.formula = new StringFormulaRecord(t, excelFile, fr, es, nt, si, ws);
} else if (data[6] == 1 && data[12] == -1 && data[13] == -1) {
this.formula = new BooleanFormulaRecord(t, fr, es, nt, si);
} else if (data[6] == 2 && data[12] == -1 && data[13] == -1) {
this.formula = new ErrorFormulaRecord(t, fr, es, nt, si);
} else {
this.formula = new NumberFormulaRecord(t, fr, es, nt, si);
}
}
public String getContents() {
Assert.verify(false);
return "";
}
public CellType getType() {
Assert.verify(false);
return CellType.EMPTY;
}
final CellValue getFormula() {
return this.formula;
}
final boolean isShared() {
return this.shared;
}
}

View File

@@ -0,0 +1,46 @@
package jxl.read.biff;
import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;
public class HeaderRecord extends RecordData {
private static Logger logger = Logger.getLogger(HeaderRecord.class);
private String header;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
HeaderRecord(Record t, WorkbookSettings ws) {
super(t);
byte[] data = getRecord().getData();
if (data.length == 0)
return;
int chars = IntegerHelper.getInt(data[0], data[1]);
boolean unicode = (data[2] == 1);
if (unicode) {
this.header = StringHelper.getUnicodeString(data, chars, 3);
} else {
this.header = StringHelper.getString(data, chars, 3, ws);
}
}
HeaderRecord(Record t, WorkbookSettings ws, Biff7 dummy) {
super(t);
byte[] data = getRecord().getData();
if (data.length == 0)
return;
int chars = data[0];
this.header = StringHelper.getString(data, chars, 1, ws);
}
String getHeader() {
return this.header;
}
}

View File

@@ -0,0 +1,45 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class HorizontalPageBreaksRecord extends RecordData {
private final Logger logger = Logger.getLogger(HorizontalPageBreaksRecord.class);
private int[] rowBreaks;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
public HorizontalPageBreaksRecord(Record t) {
super(t);
byte[] data = t.getData();
int numbreaks = IntegerHelper.getInt(data[0], data[1]);
int pos = 2;
this.rowBreaks = new int[numbreaks];
for (int i = 0; i < numbreaks; i++) {
this.rowBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 6;
}
}
public HorizontalPageBreaksRecord(Record t, Biff7 biff7) {
super(t);
byte[] data = t.getData();
int numbreaks = IntegerHelper.getInt(data[0], data[1]);
int pos = 2;
this.rowBreaks = new int[numbreaks];
for (int i = 0; i < numbreaks; i++) {
this.rowBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
}
}
public int[] getRowBreaks() {
return this.rowBreaks;
}
}

View File

@@ -0,0 +1,189 @@
package jxl.read.biff;
import common.Logger;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import jxl.CellReferenceHelper;
import jxl.Hyperlink;
import jxl.Range;
import jxl.Sheet;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.SheetRangeImpl;
import jxl.biff.StringHelper;
public class HyperlinkRecord extends RecordData implements Hyperlink {
private static Logger logger = Logger.getLogger(HyperlinkRecord.class);
private int firstRow;
private int lastRow;
private int firstColumn;
private int lastColumn;
private URL url;
private File file;
private String location;
private SheetRangeImpl range;
private LinkType linkType;
private static class LinkType {
private LinkType() {}
}
private static final LinkType urlLink = new LinkType();
private static final LinkType fileLink = new LinkType();
private static final LinkType workbookLink = new LinkType();
private static final LinkType unknown = new LinkType();
HyperlinkRecord(Record t, Sheet s, WorkbookSettings ws) {
super(t);
this.linkType = unknown;
byte[] data = getRecord().getData();
this.firstRow = IntegerHelper.getInt(data[0], data[1]);
this.lastRow = IntegerHelper.getInt(data[2], data[3]);
this.firstColumn = IntegerHelper.getInt(data[4], data[5]);
this.lastColumn = IntegerHelper.getInt(data[6], data[7]);
this.range = new SheetRangeImpl(s, this.firstColumn, this.firstRow, this.lastColumn, this.lastRow);
int options = IntegerHelper.getInt(data[28], data[29], data[30], data[31]);
boolean description = ((options & 0x14) != 0);
int startpos = 32;
int descbytes = 0;
if (description) {
int descchars = IntegerHelper.getInt(data[startpos], data[startpos + 1], data[startpos + 2], data[startpos + 3]);
descbytes = descchars * 2 + 4;
}
startpos += descbytes;
boolean targetFrame = ((options & 0x80) != 0);
int targetbytes = 0;
if (targetFrame) {
int targetchars = IntegerHelper.getInt(data[startpos], data[startpos + 1], data[startpos + 2], data[startpos + 3]);
targetbytes = targetchars * 2 + 4;
}
startpos += targetbytes;
if ((options & 0x3) == 3) {
this.linkType = urlLink;
if (data[startpos] == 3)
this.linkType = fileLink;
} else if ((options & 0x1) != 0) {
this.linkType = fileLink;
if (data[startpos] == -32)
this.linkType = urlLink;
} else if ((options & 0x8) != 0) {
this.linkType = workbookLink;
}
if (this.linkType == urlLink) {
String urlString = null;
try {
startpos += 16;
int bytes = IntegerHelper.getInt(data[startpos], data[startpos + 1], data[startpos + 2], data[startpos + 3]);
urlString = StringHelper.getUnicodeString(data, bytes / 2 - 1, startpos + 4);
this.url = new URL(urlString);
} catch (MalformedURLException e) {
logger.warn("URL " + urlString + " is malformed. Trying a file");
try {
this.linkType = fileLink;
this.file = new File(urlString);
} catch (Exception e3) {
logger.warn("Cannot set to file. Setting a default URL");
try {
this.linkType = urlLink;
this.url = new URL("http://www.andykhan.com/jexcelapi/index.html");
} catch (MalformedURLException e2) {}
}
} catch (Throwable e) {
StringBuffer sb1 = new StringBuffer();
StringBuffer sb2 = new StringBuffer();
CellReferenceHelper.getCellReference(this.firstColumn, this.firstRow, sb1);
CellReferenceHelper.getCellReference(this.lastColumn, this.lastRow, sb2);
sb1.insert(0, "Exception when parsing URL ");
sb1.append('"').append(sb2.toString()).append("\". Using default.");
logger.warn(sb1, e);
try {
this.url = new URL("http://www.andykhan.com/jexcelapi/index.html");
} catch (MalformedURLException e2) {}
}
} else if (this.linkType == fileLink) {
try {
startpos += 16;
int upLevelCount = IntegerHelper.getInt(data[startpos], data[startpos + 1]);
int chars = IntegerHelper.getInt(data[startpos + 2], data[startpos + 3], data[startpos + 4], data[startpos + 5]);
String fileName = StringHelper.getString(data, chars - 1, startpos + 6, ws);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < upLevelCount; i++)
sb.append("..\\");
sb.append(fileName);
this.file = new File(sb.toString());
} catch (Throwable e) {
e.printStackTrace();
logger.warn("Exception when parsing file " + e.getClass().getName() + ".");
this.file = new File(".");
}
} else if (this.linkType == workbookLink) {
int chars = IntegerHelper.getInt(data[32], data[33], data[34], data[35]);
this.location = StringHelper.getUnicodeString(data, chars - 1, 36);
} else {
logger.warn("Cannot determine link type");
return;
}
}
public boolean isFile() {
return (this.linkType == fileLink);
}
public boolean isURL() {
return (this.linkType == urlLink);
}
public boolean isLocation() {
return (this.linkType == workbookLink);
}
public int getRow() {
return this.firstRow;
}
public int getColumn() {
return this.firstColumn;
}
public int getLastRow() {
return this.lastRow;
}
public int getLastColumn() {
return this.lastColumn;
}
public URL getURL() {
return this.url;
}
public File getFile() {
return this.file;
}
public Record getRecord() {
return super.getRecord();
}
public Range getRange() {
return (Range)this.range;
}
public String getLocation() {
return this.location;
}
}

View File

@@ -0,0 +1,50 @@
package jxl.read.biff;
import jxl.CellType;
import jxl.LabelCell;
import jxl.WorkbookSettings;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
class LabelRecord extends CellValue implements LabelCell {
private int length;
private String string;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
public LabelRecord(Record t, FormattingRecords fr, SheetImpl si, WorkbookSettings ws) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.length = IntegerHelper.getInt(data[6], data[7]);
if (data[8] == 0) {
this.string = StringHelper.getString(data, this.length, 9, ws);
} else {
this.string = StringHelper.getUnicodeString(data, this.length, 9);
}
}
public LabelRecord(Record t, FormattingRecords fr, SheetImpl si, WorkbookSettings ws, Biff7 dummy) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.length = IntegerHelper.getInt(data[6], data[7]);
this.string = StringHelper.getString(data, this.length, 8, ws);
}
public String getString() {
return this.string;
}
public String getContents() {
return this.string;
}
public CellType getType() {
return CellType.LABEL;
}
}

View File

@@ -0,0 +1,31 @@
package jxl.read.biff;
import jxl.CellType;
import jxl.LabelCell;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
class LabelSSTRecord extends CellValue implements LabelCell {
private int index;
private String string;
public LabelSSTRecord(Record t, SSTRecord stringTable, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.index = IntegerHelper.getInt(data[6], data[7], data[8], data[9]);
this.string = stringTable.getString(this.index);
}
public String getString() {
return this.string;
}
public String getContents() {
return this.string;
}
public CellType getType() {
return CellType.LABEL;
}
}

View File

@@ -0,0 +1,9 @@
package jxl.read.biff;
import jxl.biff.Type;
class LeftMarginRecord extends MarginRecord {
LeftMarginRecord(Record r) {
super(Type.LEFTMARGIN, r);
}
}

View File

@@ -0,0 +1,19 @@
package jxl.read.biff;
import jxl.biff.DoubleHelper;
import jxl.biff.RecordData;
import jxl.biff.Type;
abstract class MarginRecord extends RecordData {
private double margin;
protected MarginRecord(Type t, Record r) {
super(t);
byte[] data = r.getData();
this.margin = DoubleHelper.getIEEEDouble(data, 0);
}
double getMargin() {
return this.margin;
}
}

View File

@@ -0,0 +1,35 @@
package jxl.read.biff;
import jxl.Range;
import jxl.Sheet;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.SheetRangeImpl;
public class MergedCellsRecord extends RecordData {
private Range[] ranges;
MergedCellsRecord(Record t, Sheet s) {
super(t);
byte[] data = getRecord().getData();
int numRanges = IntegerHelper.getInt(data[0], data[1]);
this.ranges = new Range[numRanges];
int pos = 2;
int firstRow = 0;
int lastRow = 0;
int firstCol = 0;
int lastCol = 0;
for (int i = 0; i < numRanges; i++) {
firstRow = IntegerHelper.getInt(data[pos], data[pos + 1]);
lastRow = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
firstCol = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
lastCol = IntegerHelper.getInt(data[pos + 6], data[pos + 7]);
this.ranges[i] = (Range)new SheetRangeImpl(s, firstCol, firstRow, lastCol, lastRow);
pos += 8;
}
}
public Range[] getRanges() {
return this.ranges;
}
}

View File

@@ -0,0 +1,81 @@
package jxl.read.biff;
import common.Logger;
import jxl.Cell;
import jxl.CellFeatures;
import jxl.CellType;
import jxl.biff.FormattingRecords;
import jxl.format.CellFormat;
class MulBlankCell implements Cell, CellFeaturesAccessor {
private static Logger logger = Logger.getLogger(MulBlankCell.class);
private int row;
private int column;
private CellFormat cellFormat;
private int xfIndex;
private FormattingRecords formattingRecords;
private boolean initialized;
private SheetImpl sheet;
private CellFeatures features;
public MulBlankCell(int r, int c, int xfi, FormattingRecords fr, SheetImpl si) {
this.row = r;
this.column = c;
this.xfIndex = xfi;
this.formattingRecords = fr;
this.sheet = si;
this.initialized = false;
}
public final int getRow() {
return this.row;
}
public final int getColumn() {
return this.column;
}
public String getContents() {
return "";
}
public CellType getType() {
return CellType.EMPTY;
}
public CellFormat getCellFormat() {
if (!this.initialized) {
this.cellFormat = (CellFormat)this.formattingRecords.getXFRecord(this.xfIndex);
this.initialized = true;
}
return this.cellFormat;
}
public boolean isHidden() {
ColumnInfoRecord cir = this.sheet.getColumnInfo(this.column);
if (cir != null && cir.getWidth() == 0)
return true;
RowRecord rr = this.sheet.getRowInfo(this.row);
if (rr != null && (rr.getRowHeight() == 0 || rr.isCollapsed()))
return true;
return false;
}
public CellFeatures getCellFeatures() {
return this.features;
}
public void setCellFeatures(CellFeatures cf) {
if (this.features != null)
logger.warn("current cell features not null - overwriting");
this.features = cf;
}
}

View File

@@ -0,0 +1,55 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class MulBlankRecord extends RecordData {
private static Logger logger = Logger.getLogger(MulBlankRecord.class);
private int row;
private int colFirst;
private int colLast;
private int numblanks;
private int[] xfIndices;
public MulBlankRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
int length = getRecord().getLength();
this.row = IntegerHelper.getInt(data[0], data[1]);
this.colFirst = IntegerHelper.getInt(data[2], data[3]);
this.colLast = IntegerHelper.getInt(data[length - 2], data[length - 1]);
this.numblanks = this.colLast - this.colFirst + 1;
this.xfIndices = new int[this.numblanks];
readBlanks(data);
}
private void readBlanks(byte[] data) {
int pos = 4;
for (int i = 0; i < this.numblanks; i++) {
this.xfIndices[i] = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
}
}
public int getRow() {
return this.row;
}
public int getFirstColumn() {
return this.colFirst;
}
public int getNumberOfColumns() {
return this.numblanks;
}
public int getXFIndex(int index) {
return this.xfIndices[index];
}
}

View File

@@ -0,0 +1,64 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class MulRKRecord extends RecordData {
private static Logger logger = Logger.getLogger(MulRKRecord.class);
private int row;
private int colFirst;
private int colLast;
private int numrks;
private int[] rknumbers;
private int[] xfIndices;
public MulRKRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
int length = getRecord().getLength();
this.row = IntegerHelper.getInt(data[0], data[1]);
this.colFirst = IntegerHelper.getInt(data[2], data[3]);
this.colLast = IntegerHelper.getInt(data[length - 2], data[length - 1]);
this.numrks = this.colLast - this.colFirst + 1;
this.rknumbers = new int[this.numrks];
this.xfIndices = new int[this.numrks];
readRks(data);
}
private void readRks(byte[] data) {
int pos = 4;
for (int i = 0; i < this.numrks; i++) {
this.xfIndices[i] = IntegerHelper.getInt(data[pos], data[pos + 1]);
int rk = IntegerHelper.getInt(data[pos + 2], data[pos + 3], data[pos + 4], data[pos + 5]);
this.rknumbers[i] = rk;
pos += 6;
}
}
public int getRow() {
return this.row;
}
public int getFirstColumn() {
return this.colFirst;
}
public int getNumberOfColumns() {
return this.numrks;
}
public int getRKNumber(int index) {
return this.rknumbers[index];
}
public int getXFIndex(int index) {
return this.xfIndices[index];
}
}

View File

@@ -0,0 +1,283 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import java.util.ArrayList;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;
public class NameRecord extends RecordData {
private static Logger logger = Logger.getLogger(NameRecord.class);
private String name;
private int index;
private int sheetRef = 0;
private boolean isbiff8;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
private static final int commandMacro = 12;
private static final int builtIn = 32;
private static final int cellReference = 58;
private static final int areaReference = 59;
private static final int subExpression = 41;
private static final int union = 16;
private ArrayList ranges;
public class NameRange {
private int columnFirst;
private int rowFirst;
private int columnLast;
private int rowLast;
private int externalSheet;
private final NameRecord this$0;
NameRange(NameRecord this$0, int s1, int c1, int r1, int c2, int r2) {
this.this$0 = this$0;
this.columnFirst = c1;
this.rowFirst = r1;
this.columnLast = c2;
this.rowLast = r2;
this.externalSheet = s1;
}
public int getFirstColumn() {
return this.columnFirst;
}
public int getFirstRow() {
return this.rowFirst;
}
public int getLastColumn() {
return this.columnLast;
}
public int getLastRow() {
return this.rowLast;
}
public int getExternalSheet() {
return this.externalSheet;
}
}
private static final String[] builtInNames = new String[] {
"Consolidate_Area", "Auto_Open", "Auto_Close", "Extract", "Database", "Criteria", "Print_Area", "Print_Titles", "Recorder", "Data_Form",
"Auto_Activate", "Auto_Deactivate", "Sheet_Title", "_FilterDatabase" };
NameRecord(Record t, WorkbookSettings ws, int ind) {
super(t);
this.index = ind;
this.isbiff8 = true;
try {
this.ranges = new ArrayList();
byte[] data = getRecord().getData();
int option = IntegerHelper.getInt(data[0], data[1]);
int length = data[3];
this.sheetRef = IntegerHelper.getInt(data[8], data[9]);
if ((option & 0x20) != 0) {
this.name = (data[15] < 13) ? builtInNames[data[15]] : ("Builtin_" + Integer.toString(data[15], 16));
return;
}
this.name = StringHelper.getString(data, length, 15, ws);
if ((option & 0xC) != 0)
return;
int pos = length + 15;
if (data[pos] == 58) {
int sheet = IntegerHelper.getInt(data[pos + 1], data[pos + 2]);
int row = IntegerHelper.getInt(data[pos + 3], data[pos + 4]);
int columnMask = IntegerHelper.getInt(data[pos + 5], data[pos + 6]);
int column = columnMask & 0xFF;
Assert.verify(((columnMask & 0xC0000) == 0));
NameRange r = new NameRange(this, sheet, column, row, column, row);
this.ranges.add(r);
} else if (data[pos] == 59) {
int sheet1 = 0;
int r1 = 0;
int columnMask = 0;
int c1 = 0;
int r2 = 0;
int c2 = 0;
NameRange range = null;
while (pos < data.length) {
sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]);
r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]);
r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]);
columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]);
c1 = columnMask & 0xFF;
Assert.verify(((columnMask & 0xC0000) == 0));
columnMask = IntegerHelper.getInt(data[pos + 9], data[pos + 10]);
c2 = columnMask & 0xFF;
Assert.verify(((columnMask & 0xC0000) == 0));
range = new NameRange(this, sheet1, c1, r1, c2, r2);
this.ranges.add(range);
pos += 11;
}
} else if (data[pos] == 41) {
int sheet1 = 0;
int r1 = 0;
int columnMask = 0;
int c1 = 0;
int r2 = 0;
int c2 = 0;
NameRange range = null;
if (pos < data.length && data[pos] != 58 && data[pos] != 59)
if (data[pos] == 41) {
pos += 3;
} else if (data[pos] == 16) {
pos++;
}
while (pos < data.length) {
sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]);
r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]);
r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]);
columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]);
c1 = columnMask & 0xFF;
Assert.verify(((columnMask & 0xC0000) == 0));
columnMask = IntegerHelper.getInt(data[pos + 9], data[pos + 10]);
c2 = columnMask & 0xFF;
Assert.verify(((columnMask & 0xC0000) == 0));
range = new NameRange(this, sheet1, c1, r1, c2, r2);
this.ranges.add(range);
pos += 11;
if (pos < data.length && data[pos] != 58 && data[pos] != 59) {
if (data[pos] == 41) {
pos += 3;
continue;
}
if (data[pos] == 16)
pos++;
}
}
}
} catch (Throwable t1) {
logger.warn("Cannot read name");
this.name = "ERROR";
}
}
NameRecord(Record t, WorkbookSettings ws, int ind, Biff7 dummy) {
super(t);
this.index = ind;
this.isbiff8 = false;
try {
this.ranges = new ArrayList();
byte[] data = getRecord().getData();
int length = data[3];
this.sheetRef = IntegerHelper.getInt(data[8], data[9]);
this.name = StringHelper.getString(data, length, 14, ws);
int pos = length + 14;
if (pos >= data.length)
return;
if (data[pos] == 58) {
int sheet = IntegerHelper.getInt(data[pos + 11], data[pos + 12]);
int row = IntegerHelper.getInt(data[pos + 15], data[pos + 16]);
int column = data[pos + 17];
NameRange r = new NameRange(this, sheet, column, row, column, row);
this.ranges.add(r);
} else if (data[pos] == 59) {
int sheet1 = 0;
int r1 = 0;
int c1 = 0;
int r2 = 0;
int c2 = 0;
NameRange range = null;
while (pos < data.length) {
sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]);
r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]);
r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]);
c1 = data[pos + 19];
c2 = data[pos + 20];
range = new NameRange(this, sheet1, c1, r1, c2, r2);
this.ranges.add(range);
pos += 21;
}
} else if (data[pos] == 41) {
int sheet1 = 0;
int sheet2 = 0;
int r1 = 0;
int c1 = 0;
int r2 = 0;
int c2 = 0;
NameRange range = null;
if (pos < data.length && data[pos] != 58 && data[pos] != 59)
if (data[pos] == 41) {
pos += 3;
} else if (data[pos] == 16) {
pos++;
}
while (pos < data.length) {
sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]);
r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]);
r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]);
c1 = data[pos + 19];
c2 = data[pos + 20];
range = new NameRange(this, sheet1, c1, r1, c2, r2);
this.ranges.add(range);
pos += 21;
if (pos < data.length && data[pos] != 58 && data[pos] != 59) {
if (data[pos] == 41) {
pos += 3;
continue;
}
if (data[pos] == 16)
pos++;
}
}
}
} catch (Throwable t1) {
logger.warn("Cannot read name.");
this.name = "ERROR";
}
}
public String getName() {
return this.name;
}
public NameRange[] getRanges() {
NameRange[] nr = new NameRange[this.ranges.size()];
return (NameRange[])this.ranges.toArray((Object[])nr);
}
int getIndex() {
return this.index;
}
public int getSheetRef() {
return this.sheetRef;
}
public void setSheetRef(int i) {
this.sheetRef = i;
}
public byte[] getData() {
return getRecord().getData();
}
public boolean isBiff8() {
return this.isbiff8;
}
}

View File

@@ -0,0 +1,17 @@
package jxl.read.biff;
import jxl.biff.RecordData;
class NineteenFourRecord extends RecordData {
private boolean nineteenFour;
public NineteenFourRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.nineteenFour = (data[0] == 1);
}
public boolean is1904() {
return this.nineteenFour;
}
}

View File

@@ -0,0 +1,79 @@
package jxl.read.biff;
import common.Logger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import jxl.CellType;
import jxl.NumberCell;
import jxl.NumberFormulaCell;
import jxl.biff.DoubleHelper;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
class NumberFormulaRecord extends CellValue implements NumberCell, FormulaData, NumberFormulaCell {
private static Logger logger = Logger.getLogger(NumberFormulaRecord.class);
private double value;
private NumberFormat format;
private static final DecimalFormat defaultFormat = new DecimalFormat("#.###");
private String formulaString;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private byte[] data;
public NumberFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.data = getRecord().getData();
this.format = fr.getNumberFormat(getXFIndex());
if (this.format == null)
this.format = defaultFormat;
this.value = DoubleHelper.getIEEEDouble(this.data, 6);
}
public double getValue() {
return this.value;
}
public String getContents() {
return !Double.isNaN(this.value) ? this.format.format(this.value) : "";
}
public CellType getType() {
return CellType.NUMBER_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
byte[] d = new byte[this.data.length - 6];
System.arraycopy(this.data, 6, d, 0, this.data.length - 6);
return d;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
byte[] tokens = new byte[this.data.length - 22];
System.arraycopy(this.data, 22, tokens, 0, tokens.length);
FormulaParser fp = new FormulaParser(tokens, this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
public NumberFormat getNumberFormat() {
return this.format;
}
}

View File

@@ -0,0 +1,44 @@
package jxl.read.biff;
import common.Logger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import jxl.CellType;
import jxl.NumberCell;
import jxl.biff.DoubleHelper;
import jxl.biff.FormattingRecords;
class NumberRecord extends CellValue implements NumberCell {
private static Logger logger = Logger.getLogger(NumberRecord.class);
private double value;
private NumberFormat format;
private static DecimalFormat defaultFormat = new DecimalFormat("#.###");
public NumberRecord(Record t, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.value = DoubleHelper.getIEEEDouble(data, 6);
this.format = fr.getNumberFormat(getXFIndex());
if (this.format == null)
this.format = defaultFormat;
}
public double getValue() {
return this.value;
}
public String getContents() {
return this.format.format(this.value);
}
public CellType getType() {
return CellType.NUMBER;
}
public NumberFormat getNumberFormat() {
return this.format;
}
}

View File

@@ -0,0 +1,99 @@
package jxl.read.biff;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import jxl.CellFeatures;
import jxl.CellType;
import jxl.NumberCell;
import jxl.biff.FormattingRecords;
import jxl.format.CellFormat;
class NumberValue implements NumberCell, CellFeaturesAccessor {
private int row;
private int column;
private double value;
private NumberFormat format;
private CellFormat cellFormat;
private CellFeatures features;
private int xfIndex;
private FormattingRecords formattingRecords;
private boolean initialized;
private SheetImpl sheet;
private static DecimalFormat defaultFormat = new DecimalFormat("#.###");
public NumberValue(int r, int c, double val, int xfi, FormattingRecords fr, SheetImpl si) {
this.row = r;
this.column = c;
this.value = val;
this.format = defaultFormat;
this.xfIndex = xfi;
this.formattingRecords = fr;
this.sheet = si;
this.initialized = false;
}
final void setNumberFormat(NumberFormat f) {
if (f != null)
this.format = f;
}
public final int getRow() {
return this.row;
}
public final int getColumn() {
return this.column;
}
public double getValue() {
return this.value;
}
public String getContents() {
return this.format.format(this.value);
}
public CellType getType() {
return CellType.NUMBER;
}
public CellFormat getCellFormat() {
if (!this.initialized) {
this.cellFormat = (CellFormat)this.formattingRecords.getXFRecord(this.xfIndex);
this.initialized = true;
}
return this.cellFormat;
}
public boolean isHidden() {
ColumnInfoRecord cir = this.sheet.getColumnInfo(this.column);
if (cir != null && cir.getWidth() == 0)
return true;
RowRecord rr = this.sheet.getRowInfo(this.row);
if (rr != null && (rr.getRowHeight() == 0 || rr.isCollapsed()))
return true;
return false;
}
public NumberFormat getNumberFormat() {
return this.format;
}
public CellFeatures getCellFeatures() {
return this.features;
}
public void setCellFeatures(CellFeatures cf) {
this.features = cf;
}
}

View File

@@ -0,0 +1,13 @@
package jxl.read.biff;
import jxl.biff.RecordData;
public class PLSRecord extends RecordData {
public PLSRecord(Record r) {
super(r);
}
public byte[] getData() {
return getRecord().getData();
}
}

View File

@@ -0,0 +1,28 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class PaneRecord extends RecordData {
private static Logger logger = Logger.getLogger(PaneRecord.class);
private int rowsVisible;
private int columnsVisible;
public PaneRecord(Record t) {
super(t);
byte[] data = t.getData();
this.columnsVisible = IntegerHelper.getInt(data[0], data[1]);
this.rowsVisible = IntegerHelper.getInt(data[2], data[3]);
}
public final int getRowsVisible() {
return this.rowsVisible;
}
public final int getColumnsVisible() {
return this.columnsVisible;
}
}

View File

@@ -0,0 +1,7 @@
package jxl.read.biff;
public class PasswordException extends BiffException {
public PasswordException() {
super(passwordProtected);
}
}

View File

@@ -0,0 +1,21 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.Type;
class PasswordRecord extends RecordData {
private String password;
private int passwordHash;
public PasswordRecord(Record t) {
super(Type.PASSWORD);
byte[] data = t.getData();
this.passwordHash = IntegerHelper.getInt(data[0], data[1]);
}
public int getPasswordHash() {
return this.passwordHash;
}
}

View File

@@ -0,0 +1,17 @@
package jxl.read.biff;
import jxl.biff.RecordData;
class PrintGridLinesRecord extends RecordData {
private boolean printGridLines;
public PrintGridLinesRecord(Record pgl) {
super(pgl);
byte[] data = pgl.getData();
this.printGridLines = (data[0] == 1);
}
public boolean getPrintGridLines() {
return this.printGridLines;
}
}

View File

@@ -0,0 +1,17 @@
package jxl.read.biff;
import jxl.biff.RecordData;
class PrintHeadersRecord extends RecordData {
private boolean printHeaders;
public PrintHeadersRecord(Record ph) {
super(ph);
byte[] data = ph.getData();
this.printHeaders = (data[0] == 1);
}
public boolean getPrintHeaders() {
return this.printHeaders;
}
}

View File

@@ -0,0 +1,19 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class ProtectRecord extends RecordData {
private boolean prot;
ProtectRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
int protflag = IntegerHelper.getInt(data[0], data[1]);
this.prot = (protflag == 1);
}
boolean isProtected() {
return this.prot;
}
}

View File

@@ -0,0 +1,19 @@
package jxl.read.biff;
final class RKHelper {
public static double getDouble(int rk) {
if ((rk & 0x2) != 0) {
int intval = rk >> 2;
double d = intval;
if ((rk & 0x1) != 0)
d /= 100.0D;
return d;
}
long valbits = (rk & 0xFFFFFFFC);
valbits <<= 32L;
double value = Double.longBitsToDouble(valbits);
if ((rk & 0x1) != 0)
value /= 100.0D;
return value;
}
}

View File

@@ -0,0 +1,45 @@
package jxl.read.biff;
import common.Logger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import jxl.CellType;
import jxl.NumberCell;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
class RKRecord extends CellValue implements NumberCell {
private static Logger logger = Logger.getLogger(RKRecord.class);
private double value;
private NumberFormat format;
private static DecimalFormat defaultFormat = new DecimalFormat("#.###");
public RKRecord(Record t, FormattingRecords fr, SheetImpl si) {
super(t, fr, si);
byte[] data = getRecord().getData();
int rknum = IntegerHelper.getInt(data[6], data[7], data[8], data[9]);
this.value = RKHelper.getDouble(rknum);
this.format = fr.getNumberFormat(getXFIndex());
if (this.format == null)
this.format = defaultFormat;
}
public double getValue() {
return this.value;
}
public String getContents() {
return this.format.format(this.value);
}
public CellType getType() {
return CellType.NUMBER;
}
public NumberFormat getNumberFormat() {
return this.format;
}
}

View File

@@ -0,0 +1,39 @@
package jxl.read.biff;
import jxl.CellType;
import jxl.LabelCell;
import jxl.WorkbookSettings;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
class RStringRecord extends CellValue implements LabelCell {
private int length;
private String string;
private static class Biff7 {
private Biff7() {}
}
public static Biff7 biff7 = new Biff7();
public RStringRecord(Record t, FormattingRecords fr, SheetImpl si, WorkbookSettings ws, Biff7 dummy) {
super(t, fr, si);
byte[] data = getRecord().getData();
this.length = IntegerHelper.getInt(data[6], data[7]);
this.string = StringHelper.getString(data, this.length, 8, ws);
}
public String getString() {
return this.string;
}
public String getContents() {
return this.string;
}
public CellType getType() {
return CellType.LABEL;
}
}

View File

@@ -0,0 +1,81 @@
package jxl.read.biff;
import common.Logger;
import java.util.ArrayList;
import jxl.biff.IntegerHelper;
import jxl.biff.Type;
public final class Record {
private static final Logger logger = Logger.getLogger(Record.class);
private int code;
private Type type;
private int length;
private int dataPos;
private File file;
private byte[] data;
private ArrayList continueRecords;
Record(byte[] d, int offset, File f) {
this.code = IntegerHelper.getInt(d[offset], d[offset + 1]);
this.length = IntegerHelper.getInt(d[offset + 2], d[offset + 3]);
this.file = f;
this.file.skip(4);
this.dataPos = f.getPos();
this.file.skip(this.length);
this.type = Type.getType(this.code);
}
public Type getType() {
return this.type;
}
public int getLength() {
return this.length;
}
public byte[] getData() {
if (this.data == null)
this.data = this.file.read(this.dataPos, this.length);
if (this.continueRecords != null) {
int size = 0;
byte[][] contData = new byte[this.continueRecords.size()][];
for (int i = 0; i < this.continueRecords.size(); i++) {
Record r = this.continueRecords.get(i);
contData[i] = r.getData();
byte[] d2 = contData[i];
size += d2.length;
}
byte[] d3 = new byte[this.data.length + size];
System.arraycopy(this.data, 0, d3, 0, this.data.length);
int pos = this.data.length;
for (int j = 0; j < contData.length; j++) {
byte[] d2 = contData[j];
System.arraycopy(d2, 0, d3, pos, d2.length);
pos += d2.length;
}
this.data = d3;
}
return this.data;
}
public int getCode() {
return this.code;
}
void setType(Type t) {
this.type = t;
}
public void addContinueRecord(Record d) {
if (this.continueRecords == null)
this.continueRecords = new ArrayList();
this.continueRecords.add(d);
}
}

View File

@@ -0,0 +1,9 @@
package jxl.read.biff;
import jxl.biff.Type;
class RightMarginRecord extends MarginRecord {
RightMarginRecord(Record r) {
super(Type.RIGHTMARGIN, r);
}
}

View File

@@ -0,0 +1,63 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
public class RowRecord extends RecordData {
private static Logger logger = Logger.getLogger(RowRecord.class);
private int rowNumber;
private int rowHeight;
private boolean collapsed;
private boolean defaultFormat;
private boolean matchesDefFontHeight;
private int xfIndex;
private static final int defaultHeightIndicator = 255;
RowRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
this.rowNumber = IntegerHelper.getInt(data[0], data[1]);
this.rowHeight = IntegerHelper.getInt(data[6], data[7]);
int options = IntegerHelper.getInt(data[12], data[13], data[14], data[15]);
this.collapsed = ((options & 0x20) != 0);
this.matchesDefFontHeight = ((options & 0x40) == 0);
this.defaultFormat = ((options & 0x80) != 0);
this.xfIndex = (options & 0xFFF0000) >> 16;
}
boolean isDefaultHeight() {
return (this.rowHeight == 255);
}
public boolean matchesDefaultFontHeight() {
return this.matchesDefFontHeight;
}
public int getRowNumber() {
return this.rowNumber;
}
public int getRowHeight() {
return this.rowHeight;
}
public boolean isCollapsed() {
return this.collapsed;
}
public int getXFIndex() {
return this.xfIndex;
}
public boolean hasDefaultFormat() {
return this.defaultFormat;
}
}

View File

@@ -0,0 +1,22 @@
package jxl.read.biff;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.Type;
class SCLRecord extends RecordData {
private int numerator;
private int denominator;
protected SCLRecord(Record r) {
super(Type.SCL);
byte[] data = r.getData();
this.numerator = IntegerHelper.getInt(data[0], data[1]);
this.denominator = IntegerHelper.getInt(data[2], data[3]);
}
public int getZoomFactor() {
return this.numerator * 100 / this.denominator;
}
}

View File

@@ -0,0 +1,179 @@
package jxl.read.biff;
import common.Assert;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;
class SSTRecord extends RecordData {
private int totalStrings;
private int uniqueStrings;
private String[] strings;
private int[] continuationBreaks;
private static class ByteArrayHolder {
public byte[] bytes;
private ByteArrayHolder() {}
}
private static class BooleanHolder {
public boolean value;
private BooleanHolder() {}
}
public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws) {
super(t);
int totalRecordLength = 0;
for (int i = 0; i < continuations.length; i++)
totalRecordLength += continuations[i].getLength();
totalRecordLength += getRecord().getLength();
byte[] data = new byte[totalRecordLength];
int pos = 0;
System.arraycopy(getRecord().getData(), 0, data, 0, getRecord().getLength());
pos += getRecord().getLength();
this.continuationBreaks = new int[continuations.length];
Record r = null;
for (int j = 0; j < continuations.length; j++) {
r = continuations[j];
System.arraycopy(r.getData(), 0, data, pos, r.getLength());
this.continuationBreaks[j] = pos;
pos += r.getLength();
}
this.totalStrings = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
this.uniqueStrings = IntegerHelper.getInt(data[4], data[5], data[6], data[7]);
this.strings = new String[this.uniqueStrings];
readStrings(data, 8, ws);
}
private void readStrings(byte[] data, int offset, WorkbookSettings ws) {
int pos = offset;
String s = null;
boolean asciiEncoding = false;
boolean richString = false;
boolean extendedString = false;
int formattingRuns = 0;
int extendedRunLength = 0;
for (int i = 0; i < this.uniqueStrings; i++) {
int numChars = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
byte optionFlags = data[pos];
pos++;
extendedString = ((optionFlags & 0x4) != 0);
richString = ((optionFlags & 0x8) != 0);
if (richString) {
formattingRuns = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
}
if (extendedString) {
extendedRunLength = IntegerHelper.getInt(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]);
pos += 4;
}
asciiEncoding = ((optionFlags & 0x1) == 0);
ByteArrayHolder bah = new ByteArrayHolder();
BooleanHolder bh = new BooleanHolder();
bh.value = asciiEncoding;
pos += getChars(data, bah, pos, bh, numChars);
asciiEncoding = bh.value;
if (asciiEncoding) {
s = StringHelper.getString(bah.bytes, numChars, 0, ws);
} else {
s = StringHelper.getUnicodeString(bah.bytes, numChars, 0);
}
this.strings[i] = s;
if (richString)
pos += 4 * formattingRuns;
if (extendedString)
pos += extendedRunLength;
if (pos > data.length)
Assert.verify(false, "pos exceeds record length");
}
}
private int getChars(byte[] source, ByteArrayHolder bah, int pos, BooleanHolder ascii, int numChars) {
int charsRead, i = 0;
boolean spansBreak = false;
if (ascii.value) {
bah.bytes = new byte[numChars];
} else {
bah.bytes = new byte[numChars * 2];
}
while (i < this.continuationBreaks.length && !spansBreak) {
spansBreak = (pos <= this.continuationBreaks[i] && pos + bah.bytes.length > this.continuationBreaks[i]);
if (!spansBreak)
i++;
}
if (!spansBreak) {
System.arraycopy(source, pos, bah.bytes, 0, bah.bytes.length);
return bah.bytes.length;
}
int breakpos = this.continuationBreaks[i];
System.arraycopy(source, pos, bah.bytes, 0, breakpos - pos);
int bytesRead = breakpos - pos;
if (ascii.value) {
charsRead = bytesRead;
} else {
charsRead = bytesRead / 2;
}
bytesRead += getContinuedString(source, bah, bytesRead, i, ascii, numChars - charsRead);
return bytesRead;
}
private int getContinuedString(byte[] source, ByteArrayHolder bah, int destPos, int contBreakIndex, BooleanHolder ascii, int charsLeft) {
int breakpos = this.continuationBreaks[contBreakIndex];
int bytesRead = 0;
while (charsLeft > 0) {
Assert.verify((contBreakIndex < this.continuationBreaks.length), "continuation break index");
if (ascii.value && source[breakpos] == 0) {
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? charsLeft : Math.min(charsLeft, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
destPos += length;
bytesRead += length + 1;
charsLeft -= length;
ascii.value = true;
} else if (!ascii.value && source[breakpos] != 0) {
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? (charsLeft * 2) : Math.min(charsLeft * 2, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
destPos += length;
bytesRead += length + 1;
charsLeft -= length / 2;
ascii.value = false;
} else if (!ascii.value && source[breakpos] == 0) {
int chars = (contBreakIndex == this.continuationBreaks.length - 1) ? charsLeft : Math.min(charsLeft, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
for (int j = 0; j < chars; j++) {
bah.bytes[destPos] = source[breakpos + j + 1];
destPos += 2;
}
bytesRead += chars + 1;
charsLeft -= chars;
ascii.value = false;
} else {
byte[] oldBytes = bah.bytes;
bah.bytes = new byte[destPos * 2 + charsLeft * 2];
for (int j = 0; j < destPos; j++)
bah.bytes[j * 2] = oldBytes[j];
destPos *= 2;
int length = (contBreakIndex == this.continuationBreaks.length - 1) ? (charsLeft * 2) : Math.min(charsLeft * 2, this.continuationBreaks[contBreakIndex + 1] - breakpos - 1);
System.arraycopy(source, breakpos + 1, bah.bytes, destPos, length);
destPos += length;
bytesRead += length + 1;
charsLeft -= length / 2;
ascii.value = false;
}
contBreakIndex++;
if (contBreakIndex < this.continuationBreaks.length)
breakpos = this.continuationBreaks[contBreakIndex];
}
return bytesRead;
}
public String getString(int index) {
Assert.verify((index < this.uniqueStrings));
return this.strings[index];
}
}

View File

@@ -0,0 +1,22 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class SaveRecalcRecord extends RecordData {
private static Logger logger = Logger.getLogger(SaveRecalcRecord.class);
private boolean recalculateOnSave;
public SaveRecalcRecord(Record t) {
super(t);
byte[] data = t.getData();
int mode = IntegerHelper.getInt(data[0], data[1]);
this.recalculateOnSave = (mode == 1);
}
public boolean getRecalculateOnSave() {
return this.recalculateOnSave;
}
}

View File

@@ -0,0 +1,93 @@
package jxl.read.biff;
import jxl.biff.DoubleHelper;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.Type;
public class SetupRecord extends RecordData {
private byte[] data;
private boolean portraitOrientation;
private double headerMargin;
private double footerMargin;
private int paperSize;
private int scaleFactor;
private int pageStart;
private int fitWidth;
private int fitHeight;
private int horizontalPrintResolution;
private int verticalPrintResolution;
private int copies;
SetupRecord(Record t) {
super(Type.SETUP);
this.data = t.getData();
this.paperSize = IntegerHelper.getInt(this.data[0], this.data[1]);
this.scaleFactor = IntegerHelper.getInt(this.data[2], this.data[3]);
this.pageStart = IntegerHelper.getInt(this.data[4], this.data[5]);
this.fitWidth = IntegerHelper.getInt(this.data[6], this.data[7]);
this.fitHeight = IntegerHelper.getInt(this.data[8], this.data[9]);
this.horizontalPrintResolution = IntegerHelper.getInt(this.data[12], this.data[13]);
this.verticalPrintResolution = IntegerHelper.getInt(this.data[14], this.data[15]);
this.copies = IntegerHelper.getInt(this.data[32], this.data[33]);
this.headerMargin = DoubleHelper.getIEEEDouble(this.data, 16);
this.footerMargin = DoubleHelper.getIEEEDouble(this.data, 24);
int grbit = IntegerHelper.getInt(this.data[10], this.data[11]);
this.portraitOrientation = ((grbit & 0x2) != 0);
}
public boolean isPortrait() {
return this.portraitOrientation;
}
public double getHeaderMargin() {
return this.headerMargin;
}
public double getFooterMargin() {
return this.footerMargin;
}
public int getPaperSize() {
return this.paperSize;
}
public int getScaleFactor() {
return this.scaleFactor;
}
public int getPageStart() {
return this.pageStart;
}
public int getFitWidth() {
return this.fitWidth;
}
public int getFitHeight() {
return this.fitHeight;
}
public int getHorizontalPrintResolution() {
return this.horizontalPrintResolution;
}
public int getVerticalPrintResolution() {
return this.verticalPrintResolution;
}
public int getCopies() {
return this.copies;
}
}

View File

@@ -0,0 +1,67 @@
package jxl.read.biff;
import java.text.DateFormat;
import java.util.Date;
import jxl.CellType;
import jxl.DateCell;
import jxl.DateFormulaCell;
import jxl.biff.DoubleHelper;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.IntegerHelper;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
public class SharedDateFormulaRecord extends BaseSharedFormulaRecord implements DateCell, FormulaData, DateFormulaCell {
private DateRecord dateRecord;
private double value;
public SharedDateFormulaRecord(SharedNumberFormulaRecord nfr, FormattingRecords fr, boolean nf, SheetImpl si, int pos) {
super(nfr.getRecord(), fr, nfr.getExternalSheet(), nfr.getNameTable(), si, pos);
this.dateRecord = new DateRecord(nfr, nfr.getXFIndex(), fr, nf, si);
this.value = nfr.getValue();
}
public double getValue() {
return this.value;
}
public String getContents() {
return this.dateRecord.getContents();
}
public CellType getType() {
return CellType.DATE_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
FormulaParser fp = new FormulaParser(getTokens(), this, getExternalSheet(), getNameTable(), getSheet().getWorkbook().getSettings());
fp.parse();
byte[] rpnTokens = fp.getBytes();
byte[] data = new byte[rpnTokens.length + 22];
IntegerHelper.getTwoBytes(getRow(), data, 0);
IntegerHelper.getTwoBytes(getColumn(), data, 2);
IntegerHelper.getTwoBytes(getXFIndex(), data, 4);
DoubleHelper.getIEEEBytes(this.value, data, 6);
System.arraycopy(rpnTokens, 0, data, 22, rpnTokens.length);
IntegerHelper.getTwoBytes(rpnTokens.length, data, 20);
byte[] d = new byte[data.length - 6];
System.arraycopy(data, 6, d, 0, data.length - 6);
return d;
}
public Date getDate() {
return this.dateRecord.getDate();
}
public boolean isTime() {
return this.dateRecord.isTime();
}
public DateFormat getDateFormat() {
return this.dateRecord.getDateFormat();
}
}

View File

@@ -0,0 +1,64 @@
package jxl.read.biff;
import common.Logger;
import jxl.CellType;
import jxl.ErrorCell;
import jxl.ErrorFormulaCell;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.IntegerHelper;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaErrorCode;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
public class SharedErrorFormulaRecord extends BaseSharedFormulaRecord implements ErrorCell, FormulaData, ErrorFormulaCell {
private static Logger logger = Logger.getLogger(SharedErrorFormulaRecord.class);
private int errorCode;
private byte[] data;
private FormulaErrorCode error;
public SharedErrorFormulaRecord(Record t, File excelFile, int ec, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, es, nt, si, excelFile.getPos());
this.errorCode = ec;
}
public int getErrorCode() {
return this.errorCode;
}
public String getContents() {
if (this.error == null)
this.error = FormulaErrorCode.getErrorCode(this.errorCode);
return (this.error != FormulaErrorCode.UNKNOWN) ? this.error.getDescription() : ("ERROR " + this.errorCode);
}
public CellType getType() {
return CellType.FORMULA_ERROR;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
FormulaParser fp = new FormulaParser(getTokens(), this, getExternalSheet(), getNameTable(), getSheet().getWorkbook().getSettings());
fp.parse();
byte[] rpnTokens = fp.getBytes();
byte[] data = new byte[rpnTokens.length + 22];
IntegerHelper.getTwoBytes(getRow(), data, 0);
IntegerHelper.getTwoBytes(getColumn(), data, 2);
IntegerHelper.getTwoBytes(getXFIndex(), data, 4);
data[6] = 2;
data[8] = (byte)this.errorCode;
data[12] = -1;
data[13] = -1;
System.arraycopy(rpnTokens, 0, data, 22, rpnTokens.length);
IntegerHelper.getTwoBytes(rpnTokens.length, data, 20);
byte[] d = new byte[data.length - 6];
System.arraycopy(data, 6, d, 0, data.length - 6);
return d;
}
}

View File

@@ -0,0 +1,94 @@
package jxl.read.biff;
import common.Logger;
import java.text.NumberFormat;
import java.util.ArrayList;
import jxl.Cell;
import jxl.CellType;
import jxl.biff.FormattingRecords;
import jxl.biff.IntegerHelper;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
class SharedFormulaRecord {
private static Logger logger = Logger.getLogger(SharedFormulaRecord.class);
private int firstRow;
private int lastRow;
private int firstCol;
private int lastCol;
private BaseSharedFormulaRecord templateFormula;
private ArrayList formulas;
private byte[] tokens;
private ExternalSheet externalSheet;
private SheetImpl sheet;
public SharedFormulaRecord(Record t, BaseSharedFormulaRecord fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
this.sheet = si;
byte[] data = t.getData();
this.firstRow = IntegerHelper.getInt(data[0], data[1]);
this.lastRow = IntegerHelper.getInt(data[2], data[3]);
this.firstCol = data[4] & 0xFF;
this.lastCol = data[5] & 0xFF;
this.formulas = new ArrayList();
this.templateFormula = fr;
this.tokens = new byte[data.length - 10];
System.arraycopy(data, 10, this.tokens, 0, this.tokens.length);
}
public boolean add(BaseSharedFormulaRecord fr) {
boolean added = false;
int r = fr.getRow();
if (r >= this.firstRow && r <= this.lastRow) {
int c = fr.getColumn();
if (c >= this.firstCol && c <= this.lastCol) {
this.formulas.add(fr);
added = true;
}
}
return added;
}
Cell[] getFormulas(FormattingRecords fr, boolean nf) {
Cell[] sfs = new Cell[this.formulas.size() + 1];
if (this.templateFormula == null) {
logger.warn("Shared formula template formula is null");
return new Cell[0];
}
this.templateFormula.setTokens(this.tokens);
NumberFormat templateNumberFormat = null;
if (this.templateFormula.getType() == CellType.NUMBER_FORMULA) {
SharedNumberFormulaRecord snfr = (SharedNumberFormulaRecord)this.templateFormula;
templateNumberFormat = snfr.getNumberFormat();
if (fr.isDate(this.templateFormula.getXFIndex())) {
this.templateFormula = new SharedDateFormulaRecord(snfr, fr, nf, this.sheet, snfr.getFilePos());
this.templateFormula.setTokens(snfr.getTokens());
}
}
sfs[0] = this.templateFormula;
BaseSharedFormulaRecord f = null;
for (int i = 0; i < this.formulas.size(); i++) {
f = this.formulas.get(i);
if (f.getType() == CellType.NUMBER_FORMULA) {
SharedNumberFormulaRecord snfr = (SharedNumberFormulaRecord)f;
if (fr.isDate(f.getXFIndex()))
f = new SharedDateFormulaRecord(snfr, fr, nf, this.sheet, snfr.getFilePos());
}
f.setTokens(this.tokens);
sfs[i + 1] = f;
}
return sfs;
}
BaseSharedFormulaRecord getTemplateFormula() {
return this.templateFormula;
}
}

View File

@@ -0,0 +1,73 @@
package jxl.read.biff;
import common.Logger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import jxl.CellType;
import jxl.NumberCell;
import jxl.NumberFormulaCell;
import jxl.biff.DoubleHelper;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.IntegerHelper;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
public class SharedNumberFormulaRecord extends BaseSharedFormulaRecord implements NumberCell, FormulaData, NumberFormulaCell {
private static Logger logger = Logger.getLogger(SharedNumberFormulaRecord.class);
private double value;
private NumberFormat format;
private FormattingRecords formattingRecords;
private static DecimalFormat defaultFormat = new DecimalFormat("#.###");
public SharedNumberFormulaRecord(Record t, File excelFile, double v, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, es, nt, si, excelFile.getPos());
this.value = v;
this.format = defaultFormat;
}
final void setNumberFormat(NumberFormat f) {
if (f != null)
this.format = f;
}
public double getValue() {
return this.value;
}
public String getContents() {
return !Double.isNaN(this.value) ? this.format.format(this.value) : "";
}
public CellType getType() {
return CellType.NUMBER_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
FormulaParser fp = new FormulaParser(getTokens(), this, getExternalSheet(), getNameTable(), getSheet().getWorkbook().getSettings());
fp.parse();
byte[] rpnTokens = fp.getBytes();
byte[] data = new byte[rpnTokens.length + 22];
IntegerHelper.getTwoBytes(getRow(), data, 0);
IntegerHelper.getTwoBytes(getColumn(), data, 2);
IntegerHelper.getTwoBytes(getXFIndex(), data, 4);
DoubleHelper.getIEEEBytes(this.value, data, 6);
System.arraycopy(rpnTokens, 0, data, 22, rpnTokens.length);
IntegerHelper.getTwoBytes(rpnTokens.length, data, 20);
byte[] d = new byte[data.length - 6];
System.arraycopy(data, 6, d, 0, data.length - 6);
return d;
}
public NumberFormat getNumberFormat() {
return this.format;
}
}

View File

@@ -0,0 +1,88 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import jxl.CellType;
import jxl.LabelCell;
import jxl.StringFormulaCell;
import jxl.WorkbookSettings;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
import jxl.biff.Type;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
public class SharedStringFormulaRecord extends BaseSharedFormulaRecord implements LabelCell, FormulaData, StringFormulaCell {
private static Logger logger = Logger.getLogger(SharedStringFormulaRecord.class);
private String value;
public SharedStringFormulaRecord(Record t, File excelFile, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si, WorkbookSettings ws) {
super(t, fr, es, nt, si, excelFile.getPos());
int pos = excelFile.getPos();
int filepos = excelFile.getPos();
Record nextRecord = excelFile.next();
int count = 0;
while (nextRecord.getType() != Type.STRING && count < 4) {
nextRecord = excelFile.next();
count++;
}
Assert.verify((count < 4), " @ " + pos);
byte[] stringData = nextRecord.getData();
int chars = IntegerHelper.getInt(stringData[0], stringData[1]);
boolean unicode = false;
int startpos = 3;
if (stringData.length == chars + 2) {
startpos = 2;
unicode = false;
} else if (stringData[2] == 1) {
startpos = 3;
unicode = true;
} else {
startpos = 3;
unicode = false;
}
if (!unicode) {
this.value = StringHelper.getString(stringData, chars, startpos, ws);
} else {
this.value = StringHelper.getUnicodeString(stringData, chars, startpos);
}
excelFile.setPos(filepos);
}
public String getString() {
return this.value;
}
public String getContents() {
return this.value;
}
public CellType getType() {
return CellType.STRING_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
FormulaParser fp = new FormulaParser(getTokens(), this, getExternalSheet(), getNameTable(), getSheet().getWorkbook().getSettings());
fp.parse();
byte[] rpnTokens = fp.getBytes();
byte[] data = new byte[rpnTokens.length + 22];
IntegerHelper.getTwoBytes(getRow(), data, 0);
IntegerHelper.getTwoBytes(getColumn(), data, 2);
IntegerHelper.getTwoBytes(getXFIndex(), data, 4);
data[6] = 0;
data[12] = -1;
data[13] = -1;
System.arraycopy(rpnTokens, 0, data, 22, rpnTokens.length);
IntegerHelper.getTwoBytes(rpnTokens.length, data, 20);
byte[] d = new byte[data.length - 6];
System.arraycopy(data, 6, d, 0, data.length - 6);
return d;
}
}

View File

@@ -0,0 +1,460 @@
package jxl.read.biff;
import java.util.ArrayList;
import java.util.Iterator;
import jxl.Cell;
import jxl.CellType;
import jxl.CellView;
import jxl.Hyperlink;
import jxl.Image;
import jxl.LabelCell;
import jxl.Range;
import jxl.Sheet;
import jxl.SheetSettings;
import jxl.WorkbookSettings;
import jxl.biff.CellReferenceHelper;
import jxl.biff.EmptyCell;
import jxl.biff.FormattingRecords;
import jxl.biff.Type;
import jxl.biff.WorkspaceInformationRecord;
import jxl.biff.drawing.Chart;
import jxl.biff.drawing.DrawingData;
import jxl.biff.drawing.DrawingGroupObject;
import jxl.format.CellFormat;
public class SheetImpl implements Sheet {
private File excelFile;
private SSTRecord sharedStrings;
private BOFRecord sheetBof;
private BOFRecord workbookBof;
private FormattingRecords formattingRecords;
private String name;
private int numRows;
private int numCols;
private Cell[][] cells;
private int startPosition;
private ColumnInfoRecord[] columnInfos;
private RowRecord[] rowRecords;
private ArrayList rowProperties;
private ArrayList columnInfosArray;
private ArrayList sharedFormulas;
private ArrayList hyperlinks;
private ArrayList charts;
private ArrayList drawings;
private ArrayList images;
private DataValidation dataValidation;
private Range[] mergedCells;
private boolean columnInfosInitialized;
private boolean rowRecordsInitialized;
private boolean nineteenFour;
private WorkspaceInformationRecord workspaceOptions;
private boolean hidden;
private PLSRecord plsRecord;
private ButtonPropertySetRecord buttonPropertySet;
private SheetSettings settings;
private int[] rowBreaks;
private WorkbookParser workbook;
private WorkbookSettings workbookSettings;
SheetImpl(File f, SSTRecord sst, FormattingRecords fr, BOFRecord sb, BOFRecord wb, boolean nf, WorkbookParser wp) throws BiffException {
this.excelFile = f;
this.sharedStrings = sst;
this.formattingRecords = fr;
this.sheetBof = sb;
this.workbookBof = wb;
this.columnInfosArray = new ArrayList();
this.sharedFormulas = new ArrayList();
this.hyperlinks = new ArrayList();
this.rowProperties = new ArrayList(10);
this.columnInfosInitialized = false;
this.rowRecordsInitialized = false;
this.nineteenFour = nf;
this.workbook = wp;
this.workbookSettings = this.workbook.getSettings();
this.startPosition = f.getPos();
if (this.sheetBof.isChart())
this.startPosition -= this.sheetBof.getLength() + 4;
Record r = null;
int bofs = 1;
while (bofs >= 1) {
r = f.next();
if (r.getCode() == Type.EOF.value)
bofs--;
if (r.getCode() == Type.BOF.value)
bofs++;
}
}
public Cell getCell(String loc) {
return getCell(CellReferenceHelper.getColumn(loc), CellReferenceHelper.getRow(loc));
}
public Cell getCell(int column, int row) {
EmptyCell emptyCell;
if (this.cells == null)
readSheet();
Cell c = this.cells[row][column];
if (c == null) {
emptyCell = new EmptyCell(column, row);
this.cells[row][column] = (Cell)emptyCell;
}
return (Cell)emptyCell;
}
public Cell findCell(String contents) {
Cell cell = null;
boolean found = false;
for (int i = 0; i < getRows() && !found; i++) {
Cell[] row = getRow(i);
for (int j = 0; j < row.length && !found; j++) {
if (row[j].getContents().equals(contents)) {
cell = row[j];
found = true;
}
}
}
return cell;
}
public LabelCell findLabelCell(String contents) {
LabelCell cell = null;
boolean found = false;
for (int i = 0; i < getRows() && !found; i++) {
Cell[] row = getRow(i);
for (int j = 0; j < row.length && !found; j++) {
if ((row[j].getType() == CellType.LABEL || row[j].getType() == CellType.STRING_FORMULA) && row[j].getContents().equals(contents)) {
cell = (LabelCell)row[j];
found = true;
}
}
}
return cell;
}
public int getRows() {
if (this.cells == null)
readSheet();
return this.numRows;
}
public int getColumns() {
if (this.cells == null)
readSheet();
return this.numCols;
}
public Cell[] getRow(int row) {
if (this.cells == null)
readSheet();
boolean found = false;
int col = this.numCols - 1;
while (col >= 0 && !found) {
if (this.cells[row][col] != null) {
found = true;
continue;
}
col--;
}
Cell[] c = new Cell[col + 1];
for (int i = 0; i <= col; i++)
c[i] = getCell(i, row);
return c;
}
public Cell[] getColumn(int col) {
if (this.cells == null)
readSheet();
boolean found = false;
int row = this.numRows - 1;
while (row >= 0 && !found) {
if (this.cells[row][col] != null) {
found = true;
continue;
}
row--;
}
Cell[] c = new Cell[row + 1];
for (int i = 0; i <= row; i++)
c[i] = getCell(col, i);
return c;
}
public String getName() {
return this.name;
}
final void setName(String s) {
this.name = s;
}
public boolean isHidden() {
return this.hidden;
}
public ColumnInfoRecord getColumnInfo(int col) {
if (!this.columnInfosInitialized) {
Iterator i = this.columnInfosArray.iterator();
ColumnInfoRecord cir = null;
while (i.hasNext()) {
cir = i.next();
int startcol = Math.max(0, cir.getStartColumn());
int endcol = Math.min(this.columnInfos.length - 1, cir.getEndColumn());
for (int c = startcol; c <= endcol; c++)
this.columnInfos[c] = cir;
if (endcol < startcol)
this.columnInfos[startcol] = cir;
}
this.columnInfosInitialized = true;
}
return (col < this.columnInfos.length) ? this.columnInfos[col] : null;
}
public ColumnInfoRecord[] getColumnInfos() {
ColumnInfoRecord[] infos = new ColumnInfoRecord[this.columnInfosArray.size()];
for (int i = 0; i < this.columnInfosArray.size(); i++)
infos[i] = this.columnInfosArray.get(i);
return infos;
}
final void setHidden(boolean h) {
this.hidden = h;
}
final void clear() {
this.cells = (Cell[][])null;
this.mergedCells = null;
this.columnInfosArray.clear();
this.sharedFormulas.clear();
this.hyperlinks.clear();
this.columnInfosInitialized = false;
if (!this.workbookSettings.getGCDisabled())
System.gc();
}
final void readSheet() {
if (!this.sheetBof.isWorksheet()) {
this.numRows = 0;
this.numCols = 0;
this.cells = new Cell[0][0];
}
SheetReader reader = new SheetReader(this.excelFile, this.sharedStrings, this.formattingRecords, this.sheetBof, this.workbookBof, this.nineteenFour, this.workbook, this.startPosition, this);
reader.read();
this.numRows = reader.getNumRows();
this.numCols = reader.getNumCols();
this.cells = reader.getCells();
this.rowProperties = reader.getRowProperties();
this.columnInfosArray = reader.getColumnInfosArray();
this.hyperlinks = reader.getHyperlinks();
this.charts = reader.getCharts();
this.drawings = reader.getDrawings();
this.dataValidation = reader.getDataValidation();
this.mergedCells = reader.getMergedCells();
this.settings = reader.getSettings();
this.settings.setHidden(this.hidden);
this.rowBreaks = reader.getRowBreaks();
this.workspaceOptions = reader.getWorkspaceOptions();
this.plsRecord = reader.getPLS();
this.buttonPropertySet = reader.getButtonPropertySet();
reader = null;
if (!this.workbookSettings.getGCDisabled())
System.gc();
if (this.columnInfosArray.size() > 0) {
ColumnInfoRecord cir = this.columnInfosArray.get(this.columnInfosArray.size() - 1);
this.columnInfos = new ColumnInfoRecord[cir.getEndColumn() + 1];
} else {
this.columnInfos = new ColumnInfoRecord[0];
}
}
public Hyperlink[] getHyperlinks() {
Hyperlink[] hl = new Hyperlink[this.hyperlinks.size()];
for (int i = 0; i < this.hyperlinks.size(); i++)
hl[i] = this.hyperlinks.get(i);
return hl;
}
public Range[] getMergedCells() {
if (this.mergedCells == null)
return new Range[0];
return this.mergedCells;
}
public RowRecord[] getRowProperties() {
RowRecord[] rp = new RowRecord[this.rowProperties.size()];
for (int i = 0; i < rp.length; i++)
rp[i] = this.rowProperties.get(i);
return rp;
}
public DataValidation getDataValidation() {
return this.dataValidation;
}
RowRecord getRowInfo(int r) {
if (!this.rowRecordsInitialized) {
this.rowRecords = new RowRecord[getRows()];
Iterator i = this.rowProperties.iterator();
int rownum = 0;
RowRecord rr = null;
while (i.hasNext()) {
rr = i.next();
rownum = rr.getRowNumber();
if (rownum < this.rowRecords.length)
this.rowRecords[rownum] = rr;
}
this.rowRecordsInitialized = true;
}
return this.rowRecords[r];
}
public final int[] getRowPageBreaks() {
return this.rowBreaks;
}
public final Chart[] getCharts() {
Chart[] ch = new Chart[this.charts.size()];
for (int i = 0; i < ch.length; i++)
ch[i] = this.charts.get(i);
return ch;
}
public final DrawingGroupObject[] getDrawings() {
DrawingGroupObject[] dr = new DrawingGroupObject[this.drawings.size()];
dr = (DrawingGroupObject[])this.drawings.toArray((Object[])dr);
return dr;
}
public boolean isProtected() {
return this.settings.isProtected();
}
public WorkspaceInformationRecord getWorkspaceOptions() {
return this.workspaceOptions;
}
public SheetSettings getSettings() {
return this.settings;
}
WorkbookParser getWorkbook() {
return this.workbook;
}
public CellFormat getColumnFormat(int col) {
CellView cv = getColumnView(col);
return cv.getFormat();
}
public int getColumnWidth(int col) {
return getColumnView(col).getSize() / 256;
}
public CellView getColumnView(int col) {
ColumnInfoRecord cir = getColumnInfo(col);
CellView cv = new CellView();
if (cir != null) {
cv.setDimension(cir.getWidth() / 256);
cv.setSize(cir.getWidth());
cv.setHidden(cir.getHidden());
cv.setFormat((CellFormat)this.formattingRecords.getXFRecord(cir.getXFIndex()));
} else {
cv.setDimension(this.settings.getDefaultColumnWidth() / 256);
cv.setSize(this.settings.getDefaultColumnWidth());
}
return cv;
}
public int getRowHeight(int row) {
return getRowView(row).getDimension();
}
public CellView getRowView(int row) {
RowRecord rr = getRowInfo(row);
CellView cv = new CellView();
if (rr != null) {
cv.setDimension(rr.getRowHeight());
cv.setSize(rr.getRowHeight());
cv.setHidden(rr.isCollapsed());
} else {
cv.setDimension(this.settings.getDefaultRowHeight());
cv.setSize(this.settings.getDefaultRowHeight());
}
return cv;
}
public BOFRecord getSheetBof() {
return this.sheetBof;
}
public BOFRecord getWorkbookBof() {
return this.workbookBof;
}
public PLSRecord getPLS() {
return this.plsRecord;
}
public ButtonPropertySetRecord getButtonPropertySet() {
return this.buttonPropertySet;
}
public int getNumberOfImages() {
if (this.images == null)
initializeImages();
return this.images.size();
}
public Image getDrawing(int i) {
if (this.images == null)
initializeImages();
return this.images.get(i);
}
private void initializeImages() {
if (this.images != null)
return;
this.images = new ArrayList();
DrawingGroupObject[] dgos = getDrawings();
for (int i = 0; i < dgos.length; i++) {
if (dgos[i] instanceof jxl.biff.drawing.Drawing)
this.images.add(dgos[i]);
}
}
public DrawingData getDrawingData() {
SheetReader reader = new SheetReader(this.excelFile, this.sharedStrings, this.formattingRecords, this.sheetBof, this.workbookBof, this.nineteenFour, this.workbook, this.startPosition, this);
reader.read();
return reader.getDrawingData();
}
}

View File

@@ -0,0 +1,753 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.Cell;
import jxl.CellFeatures;
import jxl.CellReferenceHelper;
import jxl.CellType;
import jxl.DateCell;
import jxl.HeaderFooter;
import jxl.Range;
import jxl.SheetSettings;
import jxl.WorkbookSettings;
import jxl.biff.ContinueRecord;
import jxl.biff.FormattingRecords;
import jxl.biff.Type;
import jxl.biff.WorkspaceInformationRecord;
import jxl.biff.drawing.Button;
import jxl.biff.drawing.Chart;
import jxl.biff.drawing.Comment;
import jxl.biff.drawing.Drawing;
import jxl.biff.drawing.DrawingData;
import jxl.biff.drawing.MsoDrawingRecord;
import jxl.biff.drawing.NoteRecord;
import jxl.biff.drawing.ObjRecord;
import jxl.biff.drawing.TextObjectRecord;
import jxl.biff.formula.FormulaException;
import jxl.format.PageOrientation;
import jxl.format.PaperSize;
final class SheetReader {
private static Logger logger = Logger.getLogger(SheetReader.class);
private File excelFile;
private SSTRecord sharedStrings;
private BOFRecord sheetBof;
private BOFRecord workbookBof;
private FormattingRecords formattingRecords;
private int numRows;
private int numCols;
private Cell[][] cells;
private int startPosition;
private ArrayList rowProperties;
private ArrayList columnInfosArray;
private ArrayList sharedFormulas;
private ArrayList hyperlinks;
private Range[] mergedCells;
private DataValidation dataValidation;
private ArrayList charts;
private ArrayList drawings;
private DrawingData drawingData;
private boolean nineteenFour;
private PLSRecord plsRecord;
private ButtonPropertySetRecord buttonPropertySet;
private WorkspaceInformationRecord workspaceOptions;
private int[] rowBreaks;
private SheetSettings settings;
private WorkbookSettings workbookSettings;
private WorkbookParser workbook;
private SheetImpl sheet;
SheetReader(File f, SSTRecord sst, FormattingRecords fr, BOFRecord sb, BOFRecord wb, boolean nf, WorkbookParser wp, int sp, SheetImpl sh) {
this.excelFile = f;
this.sharedStrings = sst;
this.formattingRecords = fr;
this.sheetBof = sb;
this.workbookBof = wb;
this.columnInfosArray = new ArrayList();
this.sharedFormulas = new ArrayList();
this.hyperlinks = new ArrayList();
this.rowProperties = new ArrayList(10);
this.charts = new ArrayList();
this.drawings = new ArrayList();
this.nineteenFour = nf;
this.workbook = wp;
this.startPosition = sp;
this.sheet = sh;
this.settings = new SheetSettings();
this.workbookSettings = this.workbook.getSettings();
}
private void addCell(Cell cell) {
if (cell.getRow() < this.numRows && cell.getColumn() < this.numCols) {
if (this.cells[cell.getRow()][cell.getColumn()] != null) {
StringBuffer sb = new StringBuffer();
CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow(), sb);
logger.warn("Cell " + sb.toString() + " already contains data");
}
this.cells[cell.getRow()][cell.getColumn()] = cell;
} else {
logger.warn("Cell " + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow()) + " exceeds defined cell boundaries in Dimension record " + "(" + this.numCols + "x" + this.numRows + ")");
}
}
final void read() {
Record r = null;
BaseSharedFormulaRecord sharedFormula = null;
boolean sharedFormulaAdded = false;
boolean cont = true;
this.excelFile.setPos(this.startPosition);
MsoDrawingRecord msoRecord = null;
ObjRecord objRecord = null;
boolean firstMsoRecord = true;
Window2Record window2Record = null;
PrintGridLinesRecord printGridLinesRecord = null;
PrintHeadersRecord printHeadersRecord = null;
HashMap comments = new HashMap();
while (cont) {
r = this.excelFile.next();
Type type = r.getType();
if (type == Type.UNKNOWN && r.getCode() == 0) {
logger.warn("Biff code zero found");
if (r.getLength() == 10) {
logger.warn("Biff code zero found - trying a dimension record.");
r.setType(Type.DIMENSION);
} else {
logger.warn("Biff code zero found - Ignoring.");
}
}
if (type == Type.DIMENSION) {
DimensionRecord dr = null;
if (this.workbookBof.isBiff8()) {
dr = new DimensionRecord(r);
} else {
dr = new DimensionRecord(r, DimensionRecord.biff7);
}
this.numRows = dr.getNumberOfRows();
this.numCols = dr.getNumberOfColumns();
this.cells = new Cell[this.numRows][this.numCols];
continue;
}
if (type == Type.LABELSST) {
LabelSSTRecord label = new LabelSSTRecord(r, this.sharedStrings, this.formattingRecords, this.sheet);
addCell(label);
continue;
}
if (type == Type.RK || type == Type.RK2) {
RKRecord rkr = new RKRecord(r, this.formattingRecords, this.sheet);
if (this.formattingRecords.isDate(rkr.getXFIndex())) {
DateCell dc = new DateRecord(rkr, rkr.getXFIndex(), this.formattingRecords, this.nineteenFour, this.sheet);
addCell((Cell)dc);
continue;
}
addCell(rkr);
continue;
}
if (type == Type.HLINK) {
HyperlinkRecord hr = new HyperlinkRecord(r, this.sheet, this.workbookSettings);
this.hyperlinks.add(hr);
continue;
}
if (type == Type.MERGEDCELLS) {
MergedCellsRecord mc = new MergedCellsRecord(r, this.sheet);
if (this.mergedCells == null) {
this.mergedCells = mc.getRanges();
continue;
}
Range[] newMergedCells = new Range[this.mergedCells.length + (mc.getRanges()).length];
System.arraycopy(this.mergedCells, 0, newMergedCells, 0, this.mergedCells.length);
System.arraycopy(mc.getRanges(), 0, newMergedCells, this.mergedCells.length, (mc.getRanges()).length);
this.mergedCells = newMergedCells;
continue;
}
if (type == Type.MULRK) {
MulRKRecord mulrk = new MulRKRecord(r);
int num = mulrk.getNumberOfColumns();
int ixf = 0;
for (int j = 0; j < num; j++) {
ixf = mulrk.getXFIndex(j);
NumberValue nv = new NumberValue(mulrk.getRow(), mulrk.getFirstColumn() + j, RKHelper.getDouble(mulrk.getRKNumber(j)), ixf, this.formattingRecords, this.sheet);
if (this.formattingRecords.isDate(ixf)) {
DateCell dc = new DateRecord(nv, ixf, this.formattingRecords, this.nineteenFour, this.sheet);
addCell((Cell)dc);
} else {
nv.setNumberFormat(this.formattingRecords.getNumberFormat(ixf));
addCell((Cell)nv);
}
}
continue;
}
if (type == Type.NUMBER) {
NumberRecord nr = new NumberRecord(r, this.formattingRecords, this.sheet);
if (this.formattingRecords.isDate(nr.getXFIndex())) {
DateCell dc = new DateRecord(nr, nr.getXFIndex(), this.formattingRecords, this.nineteenFour, this.sheet);
addCell((Cell)dc);
continue;
}
addCell(nr);
continue;
}
if (type == Type.BOOLERR) {
BooleanRecord br = new BooleanRecord(r, this.formattingRecords, this.sheet);
if (br.isError()) {
ErrorRecord er = new ErrorRecord(br.getRecord(), this.formattingRecords, this.sheet);
addCell(er);
continue;
}
addCell(br);
continue;
}
if (type == Type.PRINTGRIDLINES) {
printGridLinesRecord = new PrintGridLinesRecord(r);
this.settings.setPrintGridLines(printGridLinesRecord.getPrintGridLines());
continue;
}
if (type == Type.PRINTHEADERS) {
printHeadersRecord = new PrintHeadersRecord(r);
this.settings.setPrintHeaders(printHeadersRecord.getPrintHeaders());
continue;
}
if (type == Type.WINDOW2) {
window2Record = new Window2Record(r);
this.settings.setShowGridLines(window2Record.getShowGridLines());
this.settings.setDisplayZeroValues(window2Record.getDisplayZeroValues());
this.settings.setSelected(true);
continue;
}
if (type == Type.PANE) {
PaneRecord pr = new PaneRecord(r);
if (window2Record != null && window2Record.getFrozen()) {
this.settings.setVerticalFreeze(pr.getRowsVisible());
this.settings.setHorizontalFreeze(pr.getColumnsVisible());
}
continue;
}
if (type == Type.CONTINUE)
continue;
if (type == Type.NOTE) {
if (!this.workbookSettings.getDrawingsDisabled()) {
NoteRecord nr = new NoteRecord(r);
Comment comment = (Comment)comments.remove(new Integer(nr.getObjectId()));
if (comment == null) {
logger.warn(" cannot find comment for note id " + nr.getObjectId() + "...ignoring");
continue;
}
comment.setNote(nr);
this.drawings.add(comment);
addCellComment(comment.getColumn(), comment.getRow(), comment.getText(), comment.getWidth(), comment.getHeight());
}
continue;
}
if (type == Type.ARRAY)
continue;
if (type == Type.PROTECT) {
ProtectRecord pr = new ProtectRecord(r);
this.settings.setProtected(pr.isProtected());
continue;
}
if (type == Type.SHAREDFORMULA) {
if (sharedFormula == null) {
logger.warn("Shared template formula is null - trying most recent formula template");
SharedFormulaRecord lastSharedFormula = this.sharedFormulas.get(this.sharedFormulas.size() - 1);
if (lastSharedFormula != null)
sharedFormula = lastSharedFormula.getTemplateFormula();
}
SharedFormulaRecord sfr = new SharedFormulaRecord(r, sharedFormula, this.workbook, this.workbook, this.sheet);
this.sharedFormulas.add(sfr);
sharedFormula = null;
continue;
}
if (type == Type.FORMULA || type == Type.FORMULA2) {
DateFormulaRecord dateFormulaRecord;
FormulaRecord fr = new FormulaRecord(r, this.excelFile, this.formattingRecords, this.workbook, this.workbook, this.sheet, this.workbookSettings);
if (fr.isShared()) {
BaseSharedFormulaRecord prevSharedFormula = sharedFormula;
sharedFormula = (BaseSharedFormulaRecord)fr.getFormula();
sharedFormulaAdded = addToSharedFormulas(sharedFormula);
if (sharedFormulaAdded)
sharedFormula = prevSharedFormula;
if (!sharedFormulaAdded && prevSharedFormula != null)
addCell(revertSharedFormula(prevSharedFormula));
continue;
}
Cell cell = fr.getFormula();
try {
if (fr.getFormula().getType() == CellType.NUMBER_FORMULA) {
NumberFormulaRecord nfr = (NumberFormulaRecord)fr.getFormula();
if (this.formattingRecords.isDate(nfr.getXFIndex()))
dateFormulaRecord = new DateFormulaRecord(nfr, this.formattingRecords, this.workbook, this.workbook, this.nineteenFour, this.sheet);
}
addCell((Cell)dateFormulaRecord);
} catch (FormulaException e) {
logger.warn(CellReferenceHelper.getCellReference(dateFormulaRecord.getColumn(), dateFormulaRecord.getRow()) + " " + e.getMessage());
}
continue;
}
if (type == Type.LABEL) {
LabelRecord lr = null;
if (this.workbookBof.isBiff8()) {
lr = new LabelRecord(r, this.formattingRecords, this.sheet, this.workbookSettings);
} else {
lr = new LabelRecord(r, this.formattingRecords, this.sheet, this.workbookSettings, LabelRecord.biff7);
}
addCell(lr);
continue;
}
if (type == Type.RSTRING) {
RStringRecord lr = null;
Assert.verify(!this.workbookBof.isBiff8());
lr = new RStringRecord(r, this.formattingRecords, this.sheet, this.workbookSettings, RStringRecord.biff7);
addCell(lr);
continue;
}
if (type == Type.NAME)
continue;
if (type == Type.PASSWORD) {
PasswordRecord pr = new PasswordRecord(r);
this.settings.setPasswordHash(pr.getPasswordHash());
continue;
}
if (type == Type.ROW) {
RowRecord rr = new RowRecord(r);
if (!rr.isDefaultHeight() || !rr.matchesDefaultFontHeight() || rr.isCollapsed() || rr.hasDefaultFormat())
this.rowProperties.add(rr);
continue;
}
if (type == Type.BLANK) {
if (!this.workbookSettings.getIgnoreBlanks()) {
BlankCell bc = new BlankCell(r, this.formattingRecords, this.sheet);
addCell(bc);
}
continue;
}
if (type == Type.MULBLANK) {
if (!this.workbookSettings.getIgnoreBlanks()) {
MulBlankRecord mulblank = new MulBlankRecord(r);
int num = mulblank.getNumberOfColumns();
for (int j = 0; j < num; j++) {
int ixf = mulblank.getXFIndex(j);
MulBlankCell mbc = new MulBlankCell(mulblank.getRow(), mulblank.getFirstColumn() + j, ixf, this.formattingRecords, this.sheet);
addCell(mbc);
}
}
continue;
}
if (type == Type.SCL) {
SCLRecord scl = new SCLRecord(r);
this.settings.setZoomFactor(scl.getZoomFactor());
continue;
}
if (type == Type.COLINFO) {
ColumnInfoRecord cir = new ColumnInfoRecord(r);
this.columnInfosArray.add(cir);
continue;
}
if (type == Type.HEADER) {
HeaderRecord hr = null;
if (this.workbookBof.isBiff8()) {
hr = new HeaderRecord(r, this.workbookSettings);
} else {
hr = new HeaderRecord(r, this.workbookSettings, HeaderRecord.biff7);
}
HeaderFooter header = new HeaderFooter(hr.getHeader());
this.settings.setHeader(header);
continue;
}
if (type == Type.FOOTER) {
FooterRecord fr = null;
if (this.workbookBof.isBiff8()) {
fr = new FooterRecord(r, this.workbookSettings);
} else {
fr = new FooterRecord(r, this.workbookSettings, FooterRecord.biff7);
}
HeaderFooter footer = new HeaderFooter(fr.getFooter());
this.settings.setFooter(footer);
continue;
}
if (type == Type.SETUP) {
SetupRecord sr = new SetupRecord(r);
if (sr.isPortrait()) {
this.settings.setOrientation(PageOrientation.PORTRAIT);
} else {
this.settings.setOrientation(PageOrientation.LANDSCAPE);
}
this.settings.setPaperSize(PaperSize.getPaperSize(sr.getPaperSize()));
this.settings.setHeaderMargin(sr.getHeaderMargin());
this.settings.setFooterMargin(sr.getFooterMargin());
this.settings.setScaleFactor(sr.getScaleFactor());
this.settings.setPageStart(sr.getPageStart());
this.settings.setFitWidth(sr.getFitWidth());
this.settings.setFitHeight(sr.getFitHeight());
this.settings.setHorizontalPrintResolution(sr.getHorizontalPrintResolution());
this.settings.setVerticalPrintResolution(sr.getVerticalPrintResolution());
this.settings.setCopies(sr.getCopies());
if (this.workspaceOptions != null)
this.settings.setFitToPages(this.workspaceOptions.getFitToPages());
continue;
}
if (type == Type.WSBOOL) {
this.workspaceOptions = new WorkspaceInformationRecord(r);
continue;
}
if (type == Type.DEFCOLWIDTH) {
DefaultColumnWidthRecord dcwr = new DefaultColumnWidthRecord(r);
this.settings.setDefaultColumnWidth(dcwr.getWidth());
continue;
}
if (type == Type.DEFAULTROWHEIGHT) {
DefaultRowHeightRecord drhr = new DefaultRowHeightRecord(r);
if (drhr.getHeight() != 0)
this.settings.setDefaultRowHeight(drhr.getHeight());
continue;
}
if (type == Type.LEFTMARGIN) {
MarginRecord m = new LeftMarginRecord(r);
this.settings.setLeftMargin(m.getMargin());
continue;
}
if (type == Type.RIGHTMARGIN) {
MarginRecord m = new RightMarginRecord(r);
this.settings.setRightMargin(m.getMargin());
continue;
}
if (type == Type.TOPMARGIN) {
MarginRecord m = new TopMarginRecord(r);
this.settings.setTopMargin(m.getMargin());
continue;
}
if (type == Type.BOTTOMMARGIN) {
MarginRecord m = new BottomMarginRecord(r);
this.settings.setBottomMargin(m.getMargin());
continue;
}
if (type == Type.HORIZONTALPAGEBREAKS) {
HorizontalPageBreaksRecord dr = null;
if (this.workbookBof.isBiff8()) {
dr = new HorizontalPageBreaksRecord(r);
} else {
dr = new HorizontalPageBreaksRecord(r, HorizontalPageBreaksRecord.biff7);
}
this.rowBreaks = dr.getRowBreaks();
continue;
}
if (type == Type.PLS) {
this.plsRecord = new PLSRecord(r);
continue;
}
if (type == Type.DVAL)
continue;
if (type == Type.HCENTER) {
CentreRecord hr = new CentreRecord(r);
this.settings.setHorizontalCentre(hr.isCentre());
continue;
}
if (type == Type.VCENTER) {
CentreRecord vc = new CentreRecord(r);
this.settings.setVerticalCentre(vc.isCentre());
continue;
}
if (type == Type.DV)
continue;
if (type == Type.OBJ) {
objRecord = new ObjRecord(r);
if (!this.workbookSettings.getDrawingsDisabled())
handleObjectRecord(objRecord, msoRecord, comments);
if (objRecord.getType() != ObjRecord.CHART) {
objRecord = null;
msoRecord = null;
}
continue;
}
if (type == Type.MSODRAWING) {
if (!this.workbookSettings.getDrawingsDisabled()) {
if (msoRecord != null)
this.drawingData.addRawData(msoRecord.getData());
msoRecord = new MsoDrawingRecord(r);
if (firstMsoRecord) {
msoRecord.setFirst();
firstMsoRecord = false;
}
}
continue;
}
if (type == Type.BUTTONPROPERTYSET) {
this.buttonPropertySet = new ButtonPropertySetRecord(r);
continue;
}
if (type == Type.CALCMODE) {
CalcModeRecord cmr = new CalcModeRecord(r);
this.settings.setAutomaticFormulaCalculation(cmr.isAutomatic());
continue;
}
if (type == Type.SAVERECALC) {
SaveRecalcRecord cmr = new SaveRecalcRecord(r);
this.settings.setRecalculateFormulasBeforeSave(cmr.getRecalculateOnSave());
continue;
}
if (type == Type.BOF) {
BOFRecord br = new BOFRecord(r);
Assert.verify(!br.isWorksheet());
int startpos = this.excelFile.getPos() - r.getLength() - 4;
Record r2 = this.excelFile.next();
while (r2.getCode() != Type.EOF.value)
r2 = this.excelFile.next();
if (br.isChart()) {
if (!this.workbook.getWorkbookBof().isBiff8()) {
logger.warn("only biff8 charts are supported");
} else {
if (this.drawingData == null)
this.drawingData = new DrawingData();
if (!this.workbookSettings.getDrawingsDisabled()) {
Chart chart = new Chart(msoRecord, objRecord, this.drawingData, startpos, this.excelFile.getPos(), this.excelFile, this.workbookSettings);
this.charts.add(chart);
if (this.workbook.getDrawingGroup() != null)
this.workbook.getDrawingGroup().add(chart);
}
}
msoRecord = null;
objRecord = null;
}
if (this.sheetBof.isChart())
cont = false;
continue;
}
if (type == Type.EOF)
cont = false;
}
this.excelFile.restorePos();
Iterator i = this.sharedFormulas.iterator();
while (i.hasNext()) {
SharedFormulaRecord sfr = i.next();
Cell[] sfnr = sfr.getFormulas(this.formattingRecords, this.nineteenFour);
for (int sf = 0; sf < sfnr.length; sf++)
addCell(sfnr[sf]);
}
if (!sharedFormulaAdded && sharedFormula != null)
addCell(revertSharedFormula(sharedFormula));
if (msoRecord != null && this.workbook.getDrawingGroup() != null)
this.workbook.getDrawingGroup().setDrawingsOmitted(msoRecord, objRecord);
if (!comments.isEmpty())
logger.warn("Not all comments have a corresponding Note record");
}
private boolean addToSharedFormulas(BaseSharedFormulaRecord fr) {
boolean added = false;
SharedFormulaRecord sfr = null;
for (int i = 0, size = this.sharedFormulas.size(); i < size && !added; i++) {
sfr = this.sharedFormulas.get(i);
added = sfr.add(fr);
}
return added;
}
private Cell revertSharedFormula(BaseSharedFormulaRecord f) {
int pos = this.excelFile.getPos();
this.excelFile.setPos(f.getFilePos());
FormulaRecord fr = new FormulaRecord(f.getRecord(), this.excelFile, this.formattingRecords, this.workbook, this.workbook, FormulaRecord.ignoreSharedFormula, this.sheet, this.workbookSettings);
try {
DateFormulaRecord dateFormulaRecord;
Cell cell = fr.getFormula();
if (fr.getFormula().getType() == CellType.NUMBER_FORMULA) {
NumberFormulaRecord nfr = (NumberFormulaRecord)fr.getFormula();
if (this.formattingRecords.isDate(fr.getXFIndex()))
dateFormulaRecord = new DateFormulaRecord(nfr, this.formattingRecords, this.workbook, this.workbook, this.nineteenFour, this.sheet);
}
this.excelFile.setPos(pos);
return (Cell)dateFormulaRecord;
} catch (FormulaException e) {
logger.warn(CellReferenceHelper.getCellReference(fr.getColumn(), fr.getRow()) + " " + e.getMessage());
return null;
}
}
final int getNumRows() {
return this.numRows;
}
final int getNumCols() {
return this.numCols;
}
final Cell[][] getCells() {
return this.cells;
}
final ArrayList getRowProperties() {
return this.rowProperties;
}
final ArrayList getColumnInfosArray() {
return this.columnInfosArray;
}
final ArrayList getHyperlinks() {
return this.hyperlinks;
}
final ArrayList getCharts() {
return this.charts;
}
final ArrayList getDrawings() {
return this.drawings;
}
final DataValidation getDataValidation() {
return this.dataValidation;
}
final Range[] getMergedCells() {
return this.mergedCells;
}
final SheetSettings getSettings() {
return this.settings;
}
final int[] getRowBreaks() {
return this.rowBreaks;
}
final WorkspaceInformationRecord getWorkspaceOptions() {
return this.workspaceOptions;
}
final PLSRecord getPLS() {
return this.plsRecord;
}
final ButtonPropertySetRecord getButtonPropertySet() {
return this.buttonPropertySet;
}
private void addCellComment(int col, int row, String text, double width, double height) {
Cell c = this.cells[row][col];
if (c == null) {
logger.warn("Cell at " + CellReferenceHelper.getCellReference(col, row) + " not present - adding a blank");
MulBlankCell mbc = new MulBlankCell(row, col, 0, this.formattingRecords, this.sheet);
CellFeatures cf = new CellFeatures();
cf.setReadComment(text, width, height);
mbc.setCellFeatures(cf);
addCell(mbc);
return;
}
if (c instanceof CellFeaturesAccessor) {
CellFeaturesAccessor cv = (CellFeaturesAccessor)c;
CellFeatures cf = cv.getCellFeatures();
if (cf == null) {
cf = new CellFeatures();
cv.setCellFeatures(cf);
}
cf.setReadComment(text, width, height);
} else {
logger.warn("Not able to add comment to cell type " + c.getClass().getName() + " at " + CellReferenceHelper.getCellReference(col, row));
}
}
private void handleObjectRecord(ObjRecord objRecord, MsoDrawingRecord msoRecord, HashMap comments) {
if (msoRecord == null) {
logger.warn("Object record is not associated with a drawing record - ignoring");
return;
}
if (objRecord.getType() == ObjRecord.PICTURE) {
if (this.drawingData == null)
this.drawingData = new DrawingData();
Drawing drawing = new Drawing(msoRecord, objRecord, this.drawingData, this.workbook.getDrawingGroup());
this.drawings.add(drawing);
return;
}
if (objRecord.getType() == ObjRecord.EXCELNOTE) {
if (this.drawingData == null)
this.drawingData = new DrawingData();
Comment comment = new Comment(msoRecord, objRecord, this.drawingData, this.workbook.getDrawingGroup(), this.workbookSettings);
Record r2 = this.excelFile.next();
if (r2.getType() == Type.MSODRAWING) {
MsoDrawingRecord mso = new MsoDrawingRecord(r2);
comment.addMso(mso);
r2 = this.excelFile.next();
}
Assert.verify((r2.getType() == Type.TXO));
TextObjectRecord txo = new TextObjectRecord(r2);
comment.setTextObject(txo);
r2 = this.excelFile.next();
Assert.verify((r2.getType() == Type.CONTINUE));
ContinueRecord text = new ContinueRecord(r2);
comment.setText(text);
r2 = this.excelFile.next();
if (r2.getType() == Type.CONTINUE) {
ContinueRecord formatting = new ContinueRecord(r2);
comment.setFormatting(formatting);
}
comments.put(new Integer(comment.getObjectId()), comment);
return;
}
if (objRecord.getType() == ObjRecord.BUTTON) {
if (this.drawingData == null)
this.drawingData = new DrawingData();
Button button = new Button(msoRecord, objRecord, this.drawingData, this.workbook.getDrawingGroup(), this.workbookSettings);
Record r2 = this.excelFile.next();
if (r2.getType() == Type.MSODRAWING) {
MsoDrawingRecord mso = new MsoDrawingRecord(r2);
button.addMso(mso);
r2 = this.excelFile.next();
}
Assert.verify((r2.getType() == Type.TXO));
TextObjectRecord txo = new TextObjectRecord(r2);
button.setTextObject(txo);
r2 = this.excelFile.next();
Assert.verify((r2.getType() == Type.CONTINUE));
ContinueRecord text = new ContinueRecord(r2);
button.setText(text);
r2 = this.excelFile.next();
if (r2.getType() == Type.CONTINUE) {
ContinueRecord formatting = new ContinueRecord(r2);
button.setFormatting(formatting);
}
this.drawings.add(button);
return;
}
if (objRecord.getType() != ObjRecord.CHART) {
logger.warn(objRecord.getType() + " on sheet \"" + this.sheet.getName() + "\" not supported - omitting");
if (this.drawingData == null)
this.drawingData = new DrawingData();
this.drawingData.addData(msoRecord.getData());
if (this.workbook.getDrawingGroup() != null)
this.workbook.getDrawingGroup().setDrawingsOmitted(msoRecord, objRecord);
return;
}
}
DrawingData getDrawingData() {
return this.drawingData;
}
}

View File

@@ -0,0 +1,116 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import jxl.CellType;
import jxl.LabelCell;
import jxl.StringFormulaCell;
import jxl.WorkbookSettings;
import jxl.biff.FormattingRecords;
import jxl.biff.FormulaData;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
import jxl.biff.Type;
import jxl.biff.WorkbookMethods;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
class StringFormulaRecord extends CellValue implements LabelCell, FormulaData, StringFormulaCell {
private static Logger logger = Logger.getLogger(StringFormulaRecord.class);
private String value;
private ExternalSheet externalSheet;
private WorkbookMethods nameTable;
private String formulaString;
private byte[] data;
public StringFormulaRecord(Record t, File excelFile, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si, WorkbookSettings ws) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.data = getRecord().getData();
int pos = excelFile.getPos();
Record nextRecord = excelFile.next();
int count = 0;
while (nextRecord.getType() != Type.STRING && count < 4) {
nextRecord = excelFile.next();
count++;
}
Assert.verify((count < 4), " @ " + pos);
readString(nextRecord.getData(), ws);
}
public StringFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, SheetImpl si) {
super(t, fr, si);
this.externalSheet = es;
this.nameTable = nt;
this.data = getRecord().getData();
this.value = "";
}
private void readString(byte[] d, WorkbookSettings ws) {
int pos = 0;
int chars = IntegerHelper.getInt(d[0], d[1]);
if (chars == 0) {
this.value = "";
return;
}
pos += 2;
int optionFlags = d[pos];
pos++;
if ((optionFlags & 0xF) != optionFlags) {
pos = 0;
chars = IntegerHelper.getInt(d[0], (byte)0);
optionFlags = d[1];
pos = 2;
}
boolean extendedString = ((optionFlags & 0x4) != 0);
boolean richString = ((optionFlags & 0x8) != 0);
if (richString)
pos += 2;
if (extendedString)
pos += 4;
boolean asciiEncoding = ((optionFlags & 0x1) == 0);
if (asciiEncoding) {
this.value = StringHelper.getString(d, chars, pos, ws);
} else {
this.value = StringHelper.getUnicodeString(d, chars, pos);
}
}
public String getContents() {
return this.value;
}
public String getString() {
return this.value;
}
public CellType getType() {
return CellType.STRING_FORMULA;
}
public byte[] getFormulaData() throws FormulaException {
if (!getSheet().getWorkbook().getWorkbookBof().isBiff8())
throw new FormulaException(FormulaException.biff8Supported);
byte[] d = new byte[this.data.length - 6];
System.arraycopy(this.data, 6, d, 0, this.data.length - 6);
return d;
}
public String getFormula() throws FormulaException {
if (this.formulaString == null) {
byte[] tokens = new byte[this.data.length - 22];
System.arraycopy(this.data, 22, tokens, 0, tokens.length);
FormulaParser fp = new FormulaParser(tokens, this, this.externalSheet, this.nameTable, getSheet().getWorkbook().getSettings());
fp.parse();
this.formulaString = fp.getFormula();
}
return this.formulaString;
}
}

View File

@@ -0,0 +1,161 @@
package jxl.read.biff;
import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;
public class SupbookRecord extends RecordData {
private static Logger logger = Logger.getLogger(SupbookRecord.class);
private Type type;
private int numSheets;
private String fileName;
private String[] sheetNames;
private static class Type {
private Type() {}
}
public static final Type INTERNAL = new Type();
public static final Type EXTERNAL = new Type();
public static final Type ADDIN = new Type();
public static final Type LINK = new Type();
public static final Type UNKNOWN = new Type();
SupbookRecord(Record t, WorkbookSettings ws) {
super(t);
byte[] data = getRecord().getData();
if (data.length == 4) {
if (data[2] == 1 && data[3] == 4) {
this.type = INTERNAL;
} else if (data[2] == 1 && data[3] == 58) {
this.type = ADDIN;
} else {
this.type = UNKNOWN;
}
} else if (data[0] == 0 && data[1] == 0) {
this.type = LINK;
} else {
this.type = EXTERNAL;
}
if (this.type == INTERNAL)
this.numSheets = IntegerHelper.getInt(data[0], data[1]);
if (this.type == EXTERNAL)
readExternal(data, ws);
}
private void readExternal(byte[] data, WorkbookSettings ws) {
this.numSheets = IntegerHelper.getInt(data[0], data[1]);
int ln = IntegerHelper.getInt(data[2], data[3]) - 1;
int pos = 0;
if (data[4] == 0) {
int encoding = data[5];
pos = 6;
if (encoding == 0) {
this.fileName = StringHelper.getString(data, ln, pos, ws);
pos += ln;
} else {
this.fileName = getEncodedFilename(data, ln, pos);
pos += ln;
}
} else {
int encoding = IntegerHelper.getInt(data[5], data[6]);
pos = 7;
if (encoding == 0) {
this.fileName = StringHelper.getUnicodeString(data, ln, pos);
pos += ln * 2;
} else {
this.fileName = getUnicodeEncodedFilename(data, ln, pos);
pos += ln * 2;
}
}
this.sheetNames = new String[this.numSheets];
for (int i = 0; i < this.sheetNames.length; i++) {
ln = IntegerHelper.getInt(data[pos], data[pos + 1]);
if (data[pos + 2] == 0) {
this.sheetNames[i] = StringHelper.getString(data, ln, pos + 3, ws);
pos += ln + 3;
} else if (data[pos + 2] == 1) {
this.sheetNames[i] = StringHelper.getUnicodeString(data, ln, pos + 3);
pos += ln * 2 + 3;
}
}
}
public Type getType() {
return this.type;
}
public int getNumberOfSheets() {
return this.numSheets;
}
public String getFileName() {
return this.fileName;
}
public String getSheetName(int i) {
return this.sheetNames[i];
}
public byte[] getData() {
return getRecord().getData();
}
private String getEncodedFilename(byte[] data, int ln, int pos) {
StringBuffer buf = new StringBuffer();
int endpos = pos + ln;
while (pos < endpos) {
char c = (char)data[pos];
if (c == '\001') {
pos++;
c = (char)data[pos];
buf.append(c);
buf.append(":\\\\");
} else if (c == '\002') {
buf.append('\\');
} else if (c == '\003') {
buf.append('\\');
} else if (c == '\004') {
buf.append("..\\");
} else {
buf.append(c);
}
pos++;
}
return buf.toString();
}
private String getUnicodeEncodedFilename(byte[] data, int ln, int pos) {
StringBuffer buf = new StringBuffer();
int endpos = pos + ln * 2;
while (pos < endpos) {
char c = (char)IntegerHelper.getInt(data[pos], data[pos + 1]);
if (c == '\001') {
pos += 2;
c = (char)IntegerHelper.getInt(data[pos], data[pos + 1]);
buf.append(c);
buf.append(":\\\\");
} else if (c == '\002') {
buf.append('\\');
} else if (c == '\003') {
buf.append('\\');
} else if (c == '\004') {
buf.append("..\\");
} else {
buf.append(c);
}
pos += 2;
}
return buf.toString();
}
}

View File

@@ -0,0 +1,9 @@
package jxl.read.biff;
import jxl.biff.Type;
class TopMarginRecord extends MarginRecord {
TopMarginRecord(Record r) {
super(Type.TOPMARGIN, r);
}
}

View File

@@ -0,0 +1,50 @@
package jxl.read.biff;
import common.Logger;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
class Window2Record extends RecordData {
private static Logger logger = Logger.getLogger(Window2Record.class);
private boolean selected;
private boolean showGridLines;
private boolean displayZeroValues;
private boolean frozenPanes;
private boolean frozenNotSplit;
public Window2Record(Record t) {
super(t);
byte[] data = t.getData();
int options = IntegerHelper.getInt(data[0], data[1]);
this.selected = ((options & 0x200) != 0);
this.showGridLines = ((options & 0x2) != 0);
this.frozenPanes = ((options & 0x8) != 0);
this.displayZeroValues = ((options & 0x10) != 0);
this.frozenNotSplit = ((options & 0x100) != 0);
}
public boolean isSelected() {
return this.selected;
}
public boolean getShowGridLines() {
return this.showGridLines;
}
public boolean getDisplayZeroValues() {
return this.displayZeroValues;
}
public boolean getFrozen() {
return this.frozenPanes;
}
public boolean getFrozenNotSplit() {
return this.frozenNotSplit;
}
}

View File

@@ -0,0 +1,520 @@
package jxl.read.biff;
import common.Assert;
import common.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.Cell;
import jxl.Range;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.biff.CellReferenceHelper;
import jxl.biff.DisplayFormat;
import jxl.biff.FontRecord;
import jxl.biff.Fonts;
import jxl.biff.FormatRecord;
import jxl.biff.FormattingRecords;
import jxl.biff.NumFormatRecordsException;
import jxl.biff.PaletteRecord;
import jxl.biff.RangeImpl;
import jxl.biff.Type;
import jxl.biff.WorkbookMethods;
import jxl.biff.XFRecord;
import jxl.biff.drawing.DrawingGroup;
import jxl.biff.drawing.MsoDrawingGroupRecord;
import jxl.biff.drawing.Origin;
import jxl.biff.formula.ExternalSheet;
public class WorkbookParser extends Workbook implements ExternalSheet, WorkbookMethods {
private static Logger logger = Logger.getLogger(WorkbookParser.class);
private File excelFile;
private int bofs;
private boolean nineteenFour;
private SSTRecord sharedStrings;
private ArrayList boundsheets;
private FormattingRecords formattingRecords;
private Fonts fonts;
private ArrayList sheets;
private SheetImpl lastSheet;
private int lastSheetIndex;
private HashMap namedRecords;
private ArrayList nameTable;
private ExternalSheetRecord externSheet;
private ArrayList supbooks;
private BOFRecord workbookBof;
private MsoDrawingGroupRecord msoDrawingGroup;
private ButtonPropertySetRecord buttonPropertySet;
private boolean wbProtected;
private boolean containsMacros;
private WorkbookSettings settings;
private DrawingGroup drawingGroup;
private CountryRecord countryRecord;
public WorkbookParser(File f, WorkbookSettings s) {
this.excelFile = f;
this.boundsheets = new ArrayList(10);
this.fonts = new Fonts();
this.formattingRecords = new FormattingRecords(this.fonts);
this.sheets = new ArrayList(10);
this.supbooks = new ArrayList(10);
this.namedRecords = new HashMap();
this.lastSheetIndex = -1;
this.wbProtected = false;
this.containsMacros = false;
this.settings = s;
}
public Sheet[] getSheets() {
Sheet[] sheetArray = new Sheet[getNumberOfSheets()];
return (Sheet[])this.sheets.toArray((Object[])sheetArray);
}
public Sheet getReadSheet(int index) {
return getSheet(index);
}
public Sheet getSheet(int index) {
if (this.lastSheet != null && this.lastSheetIndex == index)
return this.lastSheet;
if (this.lastSheet != null) {
this.lastSheet.clear();
if (!this.settings.getGCDisabled())
System.gc();
}
this.lastSheet = this.sheets.get(index);
this.lastSheetIndex = index;
this.lastSheet.readSheet();
return this.lastSheet;
}
public Sheet getSheet(String name) {
int pos = 0;
boolean found = false;
Iterator i = this.boundsheets.iterator();
BoundsheetRecord br = null;
while (i.hasNext() && !found) {
br = i.next();
if (br.getName().equals(name)) {
found = true;
continue;
}
pos++;
}
return found ? getSheet(pos) : null;
}
public String[] getSheetNames() {
String[] names = new String[this.boundsheets.size()];
BoundsheetRecord br = null;
for (int i = 0; i < names.length; i++) {
br = this.boundsheets.get(i);
names[i] = br.getName();
}
return names;
}
public int getExternalSheetIndex(int index) {
if (this.workbookBof.isBiff7())
return index;
Assert.verify((this.externSheet != null));
int firstTab = this.externSheet.getFirstTabIndex(index);
return firstTab;
}
public int getLastExternalSheetIndex(int index) {
if (this.workbookBof.isBiff7())
return index;
Assert.verify((this.externSheet != null));
int lastTab = this.externSheet.getLastTabIndex(index);
return lastTab;
}
public String getExternalSheetName(int index) {
if (this.workbookBof.isBiff7()) {
BoundsheetRecord br = this.boundsheets.get(index);
return br.getName();
}
int supbookIndex = this.externSheet.getSupbookIndex(index);
SupbookRecord sr = this.supbooks.get(supbookIndex);
int firstTab = this.externSheet.getFirstTabIndex(index);
if (sr.getType() == SupbookRecord.INTERNAL) {
BoundsheetRecord br = this.boundsheets.get(firstTab);
return br.getName();
}
if (sr.getType() == SupbookRecord.EXTERNAL) {
StringBuffer sb = new StringBuffer();
sb.append('[');
sb.append(sr.getFileName());
sb.append(']');
sb.append(sr.getSheetName(firstTab));
return sb.toString();
}
return "[UNKNOWN]";
}
public String getLastExternalSheetName(int index) {
if (this.workbookBof.isBiff7()) {
BoundsheetRecord br = this.boundsheets.get(index);
return br.getName();
}
int supbookIndex = this.externSheet.getSupbookIndex(index);
SupbookRecord sr = this.supbooks.get(supbookIndex);
int lastTab = this.externSheet.getLastTabIndex(index);
if (sr.getType() == SupbookRecord.INTERNAL) {
BoundsheetRecord br = this.boundsheets.get(lastTab);
return br.getName();
}
if (sr.getType() == SupbookRecord.EXTERNAL) {
StringBuffer sb = new StringBuffer();
sb.append('[');
sb.append(sr.getFileName());
sb.append(']');
sb.append(sr.getSheetName(lastTab));
return sb.toString();
}
return "[UNKNOWN]";
}
public int getNumberOfSheets() {
return this.sheets.size();
}
public void close() {
if (this.lastSheet != null)
this.lastSheet.clear();
this.excelFile.clear();
if (!this.settings.getGCDisabled())
System.gc();
}
final void addSheet(Sheet s) {
this.sheets.add(s);
}
protected void parse() throws BiffException, PasswordException {
Record r = null;
BOFRecord bof = new BOFRecord(this.excelFile.next());
this.workbookBof = bof;
this.bofs++;
if (!bof.isBiff8() && !bof.isBiff7())
throw new BiffException(BiffException.unrecognizedBiffVersion);
if (!bof.isWorkbookGlobals())
throw new BiffException(BiffException.expectedGlobals);
ArrayList continueRecords = new ArrayList();
this.nameTable = new ArrayList();
while (this.bofs == 1) {
r = this.excelFile.next();
if (r.getType() == Type.SST) {
continueRecords.clear();
Record nextrec = this.excelFile.peek();
while (nextrec.getType() == Type.CONTINUE) {
continueRecords.add(this.excelFile.next());
nextrec = this.excelFile.peek();
}
Record[] records = new Record[continueRecords.size()];
records = continueRecords.<Record>toArray(records);
this.sharedStrings = new SSTRecord(r, records, this.settings);
continue;
}
if (r.getType() == Type.FILEPASS)
throw new PasswordException();
if (r.getType() == Type.NAME) {
NameRecord nr = null;
if (bof.isBiff8()) {
nr = new NameRecord(r, this.settings, this.namedRecords.size());
} else {
nr = new NameRecord(r, this.settings, this.namedRecords.size(), NameRecord.biff7);
}
this.namedRecords.put(nr.getName(), nr);
this.nameTable.add(nr);
continue;
}
if (r.getType() == Type.FONT) {
FontRecord fr = null;
if (bof.isBiff8()) {
fr = new FontRecord(r, this.settings);
} else {
fr = new FontRecord(r, this.settings, FontRecord.biff7);
}
this.fonts.addFont(fr);
continue;
}
if (r.getType() == Type.PALETTE) {
PaletteRecord palette = new PaletteRecord(r);
this.formattingRecords.setPalette(palette);
continue;
}
if (r.getType() == Type.NINETEENFOUR) {
NineteenFourRecord nr = new NineteenFourRecord(r);
this.nineteenFour = nr.is1904();
continue;
}
if (r.getType() == Type.FORMAT) {
FormatRecord fr = null;
if (bof.isBiff8()) {
fr = new FormatRecord(r, this.settings, FormatRecord.biff8);
} else {
fr = new FormatRecord(r, this.settings, FormatRecord.biff7);
}
try {
this.formattingRecords.addFormat((DisplayFormat)fr);
} catch (NumFormatRecordsException e) {
e.printStackTrace();
Assert.verify(false, e.getMessage());
}
continue;
}
if (r.getType() == Type.XF) {
XFRecord xfr = null;
if (bof.isBiff8()) {
xfr = new XFRecord(r, this.settings, XFRecord.biff8);
} else {
xfr = new XFRecord(r, this.settings, XFRecord.biff7);
}
try {
this.formattingRecords.addStyle(xfr);
} catch (NumFormatRecordsException e) {
Assert.verify(false, e.getMessage());
}
continue;
}
if (r.getType() == Type.BOUNDSHEET) {
BoundsheetRecord br = null;
if (bof.isBiff8()) {
br = new BoundsheetRecord(r);
} else {
br = new BoundsheetRecord(r, BoundsheetRecord.biff7);
}
if (br.isSheet()) {
this.boundsheets.add(br);
continue;
}
if (br.isChart() && !this.settings.getDrawingsDisabled())
this.boundsheets.add(br);
continue;
}
if (r.getType() == Type.EXTERNSHEET) {
if (bof.isBiff8()) {
this.externSheet = new ExternalSheetRecord(r, this.settings);
continue;
}
this.externSheet = new ExternalSheetRecord(r, this.settings, ExternalSheetRecord.biff7);
continue;
}
if (r.getType() == Type.CODEPAGE) {
CodepageRecord cr = new CodepageRecord(r);
this.settings.setCharacterSet(cr.getCharacterSet());
continue;
}
if (r.getType() == Type.SUPBOOK) {
Record nextrec = this.excelFile.peek();
while (nextrec.getType() == Type.CONTINUE) {
r.addContinueRecord(this.excelFile.next());
nextrec = this.excelFile.peek();
}
SupbookRecord sr = new SupbookRecord(r, this.settings);
this.supbooks.add(sr);
continue;
}
if (r.getType() == Type.PROTECT) {
ProtectRecord pr = new ProtectRecord(r);
this.wbProtected = pr.isProtected();
continue;
}
if (r.getType() == Type.OBJPROJ) {
this.containsMacros = true;
continue;
}
if (r.getType() == Type.COUNTRY) {
this.countryRecord = new CountryRecord(r);
continue;
}
if (r.getType() == Type.MSODRAWINGGROUP) {
if (!this.settings.getDrawingsDisabled()) {
this.msoDrawingGroup = new MsoDrawingGroupRecord(r);
if (this.drawingGroup == null)
this.drawingGroup = new DrawingGroup(Origin.READ);
this.drawingGroup.add(this.msoDrawingGroup);
Record nextrec = this.excelFile.peek();
while (nextrec.getType() == Type.CONTINUE) {
this.drawingGroup.add(this.excelFile.next());
nextrec = this.excelFile.peek();
}
}
continue;
}
if (r.getType() == Type.BUTTONPROPERTYSET) {
this.buttonPropertySet = new ButtonPropertySetRecord(r);
continue;
}
if (r.getType() == Type.EOF)
this.bofs--;
}
bof = null;
if (this.excelFile.hasNext()) {
r = this.excelFile.next();
if (r.getType() == Type.BOF)
bof = new BOFRecord(r);
}
while (bof != null && getNumberOfSheets() < this.boundsheets.size()) {
if (!bof.isBiff8() && !bof.isBiff7())
throw new BiffException(BiffException.unrecognizedBiffVersion);
if (bof.isWorksheet()) {
SheetImpl s = new SheetImpl(this.excelFile, this.sharedStrings, this.formattingRecords, bof, this.workbookBof, this.nineteenFour, this);
BoundsheetRecord br = this.boundsheets.get(getNumberOfSheets());
s.setName(br.getName());
s.setHidden(br.isHidden());
addSheet(s);
} else if (bof.isChart()) {
SheetImpl s = new SheetImpl(this.excelFile, this.sharedStrings, this.formattingRecords, bof, this.workbookBof, this.nineteenFour, this);
BoundsheetRecord br = this.boundsheets.get(getNumberOfSheets());
s.setName(br.getName());
s.setHidden(br.isHidden());
addSheet(s);
} else {
logger.warn("BOF is unrecognized");
while (this.excelFile.hasNext() && r.getType() != Type.EOF)
r = this.excelFile.next();
}
bof = null;
if (this.excelFile.hasNext()) {
r = this.excelFile.next();
if (r.getType() == Type.BOF)
bof = new BOFRecord(r);
}
}
}
public FormattingRecords getFormattingRecords() {
return this.formattingRecords;
}
public ExternalSheetRecord getExternalSheetRecord() {
return this.externSheet;
}
public MsoDrawingGroupRecord getMsoDrawingGroupRecord() {
return this.msoDrawingGroup;
}
public SupbookRecord[] getSupbookRecords() {
SupbookRecord[] sr = new SupbookRecord[this.supbooks.size()];
return (SupbookRecord[])this.supbooks.toArray((Object[])sr);
}
public NameRecord[] getNameRecords() {
NameRecord[] na = new NameRecord[this.nameTable.size()];
return (NameRecord[])this.nameTable.toArray((Object[])na);
}
public Fonts getFonts() {
return this.fonts;
}
public Cell getCell(String loc) {
Sheet s = getSheet(CellReferenceHelper.getSheet(loc));
return s.getCell(loc);
}
public Cell findCellByName(String name) {
NameRecord nr = (NameRecord)this.namedRecords.get(name);
if (nr == null)
return null;
NameRecord.NameRange[] ranges = nr.getRanges();
Sheet s = getSheet(ranges[0].getExternalSheet());
Cell cell = s.getCell(ranges[0].getFirstColumn(), ranges[0].getFirstRow());
return cell;
}
public Range[] findByName(String name) {
NameRecord nr = (NameRecord)this.namedRecords.get(name);
if (nr == null)
return null;
NameRecord.NameRange[] ranges = nr.getRanges();
Range[] cellRanges = new Range[ranges.length];
for (int i = 0; i < ranges.length; i++)
cellRanges[i] = (Range)new RangeImpl(this, getExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getFirstColumn(), ranges[i].getFirstRow(), getLastExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getLastColumn(), ranges[i].getLastRow());
return cellRanges;
}
public String[] getRangeNames() {
Object[] keys = this.namedRecords.keySet().toArray();
String[] names = new String[keys.length];
System.arraycopy(keys, 0, names, 0, keys.length);
return names;
}
public BOFRecord getWorkbookBof() {
return this.workbookBof;
}
public boolean isProtected() {
return this.wbProtected;
}
public WorkbookSettings getSettings() {
return this.settings;
}
public int getExternalSheetIndex(String sheetName) {
return 0;
}
public int getLastExternalSheetIndex(String sheetName) {
return 0;
}
public String getName(int index) {
Assert.verify((index >= 0 && index < this.nameTable.size()));
return ((NameRecord)this.nameTable.get(index)).getName();
}
public int getNameIndex(String name) {
NameRecord nr = (NameRecord)this.namedRecords.get(name);
return (nr != null) ? nr.getIndex() : 0;
}
public DrawingGroup getDrawingGroup() {
return this.drawingGroup;
}
public CompoundFile getCompoundFile() {
return this.excelFile.getCompoundFile();
}
public boolean containsMacros() {
return this.containsMacros;
}
public ButtonPropertySetRecord getButtonPropertySet() {
return this.buttonPropertySet;
}
public CountryRecord getCountryRecord() {
return this.countryRecord;
}
}