move cleaned up jxl into this project, get rid of log4j dependency

main 1.0.1
Jörg Prante 2 years ago
parent fe833de27a
commit 0925fc31f5

@ -0,0 +1,15 @@
datastructures-xslx is composed of the following works
jxl
https://sourceforge.net/projects/jexcelapi/
GNU Library or Lesser General Public License version 2.0 (LGPLv2)
with the log4j dependency removed
and
com.incesoft.tools.excel
https://code.google.com/archive/p/sjxslx/ -> https://github.com/davidpelfree/sjxlsx
License: Apache License 2.0
The code will be refactored to the org.xbib package group.

@ -1,3 +0,0 @@
dependencies {
implementation libs.jxl
}

@ -0,0 +1,45 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* This type represents the Microsoft concept of a Boolean. Accordingly, this
* cell represents either TRUE, FALSE or an error condition. This third
* state naturally makes handling BooleanCells quite tricky, and use of
* the specific access methods should be handled with care
*/
public interface BooleanCell extends Cell {
/**
* Gets the boolean value stored in this cell. If this cell contains an
* error, then returns FALSE. Always query this cell type using the
* accessor method isError() prior to calling this method
*
* @return TRUE if this cell contains TRUE, FALSE if it contains FALSE or
* an error code
*/
boolean getValue();
}

@ -0,0 +1,27 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A mixin interface for numerical formulas, which combines the interfaces
* for formulas and for numbers
*/
public interface BooleanFormulaCell extends BooleanCell, FormulaCell {
}

@ -0,0 +1,86 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import jxl.format.CellFormat;
/**
* Represents an individual Cell within a Sheet. May be queried for its
* type and its content
*/
public interface Cell {
/**
* Returns the row number of this cell
*
* @return the row number of this cell
*/
int getRow();
/**
* Returns the column number of this cell
*
* @return the column number of this cell
*/
int getColumn();
/**
* Returns the content type of this cell
*
* @return the content type for this cell
*/
CellType getType();
/**
* Indicates whether or not this cell is hidden, by virtue of either
* the entire row or column being collapsed
*
* @return TRUE if this cell is hidden, FALSE otherwise
*/
boolean isHidden();
/**
* Quick and dirty function to return the contents of this cell as a string.
* For more complex manipulation of the contents, it is necessary to cast
* this interface to correct subinterface
*
* @return the contents of this cell as a string
*/
String getContents();
/**
* Gets the cell format which applies to this cell
* Note that for cell with a cell type of EMPTY, which has no formatting
* information, this method will return null. Some empty cells (eg. on
* template spreadsheets) may have a cell type of EMPTY, but will
* actually contain formatting information
*
* @return the cell format applied to this cell, or NULL if this is an
* empty cell
*/
CellFormat getCellFormat();
/**
* Gets any special cell features, such as comments (notes) or cell
* validation present for this cell
*
* @return the cell features, or NULL if this cell has no special features
*/
CellFeatures getCellFeatures();
}

@ -0,0 +1,74 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import jxl.biff.BaseCellFeatures;
/**
* Container for any additional cell features
*/
public class CellFeatures extends BaseCellFeatures {
/**
* Constructor
*/
public CellFeatures() {
super();
}
/**
* Copy constructor
*
* @param cf cell to copy
*/
protected CellFeatures(CellFeatures cf) {
super(cf);
}
/**
* Accessor for the cell comment
*
* @return the cell comment, or NULL if this cell doesn't have
* a comment associated with it
*/
public String getComment() {
return super.getComment();
}
/**
* Gets the data validation list
*
* @return the data validation list
*/
public String getDataValidationList() {
return super.getDataValidationList();
}
/**
* Gets the range of cells to which the data validation applies. If the
* validation applies to just this cell, this will be reflected in the
* returned range
*
* @return the range to which the same validation extends, or NULL if this
* cell doesn't have a validation
*/
public Range getSharedDataValidationRange() {
return super.getSharedDataValidationRange();
}
}

@ -0,0 +1,28 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* Interface for cell formats - used for typing information
*
* @deprecated Repackaged as jxl.format.CellFormat
*/
public interface CellFormat extends jxl.format.CellFormat {
}

@ -0,0 +1,254 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import jxl.write.WritableWorkbook;
/**
* Exposes some cell reference helper methods to the public interface.
* This class merely delegates to the internally used reference helper
*/
public final class CellReferenceHelper {
/**
* Hide the default constructor
*/
private CellReferenceHelper() {
}
/**
* Appends the cell reference for the column and row passed in to the string
* buffer
*
* @param column the column
* @param row the row
* @param buf the string buffer to append
*/
public static void getCellReference(int column, int row, StringBuffer buf) {
jxl.biff.CellReferenceHelper.getCellReference(column, row, buf);
}
/**
* Overloaded method which prepends $ for absolute reference
*
* @param column the column number
* @param colabs TRUE if the column reference is absolute
* @param row the row number
* @param rowabs TRUE if the row reference is absolute
* @param buf the string buffer
*/
public static void getCellReference(int column,
boolean colabs,
int row,
boolean rowabs,
StringBuffer buf) {
jxl.biff.CellReferenceHelper.getCellReference(column, colabs,
row, rowabs,
buf);
}
/**
* Gets the cell reference for the specified column and row
*
* @param column the column
* @param row the row
* @return the cell reference
*/
public static String getCellReference(int column, int row) {
return jxl.biff.CellReferenceHelper.getCellReference(column, row);
}
/**
* Gets the columnn number of the string cell reference
*
* @param s the string to parse
* @return the column portion of the cell reference
*/
public static int getColumn(String s) {
return jxl.biff.CellReferenceHelper.getColumn(s);
}
/**
* Gets the column letter corresponding to the 0-based column number
*
* @param c the column number
* @return the letter for that column number
*/
public static String getColumnReference(int c) {
return jxl.biff.CellReferenceHelper.getColumnReference(c);
}
/**
* Gets the row number of the cell reference
*
* @param s the cell reference
* @return the row number
*/
public static int getRow(String s) {
return jxl.biff.CellReferenceHelper.getRow(s);
}
/**
* Sees if the column component is relative or not
*
* @param s the cell
* @return TRUE if the column is relative, FALSE otherwise
*/
public static boolean isColumnRelative(String s) {
return jxl.biff.CellReferenceHelper.isColumnRelative(s);
}
/**
* Sees if the row component is relative or not
*
* @param s the cell
* @return TRUE if the row is relative, FALSE otherwise
*/
public static boolean isRowRelative(String s) {
return jxl.biff.CellReferenceHelper.isRowRelative(s);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet the sheet index
* @param column the column index
* @param row the row index
* @param workbook the workbook
* @param buf a string buffer
*/
public static void getCellReference
(int sheet, int column, int row,
Workbook workbook, StringBuffer buf) {
jxl.biff.CellReferenceHelper.getCellReference
(sheet, column, row, (jxl.biff.formula.ExternalSheet) workbook, buf);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet the sheet
* @param column the column
* @param row the row
* @param workbook the workbook
* @param buf the buffer
*/
public static void getCellReference(int sheet,
int column,
int row,
WritableWorkbook workbook,
StringBuffer buf) {
jxl.biff.CellReferenceHelper.getCellReference
(sheet, column, row, (jxl.biff.formula.ExternalSheet) workbook, buf);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet the sheet
* @param column the column
* @param colabs TRUE if the column is an absolute reference
* @param row the row
* @param rowabs TRUE if the row is an absolute reference
* @param workbook the workbook
* @param buf the string buffer
*/
public static void getCellReference(int sheet,
int column,
boolean colabs,
int row,
boolean rowabs,
Workbook workbook,
StringBuffer buf) {
jxl.biff.CellReferenceHelper.getCellReference
(sheet, column, colabs, row, rowabs,
(jxl.biff.formula.ExternalSheet) workbook, buf);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet the sheet
* @param column the column
* @param row the row
* @param workbook the workbook
* @return the cell reference in the form 'Sheet 1'!A1
*/
public static String getCellReference(int sheet,
int column,
int row,
Workbook workbook) {
return jxl.biff.CellReferenceHelper.getCellReference
(sheet, column, row, (jxl.biff.formula.ExternalSheet) workbook);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet the sheet
* @param column the column
* @param row the row
* @param workbook the workbook
* @return the cell reference in the form 'Sheet 1'!A1
*/
public static String getCellReference(int sheet,
int column,
int row,
WritableWorkbook workbook) {
return jxl.biff.CellReferenceHelper.getCellReference
(sheet, column, row, (jxl.biff.formula.ExternalSheet) workbook);
}
/**
* Gets the sheet name from the cell reference string
*
* @param ref the cell reference
* @return the sheet name
*/
public static String getSheet(String ref) {
return jxl.biff.CellReferenceHelper.getSheet(ref);
}
/**
* Gets the cell reference for the cell
*
* @param the cell
*/
public static String getCellReference(Cell c) {
return getCellReference(c.getColumn(), c.getRow());
}
/**
* Gets the cell reference for the cell
*
* @param c the cell
* @param sb string buffer
*/
public static void getCellReference(Cell c, StringBuffer sb) {
getCellReference(c.getColumn(), c.getRow(), sb);
}
}

@ -0,0 +1,97 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* An enumeration type listing the available content types for a cell
*/
public final class CellType {
/**
* An empty cell can still contain formatting information and comments
*/
public static final CellType EMPTY = new CellType("Empty");
/**
*
*/
public static final CellType LABEL = new CellType("Label");
/**
*
*/
public static final CellType NUMBER = new CellType("Number");
/**
*
*/
public static final CellType BOOLEAN = new CellType("Boolean");
/**
*
*/
public static final CellType ERROR = new CellType("Error");
/**
*
*/
public static final CellType NUMBER_FORMULA =
new CellType("Numerical Formula");
/**
*
*/
public static final CellType DATE_FORMULA = new CellType("Date Formula");
/**
*
*/
public static final CellType STRING_FORMULA = new CellType("String Formula");
/**
*
*/
public static final CellType BOOLEAN_FORMULA =
new CellType("Boolean Formula");
/**
*
*/
public static final CellType FORMULA_ERROR = new CellType("Formula Error");
/**
*
*/
public static final CellType DATE = new CellType("Date");
/**
* The text description of this cell type
*/
private final String description;
/**
* Private constructor
*
* @param desc the description of this type
*/
private CellType(String desc) {
description = desc;
}
/**
* Returns a string description of this cell
*
* @return the string description for this type
*/
public String toString() {
return description;
}
}

@ -0,0 +1,196 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import jxl.format.CellFormat;
/**
* This is a bean which client applications may use to get/set various
* properties for a row or column on a spreadsheet
*/
public final class CellView {
/**
* The dimension for the associated group of cells. For columns this
* will be width in characters, for rows this will be the
* height in points
* This attribute is deprecated in favour of the size attribute
*/
private int dimension;
/**
* The size for the associated group of cells. For columns this
* will be width in characters multiplied by 256, for rows this will be the
* height in points
*/
private int size;
/**
* Indicates whether the deprecated function was used to set the dimension
*/
private boolean depUsed;
/**
* Indicates whether or not this sheet is hidden
*/
private boolean hidden;
/**
* The cell format for the row/column
*/
private CellFormat format;
/**
* Indicates that this column/row should be autosized
*/
private boolean autosize;
/**
* Default constructor
*/
public CellView() {
hidden = false;
depUsed = false;
dimension = 1;
size = 1;
autosize = false;
}
/**
* Copy constructor
*/
public CellView(CellView cv) {
hidden = cv.hidden;
depUsed = cv.depUsed;
dimension = cv.dimension;
size = cv.size;
autosize = cv.autosize;
}
/**
* Accessor for the hidden nature of this row/column
*
* @return TRUE if this row/column is hidden, FALSE otherwise
*/
public boolean isHidden() {
return hidden;
}
/**
* Sets the hidden status of this row/column
*
* @param h the hidden flag
*/
public void setHidden(boolean h) {
hidden = h;
}
/**
* Gets the width of the column in characters or the height of the
* row in 1/20ths
*
* @return the dimension
* @deprecated use getSize() instead
*/
public int getDimension() {
return dimension;
}
/**
* Sets the dimension for this view
*
* @param d the width of the column in characters, or the height of the
* row in 1/20ths of a point
* @deprecated use the setSize method instead
*/
public void setDimension(int d) {
dimension = d;
depUsed = true;
}
/**
* Gets the width of the column in characters multiplied by 256, or the
* height of the row in 1/20ths of a point
*
* @return the dimension
*/
public int getSize() {
return size;
}
/**
* Sets the dimension for this view
*
* @param d the width of the column in characters multiplied by 256,
* or the height of the row in 1/20ths of a point
*/
public void setSize(int d) {
size = d;
depUsed = false;
}
/**
* Accessor for the cell format for this group.
*
* @return the format for the column/row, or NULL if no format was
* specified
*/
public CellFormat getFormat() {
return format;
}
/**
* Sets the cell format for this group of cells
*
* @param cf the format for every cell in the column/row
*/
public void setFormat(CellFormat cf) {
format = cf;
}
/**
* Accessor for the depUsed attribute
*
* @return TRUE if the deprecated methods were used to set the size,
* FALSE otherwise
*/
public boolean depUsed() {
return depUsed;
}
/**
* Accessor for the autosize flag
* NOTE: use of the autosize function is very processor intensive, so
* use with care
*
* @return TRUE if this row/column is to be autosized
*/
public boolean isAutosize() {
return autosize;
}
/**
* Sets the autosize flag. Currently, this only works for column views
*
* @param a autosize
*/
public void setAutosize(boolean a) {
autosize = a;
}
}

@ -0,0 +1,53 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.text.DateFormat;
import java.util.Date;
/**
* A date cell
*/
public interface DateCell extends Cell {
/**
* Gets the date contained in this cell
*
* @return the cell contents
*/
Date getDate();
/**
* Indicates whether the date value contained in this cell refers to a date,
* or merely a time
*
* @return TRUE if the value refers to a time
*/
boolean isTime();
/**
* Gets the DateFormat used to format the cell. This will normally be
* the format specified in the excel spreadsheet, but in the event of any
* difficulty parsing this, it will revert to the default date/time format.
*
* @return the DateFormat object used to format the date in the original
* excel cell
*/
DateFormat getDateFormat();
}

@ -0,0 +1,27 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A mixin interface for date formulas, which combines the interfaces
* for formulas and for dates
*/
public interface DateFormulaCell extends DateCell, FormulaCell {
}

@ -0,0 +1,36 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* This type represents a cell which contains an error. This error will
* usually, but not always be the result of some error resulting from
* a formula
*/
public interface ErrorCell extends Cell {
/**
* Gets the error code for this cell. If this cell does not represent
* an error, then it returns 0. Always use the method isError() to
* determine this prior to calling this method
*
* @return the error code if this cell contains an error, 0 otherwise
*/
int getErrorCode();
}

@ -0,0 +1,27 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A mixin interface for numerical formulas, which combines the interfaces
* for formulas and for numbers
*/
public interface ErrorFormulaCell extends ErrorCell, FormulaCell {
}

@ -0,0 +1,35 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import jxl.biff.formula.FormulaException;
/**
* Interface for formulas which allow clients to read the Excel formula
*/
public interface FormulaCell extends Cell {
/**
* Gets the formula as a string
*
* @return the formula as a string
* @throws FormulaException if an error occurred whilst parsing
*/
String getFormula() throws FormulaException;
}

@ -0,0 +1,344 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan, Eric Jung
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* Class which represents an Excel header or footer.
*/
public final class HeaderFooter extends jxl.biff.HeaderFooter {
/**
* Default constructor.
*/
public HeaderFooter() {
super();
}
/**
* Copy constructor
*
* @param hf the item to copy
*/
public HeaderFooter(HeaderFooter hf) {
super(hf);
}
/**
* Constructor used when reading workbooks to separate the left, right
* a central part of the strings into their constituent parts
*
* @param s the header string
*/
public HeaderFooter(String s) {
super(s);
}
/**
* Retrieves a <code>String</code>ified
* version of this object
*
* @return the header string
*/
public String toString() {
return super.toString();
}
/**
* Accessor for the contents which appear on the right hand side of the page
*
* @return the right aligned contents
*/
public Contents getRight() {
return (Contents) super.getRightText();
}
/**
* Accessor for the contents which in the centre of the page
*
* @return the centrally aligned contents
*/
public Contents getCentre() {
return (Contents) super.getCentreText();
}
/**
* Accessor for the contents which appear on the left hand side of the page
*
* @return the left aligned contents
*/
public Contents getLeft() {
return (Contents) super.getLeftText();
}
/**
* Clears the contents of the header/footer
*/
public void clear() {
super.clear();
}
/**
* Creates internal class of the appropriate type
*
* @return the created contents
*/
protected jxl.biff.HeaderFooter.Contents createContents() {
return new Contents();
}
/**
* Creates internal class of the appropriate type
*
* @param s the string to create the contents
* @return the created contents
*/
protected jxl.biff.HeaderFooter.Contents createContents(String s) {
return new Contents(s);
}
/**
* Creates internal class of the appropriate type
*
* @param c the contents to copy
* @return the new contents
*/
protected jxl.biff.HeaderFooter.Contents
createContents(jxl.biff.HeaderFooter.Contents c) {
return new Contents((Contents) c);
}
/**
* The contents - a simple wrapper around a string buffer
*/
public static class Contents extends jxl.biff.HeaderFooter.Contents {
/**
* The constructor
*/
Contents() {
super();
}
/**
* Constructor used when reading worksheets. The string contains all
* the formatting (but not alignment characters
*
* @param s the format string
*/
Contents(String s) {
super(s);
}
/**
* Copy constructor
*
* @param copy the contents to copy
*/
Contents(Contents copy) {
super(copy);
}
/**
* Appends the text to the string buffer
*
* @param txt the text to append
*/
public void append(String txt) {
super.append(txt);
}
/**
* Turns bold printing on or off. Bold printing
* is initially off. Text subsequently appended to
* this object will be bolded until this method is
* called again.
*/
public void toggleBold() {
super.toggleBold();
}
/**
* Turns underline printing on or off. Underline printing
* is initially off. Text subsequently appended to
* this object will be underlined until this method is
* called again.
*/
public void toggleUnderline() {
super.toggleUnderline();
}
/**
* Turns italics printing on or off. Italics printing
* is initially off. Text subsequently appended to
* this object will be italicized until this method is
* called again.
*/
public void toggleItalics() {
super.toggleItalics();
}
/**
* Turns strikethrough printing on or off. Strikethrough printing
* is initially off. Text subsequently appended to
* this object will be striked out until this method is
* called again.
*/
public void toggleStrikethrough() {
super.toggleStrikethrough();
}
/**
* Turns double-underline printing on or off. Double-underline printing
* is initially off. Text subsequently appended to
* this object will be double-underlined until this method is
* called again.
*/
public void toggleDoubleUnderline() {
super.toggleDoubleUnderline();
}
/**
* Turns superscript printing on or off. Superscript printing
* is initially off. Text subsequently appended to
* this object will be superscripted until this method is
* called again.
*/
public void toggleSuperScript() {
super.toggleSuperScript();
}
/**
* Turns subscript printing on or off. Subscript printing
* is initially off. Text subsequently appended to
* this object will be subscripted until this method is
* called again.
*/
public void toggleSubScript() {
super.toggleSubScript();
}
/**
* Turns outline printing on or off (Macintosh only).
* Outline printing is initially off. Text subsequently appended
* to this object will be outlined until this method is
* called again.
*/
public void toggleOutline() {
super.toggleOutline();
}
/**
* Turns shadow printing on or off (Macintosh only).
* Shadow printing is initially off. Text subsequently appended
* to this object will be shadowed until this method is
* called again.
*/
public void toggleShadow() {
super.toggleShadow();
}
/**
* Sets the font of text subsequently appended to this
* object.. Previously appended text is not affected.
* <p/>
* <strong>Note:</strong> no checking is performed to
* determine if fontName is a valid font.
*
* @param fontName name of the font to use
*/
public void setFontName(String fontName) {
super.setFontName(fontName);
}
/**
* Sets the font size of text subsequently appended to this
* object. Previously appended text is not affected.
* <p/>
* Valid point sizes are between 1 and 99 (inclusive). If
* size is outside this range, this method returns false
* and does not change font size. If size is within this
* range, the font size is changed and true is returned.
*
* @param size The size in points. Valid point sizes are
* between 1 and 99 (inclusive).
* @return true if the font size was changed, false if font
* size was not changed because 1 > size > 99.
*/
public boolean setFontSize(int size) {
return super.setFontSize(size);
}
/**
* Appends the page number
*/
public void appendPageNumber() {
super.appendPageNumber();
}
/**
* Appends the total number of pages
*/
public void appendTotalPages() {
super.appendTotalPages();
}
/**
* Appends the current date
*/
public void appendDate() {
super.appendDate();
}
/**
* Appends the current time
*/
public void appendTime() {
super.appendTime();
}
/**
* Appends the workbook name
*/
public void appendWorkbookName() {
super.appendWorkbookName();
}
/**
* Appends the worksheet name
*/
public void appendWorkSheetName() {
super.appendWorkSheetName();
}
/**
* Clears the contents of this portion
*/
public void clear() {
super.clear();
}
/**
* Queries if the contents are empty
*
* @return TRUE if the contents are empty, FALSE otherwise
*/
public boolean empty() {
return super.empty();
}
}
}

@ -0,0 +1,106 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.io.File;
import java.net.URL;
/**
* Hyperlink information. Only URLs or file links are supported
* <p>
* Hyperlinks may apply to a range of cells; in such cases the methods
* getRow and getColumn return the cell at the top left of the range
* the hyperlink refers to. Hyperlinks have no specific cell format
* information applied to them, so the getCellFormat method will return null
*/
public interface Hyperlink {
/**
* Returns the row number of this cell
*
* @return the row number of this cell
*/
int getRow();
/**
* Returns the column number of this cell
*
* @return the column number of this cell
*/
int getColumn();
/**
* Gets the range of cells which activate this hyperlink
* The get sheet index methods will all return -1, because the
* cells will all be present on the same sheet
*
* @return the range of cells which activate the hyperlink
*/
Range getRange();
/**
* Determines whether this is a hyperlink to a file
*
* @return TRUE if this is a hyperlink to a file, FALSE otherwise
*/
boolean isFile();
/**
* Determines whether this is a hyperlink to a web resource
*
* @return TRUE if this is a URL
*/
boolean isURL();
/**
* Determines whether this is a hyperlink to a location in this workbook
*
* @return TRUE if this is a link to an internal location
*/
boolean isLocation();
/**
* Returns the row number of the bottom right cell
*
* @return the row number of this cell
*/
int getLastRow();
/**
* Returns the column number of the bottom right cell
*
* @return the column number of this cell
*/
int getLastColumn();
/**
* Gets the URL referenced by this Hyperlink
*
* @return the URL, or NULL if this hyperlink is not a URL
*/
URL getURL();
/**
* Returns the local file eferenced by this Hyperlink
*
* @return the file, or NULL if this hyperlink is not a file
*/
File getFile();
}

@ -0,0 +1,120 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.io.File;
import jxl.common.LengthUnit;
/**
* Accessor functions for an image
*/
public interface Image {
/**
* Accessor for the image position
*
* @return the column number at which the image is positioned
*/
double getColumn();
/**
* Accessor for the image position
*
* @return the row number at which the image is positioned
*/
double getRow();
/**
* Accessor for the image dimensions
*
* @return the number of columns this image spans
*/
double getWidth();
/**
* Accessor for the image dimensions
*
* @return the number of rows which this image spans
*/
double getHeight();
/**
* Accessor for the image file
*
* @return the file which the image references
*/
File getImageFile();
/**
* Accessor for the image data
*
* @return the image data
*/
byte[] getImageData();
/**
* Get the width of this image as rendered within Excel
*
* @param unit the unit of measurement
* @return the width of the image within Excel
*/
double getWidth(LengthUnit unit);
/**
* Get the height of this image as rendered within Excel
*
* @param unit the unit of measurement
* @return the height of the image within Excel
*/
double getHeight(LengthUnit unit);
/**
* Gets the width of the image. Note that this is the width of the
* underlying image, and does not take into account any size manipulations
* that may have occurred when the image was added into Excel
*
* @return the image width in pixels
*/
int getImageWidth();
/**
* Gets the height of the image. Note that this is the height of the
* underlying image, and does not take into account any size manipulations
* that may have occurred when the image was added into Excel
*
* @return the image height in pixels
*/
int getImageHeight();
/**
* Gets the horizontal resolution of the image, if that information
* is available.
*
* @return the number of dots per unit specified, if available, 0 otherwise
*/
double getHorizontalResolution(LengthUnit unit);
/**
* Gets the vertical resolution of the image, if that information
* is available.
*
* @return the number of dots per unit specified, if available, 0 otherwise
*/
double getVerticalResolution(LengthUnit unit);
}

@ -0,0 +1,34 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* Base exception class for JExcelAPI exceptions
*/
public class JXLException extends Exception {
/**
* Constructor
*
* @param message the exception message
*/
protected JXLException(String message) {
super(message);
}
}

@ -0,0 +1,33 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A label cell
*/
public interface LabelCell extends Cell {
/**
* Gets the label for this cell. The value returned will be the same
* as for the getContents method in the base class
*
* @return the cell contents
*/
String getString();
}

@ -0,0 +1,43 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.text.NumberFormat;
/**
* A cell which contains a numerical value
*/
public interface NumberCell extends Cell {
/**
* Gets the double contents for this cell.
*
* @return the cell contents
*/
double getValue();
/**
* Gets the NumberFormat used to format this cell. This is the java
* equivalent of the Excel format
*
* @return the NumberFormat used to format the cell
*/
NumberFormat getNumberFormat();
}

@ -0,0 +1,27 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A mixin interface for numerical formulas, which combines the interfaces
* for formulas and for numbers
*/
public interface NumberFormulaCell extends NumberCell, FormulaCell {
}

@ -0,0 +1,57 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* Represents a 3-D range of cells in a workbook. This object is
* returned by the method findByName in a workbook
*/
public interface Range {
/**
* Gets the cell at the top left of this range
*
* @return the cell at the top left
*/
Cell getTopLeft();
/**
* Gets the cell at the bottom right of this range
*
* @return the cell at the bottom right
*/
Cell getBottomRight();
/**
* Gets the index of the first sheet in the range
*
* @return the index of the first sheet in the range
*/
int getFirstSheetIndex();
/**
* Gets the index of the last sheet in the range
*
* @return the index of the last sheet in the range
*/
int getLastSheetIndex();
}

@ -0,0 +1,278 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.util.regex.Pattern;
import jxl.format.CellFormat;
/**
* Represents a sheet within a workbook. Provides a handle to the individual
* cells, or lines of cells (grouped by Row or Column)
*/
public interface Sheet {
/**
* Returns the cell specified at this row and at this column.
* If a column/row combination forms part of a merged group of cells
* then (unless it is the first cell of the group) a blank cell
* will be returned
*
* @param column the column number
* @param row the row number
* @return the cell at the specified co-ordinates
*/
Cell getCell(int column, int row);
/**
* Returns the cell for the specified location eg. "A4". Note that this
* method is identical to calling getCell(CellReferenceHelper.getColumn(loc),
* CellReferenceHelper.getRow(loc)) and its implicit performance
* overhead for string parsing. As such,this method should therefore
* be used sparingly
*
* @param loc the cell reference
* @return the cell at the specified co-ordinates
*/
Cell getCell(String loc);
/**
* Returns the number of rows in this sheet
*
* @return the number of rows in this sheet
*/
int getRows();
/**
* Returns the number of columns in this sheet
*
* @return the number of columns in this sheet
*/
int getColumns();
/**
* Gets all the cells on the specified row
*
* @param row the rows whose cells are to be returned
* @return the cells on the given row
*/
Cell[] getRow(int row);
/**
* Gets all the cells on the specified column
*
* @param col the column whose cells are to be returned
* @return the cells on the specified column
*/
Cell[] getColumn(int col);
/**
* Gets the name of this sheet
*
* @return the name of the sheet
*/
String getName();
/**
* Determines whether the sheet is hidden
*
* @return whether or not the sheet is hidden
* @deprecated in favour of the getSettings() method
*/
boolean isHidden();
/**
* Determines whether the sheet is protected
*
* @return whether or not the sheet is protected
* @deprecated in favour of the getSettings() method
*/
boolean isProtected();
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param contents the string to match
* @return the Cell whose contents match the paramter, null if not found
*/
Cell findCell(String contents);
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param contents the string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the range
* @param lastCol the last column within the range
* @param lastRow the last row within the range
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
Cell findCell(String contents,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse);
/**
* Gets the cell whose contents match the regular expressionstring passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param pattern the regular expression string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the rang
* @param lastCol the last column within the range
* @param lastRow the last row within the range
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
Cell findCell(Pattern pattern,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse);
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform. This method differs
* from the findCell method in that only cells with labels are
* queried - all numerical cells are ignored. This should therefore
* improve performance.
*
* @param contents the string to match
* @return the Cell whose contents match the paramter, null if not found
*/
LabelCell findLabelCell(String contents);
/**
* Gets the hyperlinks on this sheet
*
* @return an array of hyperlinks
*/
Hyperlink[] getHyperlinks();
/**
* Gets the cells which have been merged on this sheet
*
* @return an array of range objects
*/
Range[] getMergedCells();
/**
* Gets the settings used on a particular sheet
*
* @return the sheet settings
*/
SheetSettings getSettings();
/**
* Gets the column format for the specified column
*
* @param col the column number
* @return the column format, or NULL if the column has no specific format
* @deprecated Use getColumnView and the CellView bean instead
*/
CellFormat getColumnFormat(int col);
/**
* Gets the column width for the specified column
*
* @param col the column number
* @return the column width, or the default width if the column has no
* specified format
* @deprecated Use getColumnView instead
*/
int getColumnWidth(int col);
/**
* Gets the column width for the specified column
*
* @param col the column number
* @return the column format, or the default format if no override is
* specified
*/
CellView getColumnView(int col);
/**
* Gets the row height for the specified column
*
* @param row the row number
* @return the row height, or the default height if the column has no
* specified format
* @deprecated use getRowView instead
*/
int getRowHeight(int row);
/**
* Gets the row height for the specified column
*
* @param row the row number
* @return the row format, which may be the default format if no format
* is specified
*/
CellView getRowView(int row);
/**
* Accessor for the number of images on the sheet
*
* @return the number of images on this sheet
*/
int getNumberOfImages();
/**
* Accessor for the image
*
* @param i the 0 based image number
* @return the image at the specified position
*/
Image getDrawing(int i);
/**
* Accessor for the page breaks on this sheet
*
* @return the page breaks on this sheet
*/
int[] getRowPageBreaks();
/**
* Accessor for the page breaks on this sheet
*
* @return the page breaks on this sheet
*/
int[] getColumnPageBreaks();
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,29 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
/**
* A mixin interface for numerical formulas, which combines the interfaces
* for formulas and for strings
*/
public interface StringFormulaCell extends LabelCell, FormulaCell {
}

@ -0,0 +1,397 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import jxl.read.biff.BiffException;
import jxl.read.biff.File;
import jxl.read.biff.PasswordException;
import jxl.read.biff.WorkbookParser;
import jxl.write.WritableWorkbook;
import jxl.write.biff.WritableWorkbookImpl;
/**
* Represents a Workbook. Contains the various factory methods and provides
* a variety of accessors which provide access to the work sheets.
*/
public abstract class Workbook {
/**
* The current version of the software
*/
private static final String VERSION = "2.6.12";
/**
* The constructor
*/
protected Workbook() {
}
/**
* Accessor for the software version
*
* @return the version
*/
public static String getVersion() {
return VERSION;
}
/**
* A factory method which takes in an excel file and reads in the contents.
*
* @param file the excel 97 spreadsheet to parse
* @return a workbook instance
* @throws IOException
* @throws BiffException
*/
public static Workbook getWorkbook(java.io.File file)
throws IOException, BiffException {
return getWorkbook(file, new WorkbookSettings());
}
/**
* A factory method which takes in an excel file and reads in the contents.
*
* @param file the excel 97 spreadsheet to parse
* @param ws the settings for the workbook
* @return a workbook instance
* @throws IOException
* @throws BiffException
*/
public static Workbook getWorkbook(java.io.File file, WorkbookSettings ws)
throws IOException, BiffException {
FileInputStream fis = new FileInputStream(file);
// Always close down the input stream, regardless of whether or not the
// file can be parsed. Thanks to Steve Hahn for this
File dataFile = null;
try {
dataFile = new File(fis, ws);
} catch (IOException e) {
fis.close();
throw e;
} catch (BiffException e) {
fis.close();
throw e;
}
fis.close();
Workbook workbook = new WorkbookParser(dataFile, ws);
workbook.parse();
return workbook;
}
/**
* A factory method which takes in an excel file and reads in the contents.
*
* @param is an open stream which is the the excel 97 spreadsheet to parse
* @return a workbook instance
* @throws IOException
* @throws BiffException
*/
public static Workbook getWorkbook(InputStream is)
throws IOException, BiffException {
return getWorkbook(is, new WorkbookSettings());
}
/**
* A factory method which takes in an excel file and reads in the contents.
*
* @param is an open stream which is the the excel 97 spreadsheet to parse
* @param ws the settings for the workbook
* @return a workbook instance
* @throws IOException
* @throws BiffException
*/
public static Workbook getWorkbook(InputStream is, WorkbookSettings ws)
throws IOException, BiffException {
File dataFile = new File(is, ws);
Workbook workbook = new WorkbookParser(dataFile, ws);
workbook.parse();
return workbook;
}
/**
* Creates a writable workbook with the given file name
*
* @param file the workbook to copy
* @return a writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(java.io.File file)
throws IOException {
return createWorkbook(file, new WorkbookSettings());
}
/**
* Creates a writable workbook with the given file name
*
* @param file the file to copy from
* @param ws the global workbook settings
* @return a writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(java.io.File file,
WorkbookSettings ws)
throws IOException {
FileOutputStream fos = new FileOutputStream(file);
WritableWorkbook w = new WritableWorkbookImpl(fos, true, ws);
return w;
}
/**
* Creates a writable workbook with the given filename as a copy of
* the workbook passed in. Once created, the contents of the writable
* workbook may be modified
*
* @param file the output file for the copy
* @param in the workbook to copy
* @return a writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(java.io.File file,
Workbook in)
throws IOException {
return createWorkbook(file, in, new WorkbookSettings());
}
/**
* Creates a writable workbook with the given filename as a copy of
* the workbook passed in. Once created, the contents of the writable
* workbook may be modified
*
* @param file the output file for the copy
* @param in the workbook to copy
* @param ws the configuration for this workbook
* @return a writable workbook
*/
public static WritableWorkbook createWorkbook(java.io.File file,
Workbook in,
WorkbookSettings ws)
throws IOException {
FileOutputStream fos = new FileOutputStream(file);
WritableWorkbook w = new WritableWorkbookImpl(fos, in, true, ws);
return w;
}
/**
* Creates a writable workbook as a copy of
* the workbook passed in. Once created, the contents of the writable
* workbook may be modified
*
* @param os the stream to write to
* @param in the workbook to copy
* @return a writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(OutputStream os,
Workbook in)
throws IOException {
return createWorkbook(os, in, ((WorkbookParser) in).getSettings());
}
/**
* Creates a writable workbook as a copy of
* the workbook passed in. Once created, the contents of the writable
* workbook may be modified
*
* @param os the output stream to write to
* @param in the workbook to copy
* @param ws the configuration for this workbook
* @return a writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(OutputStream os,
Workbook in,
WorkbookSettings ws)
throws IOException {
WritableWorkbook w = new WritableWorkbookImpl(os, in, false, ws);
return w;
}
/**
* Creates a writable workbook. When the workbook is closed,
* it will be streamed directly to the output stream. In this
* manner, a generated excel spreadsheet can be passed from
* a servlet to the browser over HTTP
*
* @param os the output stream
* @return the writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(OutputStream os)
throws IOException {
return createWorkbook(os, new WorkbookSettings());
}
/**
* Creates a writable workbook. When the workbook is closed,
* it will be streamed directly to the output stream. In this
* manner, a generated excel spreadsheet can be passed from
* a servlet to the browser over HTTP
*
* @param os the output stream
* @param ws the configuration for this workbook
* @return the writable workbook
* @throws IOException
*/
public static WritableWorkbook createWorkbook(OutputStream os,
WorkbookSettings ws)
throws IOException {
WritableWorkbook w = new WritableWorkbookImpl(os, false, ws);
return w;
}
/**
* Gets the sheets within this workbook. Use of this method for
* large worksheets can cause performance problems.
*
* @return an array of the individual sheets
*/
public abstract Sheet[] getSheets();
/**
* Gets the sheet names
*
* @return an array of strings containing the sheet names
*/
public abstract String[] getSheetNames();
/**
* Gets the specified sheet within this workbook
* As described in the accompanying technical notes, each call
* to getSheet forces a reread of the sheet (for memory reasons).
* Therefore, do not make unnecessary calls to this method. Furthermore,
* do not hold unnecessary references to Sheets in client code, as
* this will prevent the garbage collector from freeing the memory
*
* @param index the zero based index of the reQuired sheet
* @return The sheet specified by the index
* @throws IndexOutOfBoundException when index refers to a non-existent
* sheet
*/
public abstract Sheet getSheet(int index)
throws IndexOutOfBoundsException;
/**
* Gets the sheet with the specified name from within this workbook.
* As described in the accompanying technical notes, each call
* to getSheet forces a reread of the sheet (for memory reasons).
* Therefore, do not make unnecessary calls to this method. Furthermore,
* do not hold unnecessary references to Sheets in client code, as
* this will prevent the garbage collector from freeing the memory
*
* @param name the sheet name
* @return The sheet with the specified name, or null if it is not found
*/
public abstract Sheet getSheet(String name);
/**
* Returns the number of sheets in this workbook
*
* @return the number of sheets in this workbook
*/
public abstract int getNumberOfSheets();
/**
* Gets the named cell from this workbook. If the name refers to a
* range of cells, then the cell on the top left is returned. If
* the name cannot be found, null is returned.
* This is a convenience function to quickly access the contents
* of a single cell. If you need further information (such as the
* sheet or adjacent cells in the range) use the functionally
* richer method, findByName which returns a list of ranges
*
* @param name the name of the cell/range to search for
* @return the cell in the top left of the range if found, NULL
* otherwise
*/
public abstract Cell findCellByName(String name);
/**
* Returns the cell for the specified location eg. "Sheet1!A4".
* This is identical to using the CellReferenceHelper with its
* associated performance overheads, consequently it should
* be use sparingly
*
* @param loc the cell to retrieve
* @return the cell at the specified location
*/
public abstract Cell getCell(String loc);
/**
* Gets the named range from this workbook. The Range object returns
* contains all the cells from the top left to the bottom right
* of the range.
* If the named range comprises an adjacent range,
* the Range[] will contain one object; for non-adjacent
* ranges, it is necessary to return an array of length greater than
* one.
* If the named range contains a single cell, the top left and
* bottom right cell will be the same cell
*
* @param name the name of the cell/range to search for
* @return the range of cells, or NULL if the range does not exist
*/
public abstract Range[] findByName(String name);
/**
* Gets the named ranges
*
* @return the list of named cells within the workbook
*/
public abstract String[] getRangeNames();
/**
* Determines whether the sheet is protected
*
* @return TRUE if the workbook is protected, FALSE otherwise
*/
public abstract boolean isProtected();
/**
* Parses the excel file.
* If the workbook is password protected a PasswordException is thrown
* in case consumers of the API wish to handle this in a particular way
*
* @throws BiffException
* @throws PasswordException
*/
protected abstract void parse() throws BiffException, PasswordException;
/**
* Closes this workbook, and frees makes any memory allocated available
* for garbage collection
*/
public abstract void close();
}

@ -0,0 +1,798 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl;
import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import jxl.biff.CountryCode;
import jxl.biff.formula.FunctionNames;
import jxl.common.Logger;
/**
* This is a bean which client applications may use to set various advanced
* workbook properties. Use of this bean is not mandatory, and its absence
* will merely result in workbooks being read/written using the default
* settings
*/
public final class WorkbookSettings {
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab.
*/
public final static int HIDEOBJ_HIDE_ALL = 2;
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab.
*/
public final static int HIDEOBJ_SHOW_PLACEHOLDERS = 1;
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab.
*/
public final static int HIDEOBJ_SHOW_ALL = 0;
// **
// The default values
// **
private static final int DEFAULT_INITIAL_FILE_SIZE = 5 * 1024 * 1024;
// 5 megabytes
private static final int DEFAULT_ARRAY_GROW_SIZE = 1024 * 1024; // 1 megabyte
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(WorkbookSettings.class);
/**
* The amount of memory allocated to store the workbook data when
* reading a worksheet. For processeses reading many small workbooks inside
* a WAS it might be necessary to reduce the default size
*/
private int initialFileSize;
/**
* The amount of memory allocated to the array containing the workbook
* data when its current amount is exhausted.
*/
private int arrayGrowSize;
/**
* Flag to indicate whether the drawing feature is enabled or not
* Drawings deactivated using -Djxl.nodrawings=true on the JVM command line
* Activated by default or by using -Djxl.nodrawings=false on the JVM command
* line
*/
private boolean drawingsDisabled;
/**
* Flag to indicate whether the name feature is enabled or not
* Names deactivated using -Djxl.nonames=true on the JVM command line
* Activated by default or by using -Djxl.nonames=false on the JVM command
* line
*/
private boolean namesDisabled;
/**
* Flag to indicate whether formula cell references should be adjusted
* following row/column insertion/deletion
*/
private boolean formulaReferenceAdjustDisabled;
/**
* Flag to indicate whether the system hint garbage collection
* is enabled or not.
* As a rule of thumb, it is desirable to enable garbage collection
* when reading large spreadsheets from a batch process or from the
* command line, but better to deactivate the feature when reading
* large spreadsheets within a WAS, as the calls to System.gc() not
* only garbage collect the junk in JExcelApi, but also in the
* webservers JVM and can cause significant slowdown
* GC deactivated using -Djxl.nogc=true on the JVM command line
* Activated by default or by using -Djxl.nogc=false on the JVM command line
*/
private boolean gcDisabled;
/**
* Flag to indicate whether the rationalization of cell formats is
* disabled or not.
* Rationalization is enabled by default, but may be disabled for
* performance reasons. It can be deactivated using -Djxl.norat=true on
* the JVM command line
*/
private boolean rationalizationDisabled;
/**
* Flag to indicate whether or not the merged cell checking has been
* disabled
*/
private boolean mergedCellCheckingDisabled;
/**
* Flag to indicate whether the copying of additional property sets
* are disabled
*/
private boolean propertySetsDisabled;
/**
* Flag to indicate that cell validation criteria are ignored
*/
private boolean cellValidationDisabled;
/**
* Flag to indicate whether or not to ignore blank cells when processing
* sheets. Cells which are identified as blank can still have associated
* cell formats which the processing program may still need to read
*/
private boolean ignoreBlankCells;
/**
* Flag to indicate whether auto filtering should be read/copied
*/
private boolean autoFilterDisabled;
/**
* Flag to indicate whether a temporary file should be used when
* writing out the workbook
*/
private boolean useTemporaryFileDuringWrite;
/**
* The directory for used for the temporary file during write. If this
* is NULL, the default system directory is used
*/
private File temporaryFileDuringWriteDirectory;
/**
* The locale. Normally this is the same as the system locale, but there
* may be cases (eg. where you are uploading many spreadsheets from foreign
* sources) where you may want to specify the locale on an individual
* worksheet basis
* The locale may also be specified on the command line using the lang and
* country System properties eg. -Djxl.lang=en -Djxl.country=UK for UK
* English
*/
private Locale locale;
/**
* The locale specific function names for this workbook
*/
private FunctionNames functionNames;
/**
* The character encoding used for reading non-unicode strings. This can
* be different from the default platform encoding if processing spreadsheets
* from abroad. This may also be set using the system property jxl.encoding
*/
private String encoding;
/**
* The character set used by the readable spreadsheeet
*/
private int characterSet;
/**
* The display language used by Excel (ISO 3166 mnemonic)
*/
private String excelDisplayLanguage;
/**
* The regional settings used by Excel (ISO 3166 mnemonic)
*/
private String excelRegionalSettings;
/**
* A hash map of function names keyed on locale
*/
private final HashMap localeFunctionNames;
/**
* Flag to indicate whether all external data and pivot stuff should
* refreshed
*/
private boolean refreshAll;
/**
* Flag to indicate whether the file is a template or not (Usually with .xlt
* file name extension)
*/
private boolean template;
/**
* Flag to indicate whether the file has been written by excel 2000.
* <p>
* The EXCEL9FILE record indicates the file was written by Excel 2000. It has
* no record data field and is C0010000h. Any application other than Excel
* 2000 that edits the file should not write out this record.
* <p>
* However, it seemas that excel 2003 + 2007 still set this flag....
*/
private boolean excel9file = false;
/**
* The WINDOWPROTECT record stores an option from the Protect Workbook
* dialog box.
* <p>
* =1 if the workbook windows are protected
*/
private boolean windowProtected;
/**
* Write access user name.
* When not set (null) then we set it to Java Excel API + Version number
*/
private String writeAccess;
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab.
*/
private int hideobj;
/**
* Default constructor
*/
public WorkbookSettings() {
initialFileSize = DEFAULT_INITIAL_FILE_SIZE;
arrayGrowSize = DEFAULT_ARRAY_GROW_SIZE;
localeFunctionNames = new HashMap();
excelDisplayLanguage = CountryCode.USA.getCode();
excelRegionalSettings = CountryCode.UK.getCode();
refreshAll = false;
template = false;
excel9file = false;
windowProtected = false;
hideobj = HIDEOBJ_SHOW_ALL;
// Initialize other properties from the system properties
try {
boolean suppressWarnings = Boolean.getBoolean("jxl.nowarnings");
setSuppressWarnings(suppressWarnings);
drawingsDisabled = Boolean.getBoolean("jxl.nodrawings");
namesDisabled = Boolean.getBoolean("jxl.nonames");
gcDisabled = Boolean.getBoolean("jxl.nogc");
rationalizationDisabled = Boolean.getBoolean("jxl.norat");
mergedCellCheckingDisabled =
Boolean.getBoolean("jxl.nomergedcellchecks");
formulaReferenceAdjustDisabled =
Boolean.getBoolean("jxl.noformulaadjust");
propertySetsDisabled = Boolean.getBoolean("jxl.nopropertysets");
ignoreBlankCells = Boolean.getBoolean("jxl.ignoreblanks");
cellValidationDisabled = Boolean.getBoolean("jxl.nocellvalidation");
autoFilterDisabled = !Boolean.getBoolean("jxl.autofilter");
// autofilter currently disabled by default
useTemporaryFileDuringWrite =
Boolean.getBoolean("jxl.usetemporaryfileduringwrite");
String tempdir =
System.getProperty("jxl.temporaryfileduringwritedirectory");
if (tempdir != null) {
temporaryFileDuringWriteDirectory = new File(tempdir);
}
encoding = System.getProperty("file.encoding");
} catch (SecurityException e) {
logger.warn("Error accessing system properties.", e);
}
// Initialize the locale to the system locale
try {
if (System.getProperty("jxl.lang") == null ||
System.getProperty("jxl.country") == null) {
locale = Locale.getDefault();
} else {
locale = new Locale(System.getProperty("jxl.lang"),
System.getProperty("jxl.country"));
}
if (System.getProperty("jxl.encoding") != null) {
encoding = System.getProperty("jxl.encoding");
}
} catch (SecurityException e) {
logger.warn("Error accessing system properties.", e);
locale = Locale.getDefault();
}
}
/**
* Accessor for the array grow size property
*
* @return the array grow size
*/
public int getArrayGrowSize() {
return arrayGrowSize;
}
/**
* Sets the amount of memory by which to increase the amount of
* memory allocated to storing the workbook data.
* For processeses reading many small workbooks
* inside a WAS it might be necessary to reduce the default size
* Default value is 1 megabyte
*
* @param sz the file size in bytes
*/
public void setArrayGrowSize(int sz) {
arrayGrowSize = sz;
}
/**
* Accessor for the initial file size property
*
* @return the initial file size
*/
public int getInitialFileSize() {
return initialFileSize;
}
/**
* Sets the initial amount of memory allocated to store the workbook data
* when reading a worksheet. For processeses reading many small workbooks
* inside a WAS it might be necessary to reduce the default size
* Default value is 5 megabytes
*
* @param sz the file size in bytes
*/
public void setInitialFileSize(int sz) {
initialFileSize = sz;
}
/**
* Gets the drawings disabled flag
*
* @return TRUE if drawings are disabled, FALSE otherwise
*/
public boolean getDrawingsDisabled() {
return drawingsDisabled;
}
/**
* Disables the handling of drawings
*
* @param b TRUE to disable the names feature, FALSE otherwise
*/
public void setDrawingsDisabled(boolean b) {
drawingsDisabled = b;
}
/**
* Accessor for the disabling of garbage collection
*
* @return FALSE if JExcelApi hints for garbage collection, TRUE otherwise
*/
public boolean getGCDisabled() {
return gcDisabled;
}
/**
* Sets the garbage collection disabled
*
* @param disabled TRUE to disable garbage collection, FALSE to enable it
*/
public void setGCDisabled(boolean disabled) {
gcDisabled = disabled;
}
/**
* Accessor for the disabling of interpretation of named ranges
*
* @return FALSE if named cells are interpreted, TRUE otherwise
*/
public boolean getNamesDisabled() {
return namesDisabled;
}
/**
* Disables the handling of names
*
* @param b TRUE to disable the names feature, FALSE otherwise
*/
public void setNamesDisabled(boolean b) {
namesDisabled = b;
}
/**
* Sets whether or not to rationalize the cell formats before
* writing out the sheet. The default value is true
*
* @param r the rationalization flag
*/
public void setRationalization(boolean r) {
rationalizationDisabled = !r;
}
/**
* Accessor to retrieve the rationalization flag
*
* @return TRUE if rationalization is off, FALSE if rationalization is on
*/
public boolean getRationalizationDisabled() {
return rationalizationDisabled;
}
/**
* Accessor to retrieve the merged cell checking flag
*
* @return TRUE if merged cell checking is off, FALSE if it is on
*/
public boolean getMergedCellCheckingDisabled() {
return mergedCellCheckingDisabled;
}
/**
* Accessor to set the merged cell checking
*
* @param b - TRUE to enable merged cell checking, FALSE otherwise
*/
public void setMergedCellChecking(boolean b) {
mergedCellCheckingDisabled = !b;
}
/**
* Sets whether or not to enable any property sets (such as macros)
* to be copied along with the workbook
* Leaving this feature enabled will result in the JXL process using
* more memory
*
* @param r the property sets flag
*/
public void setPropertySets(boolean r) {
propertySetsDisabled = !r;
}
/**
* Accessor to retrieve the property sets disabled flag
*
* @return TRUE if property sets are disabled, FALSE otherwise
*/
public boolean getPropertySetsDisabled() {
return propertySetsDisabled;
}
/**
* Accessor to set the suppress warnings flag. Due to the change
* in logging in version 2.4, this will now set the warning
* behaviour across the JVM (depending on the type of logger used)
*
* @param w the flag
*/
public void setSuppressWarnings(boolean w) {
logger.setSuppressWarnings(w);
}
/**
* Accessor for the formula adjust disabled
*
* @return TRUE if formulas are adjusted following row/column inserts/deletes
* FALSE otherwise
*/
public boolean getFormulaAdjust() {
return !formulaReferenceAdjustDisabled;
}
/**
* Setter for the formula adjust disabled property
*
* @param b TRUE to adjust formulas, FALSE otherwise
*/
public void setFormulaAdjust(boolean b) {
formulaReferenceAdjustDisabled = !b;
}
/**
* Returns the locale used by JExcelAPI to read the spreadsheet
*
* @return the locale
*/
public Locale getLocale() {
return locale;
}
/**
* Sets the locale used by JExcelApi to generate the spreadsheet.
* Setting this value has no effect on the language or region of
* the generated excel file
*
* @param l the locale
*/
public void setLocale(Locale l) {
locale = l;
}
/**
* Accessor for the character encoding
*
* @return the character encoding for this workbook
*/
public String getEncoding() {
return encoding;
}
/**
* Sets the encoding for this workbook
*
* @param enc the encoding
*/
public void setEncoding(String enc) {
encoding = enc;
}
/**
* Gets the function names. This is used by the formula parsing package
* in order to get the locale specific function names for this particular
* workbook
*
* @return the list of function names
*/
public FunctionNames getFunctionNames() {
if (functionNames == null) {
functionNames = (FunctionNames) localeFunctionNames.get(locale);
// have not previously accessed function names for this locale,
// so create a brand new one and add it to the list
if (functionNames == null) {
functionNames = new FunctionNames(locale);
localeFunctionNames.put(locale, functionNames);
}
}
return functionNames;
}
/**
* Accessor for the character set. This value is only used for reading
* and has no effect when writing out the spreadsheet
*
* @return the character set used by this spreadsheet
*/
public int getCharacterSet() {
return characterSet;
}
/**
* Sets the character set. This is only used when the spreadsheet is
* read, and has no effect when the spreadsheet is written
*
* @param cs the character set encoding value
*/
public void setCharacterSet(int cs) {
characterSet = cs;
}
/**
* Accessor for the ignore blanks flag
*
* @return TRUE if blank cells are being ignored, FALSE otherwise
*/
public boolean getIgnoreBlanks() {
return ignoreBlankCells;
}
/**
* Sets the ignore blanks flag
*
* @param ignoreBlanks TRUE to ignore blanks, FALSE to take them into account
*/
public void setIgnoreBlanks(boolean ignoreBlanks) {
ignoreBlankCells = ignoreBlanks;
}
/**
* Accessor for the ignore cell validation
*
* @return TRUE if cell validation is disabled
*/
public boolean getCellValidationDisabled() {
return cellValidationDisabled;
}
/**
* Sets the ignore cell validation flag
*
* @param cv TRUE to disable cell validation, FALSE to enable it
*/
public void setCellValidationDisabled(boolean cv) {
cellValidationDisabled = cv;
}
/**
* Returns the two character ISO 3166 mnemonic used by excel for user
* language displayto display
*
* @return the display language
*/
public String getExcelDisplayLanguage() {
return excelDisplayLanguage;
}
/**
* Sets the language in which the generated file will display
*
* @param code the two character ISO 3166 country code
*/
public void setExcelDisplayLanguage(String code) {
excelDisplayLanguage = code;
}
/**
* Returns the two character ISO 3166 mnemonic used by excel for
* its regional settings
*
* @return the regional settings
*/
public String getExcelRegionalSettings() {
return excelRegionalSettings;
}
/**
* Sets the regional settings for the generated excel file
*
* @param code the two character ISO 3166 country code
*/
public void setExcelRegionalSettings(String code) {
excelRegionalSettings = code;
}
/**
* Accessor for the autofilter disabled feature
*
* @return TRUE if autofilter is disabled, FALSE otherwise
*/
public boolean getAutoFilterDisabled() {
return autoFilterDisabled;
}
/**
* Sets the autofilter disabled
*
* @param disabled
*/
public void setAutoFilterDisabled(boolean disabled) {
autoFilterDisabled = disabled;
}
/**
* Accessor for the temporary file during write. If this is set, then
* when the workbook is written a temporary file will be used to store
* the interim binary data, otherwise it will take place in memory. Setting
* this flag involves an assessment of the trade-offs between memory usage
* and performance
*
* @return TRUE if a temporary is file is used during writing,
* FALSE otherwise
*/
public boolean getUseTemporaryFileDuringWrite() {
return useTemporaryFileDuringWrite;
}
/**
* Sets whether a temporary file is used during the generation of
* the workbook. If not set, the workbook will take place entirely in
* memory. Setting
* this flag involves an assessment of the trade-offs between memory usage
* and performance
*
* @return TRUE if a temporary is file is used during writing,
* FALSE otherwise
*/
public void setUseTemporaryFileDuringWrite(boolean temp) {
useTemporaryFileDuringWrite = temp;
}
/**
* Used in conjunction with the UseTemporaryFileDuringWrite setting to
* set the target directory for the temporary files. This value can
* be NULL, in which case the normal system default temporary directory
* is used instead
*
* @return the temporary directory used during write, or NULL if it is
* not set
*/
public File getTemporaryFileDuringWriteDirectory() {
return temporaryFileDuringWriteDirectory;
}
/**
* Used in conjunction with the UseTemporaryFileDuringWrite setting to
* set the target directory for the temporary files. If this is not set,
* the system default temporary directory is used.
* This has no effect unless the useTemporaryFileDuringWrite setting
* is TRUE
*
* @param dir the directory to which temporary files should be written
*/
public void setTemporaryFileDuringWriteDirectory(File dir) {
temporaryFileDuringWriteDirectory = dir;
}
/**
* When true then Refresh All should be done on all external data ranges and
* PivotTables when loading the workbook (the default is =0)
*
* @return the refreshAll value
*/
public boolean getRefreshAll() {
return refreshAll;
}
/**
* When true then Refresh All should be done on all external data ranges and
* PivotTables when loading the workbook (the default is =0)
*
* @param refreshAll the refreshAll to set
*/
public void setRefreshAll(boolean refreshAll) {
this.refreshAll = refreshAll;
}
/**
* Workbook Is a Template
*
* @return the template
*/
public boolean getTemplate() {
return template;
}
/**
* Workbook Is a Template
*
* @param template the template to set
*/
public void setTemplate(boolean template) {
this.template = template;
}
/**
* Has this file been written by excel 2000?
*
* @return the excel9file
*/
public boolean getExcel9File() {
return excel9file;
}
/**
* @param excel9file the excel9file to set
*/
public void setExcel9File(boolean excel9file) {
this.excel9file = excel9file;
}
/**
* @return the windowprotected
*/
public boolean getWindowProtected() {
return windowProtected;
}
/**
* @param windowprotected the windowprotected to set
*/
public void setWindowProtected(boolean windowprotected) {
this.windowProtected = windowProtected;
}
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab
* <p>
* Possible values are:
* HIDEOBJ_HIDE_ALL, HIDEOBJ_SHOW_ALL and HIDEOBJ_SHOW_PLACEHOLDERS
*
* @return the hideobj
*/
public int getHideobj() {
return hideobj;
}
/**
* The HIDEOBJ record stores options selected in the Options dialog,View tab
* <p>
* Possible values are:
* HIDEOBJ_HIDE_ALL, HIDEOBJ_SHOW_ALL and HIDEOBJ_SHOW_PLACEHOLDERS
*
* @param hideobj the hideobj to set
*/
public void setHideobj(int hideobj) {
this.hideobj = hideobj;
}
/**
* @return the writeAccess
*/
public String getWriteAccess() {
return writeAccess;
}
/**
* @param writeAccess the writeAccess to set
*/
public void setWriteAccess(String writeAccess) {
this.writeAccess = writeAccess;
}
}

@ -0,0 +1,65 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.IOException;
import jxl.write.biff.File;
/**
* Information for autofiltering
*/
public class AutoFilter {
private final FilterModeRecord filterMode;
private final AutoFilterInfoRecord autoFilterInfo;
private AutoFilterRecord autoFilter;
/**
* Constructor
*/
public AutoFilter(FilterModeRecord fmr,
AutoFilterInfoRecord afir) {
filterMode = fmr;
autoFilterInfo = afir;
}
public void add(AutoFilterRecord af) {
autoFilter = af; // make this into a list sometime
}
/**
* Writes out the data validation
*
* @param outputFile the output file
* @throws IOException
*/
public void write(File outputFile) throws IOException {
if (filterMode != null) {
outputFile.write(filterMode);
}
if (autoFilterInfo != null) {
outputFile.write(autoFilterInfo);
}
if (autoFilter != null) {
outputFile.write(autoFilter);
}
}
}

@ -0,0 +1,56 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Range information for conditional formatting
*/
public class AutoFilterInfoRecord extends WritableRecordData {
// The logger
private static final Logger logger = Logger.getLogger(AutoFilterInfoRecord.class);
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*/
public AutoFilterInfoRecord(Record t) {
super(t);
data = getRecord().getData();
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
return data;
}
}

@ -0,0 +1,56 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Range information for conditional formatting
*/
public class AutoFilterRecord extends WritableRecordData {
// The logger
private static final Logger logger = Logger.getLogger(AutoFilterRecord.class);
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*/
public AutoFilterRecord(Record t) {
super(t);
data = getRecord().getData();
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
return data;
}
}

@ -0,0 +1,489 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.util.Collection;
import jxl.CellReferenceHelper;
import jxl.Range;
import jxl.biff.drawing.ComboBox;
import jxl.biff.drawing.Comment;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.CellValue;
/**
* Container for any additional cell features
*/
public class BaseCellFeatures {
public static final ValidationCondition BETWEEN =
new ValidationCondition(DVParser.BETWEEN);
public static final ValidationCondition NOT_BETWEEN =
new ValidationCondition(DVParser.NOT_BETWEEN);
public static final ValidationCondition EQUAL =
new ValidationCondition(DVParser.EQUAL);
public static final ValidationCondition NOT_EQUAL =
new ValidationCondition(DVParser.NOT_EQUAL);
public static final ValidationCondition GREATER_THAN =
new ValidationCondition(DVParser.GREATER_THAN);
public static final ValidationCondition LESS_THAN =
new ValidationCondition(DVParser.LESS_THAN);
public static final ValidationCondition GREATER_EQUAL =
new ValidationCondition(DVParser.GREATER_EQUAL);
public static final ValidationCondition LESS_EQUAL =
new ValidationCondition(DVParser.LESS_EQUAL);
// Constants
private final static double defaultCommentWidth = 3;
private final static double defaultCommentHeight = 4;
/**
* The logger
*/
public static Logger logger = Logger.getLogger(BaseCellFeatures.class);
/**
* The comment
*/
private String comment;
/**
* The comment width in cells
*/
private double commentWidth;
/**
* The comment height in cells
*/
private double commentHeight;
/**
* A handle to the drawing object
*/
private Comment commentDrawing;
/**
* A handle to the combo box object
*/
private ComboBox comboBox;
/**
* The data validation settings
*/
private DataValiditySettingsRecord validationSettings;
/**
* The DV Parser used to contain the validation details
*/
private DVParser dvParser;
/**
* Indicates whether a drop down is required
*/
private boolean dropDown;
/**
* Indicates whether this cell features has data validation
*/
private boolean dataValidation;
/**
* The cell to which this is attached, and which may need to be notified
*/
private CellValue writableCell;
/**
* Constructor
*/
protected BaseCellFeatures() {
}
/**
* Copy constructor
*
* @param the cell to copy
*/
public BaseCellFeatures(BaseCellFeatures cf) {
// The comment stuff
comment = cf.comment;
commentWidth = cf.commentWidth;
commentHeight = cf.commentHeight;
// The data validation stuff.
dropDown = cf.dropDown;
dataValidation = cf.dataValidation;
validationSettings = cf.validationSettings; // ?
if (cf.dvParser != null) {
dvParser = new DVParser(cf.dvParser);
}
}
/**
* Accessor for the cell comment
*/
protected String getComment() {
return comment;
}
/**
* Sets the cell comment
*
* @param s the comment
*/
public void setComment(String s) {
setComment(s, defaultCommentWidth, defaultCommentHeight);
}
/**
* Accessor for the comment width
*/
public double getCommentWidth() {
return commentWidth;
}
/**
* Accessor for the comment height
*/
public double getCommentHeight() {
return commentHeight;
}
/**
* Called by the cell when the features are added
*
* @param wc the writable cell
*/
public final void setWritableCell(CellValue wc) {
writableCell = wc;
}
/**
* Internal method to set the cell comment. Used when reading
*/
public void setReadComment(String s, double w, double h) {
comment = s;
commentWidth = w;
commentHeight = h;
}
/**
* Internal method to set the data validation. Used when reading
*/
public void setValidationSettings(DataValiditySettingsRecord dvsr) {
Assert.verify(dvsr != null);
validationSettings = dvsr;
dataValidation = true;
}
/**
* Sets the cell comment
*
* @param s the comment
* @param height the height of the comment box in cells
* @param width the width of the comment box in cells
*/
public void setComment(String s, double width, double height) {
comment = s;
commentWidth = width;
commentHeight = height;
if (commentDrawing != null) {
commentDrawing.setCommentText(s);
commentDrawing.setWidth(width);
commentDrawing.setWidth(height);
// commentDrawing is set up when trying to modify a copied cell
}
}
/**
* Removes the cell comment, if present
*/
public void removeComment() {
// Set the comment string to be empty
comment = null;
// Remove the drawing from the drawing group
if (commentDrawing != null) {
// do not call DrawingGroup.remove() because comments are not present
// on the Workbook DrawingGroup record
writableCell.removeComment(commentDrawing);
commentDrawing = null;
}
}
/**
* Public function which removes any data validation, if present
*/
public void removeDataValidation() {
if (!dataValidation) {
return;
}
// If the data validation is shared, then generate a warning
DVParser dvp = getDVParser();
if (dvp.extendedCellsValidation()) {
logger.warn("Cannot remove data validation from " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of the shared reference " +
CellReferenceHelper.getCellReference(dvp.getFirstColumn(),
dvp.getFirstRow()) +
"-" +
CellReferenceHelper.getCellReference(dvp.getLastColumn(),
dvp.getLastRow()));
return;
}
// Remove the validation from the WritableSheet object if present
writableCell.removeDataValidation();
clearValidationSettings();
}
/**
* Internal function which removes any data validation, including
* shared ones, if present. This is called from WritableSheetImpl
* in response to a call to removeDataValidation
*/
public void removeSharedDataValidation() {
if (!dataValidation) {
return;
}
// Remove the validation from the WritableSheet object if present
writableCell.removeDataValidation();
clearValidationSettings();
}
/**
* Accessor for the comment drawing
*/
public final Comment getCommentDrawing() {
return commentDrawing;
}
/**
* Sets the comment drawing object
*/
public final void setCommentDrawing(Comment c) {
commentDrawing = c;
}
/**
* Gets the data validation list as a formula. Used only when reading
*
* @return the validation formula as a list
*/
public String getDataValidationList() {
if (validationSettings == null) {
return null;
}
return validationSettings.getValidationFormula();
}
/**
* The list of items to validate for this cell. For each object in the
* collection, the toString() method will be called and the data entered
* will be validated against that string
*
* @param c the list of valid values
*/
public void setDataValidationList(Collection c) {
if (dataValidation && getDVParser().extendedCellsValidation()) {
logger.warn("Cannot set data validation on " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of a shared data validation");
return;
}
clearValidationSettings();
dvParser = new DVParser(c);
dropDown = true;
dataValidation = true;
}
/**
* The list of items to validate for this cell in the form of a cell range.
*
* @param c the list of valid values
*/
public void setDataValidationRange(int col1, int r1, int col2, int r2) {
if (dataValidation && getDVParser().extendedCellsValidation()) {
logger.warn("Cannot set data validation on " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of a shared data validation");
return;
}
clearValidationSettings();
dvParser = new DVParser(col1, r1, col2, r2);
dropDown = true;
dataValidation = true;
}
/**
* Sets the data validation based upon a named range
*/
public void setDataValidationRange(String namedRange) {
if (dataValidation && getDVParser().extendedCellsValidation()) {
logger.warn("Cannot set data validation on " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of a shared data validation");
return;
}
clearValidationSettings();
dvParser = new DVParser(namedRange);
dropDown = true;
dataValidation = true;
}
/**
* Sets the data validation based upon a numerical condition
*/
public void setNumberValidation(double val, ValidationCondition c) {
if (dataValidation && getDVParser().extendedCellsValidation()) {
logger.warn("Cannot set data validation on " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of a shared data validation");
return;
}
clearValidationSettings();
dvParser = new DVParser(val, Double.NaN, c.getCondition());
dropDown = false;
dataValidation = true;
}
public void setNumberValidation(double val1, double val2,
ValidationCondition c) {
if (dataValidation && getDVParser().extendedCellsValidation()) {
logger.warn("Cannot set data validation on " +
CellReferenceHelper.getCellReference(writableCell) +
" as it is part of a shared data validation");
return;
}
clearValidationSettings();
dvParser = new DVParser(val1, val2, c.getCondition());
dropDown = false;
dataValidation = true;
}
/**
* Accessor for the data validation
*
* @return TRUE if this has a data validation associated with it,
* FALSE otherwise
*/
public boolean hasDataValidation() {
return dataValidation;
}
/**
* Clears out any existing validation settings
*/
private void clearValidationSettings() {
validationSettings = null;
dvParser = null;
dropDown = false;
comboBox = null;
dataValidation = false;
}
/**
* Accessor for whether a drop down is required
*
* @return TRUE if this requires a drop down, FALSE otherwise
*/
public boolean hasDropDown() {
return dropDown;
}
/**
* Sets the combo box drawing object for list validations
*
* @param cb the combo box
*/
public void setComboBox(ComboBox cb) {
comboBox = cb;
}
/**
* Gets the dv parser
*/
public DVParser getDVParser() {
// straightforward - this was created as a writable cell
if (dvParser != null) {
return dvParser;
}
// this was copied from a readable cell, and then copied again
if (validationSettings != null) {
dvParser = new DVParser(validationSettings.getDVParser());
return dvParser;
}
return null; // keep the compiler happy
}
/**
* Use the same data validation logic as the specified cell features
*
* @param cf the data validation to reuse
*/
public void shareDataValidation(BaseCellFeatures source) {
if (dataValidation) {
logger.warn("Attempting to share a data validation on cell " +
CellReferenceHelper.getCellReference(writableCell) +
" which already has a data validation");
return;
}
clearValidationSettings();
dvParser = source.getDVParser();
validationSettings = null;
dataValidation = true;
dropDown = source.dropDown;
comboBox = source.comboBox;
}
/**
* Gets the range of cells to which the data validation applies. If the
* validation applies to just this cell, this will be reflected in the
* returned range
*
* @return the range to which the same validation extends, or NULL if this
* cell doesn't have a validation
*/
public Range getSharedDataValidationRange() {
if (!dataValidation) {
return null;
}
DVParser dvp = getDVParser();
return new SheetRangeImpl(writableCell.getSheet(),
dvp.getFirstColumn(),
dvp.getFirstRow(),
dvp.getLastColumn(),
dvp.getLastRow());
}
// Validation conditions
protected static class ValidationCondition {
private static ValidationCondition[] types = new ValidationCondition[0];
private final DVParser.Condition condition;
ValidationCondition(DVParser.Condition c) {
condition = c;
ValidationCondition[] oldtypes = types;
types = new ValidationCondition[oldtypes.length + 1];
System.arraycopy(oldtypes, 0, types, 0, oldtypes.length);
types[oldtypes.length] = this;
}
public DVParser.Condition getCondition() {
return condition;
}
}
}

@ -0,0 +1,349 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Assert;
import jxl.common.Logger;
/**
* Contains the common data for a compound file
*/
public abstract class BaseCompoundFile {
/**
* The standard property sets
*/
public final static String ROOT_ENTRY_NAME = "Root Entry";
public final static String WORKBOOK_NAME = "Workbook";
public final static String SUMMARY_INFORMATION_NAME =
"\u0005SummaryInformation";
public final static String DOCUMENT_SUMMARY_INFORMATION_NAME =
"\u0005DocumentSummaryInformation";
public final static String COMP_OBJ_NAME =
"\u0001CompObj";
public final static String[] STANDARD_PROPERTY_SETS =
new String[]{ROOT_ENTRY_NAME, WORKBOOK_NAME,
SUMMARY_INFORMATION_NAME,
DOCUMENT_SUMMARY_INFORMATION_NAME};
/**
* Property storage types
*/
public final static int NONE_PS_TYPE = 0;
public final static int DIRECTORY_PS_TYPE = 1;
public final static int FILE_PS_TYPE = 2;
public final static int ROOT_ENTRY_PS_TYPE = 5;
/**
* The identifier at the beginning of every OLE file
*/
protected static final byte[] IDENTIFIER = new byte[]
{(byte) 0xd0,
(byte) 0xcf,
(byte) 0x11,
(byte) 0xe0,
(byte) 0xa1,
(byte) 0xb1,
(byte) 0x1a,
(byte) 0xe1};
/**
*
*/
protected static final int NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
/**
*
*/
protected static final int SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
// property storage offsets
/**
*
*/
protected static final int NUM_SMALL_BLOCK_DEPOT_BLOCKS_POS = 0x40;
/**
*
*/
protected static final int ROOT_START_BLOCK_POS = 0x30;
/**
*
*/
protected static final int BIG_BLOCK_SIZE = 0x200;
/**
*
*/
protected static final int SMALL_BLOCK_SIZE = 0x40;
/**
*
*/
protected static final int EXTENSION_BLOCK_POS = 0x44;
/**
*
*/
protected static final int NUM_EXTENSION_BLOCK_POS = 0x48;
/**
*
*/
protected static final int PROPERTY_STORAGE_BLOCK_SIZE = 0x80;
/**
*
*/
protected static final int BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;
/**
*
*/
protected static final int SMALL_BLOCK_THRESHOLD = 0x1000;
/**
*
*/
private static final int SIZE_OF_NAME_POS = 0x40;
/**
*
*/
private static final int TYPE_POS = 0x42;
/**
*
*/
private static final int COLOUR_POS = 0x43;
/**
*
*/
private static final int PREVIOUS_POS = 0x44;
/**
*
*/
private static final int NEXT_POS = 0x48;
/**
*
*/
private static final int CHILD_POS = 0x4c;
/**
*
*/
private static final int START_BLOCK_POS = 0x74;
/**
*
*/
private static final int SIZE_POS = 0x78;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(BaseCompoundFile.class);
/**
* Constructor
*/
protected BaseCompoundFile() {
}
/**
* Inner class to represent the property storage sets. Access is public
* to allow access from the PropertySetsReader demo utility
*/
public class PropertyStorage {
/**
* The name of this property set
*/
public String name;
/**
* The type of the property set
*/
public int type;
/**
* The colour of the property set
*/
public int colour;
/**
* The block number in the stream which this property sets starts at
*/
public int startBlock;
/**
* The size, in bytes, of this property set
*/
public int size;
/**
* The previous property set
*/
public int previous;
/**
* The next property set
*/
public int next;
/**
* The child for this property set
*/
public int child;
/**
* The data that created this set
*/
public byte[] data;
/**
* Constructs a property set
*
* @param d the bytes
*/
public PropertyStorage(byte[] d) {
data = d;
int nameSize = IntegerHelper.getInt(data[SIZE_OF_NAME_POS],
data[SIZE_OF_NAME_POS + 1]);
if (nameSize > SIZE_OF_NAME_POS) {
logger.warn("property set name exceeds max length - truncating");
nameSize = SIZE_OF_NAME_POS;
}
type = data[TYPE_POS];
colour = data[COLOUR_POS];
startBlock = IntegerHelper.getInt
(data[START_BLOCK_POS],
data[START_BLOCK_POS + 1],
data[START_BLOCK_POS + 2],
data[START_BLOCK_POS + 3]);
size = IntegerHelper.getInt
(data[SIZE_POS],
data[SIZE_POS + 1],
data[SIZE_POS + 2],
data[SIZE_POS + 3]);
previous = IntegerHelper.getInt
(data[PREVIOUS_POS],
data[PREVIOUS_POS + 1],
data[PREVIOUS_POS + 2],
data[PREVIOUS_POS + 3]);
next = IntegerHelper.getInt
(data[NEXT_POS],
data[NEXT_POS + 1],
data[NEXT_POS + 2],
data[NEXT_POS + 3]);
child = IntegerHelper.getInt
(data[CHILD_POS],
data[CHILD_POS + 1],
data[CHILD_POS + 2],
data[CHILD_POS + 3]);
int chars = 0;
if (nameSize > 2) {
chars = (nameSize - 1) / 2;
}
StringBuffer n = new StringBuffer();
for (int i = 0; i < chars; i++) {
n.append((char) data[i * 2]);
}
name = n.toString();
}
/**
* Constructs an empty property set. Used when writing the file
*
* @param name the property storage name
*/
public PropertyStorage(String name) {
data = new byte[PROPERTY_STORAGE_BLOCK_SIZE];
Assert.verify(name.length() < 32);
IntegerHelper.getTwoBytes((name.length() + 1) * 2,
data,
SIZE_OF_NAME_POS);
// add one to the name length to allow for the null character at
// the end
for (int i = 0; i < name.length(); i++) {
data[i * 2] = (byte) name.charAt(i);
}
}
/**
* Sets the type
*
* @param t the type
*/
public void setType(int t) {
type = t;
data[TYPE_POS] = (byte) t;
}
/**
* Sets the number of the start block
*
* @param sb the number of the start block
*/
public void setStartBlock(int sb) {
startBlock = sb;
IntegerHelper.getFourBytes(sb, data, START_BLOCK_POS);
}
/**
* Sets the size of the file
*
* @param s the size
*/
public void setSize(int s) {
size = s;
IntegerHelper.getFourBytes(s, data, SIZE_POS);
}
/**
* Sets the previous block
*
* @param prev the previous block
*/
public void setPrevious(int prev) {
previous = prev;
IntegerHelper.getFourBytes(prev, data, PREVIOUS_POS);
}
/**
* Sets the next block
*
* @param nxt the next block
*/
public void setNext(int nxt) {
next = nxt;
IntegerHelper.getFourBytes(next, data, NEXT_POS);
}
/**
* Sets the child
*
* @param dir the child
*/
public void setChild(int dir) {
child = dir;
IntegerHelper.getFourBytes(child, data, CHILD_POS);
}
/**
* Sets the colour
*
* @param col colour
*/
public void setColour(int col) {
colour = col == 0 ? 0 : 1;
data[COLOUR_POS] = (byte) colour;
}
}
}

@ -0,0 +1,166 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.format.Format;
/**
* The excel string for the various built in formats. Used to present
* the cell format information back to the user
* <p>
* The difference between this class and the various format object contained
* in the jxl.write package is that this object contains the Excel strings,
* not their java equivalents
*/
final class BuiltInFormat implements Format, DisplayFormat {
/**
* The list of built in formats
*/
public static BuiltInFormat[] builtIns = new BuiltInFormat[0x32];
// Populate the built ins
static {
builtIns[0x0] = new BuiltInFormat("", 0);
builtIns[0x1] = new BuiltInFormat("0", 1);
builtIns[0x2] = new BuiltInFormat("0.00", 2);
builtIns[0x3] = new BuiltInFormat("#,##0", 3);
builtIns[0x4] = new BuiltInFormat("#,##0.00", 4);
builtIns[0x5] = new BuiltInFormat("($#,##0_);($#,##0)", 5);
builtIns[0x6] = new BuiltInFormat("($#,##0_);[Red]($#,##0)", 6);
builtIns[0x7] = new BuiltInFormat("($#,##0_);[Red]($#,##0)", 7);
builtIns[0x8] = new BuiltInFormat("($#,##0.00_);[Red]($#,##0.00)", 8);
builtIns[0x9] = new BuiltInFormat("0%", 9);
builtIns[0xa] = new BuiltInFormat("0.00%", 10);
builtIns[0xb] = new BuiltInFormat("0.00E+00", 11);
builtIns[0xc] = new BuiltInFormat("# ?/?", 12);
builtIns[0xd] = new BuiltInFormat("# ??/??", 13);
builtIns[0xe] = new BuiltInFormat("dd/mm/yyyy", 14);
builtIns[0xf] = new BuiltInFormat("d-mmm-yy", 15);
builtIns[0x10] = new BuiltInFormat("d-mmm", 16);
builtIns[0x11] = new BuiltInFormat("mmm-yy", 17);
builtIns[0x12] = new BuiltInFormat("h:mm AM/PM", 18);
builtIns[0x13] = new BuiltInFormat("h:mm:ss AM/PM", 19);
builtIns[0x14] = new BuiltInFormat("h:mm", 20);
builtIns[0x15] = new BuiltInFormat("h:mm:ss", 21);
builtIns[0x16] = new BuiltInFormat("m/d/yy h:mm", 22);
builtIns[0x25] = new BuiltInFormat("(#,##0_);(#,##0)", 0x25);
builtIns[0x26] = new BuiltInFormat("(#,##0_);[Red](#,##0)", 0x26);
builtIns[0x27] = new BuiltInFormat("(#,##0.00_);(#,##0.00)", 0x27);
builtIns[0x28] = new BuiltInFormat("(#,##0.00_);[Red](#,##0.00)", 0x28);
builtIns[0x29] = new BuiltInFormat
("_(*#,##0_);_(*(#,##0);_(*\"-\"_);(@_)", 0x29);
builtIns[0x2a] = new BuiltInFormat
("_($*#,##0_);_($*(#,##0);_($*\"-\"_);(@_)", 0x2a);
builtIns[0x2b] = new BuiltInFormat
("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);(@_)", 0x2b);
builtIns[0x2c] = new BuiltInFormat
("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);(@_)", 0x2c);
builtIns[0x2d] = new BuiltInFormat("mm:ss", 0x2d);
builtIns[0x2e] = new BuiltInFormat("[h]mm:ss", 0x2e);
builtIns[0x2f] = new BuiltInFormat("mm:ss.0", 0x2f);
builtIns[0x30] = new BuiltInFormat("##0.0E+0", 0x30);
builtIns[0x31] = new BuiltInFormat("@", 0x31);
}
/**
* The excel format string
*/
private final String formatString;
/**
* The index
*/
private final int formatIndex;
/**
* Constructor
*
* @param s the format string
* @param i the format index
*/
private BuiltInFormat(String s, int i) {
formatIndex = i;
formatString = s;
}
/**
* Accesses the excel format string which is applied to the cell
* Note that this is the string that excel uses, and not the java
* equivalent
*
* @return the cell format string
*/
public String getFormatString() {
return formatString;
}
/**
* Accessor for the index style of this format
*
* @return the index for this format
*/
public int getFormatIndex() {
return formatIndex;
}
/**
* Accessor to see whether this format has been initialized
*
* @return TRUE if initialized, FALSE otherwise
*/
public boolean isInitialized() {
return true;
}
/**
* Initializes this format with the specified index number
*
* @param pos the position of this format record in the workbook
*/
public void initialize(int pos) {
}
/**
* Accessor to determine whether or not this format is built in
*
* @return TRUE if this format is a built in format, FALSE otherwise
*/
public boolean isBuiltIn() {
return true;
}
/**
* Equals method
*
* @return TRUE if the two built in formats are equal, FALSE otherwise
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof BuiltInFormat)) {
return false;
}
BuiltInFormat bif = (BuiltInFormat) o;
return (formatIndex == bif.formatIndex);
}
}

@ -0,0 +1,110 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Enumeration of built in names
*/
public class BuiltInName {
// The list of built in names
public static final BuiltInName CONSOLIDATE_AREA =
new BuiltInName("Consolidate_Area", 0x0);
public static final BuiltInName AUTO_OPEN =
new BuiltInName("Auto_Open", 0x1);
public static final BuiltInName AUTO_CLOSE =
new BuiltInName("Auto_Open", 0x2);
public static final BuiltInName EXTRACT =
new BuiltInName("Extract", 0x3);
public static final BuiltInName DATABASE =
new BuiltInName("Database", 0x4);
public static final BuiltInName CRITERIA =
new BuiltInName("Criteria", 0x5);
public static final BuiltInName PRINT_AREA =
new BuiltInName("Print_Area", 0x6);
public static final BuiltInName PRINT_TITLES =
new BuiltInName("Print_Titles", 0x7);
public static final BuiltInName RECORDER =
new BuiltInName("Recorder", 0x8);
public static final BuiltInName DATA_FORM =
new BuiltInName("Data_Form", 0x9);
public static final BuiltInName AUTO_ACTIVATE =
new BuiltInName("Auto_Activate", 0xa);
public static final BuiltInName AUTO_DEACTIVATE =
new BuiltInName("Auto_Deactivate", 0xb);
public static final BuiltInName SHEET_TITLE =
new BuiltInName("Sheet_Title", 0xb);
public static final BuiltInName FILTER_DATABASE =
new BuiltInName("_FilterDatabase", 0xd);
/**
* The list of name
*/
private static BuiltInName[] builtInNames = new BuiltInName[0];
/**
* The name
*/
private final String name;
/**
* The value
*/
private final int value;
/**
* Constructor
*/
private BuiltInName(String n, int v) {
name = n;
value = v;
BuiltInName[] oldnames = builtInNames;
builtInNames = new BuiltInName[oldnames.length + 1];
System.arraycopy(oldnames, 0, builtInNames, 0, oldnames.length);
builtInNames[oldnames.length] = this;
}
/**
* Gets the built in name for the value
*/
public static BuiltInName getBuiltInName(int val) {
BuiltInName ret = FILTER_DATABASE;
for (int i = 0; i < builtInNames.length; i++) {
if (builtInNames[i].getValue() == val) {
ret = builtInNames[i];
}
}
return ret;
}
/**
* Accessor for the name
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Accessor for the value
*
* @return the value
*/
public int getValue() {
return value;
}
}

@ -0,0 +1,70 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Represents a built in, rather than a user defined, style.
* This class is used by the FormattingRecords class when writing out the hard*
* coded styles
*/
class BuiltInStyle extends WritableRecordData {
/**
* The XF index of this style
*/
private final int xfIndex;
/**
* The reference number of this style
*/
private final int styleNumber;
/**
* Constructor
*
* @param xfind the xf index of this style
* @param sn the style number of this style
*/
public BuiltInStyle(int xfind, int sn) {
super(Type.STYLE);
xfIndex = xfind;
styleNumber = sn;
}
/**
* Abstract method implementation to get the raw byte data ready to write out
*
* @return The byte data
*/
public byte[] getData() {
byte[] data = new byte[4];
IntegerHelper.getTwoBytes(xfIndex, data, 0);
// Set the built in bit
data[1] |= 0x80;
data[2] = (byte) styleNumber;
// Set the outline level
data[3] = (byte) 0xff;
return data;
}
}

@ -0,0 +1,106 @@
/*********************************************************************
*
* Copyright (C) 2005 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* A growable array of bytes
*/
public class ByteArray {
// The default grow size
private final static int defaultGrowSize = 1024;
/**
* The array grow size
*/
private final int growSize;
/**
* The current array
*/
private byte[] bytes;
/**
* The current position
*/
private int pos;
/**
* Constructor
*/
public ByteArray() {
this(defaultGrowSize);
}
/**
* Constructor
*
* @param gs
*/
public ByteArray(int gs) {
growSize = gs;
bytes = new byte[defaultGrowSize];
pos = 0;
}
/**
* Adds a byte onto the array
*
* @param b the byte
*/
public void add(byte b) {
checkSize(1);
bytes[pos] = b;
pos++;
}
/**
* Adds an array of bytes onto the array
*
* @param b the array of bytes
*/
public void add(byte[] b) {
checkSize(b.length);
System.arraycopy(b, 0, bytes, pos, b.length);
pos += b.length;
}
/**
* Gets the complete array
*
* @return the array
*/
public byte[] getBytes() {
byte[] returnArray = new byte[pos];
System.arraycopy(bytes, 0, returnArray, 0, pos);
return returnArray;
}
/**
* Checks to see if there is sufficient space left on the array. If not,
* then it grows the array
*
* @param sz the amount of bytes to add
*/
private void checkSize(int sz) {
while (pos + sz >= bytes.length) {
// Grow the array
byte[] newArray = new byte[bytes.length + growSize];
System.arraycopy(bytes, 0, newArray, 0, pos);
bytes = newArray;
}
}
}

@ -0,0 +1,33 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Interface which provides a method for transferring chunks of binary
* data from one Excel file (read in) to another (written out)
*/
public interface ByteData {
/**
* Used when writing out records
*
* @return the full data to be included in the final compound file
*/
byte[] getBytes();
}

@ -0,0 +1,196 @@
/**********************************************************************
*
* Copyright (C) 2008 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jxl.Cell;
import jxl.CellType;
import jxl.LabelCell;
import jxl.Sheet;
/**
* Refactorisation to provide more sophisticated find cell by contents
* functionality
*/
public class CellFinder {
private final Sheet sheet;
public CellFinder(Sheet s) {
sheet = s;
}
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param contents the string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the range
* @param lastCol the last column within the range
* @param lastRow the last row within the range
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
public Cell findCell(String contents,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse) {
Cell cell = null;
boolean found = false;
int numCols = lastCol - firstCol;
int numRows = lastRow - firstRow;
int row1 = reverse ? lastRow : firstRow;
int row2 = reverse ? firstRow : lastRow;
int col1 = reverse ? lastCol : firstCol;
int col2 = reverse ? firstCol : lastCol;
int inc = reverse ? -1 : 1;
for (int i = 0; i <= numCols && found == false; i++) {
for (int j = 0; j <= numRows && found == false; j++) {
int curCol = col1 + i * inc;
int curRow = row1 + j * inc;
if (curCol < sheet.getColumns() && curRow < sheet.getRows()) {
Cell c = sheet.getCell(curCol, curRow);
if (c.getType() != CellType.EMPTY) {
if (c.getContents().equals(contents)) {
cell = c;
found = true;
}
}
}
}
}
return cell;
}
/**
* Finds a cell within a given range of cells
*
* @param contents the string to match
* @return the Cell whose contents match the parameter, null if not found
*/
public Cell findCell(String contents) {
Cell cell = null;
boolean found = false;
for (int i = 0; i < sheet.getRows() && found == false; i++) {
Cell[] row = sheet.getRow(i);
for (int j = 0; j < row.length && found == false; j++) {
if (row[j].getContents().equals(contents)) {
cell = row[j];
found = true;
}
}
}
return cell;
}
/**
* Gets the cell whose contents match the regular expressionstring passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform
*
* @param pattern the regular expression string to match
* @param firstCol the first column within the range
* @param firstRow the first row of the range
* @param lastCol the last column within the range
* @param lastRow the last row within the range
* @param reverse indicates whether to perform a reverse search or not
* @return the Cell whose contents match the parameter, null if not found
*/
public Cell findCell(Pattern pattern,
int firstCol,
int firstRow,
int lastCol,
int lastRow,
boolean reverse) {
Cell cell = null;
boolean found = false;
int numCols = lastCol - firstCol;
int numRows = lastRow - firstRow;
int row1 = reverse ? lastRow : firstRow;
int row2 = reverse ? firstRow : lastRow;
int col1 = reverse ? lastCol : firstCol;
int col2 = reverse ? firstCol : lastCol;
int inc = reverse ? -1 : 1;
for (int i = 0; i <= numCols && found == false; i++) {
for (int j = 0; j <= numRows && found == false; j++) {
int curCol = col1 + i * inc;
int curRow = row1 + j * inc;
if (curCol < sheet.getColumns() && curRow < sheet.getRows()) {
Cell c = sheet.getCell(curCol, curRow);
if (c.getType() != CellType.EMPTY) {
Matcher m = pattern.matcher(c.getContents());
if (m.matches()) {
cell = c;
found = true;
}
}
}
}
}
return cell;
}
/**
* Gets the cell whose contents match the string passed in.
* If no match is found, then null is returned. The search is performed
* on a row by row basis, so the lower the row number, the more
* efficiently the algorithm will perform. This method differs
* from the findCell methods in that only cells with labels are
* queried - all numerical cells are ignored. This should therefore
* improve performance.
*
* @param contents the string to match
* @return the Cell whose contents match the paramter, null if not found
*/
public LabelCell findLabelCell(String contents) {
LabelCell cell = null;
boolean found = false;
for (int i = 0; i < sheet.getRows() && !found; i++) {
Cell[] row = sheet.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;
}
}

@ -0,0 +1,313 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.biff.formula.ExternalSheet;
import jxl.common.Logger;
/**
* A helper to transform between excel cell references and
* sheet:column:row notation
* Because this function will be called when generating a string
* representation of a formula, the cell reference will merely
* be appened to the string buffer instead of returning a full
* blooded string, for performance reasons
*/
public final class CellReferenceHelper {
/**
* The character which indicates whether a reference is fixed
*/
private static final char fixedInd = '$';
/**
* The character which indicates the sheet name terminator
*/
private static final char sheetInd = '!';
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(CellReferenceHelper.class);
/**
* Constructor to prevent instantiation
*/
private CellReferenceHelper() {
}
/**
* Gets the cell reference
*
* @param column
* @param row
* @param buf
*/
public static void getCellReference(int column, int row, StringBuffer buf) {
// Put the column letter into the buffer
getColumnReference(column, buf);
// Add the row into the buffer
buf.append(row + 1);
}
/**
* Overloaded method which prepends $ for absolute reference
*
* @param column
* @param colabs TRUE if the column reference is absolute
* @param row
* @param rowabs TRUE if the row reference is absolute
* @param buf
*/
public static void getCellReference(int column, boolean colabs,
int row, boolean rowabs,
StringBuffer buf) {
if (colabs) {
buf.append(fixedInd);
}
// Put the column letter into the buffer
getColumnReference(column, buf);
if (rowabs) {
buf.append(fixedInd);
}
// Add the row into the buffer
buf.append(row + 1);
}
/**
* Gets the column letter corresponding to the 0-based column number
*
* @param column the column number
* @return the letter for that column number
*/
public static String getColumnReference(int column) {
StringBuffer buf = new StringBuffer();
getColumnReference(column, buf);
return buf.toString();
}
/**
* Gets the column letter corresponding to the 0-based column number
*
* @param column the column number
* @param buf the string buffer in which to write the column letter
*/
public static void getColumnReference(int column, StringBuffer buf) {
int v = column / 26;
int r = column % 26;
StringBuffer tmp = new StringBuffer();
while (v != 0) {
char col = (char) ('A' + r);
tmp.append(col);
r = v % 26 - 1; // subtract one because only rows >26 preceded by A
v = v / 26;
}
char col = (char) ('A' + r);
tmp.append(col);
// Insert into the proper string buffer in reverse order
for (int i = tmp.length() - 1; i >= 0; i--) {
buf.append(tmp.charAt(i));
}
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet
* @param column
* @param row
* @param workbook
* @param buf
*/
public static void getCellReference
(int sheet, int column, int row,
ExternalSheet workbook, StringBuffer buf) {
// Quotes are added by the WorkbookParser
String name = workbook.getExternalSheetName(sheet);
buf.append(StringHelper.replace(name, "'", "''"));
buf.append(sheetInd);
getCellReference(column, row, buf);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet
* @param column
* @param colabs TRUE if the column is an absolute reference
* @param row
* @param rowabs TRUE if the row is an absolute reference
* @param workbook
* @param buf
*/
public static void getCellReference
(int sheet, int column, boolean colabs,
int row, boolean rowabs,
ExternalSheet workbook, StringBuffer buf) {
// WorkbookParser now appends quotes and escapes apostrophes
String name = workbook.getExternalSheetName(sheet);
buf.append(name);
buf.append(sheetInd);
getCellReference(column, colabs, row, rowabs, buf);
}
/**
* Gets the fully qualified cell reference given the column, row
* external sheet reference etc
*
* @param sheet
* @param column
* @param row
* @param workbook
* @return the cell reference in the form 'Sheet 1'!A1
*/
public static String getCellReference
(int sheet, int column, int row,
ExternalSheet workbook) {
StringBuffer sb = new StringBuffer();
getCellReference(sheet, column, row, workbook, sb);
return sb.toString();
}
/**
* Gets the cell reference for the specified column and row
*
* @param column
* @param row
* @return
*/
public static String getCellReference(int column, int row) {
StringBuffer buf = new StringBuffer();
getCellReference(column, row, buf);
return buf.toString();
}
/**
* Gets the columnn number of the string cell reference
*
* @param s the string to parse
* @return the column portion of the cell reference
*/
public static int getColumn(String s) {
int colnum = 0;
int numindex = getNumberIndex(s);
String s2 = s.toUpperCase();
int startPos = s.lastIndexOf(sheetInd) + 1;
if (s.charAt(startPos) == fixedInd) {
startPos++;
}
int endPos = numindex;
if (s.charAt(numindex - 1) == fixedInd) {
endPos--;
}
for (int i = startPos; i < endPos; i++) {
if (i != startPos) {
colnum = (colnum + 1) * 26;
}
colnum += (int) s2.charAt(i) - (int) 'A';
}
return colnum;
}
/**
* Gets the row number of the cell reference
*/
public static int getRow(String s) {
try {
return (Integer.parseInt(s.substring(getNumberIndex(s))) - 1);
} catch (NumberFormatException e) {
logger.warn(e, e);
return 0xffff;
}
}
/**
* Finds the position where the first number occurs in the string
*/
private static int getNumberIndex(String s) {
// Find the position of the first number
boolean numberFound = false;
int pos = s.lastIndexOf(sheetInd) + 1;
char c = '\0';
while (!numberFound && pos < s.length()) {
c = s.charAt(pos);
if (c >= '0' && c <= '9') {
numberFound = true;
} else {
pos++;
}
}
return pos;
}
/**
* Sees if the column component is relative or not
*
* @param s
* @return TRUE if the column is relative, FALSE otherwise
*/
public static boolean isColumnRelative(String s) {
return s.charAt(0) != fixedInd;
}
/**
* Sees if the row component is relative or not
*
* @param s
* @return TRUE if the row is relative, FALSE otherwise
*/
public static boolean isRowRelative(String s) {
return s.charAt(getNumberIndex(s) - 1) != fixedInd;
}
/**
* Gets the sheet name from the cell reference string
*
* @param ref
* @return the sheet reference
*/
public static String getSheet(String ref) {
int sheetPos = ref.lastIndexOf(sheetInd);
if (sheetPos == -1) {
return "";
}
return ref.substring(0, sheetPos);
}
}

@ -0,0 +1,113 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import jxl.write.biff.File;
/**
* Class containing the CONDFMT and CF records for conditionally formatting
* a cell
*/
public class ConditionalFormat {
/**
* The range of the format
*/
private final ConditionalFormatRangeRecord range;
/**
* The format conditions
*/
private final ArrayList conditions;
/**
* Constructor
*/
public ConditionalFormat(ConditionalFormatRangeRecord cfrr) {
range = cfrr;
conditions = new ArrayList();
}
/**
* Adds a condition
*
* @param cond the condition
*/
public void addCondition(ConditionalFormatRecord cond) {
conditions.add(cond);
}
/**
* Inserts a blank column into this spreadsheet. If the column is out of
* range of the columns in the sheet, then no action is taken
*
* @param col the column to insert
*/
public void insertColumn(int col) {
range.insertColumn(col);
}
/**
* Removes a column from this spreadsheet. If the column is out of range
* of the columns in the sheet, then no action is taken
*
* @param col the column to remove
*/
public void removeColumn(int col) {
range.removeColumn(col);
}
/**
* Removes a row from this spreadsheet. If the row is out of
* range of the columns in the sheet, then no action is taken
*
* @param row the row to remove
*/
public void removeRow(int row) {
range.removeRow(row);
}
/**
* Inserts a blank row into this spreadsheet. If the row is out of range
* of the rows in the sheet, then no action is taken
*
* @param row the row to insert
*/
public void insertRow(int row) {
range.insertRow(row);
}
/**
* Writes out the data validation
*
* @param outputFile the output file
* @throws IOException
*/
public void write(File outputFile) throws IOException {
outputFile.write(range);
for (Iterator i = conditions.iterator(); i.hasNext(); ) {
ConditionalFormatRecord cfr = (ConditionalFormatRecord) i.next();
outputFile.write(cfr);
}
}
}

@ -0,0 +1,344 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Range information for conditional formatting
*/
public class ConditionalFormatRangeRecord extends WritableRecordData {
// The logger
private static final Logger logger =
Logger.getLogger(ConditionalFormatRangeRecord.class);
/**
* The enclosing range
*/
private Range enclosingRange;
/**
* The discrete ranges
*/
private Range[] ranges;
/**
* The number of ranges
*/
private int numRanges;
/**
* Initialized flag
*/
private boolean initialized;
/**
* Modified flag
*/
private boolean modified;
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*/
public ConditionalFormatRangeRecord(Record t) {
super(t);
initialized = false;
modified = false;
data = getRecord().getData();
}
/**
* Initialization function
*/
private void initialize() {
enclosingRange = new Range();
enclosingRange.firstRow = IntegerHelper.getInt(data[4], data[5]);
enclosingRange.lastRow = IntegerHelper.getInt(data[6], data[7]);
enclosingRange.firstColumn = IntegerHelper.getInt(data[8], data[9]);
enclosingRange.lastColumn = IntegerHelper.getInt(data[10], data[11]);
numRanges = IntegerHelper.getInt(data[12], data[13]);
ranges = new Range[numRanges];
int pos = 14;
for (int i = 0; i < numRanges; i++) {
ranges[i] = new Range();
ranges[i].firstRow = IntegerHelper.getInt(data[pos], data[pos + 1]);
ranges[i].lastRow = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
ranges[i].firstColumn = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
ranges[i].lastColumn = IntegerHelper.getInt(data[pos + 6], data[pos + 7]);
pos += 8;
}
initialized = true;
}
/**
* Inserts a blank column into this spreadsheet. If the column is out of
* range of the columns in the sheet, then no action is taken
*
* @param col the column to insert
*/
public void insertColumn(int col) {
if (!initialized) {
initialize();
}
enclosingRange.insertColumn(col);
if (enclosingRange.modified) {
modified = true;
}
for (int i = 0; i < ranges.length; i++) {
ranges[i].insertColumn(col);
if (ranges[i].modified) {
modified = true;
}
}
return;
}
/**
* Inserts a blank column into this spreadsheet. If the column is out of
* range of the columns in the sheet, then no action is taken
*
* @param col the column to insert
*/
public void removeColumn(int col) {
if (!initialized) {
initialize();
}
enclosingRange.removeColumn(col);
if (enclosingRange.modified) {
modified = true;
}
for (int i = 0; i < ranges.length; i++) {
ranges[i].removeColumn(col);
if (ranges[i].modified) {
modified = true;
}
}
return;
}
/**
* Removes a row from this spreadsheet. If the row is out of
* range of the columns in the sheet, then no action is taken
*
* @param row the row to remove
*/
public void removeRow(int row) {
if (!initialized) {
initialize();
}
enclosingRange.removeRow(row);
if (enclosingRange.modified) {
modified = true;
}
for (int i = 0; i < ranges.length; i++) {
ranges[i].removeRow(row);
if (ranges[i].modified) {
modified = true;
}
}
return;
}
/**
* Inserts a blank row into this spreadsheet. If the row is out of range
* of the rows in the sheet, then no action is taken
*
* @param row the row to insert
*/
public void insertRow(int row) {
if (!initialized) {
initialize();
}
enclosingRange.insertRow(row);
if (enclosingRange.modified) {
modified = true;
}
for (int i = 0; i < ranges.length; i++) {
ranges[i].insertRow(row);
if (ranges[i].modified) {
modified = true;
}
}
return;
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
if (!modified) {
return data;
}
byte[] d = new byte[14 + ranges.length * 8];
// Copy in the original information
System.arraycopy(data, 0, d, 0, 4);
// Create the new range
IntegerHelper.getTwoBytes(enclosingRange.firstRow, d, 4);
IntegerHelper.getTwoBytes(enclosingRange.lastRow, d, 6);
IntegerHelper.getTwoBytes(enclosingRange.firstColumn, d, 8);
IntegerHelper.getTwoBytes(enclosingRange.lastColumn, d, 10);
IntegerHelper.getTwoBytes(numRanges, d, 12);
int pos = 14;
for (int i = 0; i < ranges.length; i++) {
IntegerHelper.getTwoBytes(ranges[i].firstRow, d, pos);
IntegerHelper.getTwoBytes(ranges[i].lastRow, d, pos + 2);
IntegerHelper.getTwoBytes(ranges[i].firstColumn, d, pos + 4);
IntegerHelper.getTwoBytes(ranges[i].lastColumn, d, pos + 6);
pos += 8;
}
return d;
}
private static class Range {
public int firstRow;
public int firstColumn;
public int lastRow;
public int lastColumn;
public boolean modified;
public Range() {
modified = false;
}
/**
* Inserts a blank column into this spreadsheet. If the column is out of
* range of the columns in the sheet, then no action is taken
*
* @param col the column to insert
*/
public void insertColumn(int col) {
if (col > lastColumn) {
return;
}
if (col <= firstColumn) {
firstColumn++;
modified = true;
}
if (col <= lastColumn) {
lastColumn++;
modified = true;
}
}
/**
* Removes a column from this spreadsheet. If the column is out of range
* of the columns in the sheet, then no action is taken
*
* @param col the column to remove
*/
public void removeColumn(int col) {
if (col > lastColumn) {
return;
}
if (col < firstColumn) {
firstColumn--;
modified = true;
}
if (col <= lastColumn) {
lastColumn--;
modified = true;
}
}
/**
* Removes a row from this spreadsheet. If the row is out of
* range of the columns in the sheet, then no action is taken
*
* @param row the row to remove
*/
public void removeRow(int row) {
if (row > lastRow) {
return;
}
if (row < firstRow) {
firstRow--;
modified = true;
}
if (row <= lastRow) {
lastRow--;
modified = true;
}
}
/**
* Inserts a blank row into this spreadsheet. If the row is out of range
* of the rows in the sheet, then no action is taken
*
* @param row the row to insert
*/
public void insertRow(int row) {
if (row > lastRow) {
return;
}
if (row <= firstRow) {
firstRow++;
modified = true;
}
if (row <= lastRow) {
lastRow++;
modified = true;
}
}
}
}

@ -0,0 +1,56 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* The conditional format conditions
*/
public class ConditionalFormatRecord extends WritableRecordData {
// the logger
private static final Logger logger =
Logger.getLogger(ConditionalFormatRecord.class);
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*/
public ConditionalFormatRecord(Record t) {
super(t);
data = getRecord().getData();
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
return data;
}
}

@ -0,0 +1,74 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.read.biff.Record;
/**
* A continue record - only used explicitly in special circumstances, as
* the general continuation record is handled directly by the records
*/
public class ContinueRecord extends WritableRecordData {
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*
* @param t the raw bytes
*/
public ContinueRecord(Record t) {
super(t);
data = t.getData();
}
/**
* Constructor invoked when creating continue records
*
* @param d the data
*/
public ContinueRecord(byte[] d) {
super(Type.CONTINUE);
data = d;
}
/**
* Accessor for the binary data - used when copying
*
* @return the binary data
*/
public byte[] getData() {
return data;
}
/**
* Accessor for the record. Used when forcibly changing this record
* into another type, notably a drawing record, as sometimes Excel appears
* to switch to writing Continue records instead of MsoDrawing records
*
* @return the record
*/
public Record getRecord() {
return super.getRecord();
}
}

@ -0,0 +1,150 @@
/*********************************************************************
*
* Copyright (C) 2005 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
/**
* Enumeration type for the excel country codes
*/
public class CountryCode {
// The country codes
public final static CountryCode USA = new CountryCode(0x1, "US", "USA");
public final static CountryCode CANADA =
new CountryCode(0x2, "CA", "Canada");
public final static CountryCode GREECE =
new CountryCode(0x1e, "GR", "Greece");
public final static CountryCode NETHERLANDS =
new CountryCode(0x1f, "NE", "Netherlands");
public final static CountryCode BELGIUM =
new CountryCode(0x20, "BE", "Belgium");
public final static CountryCode FRANCE =
new CountryCode(0x21, "FR", "France");
public final static CountryCode SPAIN = new CountryCode(0x22, "ES", "Spain");
public final static CountryCode ITALY = new CountryCode(0x27, "IT", "Italy");
public final static CountryCode SWITZERLAND =
new CountryCode(0x29, "CH", "Switzerland");
public final static CountryCode UK =
new CountryCode(0x2c, "UK", "United Kingdowm");
public final static CountryCode DENMARK =
new CountryCode(0x2d, "DK", "Denmark");
public final static CountryCode SWEDEN =
new CountryCode(0x2e, "SE", "Sweden");
public final static CountryCode NORWAY =
new CountryCode(0x2f, "NO", "Norway");
public final static CountryCode GERMANY =
new CountryCode(0x31, "DE", "Germany");
public final static CountryCode PHILIPPINES =
new CountryCode(0x3f, "PH", "Philippines");
public final static CountryCode CHINA =
new CountryCode(0x56, "CN", "China");
public final static CountryCode INDIA =
new CountryCode(0x5b, "IN", "India");
public final static CountryCode UNKNOWN =
new CountryCode(0xffff, "??", "Unknown");
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(CountryCode.class);
/**
* The array of country codes
*/
private static CountryCode[] codes = new CountryCode[0];
/**
* The country code
*/
private final int value;
/**
* The ISO 3166 two letter country mnemonic (as used by the Locale class)
*/
private final String code;
/**
* The long description
*/
private final String description;
/**
* Constructor
*/
private CountryCode(int v, String c, String d) {
value = v;
code = c;
description = d;
CountryCode[] newcodes = new CountryCode[codes.length + 1];
System.arraycopy(codes, 0, newcodes, 0, codes.length);
newcodes[codes.length] = this;
codes = newcodes;
}
/**
* Constructor used to create an arbitrary code with a specified value.
* Doesn't add the latest value to the static array
*/
private CountryCode(int v) {
value = v;
description = "Arbitrary";
code = "??";
}
/**
* Gets the country code for the given two character mnemonic string
*/
public static CountryCode getCountryCode(String s) {
if (s == null || s.length() != 2) {
logger.warn("Please specify two character ISO 3166 country code");
return USA;
}
CountryCode code = UNKNOWN;
for (int i = 0; i < codes.length && code == UNKNOWN; i++) {
if (codes[i].code.equals(s)) {
code = codes[i];
}
}
return code;
}
/**
* Creates an arbitrary country code with the specified value. Used
* when copying sheets, and the country code isn't initialized as part
* of the static data below
*/
public static CountryCode createArbitraryCode(int i) {
return new CountryCode(i);
}
/**
* Accessor for the excel value
*
* @return the excel value
*/
public int getValue() {
return value;
}
/**
* Accessor for the string
*
* @return the two character iso 3166 string
*/
public String getCode() {
return code;
}
}

@ -0,0 +1,906 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Iterator;
import jxl.WorkbookSettings;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.biff.formula.FormulaParser;
import jxl.biff.formula.ParseContext;
import jxl.common.Assert;
import jxl.common.Logger;
/**
* Class which parses the binary data associated with Data Validity (DV)
* setting
*/
public class DVParser {
// The values
public static final DVType ANY = new DVType(0, "any");
public static final DVType INTEGER = new DVType(1, "int");
public static final DVType DECIMAL = new DVType(2, "dec");
public static final DVType LIST = new DVType(3, "list");
public static final DVType DATE = new DVType(4, "date");
public static final DVType TIME = new DVType(5, "time");
public static final DVType TEXT_LENGTH = new DVType(6, "strlen");
public static final DVType FORMULA = new DVType(7, "form");
// The error styles
public static final ErrorStyle STOP = new ErrorStyle(0);
public static final ErrorStyle WARNING = new ErrorStyle(1);
public static final ErrorStyle INFO = new ErrorStyle(2);
// The conditions
public static final Condition BETWEEN = new Condition(0, "{0} <= x <= {1}");
public static final Condition NOT_BETWEEN =
new Condition(1, "!({0} <= x <= {1}");
public static final Condition EQUAL = new Condition(2, "x == {0}");
public static final Condition NOT_EQUAL = new Condition(3, "x != {0}");
public static final Condition GREATER_THAN = new Condition(4, "x > {0}");
public static final Condition LESS_THAN = new Condition(5, "x < {0}");
public static final Condition GREATER_EQUAL = new Condition(6, "x >= {0}");
public static final Condition LESS_EQUAL = new Condition(7, "x <= {0}");
// The masks
private static final int STRING_LIST_GIVEN_MASK = 0x80;
private static final int EMPTY_CELLS_ALLOWED_MASK = 0x100;
private static final int SUPPRESS_ARROW_MASK = 0x200;
private static final int SHOW_PROMPT_MASK = 0x40000;
private static final int SHOW_ERROR_MASK = 0x80000;
// The maximum string length for a data validation list
private static final int MAX_VALIDATION_LIST_LENGTH = 254;
// The maximum number of rows and columns
private static final int MAX_ROWS = 0xffff;
private static final int MAX_COLUMNS = 0xff;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(DVParser.class);
// The decimal format
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#");
/**
* The type
*/
private final DVType type;
/**
* The error style
*/
private final ErrorStyle errorStyle;
/**
* The condition
*/
private final Condition condition;
/**
* String list option
*/
private final boolean stringListGiven;
/**
* Empty cells allowed
*/
private final boolean emptyCellsAllowed;
/**
* Suppress arrow
*/
private final boolean suppressArrow;
/**
* Show prompt
*/
private final boolean showPrompt;
/**
* Show error
*/
private final boolean showError;
/**
* The title of the prompt box
*/
private String promptTitle;
/**
* The title of the error box
*/
private String errorTitle;
/**
* The text of the prompt box
*/
private String promptText;
/**
* The text of the error box
*/
private String errorText;
/**
* The first formula
*/
private FormulaParser formula1;
/**
* The first formula string
*/
private String formula1String;
/**
* The second formula
*/
private FormulaParser formula2;
/**
* The second formula string
*/
private String formula2String;
/**
* The column number of the cell at the top left of the range
*/
private int column1;
/**
* The row number of the cell at the top left of the range
*/
private int row1;
/**
* The column index of the cell at the bottom right
*/
private int column2;
/**
* The row index of the cell at the bottom right
*/
private int row2;
/**
* Flag to indicate that this DV Parser is shared amongst a group
* of cells
*/
private boolean extendedCellsValidation;
/**
* Flag indicated whether this has been copied
*/
private final boolean copied;
/**
* Constructor
*/
public DVParser(byte[] data,
ExternalSheet es,
WorkbookMethods nt,
WorkbookSettings ws) {
Assert.verify(nt != null);
copied = false;
int options = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
int typeVal = options & 0xf;
type = DVType.getType(typeVal);
int errorStyleVal = (options & 0x70) >> 4;
errorStyle = ErrorStyle.getErrorStyle(errorStyleVal);
int conditionVal = (options & 0xf00000) >> 20;
condition = Condition.getCondition(conditionVal);
stringListGiven = (options & STRING_LIST_GIVEN_MASK) != 0;
emptyCellsAllowed = (options & EMPTY_CELLS_ALLOWED_MASK) != 0;
suppressArrow = (options & SUPPRESS_ARROW_MASK) != 0;
showPrompt = (options & SHOW_PROMPT_MASK) != 0;
showError = (options & SHOW_ERROR_MASK) != 0;
int pos = 4;
int length = IntegerHelper.getInt(data[pos], data[pos + 1]);
if (length > 0 && data[pos + 2] == 0) {
promptTitle = StringHelper.getString(data, length, pos + 3, ws);
pos += length + 3;
} else if (length > 0) {
promptTitle = StringHelper.getUnicodeString(data, length, pos + 3);
pos += length * 2 + 3;
} else {
pos += 3;
}
length = IntegerHelper.getInt(data[pos], data[pos + 1]);
if (length > 0 && data[pos + 2] == 0) {
errorTitle = StringHelper.getString(data, length, pos + 3, ws);
pos += length + 3;
} else if (length > 0) {
errorTitle = StringHelper.getUnicodeString(data, length, pos + 3);
pos += length * 2 + 3;
} else {
pos += 3;
}
length = IntegerHelper.getInt(data[pos], data[pos + 1]);
if (length > 0 && data[pos + 2] == 0) {
promptText = StringHelper.getString(data, length, pos + 3, ws);
pos += length + 3;
} else if (length > 0) {
promptText = StringHelper.getUnicodeString(data, length, pos + 3);
pos += length * 2 + 3;
} else {
pos += 3;
}
length = IntegerHelper.getInt(data[pos], data[pos + 1]);
if (length > 0 && data[pos + 2] == 0) {
errorText = StringHelper.getString(data, length, pos + 3, ws);
pos += length + 3;
} else if (length > 0) {
errorText = StringHelper.getUnicodeString(data, length, pos + 3);
pos += length * 2 + 3;
} else {
pos += 3;
}
int formula1Length = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 4;
int formula1Pos = pos;
pos += formula1Length;
int formula2Length = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 4;
int formula2Pos = pos;
pos += formula2Length;
pos += 2;
row1 = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
row2 = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
column1 = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
column2 = IntegerHelper.getInt(data[pos], data[pos + 1]);
pos += 2;
extendedCellsValidation = row1 != row2 || column1 != column2;
// Do the formulas
try {
// First, create a temporary blank cell for any formula relative
// references
EmptyCell tmprt = new EmptyCell(column1, row1);
if (formula1Length != 0) {
byte[] tokens = new byte[formula1Length];
System.arraycopy(data, formula1Pos, tokens, 0, formula1Length);
formula1 = new FormulaParser(tokens, tmprt, es, nt, ws,
ParseContext.DATA_VALIDATION);
formula1.parse();
}
if (formula2Length != 0) {
byte[] tokens = new byte[formula2Length];
System.arraycopy(data, formula2Pos, tokens, 0, formula2Length);
formula2 = new FormulaParser(tokens, tmprt, es, nt, ws,
ParseContext.DATA_VALIDATION);
formula2.parse();
}
} catch (FormulaException e) {
logger.warn(e.getMessage() + " for cells " +
CellReferenceHelper.getCellReference(column1, row1) + "-" +
CellReferenceHelper.getCellReference(column2, row2));
}
}
/**
* Constructor called when creating a data validation from the API
*/
public DVParser(Collection strings) {
copied = false;
type = LIST;
errorStyle = STOP;
condition = BETWEEN;
extendedCellsValidation = false;
// the options
stringListGiven = true;
emptyCellsAllowed = true;
suppressArrow = false;
showPrompt = true;
showError = true;
promptTitle = "\0";
errorTitle = "\0";
promptText = "\0";
errorText = "\0";
if (strings.size() == 0) {
logger.warn("no validation strings - ignoring");
}
Iterator i = strings.iterator();
StringBuffer formulaString = new StringBuffer();
formulaString.append(i.next().toString());
while (i.hasNext()) {
formulaString.append('\0');
formulaString.append(' ');
formulaString.append(i.next().toString());
}
// If the formula string exceeds
// the maximum validation list length, then truncate and stop there
if (formulaString.length() > MAX_VALIDATION_LIST_LENGTH) {
logger.warn("Validation list exceeds maximum number of characters - " +
"truncating");
formulaString.delete(MAX_VALIDATION_LIST_LENGTH,
formulaString.length());
}
// Put the string in quotes
formulaString.insert(0, '\"');
formulaString.append('\"');
formula1String = formulaString.toString();
}
/**
* Constructor called when creating a data validation from the API
*/
public DVParser(String namedRange) {
// Handle the case for an empty string
if (namedRange.length() == 0) {
copied = false;
type = FORMULA;
errorStyle = STOP;
condition = EQUAL;
extendedCellsValidation = false;
// the options
stringListGiven = false;
emptyCellsAllowed = false;
suppressArrow = false;
showPrompt = true;
showError = true;
promptTitle = "\0";
errorTitle = "\0";
promptText = "\0";
errorText = "\0";
formula1String = "\"\"";
return;
}
copied = false;
type = LIST;
errorStyle = STOP;
condition = BETWEEN;
extendedCellsValidation = false;
// the options
stringListGiven = false;
emptyCellsAllowed = true;
suppressArrow = false;
showPrompt = true;
showError = true;
promptTitle = "\0";
errorTitle = "\0";
promptText = "\0";
errorText = "\0";
formula1String = namedRange;
}
/**
* Constructor called when creating a data validation from the API
*/
public DVParser(int c1, int r1, int c2, int r2) {
copied = false;
type = LIST;
errorStyle = STOP;
condition = BETWEEN;
extendedCellsValidation = false;
// the options
stringListGiven = false;
emptyCellsAllowed = true;
suppressArrow = false;
showPrompt = true;
showError = true;
promptTitle = "\0";
errorTitle = "\0";
promptText = "\0";
errorText = "\0";
StringBuffer formulaString = new StringBuffer();
CellReferenceHelper.getCellReference(c1, r1, formulaString);
formulaString.append(':');
CellReferenceHelper.getCellReference(c2, r2, formulaString);
formula1String = formulaString.toString();
}
/**
* Constructor called when creating a data validation from the API
*/
public DVParser(double val1, double val2, Condition c) {
copied = false;
type = DECIMAL;
errorStyle = STOP;
condition = c;
extendedCellsValidation = false;
// the options
stringListGiven = false;
emptyCellsAllowed = true;
suppressArrow = false;
showPrompt = true;
showError = true;
promptTitle = "\0";
errorTitle = "\0";
promptText = "\0";
errorText = "\0";
formula1String = DECIMAL_FORMAT.format(val1);
if (!Double.isNaN(val2)) {
formula2String = DECIMAL_FORMAT.format(val2);
}
}
/**
* Constructor called when doing a cell deep copy
*/
public DVParser(DVParser copy) {
copied = true;
type = copy.type;
errorStyle = copy.errorStyle;
condition = copy.condition;
stringListGiven = copy.stringListGiven;
emptyCellsAllowed = copy.emptyCellsAllowed;
suppressArrow = copy.suppressArrow;
showPrompt = copy.showPrompt;
showError = copy.showError;
promptTitle = copy.promptTitle;
promptText = copy.promptText;
errorTitle = copy.errorTitle;
errorText = copy.errorText;
extendedCellsValidation = copy.extendedCellsValidation;
row1 = copy.row1;
row2 = copy.row2;
column1 = copy.column1;
column2 = copy.column2;
// Don't copy the formula parsers - just take their string equivalents
if (copy.formula1String != null) {
formula1String = copy.formula1String;
formula2String = copy.formula2String;
} else {
try {
formula1String = copy.formula1.getFormula();
formula2String = (copy.formula2 != null) ?
copy.formula2.getFormula() : null;
} catch (FormulaException e) {
logger.warn("Cannot parse validation formula: " + e.getMessage());
}
}
// Don't copy the cell references - these will be added later
}
/**
* Gets the data
*/
public byte[] getData() {
// Compute the length of the data
byte[] f1Bytes = formula1 != null ? formula1.getBytes() : new byte[0];
byte[] f2Bytes = formula2 != null ? formula2.getBytes() : new byte[0];
int dataLength =
4 + // the options
promptTitle.length() * 2 + 3 + // the prompt title
errorTitle.length() * 2 + 3 + // the error title
promptText.length() * 2 + 3 + // the prompt text
errorText.length() * 2 + 3 + // the error text
f1Bytes.length + 2 + // first formula
f2Bytes.length + 2 + // second formula
+4 + // unused bytes
10; // cell range
byte[] data = new byte[dataLength];
// The position
int pos = 0;
// The options
int options = 0;
options |= type.getValue();
options |= errorStyle.getValue() << 4;
options |= condition.getValue() << 20;
if (stringListGiven) {
options |= STRING_LIST_GIVEN_MASK;
}
if (emptyCellsAllowed) {
options |= EMPTY_CELLS_ALLOWED_MASK;
}
if (suppressArrow) {
options |= SUPPRESS_ARROW_MASK;
}
if (showPrompt) {
options |= SHOW_PROMPT_MASK;
}
if (showError) {
options |= SHOW_ERROR_MASK;
}
// The text
IntegerHelper.getFourBytes(options, data, pos);
pos += 4;
IntegerHelper.getTwoBytes(promptTitle.length(), data, pos);
pos += 2;
data[pos] = (byte) 0x1; // unicode indicator
pos++;
StringHelper.getUnicodeBytes(promptTitle, data, pos);
pos += promptTitle.length() * 2;
IntegerHelper.getTwoBytes(errorTitle.length(), data, pos);
pos += 2;
data[pos] = (byte) 0x1; // unicode indicator
pos++;
StringHelper.getUnicodeBytes(errorTitle, data, pos);
pos += errorTitle.length() * 2;
IntegerHelper.getTwoBytes(promptText.length(), data, pos);
pos += 2;
data[pos] = (byte) 0x1; // unicode indicator
pos++;
StringHelper.getUnicodeBytes(promptText, data, pos);
pos += promptText.length() * 2;
IntegerHelper.getTwoBytes(errorText.length(), data, pos);
pos += 2;
data[pos] = (byte) 0x1; // unicode indicator
pos++;
StringHelper.getUnicodeBytes(errorText, data, pos);
pos += errorText.length() * 2;
// Formula 1
IntegerHelper.getTwoBytes(f1Bytes.length, data, pos);
pos += 4;
System.arraycopy(f1Bytes, 0, data, pos, f1Bytes.length);
pos += f1Bytes.length;
// Formula 2
IntegerHelper.getTwoBytes(f2Bytes.length, data, pos);
pos += 4;
System.arraycopy(f2Bytes, 0, data, pos, f2Bytes.length);
pos += f2Bytes.length;
// The cell ranges
IntegerHelper.getTwoBytes(1, data, pos);
pos += 2;
IntegerHelper.getTwoBytes(row1, data, pos);
pos += 2;
IntegerHelper.getTwoBytes(row2, data, pos);
pos += 2;
IntegerHelper.getTwoBytes(column1, data, pos);
pos += 2;
IntegerHelper.getTwoBytes(column2, data, pos);
pos += 2;
return data;
}
/**
* Inserts a row
*
* @param row the row to insert
*/
public void insertRow(int row) {
if (formula1 != null) {
formula1.rowInserted(0, row, true);
}
if (formula2 != null) {
formula2.rowInserted(0, row, true);
}
if (row1 >= row) {
row1++;
}
if (row2 >= row && row2 != MAX_ROWS) {
row2++;
}
}
/**
* Inserts a column
*
* @param col the column to insert
*/
public void insertColumn(int col) {
if (formula1 != null) {
formula1.columnInserted(0, col, true);
}
if (formula2 != null) {
formula2.columnInserted(0, col, true);
}
if (column1 >= col) {
column1++;
}
if (column2 >= col && column2 != MAX_COLUMNS) {
column2++;
}
}
/**
* Removes a row
*
* @param row the row to insert
*/
public void removeRow(int row) {
if (formula1 != null) {
formula1.rowRemoved(0, row, true);
}
if (formula2 != null) {
formula2.rowRemoved(0, row, true);
}
if (row1 > row) {
row1--;
}
if (row2 >= row) {
row2--;
}
}
/**
* Removes a column
*
* @param col the row to remove
*/
public void removeColumn(int col) {
if (formula1 != null) {
formula1.columnRemoved(0, col, true);
}
if (formula2 != null) {
formula2.columnRemoved(0, col, true);
}
if (column1 > col) {
column1--;
}
if (column2 >= col && column2 != MAX_COLUMNS) {
column2--;
}
}
/**
* Accessor for first column
*
* @return the first column
*/
public int getFirstColumn() {
return column1;
}
/**
* Accessor for the last column
*
* @return the last column
*/
public int getLastColumn() {
return column2;
}
/**
* Accessor for first row
*
* @return the first row
*/
public int getFirstRow() {
return row1;
}
/**
* Accessor for the last row
*
* @return the last row
*/
public int getLastRow() {
return row2;
}
/**
* Gets the formula present in the validation
*
* @return the validation formula as a string
* @throws FormulaException
*/
String getValidationFormula() throws FormulaException {
if (type == LIST) {
return formula1.getFormula();
}
String s1 = formula1.getFormula();
String s2 = formula2 != null ? formula2.getFormula() : null;
return condition.getConditionString(s1, s2) +
"; x " + type.getDescription();
}
/**
* Called by the cell value when the cell features are added to the sheet
*/
public void setCell(int col,
int row,
ExternalSheet es,
WorkbookMethods nt,
WorkbookSettings ws) throws FormulaException {
// If this is part of an extended cells validation, then do nothing
// as this will already have been called and parsed when the top left
// cell was added
if (extendedCellsValidation) {
return;
}
row1 = row;
row2 = row;
column1 = col;
column2 = col;
formula1 = new FormulaParser(formula1String,
es, nt, ws,
ParseContext.DATA_VALIDATION);
formula1.parse();
if (formula2String != null) {
formula2 = new FormulaParser(formula2String,
es, nt, ws,
ParseContext.DATA_VALIDATION);
formula2.parse();
}
}
/**
* Indicates that the data validation extends across several more cells
*
* @param cols - the number of extra columns
* @param rows - the number of extra rows
*/
public void extendCellValidation(int cols, int rows) {
row2 = row1 + rows;
column2 = column1 + cols;
extendedCellsValidation = true;
}
/**
* Accessor which indicates whether this validation applies across
* multiple cels
*/
public boolean extendedCellsValidation() {
return extendedCellsValidation;
}
public boolean copied() {
return copied;
}
// DV Type
public static class DVType {
private static DVType[] types = new DVType[0];
private final int value;
private final String desc;
DVType(int v, String d) {
value = v;
desc = d;
DVType[] oldtypes = types;
types = new DVType[oldtypes.length + 1];
System.arraycopy(oldtypes, 0, types, 0, oldtypes.length);
types[oldtypes.length] = this;
}
static DVType getType(int v) {
DVType found = null;
for (int i = 0; i < types.length && found == null; i++) {
if (types[i].value == v) {
found = types[i];
}
}
return found;
}
public int getValue() {
return value;
}
public String getDescription() {
return desc;
}
}
// Error Style
public static class ErrorStyle {
private static ErrorStyle[] types = new ErrorStyle[0];
private final int value;
ErrorStyle(int v) {
value = v;
ErrorStyle[] oldtypes = types;
types = new ErrorStyle[oldtypes.length + 1];
System.arraycopy(oldtypes, 0, types, 0, oldtypes.length);
types[oldtypes.length] = this;
}
static ErrorStyle getErrorStyle(int v) {
ErrorStyle found = null;
for (int i = 0; i < types.length && found == null; i++) {
if (types[i].value == v) {
found = types[i];
}
}
return found;
}
public int getValue() {
return value;
}
}
// Conditions
public static class Condition {
private static Condition[] types = new Condition[0];
private final int value;
private final MessageFormat format;
Condition(int v, String pattern) {
value = v;
format = new MessageFormat(pattern);
Condition[] oldtypes = types;
types = new Condition[oldtypes.length + 1];
System.arraycopy(oldtypes, 0, types, 0, oldtypes.length);
types[oldtypes.length] = this;
}
static Condition getCondition(int v) {
Condition found = null;
for (int i = 0; i < types.length && found == null; i++) {
if (types[i].value == v) {
found = types[i];
}
}
return found;
}
public int getValue() {
return value;
}
public String getConditionString(String s1, String s2) {
return format.format(new String[]{s1, s2});
}
}
}

@ -0,0 +1,149 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
/**
* Class which parses the binary data associated with Data Validity (DVal)
* setting
*/
public class DValParser {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(DValParser.class);
// The option masks
private static final int PROMPT_BOX_VISIBLE_MASK = 0x1;
private static final int PROMPT_BOX_AT_CELL_MASK = 0x2;
private static final int VALIDITY_DATA_CACHED_MASK = 0x4;
/**
* Prompt box visible
*/
private boolean promptBoxVisible;
/**
* Empty cells allowed
*/
private boolean promptBoxAtCell;
/**
* Cell validity data cached in following DV records
*/
private final boolean validityDataCached;
/**
* The number of following DV records
*/
private int numDVRecords;
/**
* The object id of the associated down arrow
*/
private final int objectId;
/**
* Constructor
*/
public DValParser(byte[] data) {
int options = IntegerHelper.getInt(data[0], data[1]);
promptBoxVisible = (options & PROMPT_BOX_VISIBLE_MASK) != 0;
promptBoxAtCell = (options & PROMPT_BOX_AT_CELL_MASK) != 0;
validityDataCached = (options & VALIDITY_DATA_CACHED_MASK) != 0;
objectId = IntegerHelper.getInt(data[10], data[11], data[12], data[13]);
numDVRecords = IntegerHelper.getInt(data[14], data[15],
data[16], data[17]);
}
/**
* Constructor
*/
public DValParser(int objid, int num) {
objectId = objid;
numDVRecords = num;
validityDataCached = true;
}
/**
* Gets the data
*/
public byte[] getData() {
byte[] data = new byte[18];
int options = 0;
if (promptBoxVisible) {
options |= PROMPT_BOX_VISIBLE_MASK;
}
if (promptBoxAtCell) {
options |= PROMPT_BOX_AT_CELL_MASK;
}
if (validityDataCached) {
options |= VALIDITY_DATA_CACHED_MASK;
}
IntegerHelper.getTwoBytes(options, data, 0);
IntegerHelper.getFourBytes(objectId, data, 10);
IntegerHelper.getFourBytes(numDVRecords, data, 14);
return data;
}
/**
* Called when a remove row or column results in one of DV records being
* removed
*/
public void dvRemoved() {
numDVRecords--;
}
/**
* Accessor for the number of DV records
*
* @return the number of DV records for this list
*/
public int getNumberOfDVRecords() {
return numDVRecords;
}
/**
* Accessor for the object id
*
* @return the object id
*/
public int getObjectId() {
return objectId;
}
/**
* Called when adding a DV record on a copied DVal
*/
public void dvAdded() {
numDVRecords++;
}
}

@ -0,0 +1,306 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import jxl.WorkbookSettings;
import jxl.biff.formula.ExternalSheet;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Class which encapsulates a data validation. This encapsulates the
* base DVAL record (DataValidityListRecord) and all the individual DV
* (DataValiditySettingsRecord) records
*/
public class DataValidation {
public static final int DEFAULT_OBJECT_ID = 0xffffffff;
private static final int MAX_NO_OF_VALIDITY_SETTINGS = 0xfffd;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(DataValidation.class);
/**
* The data validity list
*/
private DataValidityListRecord validityList;
/**
* The list of data validity (DV) records
*/
private ArrayList validitySettings;
/**
* Handle to the workbook
*/
private WorkbookMethods workbook;
/**
* Handle to the external sheet
*/
private ExternalSheet externalSheet;
/**
* Handle to the workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* The object id of the combo box used for drop downs
*/
private int comboBoxObjectId;
/**
* Indicates whether this was copied
*/
private final boolean copied;
/**
* Constructor
*/
public DataValidation(DataValidityListRecord dvlr) {
validityList = dvlr;
validitySettings = new ArrayList(validityList.getNumberOfSettings());
copied = false;
}
/**
* Constructor used to create writable data validations
*/
public DataValidation(int objId,
ExternalSheet es,
WorkbookMethods wm,
WorkbookSettings ws) {
workbook = wm;
externalSheet = es;
workbookSettings = ws;
validitySettings = new ArrayList();
comboBoxObjectId = objId;
copied = false;
}
/**
* Copy constructor used to copy from read to write
*/
public DataValidation(DataValidation dv,
ExternalSheet es,
WorkbookMethods wm,
WorkbookSettings ws) {
workbook = wm;
externalSheet = es;
workbookSettings = ws;
copied = true;
validityList = new DataValidityListRecord(dv.getDataValidityList());
validitySettings = new ArrayList();
DataValiditySettingsRecord[] settings = dv.getDataValiditySettings();
for (int i = 0; i < settings.length; i++) {
validitySettings.add(new DataValiditySettingsRecord(settings[i],
externalSheet,
workbook,
workbookSettings));
}
}
/**
* Adds a new settings object to this data validation
*/
public void add(DataValiditySettingsRecord dvsr) {
validitySettings.add(dvsr);
dvsr.setDataValidation(this);
if (copied) {
// adding a writable dv record to a copied validity list
Assert.verify(validityList != null);
validityList.dvAdded();
}
}
/**
* Accessor for the validity list. Used when copying sheets
*/
public DataValidityListRecord getDataValidityList() {
return validityList;
}
/**
* Accessor for the validity settings. Used when copying sheets
*/
public DataValiditySettingsRecord[] getDataValiditySettings() {
DataValiditySettingsRecord[] dvlr = new DataValiditySettingsRecord[0];
return (DataValiditySettingsRecord[]) validitySettings.toArray(dvlr);
}
/**
* Writes out the data validation
*
* @param outputFile the output file
* @throws IOException
*/
public void write(File outputFile) throws IOException {
if (validitySettings.size() > MAX_NO_OF_VALIDITY_SETTINGS) {
logger.warn("Maximum number of data validations exceeded - " +
"truncating...");
validitySettings = new ArrayList
(validitySettings.subList(0, MAX_NO_OF_VALIDITY_SETTINGS - 1));
Assert.verify(validitySettings.size() <= MAX_NO_OF_VALIDITY_SETTINGS);
}
if (validityList == null) {
DValParser dvp = new DValParser(comboBoxObjectId,
validitySettings.size());
validityList = new DataValidityListRecord(dvp);
}
if (!validityList.hasDVRecords()) {
return;
}
outputFile.write(validityList);
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dvsr = (DataValiditySettingsRecord) i.next();
outputFile.write(dvsr);
}
}
/**
* Inserts a row
*
* @param row the inserted row
*/
public void insertRow(int row) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
dv.insertRow(row);
}
}
/**
* Removes row
*
* @param row the row to be removed
*/
public void removeRow(int row) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
if (dv.getFirstRow() == row && dv.getLastRow() == row) {
i.remove();
validityList.dvRemoved();
} else {
dv.removeRow(row);
}
}
}
/**
* Inserts a column
*
* @param col the inserted column
*/
public void insertColumn(int col) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
dv.insertColumn(col);
}
}
/**
* Removes a column
*
* @param col the inserted column
*/
public void removeColumn(int col) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
if (dv.getFirstColumn() == col && dv.getLastColumn() == col) {
i.remove();
validityList.dvRemoved();
} else {
dv.removeColumn(col);
}
}
}
/**
* Removes the data validation for a specific cell
*
* @param col the column
* @param row the row
*/
public void removeDataValidation(int col, int row) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
if (dv.getFirstColumn() == col && dv.getLastColumn() == col &&
dv.getFirstRow() == row && dv.getLastRow() == row) {
i.remove();
validityList.dvRemoved();
break;
}
}
}
/**
* Removes the data validation for a specific cell
*
* @param col1 the first column
* @param row1 the first row
*/
public void removeSharedDataValidation(int col1, int row1,
int col2, int row2) {
for (Iterator i = validitySettings.iterator(); i.hasNext(); ) {
DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next();
if (dv.getFirstColumn() == col1 && dv.getLastColumn() == col2 &&
dv.getFirstRow() == row1 && dv.getLastRow() == row2) {
i.remove();
validityList.dvRemoved();
break;
}
}
}
/**
* Used during the copy process to retrieve the validity settings for
* a particular cell
*/
public DataValiditySettingsRecord getDataValiditySettings(int col, int row) {
boolean found = false;
DataValiditySettingsRecord foundRecord = null;
for (Iterator i = validitySettings.iterator(); i.hasNext() && !found; ) {
DataValiditySettingsRecord dvsr = (DataValiditySettingsRecord) i.next();
if (dvsr.getFirstColumn() == col && dvsr.getFirstRow() == row) {
found = true;
foundRecord = dvsr;
}
}
return foundRecord;
}
/**
* Accessor for the combo box, used when copying sheets
*/
public int getComboBoxObjectId() {
return comboBoxObjectId;
}
}

@ -0,0 +1,151 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Record containing the list of data validation settings for a given sheet
*/
public class DataValidityListRecord extends WritableRecordData {
private static final Logger logger = Logger.getLogger
(DataValidityListRecord.class);
/**
* The number of settings records associated with this list
*/
private int numSettings;
/**
* The object id of the associated down arrow
*/
private int objectId;
/**
* The dval parser
*/
private DValParser dvalParser;
/**
* The data
*/
private byte[] data;
/**
* Constructor
*/
public DataValidityListRecord(Record t) {
super(t);
data = getRecord().getData();
objectId = IntegerHelper.getInt(data[10], data[11], data[12], data[13]);
numSettings = IntegerHelper.getInt(data[14], data[15], data[16], data[17]);
}
/**
* Constructor called when generating a data validity list from the API
*/
public DataValidityListRecord(DValParser dval) {
super(Type.DVAL);
dvalParser = dval;
}
/**
* Copy constructor
*
* @param dvlr the record copied from a read only sheet
*/
DataValidityListRecord(DataValidityListRecord dvlr) {
super(Type.DVAL);
data = dvlr.getData();
}
/**
* Accessor for the number of settings records associated with this list
*/
int getNumberOfSettings() {
return numSettings;
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
if (dvalParser == null) {
return data;
}
return dvalParser.getData();
}
/**
* Called when a remove row or column results in one of DV records being
* removed
*/
void dvRemoved() {
if (dvalParser == null) {
dvalParser = new DValParser(data);
}
dvalParser.dvRemoved();
}
/**
* Called when a writable DV record is added to a copied validity list
*/
void dvAdded() {
if (dvalParser == null) {
dvalParser = new DValParser(data);
}
dvalParser.dvAdded();
}
/**
* Accessor for the number of DV records
*
* @return the number of DV records for this list
*/
public boolean hasDVRecords() {
if (dvalParser == null) {
return true;
}
return dvalParser.getNumberOfDVRecords() > 0;
}
/**
* Accessor for the object id
*
* @return the object id
*/
public int getObjectId() {
if (dvalParser == null) {
return objectId;
}
return dvalParser.getObjectId();
}
}

@ -0,0 +1,282 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.WorkbookSettings;
import jxl.biff.formula.ExternalSheet;
import jxl.biff.formula.FormulaException;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Data validity settings. Contains an individual Data validation (DV).
* All the computationa work is delegated to the DVParser object
*/
public class DataValiditySettingsRecord extends WritableRecordData {
/**
* The logger
*/
private static final Logger logger =
Logger.getLogger(DataValiditySettingsRecord.class);
/**
* The binary data
*/
private byte[] data;
/**
* The reader
*/
private DVParser dvParser;
/**
* Handle to the workbook
*/
private WorkbookMethods workbook;
/**
* Handle to the externalSheet
*/
private ExternalSheet externalSheet;
/**
* Handle to the workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* Handle to the data validation record
*/
private DataValidation dataValidation;
/**
* Constructor
*/
public DataValiditySettingsRecord(Record t,
ExternalSheet es,
WorkbookMethods wm,
WorkbookSettings ws) {
super(t);
data = t.getData();
externalSheet = es;
workbook = wm;
workbookSettings = ws;
}
/**
* Copy constructor
*/
DataValiditySettingsRecord(DataValiditySettingsRecord dvsr) {
super(Type.DV);
data = dvsr.getData();
}
/**
* Constructor used when copying sheets
*
* @param dvsr the record copied from a writable sheet
*/
DataValiditySettingsRecord(DataValiditySettingsRecord dvsr,
ExternalSheet es,
WorkbookMethods w,
WorkbookSettings ws) {
super(Type.DV);
workbook = w;
externalSheet = es;
workbookSettings = ws;
Assert.verify(w != null);
Assert.verify(es != null);
data = new byte[dvsr.data.length];
System.arraycopy(dvsr.data, 0, data, 0, data.length);
}
/**
* Constructor called when the API creates a writable data validation
*
* @param dvsr the record copied from a writable sheet
*/
public DataValiditySettingsRecord(DVParser dvp) {
super(Type.DV);
dvParser = dvp;
}
/**
* Initializes the dvParser
*/
private void initialize() {
if (dvParser == null) {
dvParser = new DVParser(data, externalSheet,
workbook, workbookSettings);
}
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
if (dvParser == null) {
return data;
}
return dvParser.getData();
}
/**
* Inserts a row
*
* @param row the row to insert
*/
public void insertRow(int row) {
if (dvParser == null) {
initialize();
}
dvParser.insertRow(row);
}
/**
* Removes a row
*
* @param row the row to insert
*/
public void removeRow(int row) {
if (dvParser == null) {
initialize();
}
dvParser.removeRow(row);
}
/**
* Inserts a row
*
* @param col the row to insert
*/
public void insertColumn(int col) {
if (dvParser == null) {
initialize();
}
dvParser.insertColumn(col);
}
/**
* Removes a column
*
* @param col the row to insert
*/
public void removeColumn(int col) {
if (dvParser == null) {
initialize();
}
dvParser.removeColumn(col);
}
/**
* Accessor for first column
*
* @return the first column
*/
public int getFirstColumn() {
if (dvParser == null) {
initialize();
}
return dvParser.getFirstColumn();
}
/**
* Accessor for the last column
*
* @return the last column
*/
public int getLastColumn() {
if (dvParser == null) {
initialize();
}
return dvParser.getLastColumn();
}
/**
* Accessor for first row
*
* @return the first row
*/
public int getFirstRow() {
if (dvParser == null) {
initialize();
}
return dvParser.getFirstRow();
}
/**
* Accessor for the last row
*
* @return the last row
*/
public int getLastRow() {
if (dvParser == null) {
initialize();
}
return dvParser.getLastRow();
}
/**
* Sets the handle to the data validation record
*
* @param dv the data validation
*/
void setDataValidation(DataValidation dv) {
dataValidation = dv;
}
/**
* Gets the DVParser. This is used when doing a deep copy of cells
* on the writable side of things
*/
DVParser getDVParser() {
return dvParser;
}
public String getValidationFormula() {
try {
if (dvParser == null) {
initialize();
}
return dvParser.getValidationFormula();
} catch (FormulaException e) {
logger.warn("Cannot read drop down range " + e.getMessage());
return "";
}
}
}

@ -0,0 +1,55 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* The interface implemented by the various number and date format styles.
* The methods on this interface are called internally when generating a
* spreadsheet
*/
public interface DisplayFormat {
/**
* Accessor for the index style of this format
*
* @return the index for this format
*/
int getFormatIndex();
/**
* Accessor to see whether this format has been initialized
*
* @return TRUE if initialized, FALSE otherwise
*/
boolean isInitialized();
/**
* Initializes this format with the specified index number
*
* @param pos the position of this format record in the workbook
*/
void initialize(int pos);
/**
* Accessor to determine whether or not this format is built in
*
* @return TRUE if this format is a built in format, FALSE otherwise
*/
boolean isBuiltIn();
}

@ -0,0 +1,84 @@
/*********************************************************************
*
* Copyright (C) 2001 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Class to help handle doubles
*/
public class DoubleHelper {
/**
* Private constructor to prevent instantiation
*/
private DoubleHelper() {
}
/**
* Gets the IEEE value from the byte array passed in
*
* @param pos the position in the data block which contains the double value
* @param data the data block containing the raw bytes
* @return the double value converted from the raw data
*/
public static double getIEEEDouble(byte[] data, int pos) {
int num1 = IntegerHelper.getInt(data[pos], data[pos + 1],
data[pos + 2], data[pos + 3]);
int num2 = IntegerHelper.getInt(data[pos + 4], data[pos + 5],
data[pos + 6], data[pos + 7]);
// Long.parseLong doesn't like the sign bit, so have to extract this
// information and put it in at the end. (Acknowledgment: thanks
// to Ruben for pointing this out)
boolean negative = ((num2 & 0x80000000) != 0);
// Thanks to Lyle for the following improved IEEE double processing
long val = ((num2 & 0x7fffffff) * 0x100000000L) +
(num1 < 0 ? 0x100000000L + num1 : num1);
double value = Double.longBitsToDouble(val);
if (negative) {
value = -value;
}
return value;
}
/**
* Puts the IEEE representation of the double provided into the array
* at the designated position
*
* @param target the data block into which the binary representation is to
* be placed
* @param pos the position in target in which to place the bytes
* @param d the double value to convert to raw bytes
*/
public static void getIEEEBytes(double d, byte[] target, int pos) {
long val = Double.doubleToLongBits(d);
target[pos] = (byte) (val & 0xff);
target[pos + 1] = (byte) ((val & 0xff00) >> 8);
target[pos + 2] = (byte) ((val & 0xff0000) >> 16);
target[pos + 3] = (byte) ((val & 0xff000000) >> 24);
target[pos + 4] = (byte) ((val & 0xff00000000L) >> 32);
target[pos + 5] = (byte) ((val & 0xff0000000000L) >> 40);
target[pos + 6] = (byte) ((val & 0xff000000000000L) >> 48);
target[pos + 7] = (byte) ((val & 0xff00000000000000L) >> 56);
}
}

@ -0,0 +1,207 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.CellFeatures;
import jxl.CellType;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.CellFormat;
import jxl.format.VerticalAlignment;
import jxl.write.WritableCell;
import jxl.write.WritableCellFeatures;
/**
* An empty cell. Represents an empty, as opposed to a blank cell
* in the workbook
*/
public class EmptyCell implements WritableCell {
/**
* The row of this empty cell
*/
private final int row;
/**
* The column number of this empty cell
*/
private final int col;
/**
* Constructs an empty cell at the specified position
*
* @param c the zero based column
* @param r the zero based row
*/
public EmptyCell(int c, int r) {
row = r;
col = c;
}
/**
* Returns the row number of this cell
*
* @return the row number of this cell
*/
public int getRow() {
return row;
}
/**
* Returns the column number of this cell
*
* @return the column number of this cell
*/
public int getColumn() {
return col;
}
/**
* Returns the content type of this cell
*
* @return the content type for this cell
*/
public CellType getType() {
return CellType.EMPTY;
}
/**
* Quick and dirty function to return the contents of this cell as a string.
*
* @return an empty string
*/
public String getContents() {
return "";
}
/**
* Accessor for the format which is applied to this cell
*
* @return the format applied to this cell
*/
public CellFormat getCellFormat() {
return null;
}
/**
* Dummy override
*
* @param cf dummy
*/
public void setCellFormat(CellFormat cf) {
}
/**
* Dummy override
*
* @param cf dummy
* @deprecated
*/
public void setCellFormat(jxl.CellFormat cf) {
}
/**
* Dummy override
*
* @param flag dummy
*/
public void setLocked(boolean flag) {
}
/**
* Dummy override
*
* @param align dummy
*/
public void setAlignment(Alignment align) {
}
/**
* Dummy override
*
* @param valign dummy
*/
public void setVerticalAlignment(VerticalAlignment valign) {
}
/**
* Dummy override
*
* @param line dummy
* @param border dummy
*/
public void setBorder(Border border, BorderLineStyle line) {
}
/**
* Indicates whether or not this cell is hidden, by virtue of either
* the entire row or column being collapsed
*
* @return TRUE if this cell is hidden, FALSE otherwise
*/
public boolean isHidden() {
return false;
}
/**
* Dummy override
*
* @param flag the hidden flag
*/
public void setHidden(boolean flag) {
}
/**
* Implementation of the deep copy function
*
* @param c the column which the new cell will occupy
* @param r the row which the new cell will occupy
* @return a copy of this cell, which can then be added to the sheet
*/
public WritableCell copyTo(int c, int r) {
return new EmptyCell(c, r);
}
/**
* Accessor for the cell features
*
* @return the cell features or NULL if this cell doesn't have any
*/
public CellFeatures getCellFeatures() {
return null;
}
/**
* Accessor for the cell features
*/
public void setCellFeatures(WritableCellFeatures wcf) {
}
/**
* Accessor for the cell features
*
* @return the cell features or NULL if this cell doesn't have any
*/
public WritableCellFeatures getWritableCellFeatures() {
return null;
}
}

@ -0,0 +1,117 @@
/*********************************************************************
*
* Copyright (C) 2005 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.WorkbookSettings;
import jxl.common.Logger;
/**
* Helper to get the Microsoft encoded URL from the given string
*/
public class EncodedURLHelper {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(EncodedURLHelper.class);
// The control codes
private static final byte msDosDriveLetter = 0x01;
private static final byte sameDrive = 0x02;
private static final byte endOfSubdirectory = 0x03;
private static final byte parentDirectory = 0x04;
private static final byte unencodedUrl = 0x05;
public static byte[] getEncodedURL(String s, WorkbookSettings ws) {
if (s.startsWith("http:")) {
return getURL(s, ws);
} else {
return getFile(s, ws);
}
}
private static byte[] getFile(String s, WorkbookSettings ws) {
ByteArray byteArray = new ByteArray();
int pos = 0;
if (s.charAt(1) == ':') {
// we have a drive letter
byteArray.add(msDosDriveLetter);
byteArray.add((byte) s.charAt(0));
pos = 2;
} else if (s.charAt(pos) == '\\' ||
s.charAt(pos) == '/') {
byteArray.add(sameDrive);
}
while (s.charAt(pos) == '\\' ||
s.charAt(pos) == '/') {
pos++;
}
while (pos < s.length()) {
int nextSepIndex1 = s.indexOf('/', pos);
int nextSepIndex2 = s.indexOf('\\', pos);
int nextSepIndex = 0;
String nextFileNameComponent = null;
if (nextSepIndex1 != -1 && nextSepIndex2 != -1) {
// choose the smallest (ie. nearest) separator
nextSepIndex = Math.min(nextSepIndex1, nextSepIndex2);
} else if (nextSepIndex1 == -1 || nextSepIndex2 == -1) {
// chose the maximum separator
nextSepIndex = Math.max(nextSepIndex1, nextSepIndex2);
}
if (nextSepIndex == -1) {
// no more separators
nextFileNameComponent = s.substring(pos);
pos = s.length();
} else {
nextFileNameComponent = s.substring(pos, nextSepIndex);
pos = nextSepIndex + 1;
}
if (nextFileNameComponent.equals(".")) {
// current directory - do nothing
} else if (nextFileNameComponent.equals("..")) {
// parent directory
byteArray.add(parentDirectory);
} else {
// add the filename component
byteArray.add(StringHelper.getBytes(nextFileNameComponent,
ws));
}
if (pos < s.length()) {
byteArray.add(endOfSubdirectory);
}
}
return byteArray.getBytes();
}
private static byte[] getURL(String s, WorkbookSettings ws) {
ByteArray byteArray = new ByteArray();
byteArray.add(unencodedUrl);
byteArray.add((byte) s.length());
byteArray.add(StringHelper.getBytes(s, ws));
return byteArray.getBytes();
}
}

@ -0,0 +1,56 @@
/*********************************************************************
*
* Copyright (C) 2007 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Range information for conditional formatting
*/
public class FilterModeRecord extends WritableRecordData {
// The logger
private static final Logger logger = Logger.getLogger(FilterModeRecord.class);
/**
* The data
*/
private final byte[] data;
/**
* Constructor
*/
public FilterModeRecord(Record t) {
super(t);
data = getRecord().getData();
}
/**
* Retrieves the data for output to binary file
*
* @return the data to be written
*/
public byte[] getData() {
return data;
}
}

@ -0,0 +1,501 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.WorkbookSettings;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.format.Colour;
import jxl.format.Font;
import jxl.format.ScriptStyle;
import jxl.format.UnderlineStyle;
import jxl.read.biff.Record;
/**
* A record containing the necessary data for the font information
*/
public class FontRecord extends WritableRecordData implements Font {
public static final Biff7 biff7 = new Biff7();
/**
* The conversion factor between microsoft internal units and point size
*/
private static final int EXCEL_UNITS_PER_POINT = 20;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(FontRecord.class);
/**
* The point height of this font
*/
private int pointHeight;
/**
* The index into the colour palette
*/
private int colourIndex;
/**
* The bold weight for this font (normal or bold)
*/
private int boldWeight;
/**
* The style of the script (italic or normal)
*/
private int scriptStyle;
/**
* The underline style for this font (none, single, double etc)
*/
private int underlineStyle;
/**
* The font family
*/
private byte fontFamily;
/**
* The character set
*/
private byte characterSet;
/**
* Indicates whether or not this font is italic
*/
private boolean italic;
/**
* Indicates whether or not this font is struck out
*/
private boolean struckout;
/**
* The name of this font
*/
private final String name;
/**
* Flag to indicate whether the derived data (such as the font index) has
* been initialized or not
*/
private boolean initialized;
/**
* The index of this font in the font list
*/
private int fontIndex;
/**
* Constructor, used when creating a new font for writing out.
*
* @param bold the bold indicator
* @param ps the point size
* @param us the underline style
* @param fn the name
* @param it italicised indicator
* @param ss the script style
* @param ci the colour index
*/
protected FontRecord(String fn, int ps, int bold, boolean it,
int us, int ci, int ss) {
super(Type.FONT);
boldWeight = bold;
underlineStyle = us;
name = fn;
pointHeight = ps;
italic = it;
scriptStyle = ss;
colourIndex = ci;
initialized = false;
struckout = false;
}
/**
* Constructs this object from the raw data. Used when reading in a
* format record
*
* @param t the raw data
* @param ws the workbook settings
*/
public FontRecord(Record t, WorkbookSettings ws) {
super(t);
byte[] data = getRecord().getData();
pointHeight = IntegerHelper.getInt(data[0], data[1]) /
EXCEL_UNITS_PER_POINT;
colourIndex = IntegerHelper.getInt(data[4], data[5]);
boldWeight = IntegerHelper.getInt(data[6], data[7]);
scriptStyle = IntegerHelper.getInt(data[8], data[9]);
underlineStyle = data[10];
fontFamily = data[11];
characterSet = data[12];
initialized = false;
if ((data[2] & 0x02) != 0) {
italic = true;
}
if ((data[2] & 0x08) != 0) {
struckout = true;
}
int numChars = data[14];
if (data[15] == 0) {
name = StringHelper.getString(data, numChars, 16, ws);
} else if (data[15] == 1) {
name = StringHelper.getUnicodeString(data, numChars, 16);
} else {
// Some font names don't have the unicode indicator
name = StringHelper.getString(data, numChars, 15, ws);
}
}
/**
* Constructs this object from the raw data. Used when reading in a
* format record
*
* @param t the raw data
* @param ws the workbook settings
* @param dummy dummy overload
*/
public FontRecord(Record t, WorkbookSettings ws, Biff7 dummy) {
super(t);
byte[] data = getRecord().getData();
pointHeight = IntegerHelper.getInt(data[0], data[1]) /
EXCEL_UNITS_PER_POINT;
colourIndex = IntegerHelper.getInt(data[4], data[5]);
boldWeight = IntegerHelper.getInt(data[6], data[7]);
scriptStyle = IntegerHelper.getInt(data[8], data[9]);
underlineStyle = data[10];
fontFamily = data[11];
initialized = false;
if ((data[2] & 0x02) != 0) {
italic = true;
}
if ((data[2] & 0x08) != 0) {
struckout = true;
}
int numChars = data[14];
name = StringHelper.getString(data, numChars, 15, ws);
}
/**
* Publicly available copy constructor
*
* @param f the font to copy
*/
protected FontRecord(Font f) {
super(Type.FONT);
Assert.verify(f != null);
pointHeight = f.getPointSize();
colourIndex = f.getColour().getValue();
boldWeight = f.getBoldWeight();
scriptStyle = f.getScriptStyle().getValue();
underlineStyle = f.getUnderlineStyle().getValue();
italic = f.isItalic();
name = f.getName();
struckout = f.isStruckout();
initialized = false;
}
/**
* Gets the byte data for writing out
*
* @return the raw data
*/
public byte[] getData() {
byte[] data = new byte[16 + name.length() * 2];
// Excel expects font heights in 1/20ths of a point
IntegerHelper.getTwoBytes(pointHeight * EXCEL_UNITS_PER_POINT, data, 0);
// Set the font attributes to be zero for now
if (italic) {
data[2] |= 0x2;
}
if (struckout) {
data[2] |= 0x08;
}
// Set the index to the colour palette
IntegerHelper.getTwoBytes(colourIndex, data, 4);
// Bold style
IntegerHelper.getTwoBytes(boldWeight, data, 6);
// Script style
IntegerHelper.getTwoBytes(scriptStyle, data, 8);
// Underline style
data[10] = (byte) underlineStyle;
// Set the font family to be 0
data[11] = fontFamily;
// Set the character set to be zero
data[12] = characterSet;
// Set the reserved bit to be zero
data[13] = 0;
// Set the length of the font name
data[14] = (byte) name.length();
data[15] = (byte) 1;
// Copy in the string
StringHelper.getUnicodeBytes(name, data, 16);
return data;
}
/**
* Accessor to see whether this object is initialized or not.
*
* @return TRUE if this font record has been initialized, FALSE otherwise
*/
public final boolean isInitialized() {
return initialized;
}
/**
* Sets the font index of this record. Called from the FormattingRecords
* object
*
* @param pos the position of this font in the workbooks font list
*/
public final void initialize(int pos) {
fontIndex = pos;
initialized = true;
}
/**
* Resets the initialize flag. This is called by the constructor of
* WritableWorkbookImpl to reset the statically declared fonts
*/
public final void uninitialize() {
initialized = false;
}
/**
* Accessor for the font index
*
* @return the font index
*/
public final int getFontIndex() {
return fontIndex;
}
/**
* Sets the point size for this font, if the font hasn't been initialized
*
* @param ps the point size
*/
protected void setFontPointSize(int ps) {
Assert.verify(!initialized);
pointHeight = ps;
}
/**
* Gets the point size for this font, if the font hasn't been initialized
*
* @return the point size
*/
public int getPointSize() {
return pointHeight;
}
/**
* Sets the bold style for this font, if the font hasn't been initialized
*
* @param bs the bold style
*/
protected void setFontBoldStyle(int bs) {
Assert.verify(!initialized);
boldWeight = bs;
}
/**
* Gets the bold weight for this font
*
* @return the bold weight for this font
*/
public int getBoldWeight() {
return boldWeight;
}
/**
* Sets the italic indicator for this font, if the font hasn't been
* initialized
*
* @param i the italic flag
*/
protected void setFontItalic(boolean i) {
Assert.verify(!initialized);
italic = i;
}
/**
* Returns the italic flag
*
* @return TRUE if this font is italic, FALSE otherwise
*/
public boolean isItalic() {
return italic;
}
/**
* Sets the underline style for this font, if the font hasn't been
* initialized
*
* @param us the underline style
*/
protected void setFontUnderlineStyle(int us) {
Assert.verify(!initialized);
underlineStyle = us;
}
/**
* Gets the underline style for this font
*
* @return the underline style
*/
public UnderlineStyle getUnderlineStyle() {
return UnderlineStyle.getStyle(underlineStyle);
}
/**
* Sets the colour for this font, if the font hasn't been
* initialized
*
* @param c the colour
*/
protected void setFontColour(int c) {
Assert.verify(!initialized);
colourIndex = c;
}
/**
* Gets the colour for this font
*
* @return the colour
*/
public Colour getColour() {
return Colour.getInternalColour(colourIndex);
}
/**
* Sets the script style (eg. superscript, subscript) for this font,
* if the font hasn't been initialized
*
* @param ss the colour
*/
protected void setFontScriptStyle(int ss) {
Assert.verify(!initialized);
scriptStyle = ss;
}
/**
* Gets the script style
*
* @return the script style
*/
public ScriptStyle getScriptStyle() {
return ScriptStyle.getStyle(scriptStyle);
}
/**
* Gets the name of this font
*
* @return the name of this font
*/
public String getName() {
return name;
}
/**
* Standard hash code method
*
* @return the hash code for this object
*/
public int hashCode() {
return name.hashCode();
}
/**
* Standard equals method
*
* @param o the object to compare
* @return TRUE if the objects are equal, FALSE otherwise
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof FontRecord)) {
return false;
}
FontRecord font = (FontRecord) o;
return pointHeight == font.pointHeight &&
colourIndex == font.colourIndex &&
boldWeight == font.boldWeight &&
scriptStyle == font.scriptStyle &&
underlineStyle == font.underlineStyle &&
italic == font.italic &&
struckout == font.struckout &&
fontFamily == font.fontFamily &&
characterSet == font.characterSet &&
name.equals(font.name);
}
/**
* Accessor for the strike out flag
*
* @return TRUE if this font is struck out, FALSE otherwise
*/
public boolean isStruckout() {
return struckout;
}
/**
* Sets the struck out flag
*
* @param os TRUE if the font is struck out, false otherwise
*/
protected void setFontStruckout(boolean os) {
struckout = os;
}
/**
* Dummy indicators for overloading the constructor
*/
private static class Biff7 {
}
}

@ -0,0 +1,162 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import jxl.common.Assert;
import jxl.write.biff.File;
/**
* A container for the list of fonts used in this workbook
*/
public class Fonts {
/**
* The default number of fonts
*/
private static final int numDefaultFonts = 4;
/**
* The list of fonts
*/
private ArrayList fonts;
/**
* Constructor
*/
public Fonts() {
fonts = new ArrayList();
}
/**
* Adds a font record to this workbook. If the FontRecord passed in has not
* been initialized, then its font index is determined based upon the size
* of the fonts list. The FontRecord's initialized method is called, and
* it is added to the list of fonts.
*
* @param f the font to add
*/
public void addFont(FontRecord f) {
if (!f.isInitialized()) {
int pos = fonts.size();
// Remember that the pos with index 4 is skipped
if (pos >= 4) {
pos++;
}
f.initialize(pos);
fonts.add(f);
}
}
/**
* Used by FormattingRecord for retrieving the fonts for the
* hardcoded styles
*
* @param index the index of the font to return
* @return the font with the specified font index
*/
public FontRecord getFont(int index) {
// remember to allow for the fact that font index 4 is not used
if (index > 4) {
index--;
}
return (FontRecord) fonts.get(index);
}
/**
* Writes out the list of fonts
*
* @param outputFile the compound file to write the data to
* @throws IOException
*/
public void write(File outputFile) throws IOException {
Iterator i = fonts.iterator();
FontRecord font = null;
while (i.hasNext()) {
font = (FontRecord) i.next();
outputFile.write(font);
}
}
/**
* Rationalizes all the fonts, removing any duplicates
*
* @return the mappings between new indexes and old ones
*/
IndexMapping rationalize() {
IndexMapping mapping = new IndexMapping(fonts.size() + 1);
// allow for skipping record 4
ArrayList newfonts = new ArrayList();
FontRecord fr = null;
int numremoved = 0;
// Preserve the default fonts
for (int i = 0; i < numDefaultFonts; i++) {
fr = (FontRecord) fonts.get(i);
newfonts.add(fr);
mapping.setMapping(fr.getFontIndex(), fr.getFontIndex());
}
// Now do the rest
Iterator it = null;
FontRecord fr2 = null;
boolean duplicate = false;
for (int i = numDefaultFonts; i < fonts.size(); i++) {
fr = (FontRecord) fonts.get(i);
// Compare to all the fonts currently on the list
duplicate = false;
it = newfonts.iterator();
while (it.hasNext() && !duplicate) {
fr2 = (FontRecord) it.next();
if (fr.equals(fr2)) {
duplicate = true;
mapping.setMapping(fr.getFontIndex(),
mapping.getNewIndex(fr2.getFontIndex()));
numremoved++;
}
}
if (!duplicate) {
// Add to the new list
newfonts.add(fr);
int newindex = fr.getFontIndex() - numremoved;
Assert.verify(newindex > 4);
mapping.setMapping(fr.getFontIndex(), newindex);
}
}
// Iterate through the remaining fonts, updating all the font indices
it = newfonts.iterator();
while (it.hasNext()) {
fr = (FontRecord) it.next();
fr.initialize(mapping.getNewIndex(fr.getFontIndex()));
}
fonts = newfonts;
return mapping;
}
}

@ -0,0 +1,551 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import jxl.WorkbookSettings;
import jxl.common.Logger;
import jxl.format.Format;
import jxl.read.biff.Record;
/**
* A non-built in format record
*/
public class FormatRecord extends WritableRecordData
implements DisplayFormat, Format {
public static final BiffType biff8 = new BiffType();
public static final BiffType biff7 = new BiffType();
/**
* The logger
*/
public static Logger logger = Logger.getLogger(FormatRecord.class);
/**
* The date strings to look for
*/
private static final String[] dateStrings = new String[]
{
"dd",
"mm",
"yy",
"hh",
"ss",
"m/",
"/d"
};
/**
* Initialized flag
*/
private boolean initialized;
/**
* The raw data
*/
private byte[] data;
/**
* The index code
*/
private int indexCode;
/**
* The formatting string
*/
private String formatString;
/**
* Indicates whether this is a date formatting record
*/
private boolean date;
/**
* Indicates whether this a number formatting record
*/
private boolean number;
/**
* The format object
*/
private java.text.Format format;
/**
* Constructor invoked when copying sheets
*
* @param fmt the format string
* @param refno the index code
*/
FormatRecord(String fmt, int refno) {
super(Type.FORMAT);
formatString = fmt;
indexCode = refno;
initialized = true;
}
/**
* Constructor used by writable formats
*/
protected FormatRecord() {
super(Type.FORMAT);
initialized = false;
}
/**
* Copy constructor - can be invoked by public access
*
* @param fr the format to copy
*/
protected FormatRecord(FormatRecord fr) {
super(Type.FORMAT);
initialized = false;
formatString = fr.formatString;
date = fr.date;
number = fr.number;
// format = (java.text.Format) fr.format.clone();
}
/**
* Constructs this object from the raw data. Used when reading in a
* format record
*
* @param t the raw data
* @param ws the workbook settings
* @param biffType biff type dummy overload
*/
public FormatRecord(Record t, WorkbookSettings ws, BiffType biffType) {
super(t);
byte[] data = getRecord().getData();
indexCode = IntegerHelper.getInt(data[0], data[1]);
initialized = true;
if (biffType == biff8) {
int numchars = IntegerHelper.getInt(data[2], data[3]);
if (data[4] == 0) {
formatString = StringHelper.getString(data, numchars, 5, ws);
} else {
formatString = StringHelper.getUnicodeString(data, numchars, 5);
}
} else {
int numchars = data[2];
byte[] chars = new byte[numchars];
System.arraycopy(data, 3, chars, 0, chars.length);
formatString = new String(chars);
}
date = false;
number = false;
// First see if this is a date format
for (int i = 0; i < dateStrings.length; i++) {
String dateString = dateStrings[i];
if (formatString.indexOf(dateString) != -1 ||
formatString.indexOf(dateString.toUpperCase()) != -1) {
date = true;
break;
}
}
// See if this is number format - look for the # or 0 characters
if (!date) {
if (formatString.indexOf('#') != -1 ||
formatString.indexOf('0') != -1) {
number = true;
}
}
}
/**
* Used to get the data when writing out the format record
*
* @return the raw data
*/
public byte[] getData() {
data = new byte[formatString.length() * 2 + 3 + 2];
IntegerHelper.getTwoBytes(indexCode, data, 0);
IntegerHelper.getTwoBytes(formatString.length(), data, 2);
data[4] = (byte) 1; // unicode indicator
StringHelper.getUnicodeBytes(formatString, data, 5);
return data;
}
/**
* Gets the format index of this record
*
* @return the format index of this record
*/
public int getFormatIndex() {
return indexCode;
}
/**
* Accessor to see whether this object is initialized or not.
*
* @return TRUE if this font record has been initialized, FALSE otherwise
*/
public boolean isInitialized() {
return initialized;
}
/**
* Sets the index of this record. Called from the FormattingRecords
* object
*
* @param pos the position of this font in the workbooks font list
*/
public void initialize(int pos) {
indexCode = pos;
initialized = true;
}
/**
* Replaces all instances of search with replace in the input. Used for
* replacing microsoft number formatting characters with java equivalents
*
* @param input the format string
* @param search the Excel character to be replaced
* @param replace the java equivalent
* @return the input string with the specified substring replaced
*/
protected final String replace(String input, String search, String replace) {
String fmtstr = input;
int pos = fmtstr.indexOf(search);
while (pos != -1) {
StringBuffer tmp = new StringBuffer(fmtstr.substring(0, pos));
tmp.append(replace);
tmp.append(fmtstr.substring(pos + search.length()));
fmtstr = tmp.toString();
pos = fmtstr.indexOf(search);
}
return fmtstr;
}
/**
* Sees if this format is a date format
*
* @return TRUE if this format is a date
*/
public final boolean isDate() {
return date;
}
/**
* Sees if this format is a number format
*
* @return TRUE if this format is a number
*/
public final boolean isNumber() {
return number;
}
/**
* Gets the java equivalent number format for the formatString
*
* @return The java equivalent of the number format for this object
*/
public final NumberFormat getNumberFormat() {
if (format != null && format instanceof NumberFormat) {
return (NumberFormat) format;
}
try {
String fs = formatString;
// Replace the Excel formatting characters with java equivalents
fs = replace(fs, "E+", "E");
fs = replace(fs, "_)", "");
fs = replace(fs, "_", "");
fs = replace(fs, "[Red]", "");
fs = replace(fs, "\\", "");
format = new DecimalFormat(fs);
} catch (IllegalArgumentException e) {
// Something went wrong with the date format - fail silently
// and return a default value
format = new DecimalFormat("#.###");
}
return (NumberFormat) format;
}
/**
* Gets the java equivalent date format for the formatString
*
* @return The java equivalent of the date format for this object
*/
public final DateFormat getDateFormat() {
if (format != null && format instanceof DateFormat) {
return (DateFormat) format;
}
String fmt = formatString;
// Replace the AM/PM indicator with an a
int pos = fmt.indexOf("AM/PM");
while (pos != -1) {
StringBuffer sb = new StringBuffer(fmt.substring(0, pos));
sb.append('a');
sb.append(fmt.substring(pos + 5));
fmt = sb.toString();
pos = fmt.indexOf("AM/PM");
}
// Replace ss.0 with ss.SSS (necessary to always specify milliseconds
// because of NT)
pos = fmt.indexOf("ss.0");
while (pos != -1) {
StringBuffer sb = new StringBuffer(fmt.substring(0, pos));
sb.append("ss.SSS");
// Keep going until we run out of zeros
pos += 4;
while (pos < fmt.length() && fmt.charAt(pos) == '0') {
pos++;
}
sb.append(fmt.substring(pos));
fmt = sb.toString();
pos = fmt.indexOf("ss.0");
}
// Filter out the backslashes
StringBuffer sb = new StringBuffer();
for (int i = 0; i < fmt.length(); i++) {
if (fmt.charAt(i) != '\\') {
sb.append(fmt.charAt(i));
}
}
fmt = sb.toString();
// If the date format starts with anything inside square brackets then
// filter tham out
if (fmt.charAt(0) == '[') {
int end = fmt.indexOf(']');
if (end != -1) {
fmt = fmt.substring(end + 1);
}
}
// Get rid of some spurious characters that can creep in
fmt = replace(fmt, ";@", "");
// We need to convert the month indicator m, to upper case when we
// are dealing with dates
char[] formatBytes = fmt.toCharArray();
for (int i = 0; i < formatBytes.length; i++) {
if (formatBytes[i] == 'm') {
// Firstly, see if the preceding character is also an m. If so,
// copy that
if (i > 0 && (formatBytes[i - 1] == 'm' || formatBytes[i - 1] == 'M')) {
formatBytes[i] = formatBytes[i - 1];
} else {
// There is no easy way out. We have to deduce whether this an
// minute or a month? See which is closest out of the
// letters H d s or y
// First, h
int minuteDist = Integer.MAX_VALUE;
for (int j = i - 1; j > 0; j--) {
if (formatBytes[j] == 'h') {
minuteDist = i - j;
break;
}
}
for (int j = i + 1; j < formatBytes.length; j++) {
if (formatBytes[j] == 'h') {
minuteDist = Math.min(minuteDist, j - i);
break;
}
}
for (int j = i - 1; j > 0; j--) {
if (formatBytes[j] == 'H') {
minuteDist = i - j;
break;
}
}
for (int j = i + 1; j < formatBytes.length; j++) {
if (formatBytes[j] == 'H') {
minuteDist = Math.min(minuteDist, j - i);
break;
}
}
// Now repeat for s
for (int j = i - 1; j > 0; j--) {
if (formatBytes[j] == 's') {
minuteDist = Math.min(minuteDist, i - j);
break;
}
}
for (int j = i + 1; j < formatBytes.length; j++) {
if (formatBytes[j] == 's') {
minuteDist = Math.min(minuteDist, j - i);
break;
}
}
// We now have the distance of the closest character which could
// indicate the the m refers to a minute
// Repeat for d and y
int monthDist = Integer.MAX_VALUE;
for (int j = i - 1; j > 0; j--) {
if (formatBytes[j] == 'd') {
monthDist = i - j;
break;
}
}
for (int j = i + 1; j < formatBytes.length; j++) {
if (formatBytes[j] == 'd') {
monthDist = Math.min(monthDist, j - i);
break;
}
}
// Now repeat for y
for (int j = i - 1; j > 0; j--) {
if (formatBytes[j] == 'y') {
monthDist = Math.min(monthDist, i - j);
break;
}
}
for (int j = i + 1; j < formatBytes.length; j++) {
if (formatBytes[j] == 'y') {
monthDist = Math.min(monthDist, j - i);
break;
}
}
if (monthDist < minuteDist) {
// The month indicator is closer, so convert to a capital M
formatBytes[i] = Character.toUpperCase(formatBytes[i]);
} else if ((monthDist == minuteDist) &&
(monthDist != Integer.MAX_VALUE)) {
// They are equidistant. As a tie-breaker, take the formatting
// character which precedes the m
char ind = formatBytes[i - monthDist];
if (ind == 'y' || ind == 'd') {
// The preceding item indicates a month measure, so convert
formatBytes[i] = Character.toUpperCase(formatBytes[i]);
}
}
}
}
}
try {
this.format = new SimpleDateFormat(new String(formatBytes));
} catch (IllegalArgumentException e) {
// There was a spurious character - fail silently
this.format = new SimpleDateFormat("dd MM yyyy hh:mm:ss");
}
return (DateFormat) this.format;
}
/**
* Gets the index code, for use as a hash value
*
* @return the ifmt code for this cell
*/
public int getIndexCode() {
return indexCode;
}
/**
* Gets the formatting string.
*
* @return the excel format string
*/
public String getFormatString() {
return formatString;
}
/**
* Called by the immediate subclass to set the string
* once the Java-Excel replacements have been done
*
* @param s the format string
*/
protected final void setFormatString(String s) {
formatString = s;
}
/**
* Indicates whether this formula is a built in
*
* @return FALSE
*/
public boolean isBuiltIn() {
return false;
}
/**
* Standard hash code method
*
* @return the hash code value for this object
*/
public int hashCode() {
return formatString.hashCode();
}
/**
* Standard equals method. This compares the contents of two
* format records, and not their indexCodes, which are ignored
*
* @param o the object to compare
* @return TRUE if the two objects are equal, FALSE otherwise
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof FormatRecord)) {
return false;
}
FormatRecord fr = (FormatRecord) o;
// Initialized format comparison
if (initialized && fr.initialized) {
// Must be either a number or a date format
if (date != fr.date ||
number != fr.number) {
return false;
}
return formatString.equals(fr.formatString);
}
// Uninitialized format comparison
return formatString.equals(fr.formatString);
}
// Type to distinguish between biff7 and biff8
private static class BiffType {
}
}

@ -0,0 +1,512 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.IOException;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.format.Colour;
import jxl.format.RGB;
import jxl.write.biff.File;
/**
* The list of XF records and formatting records for the workbook
*/
public class FormattingRecords {
/**
* The start index number for custom format records
*/
private static final int customFormatStartIndex = 0xa4;
/**
* The maximum number of format records. This is some weird internal
* Excel constraint
*/
private static final int maxFormatRecordsIndex = 0x1b9;
/**
* The minimum number of XF records for a sheet. The rationalization
* processes commences immediately after this number
*/
private static final int minXFRecords = 21;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(FormattingRecords.class);
/**
* A hash map of FormatRecords, for random access retrieval when reading
* in a spreadsheet
*/
private final HashMap formats;
/**
* A list of formats, used when writing out a spreadsheet
*/
private ArrayList formatsList;
/**
* The list of extended format records
*/
private ArrayList xfRecords;
/**
* The next available index number for custom format records
*/
private int nextCustomIndexNumber;
/**
* A handle to the available fonts
*/
private final Fonts fonts;
/**
* The colour palette
*/
private PaletteRecord palette;
/**
* Constructor
*
* @param f the container for the fonts
*/
public FormattingRecords(Fonts f) {
xfRecords = new ArrayList(10);
formats = new HashMap(10);
formatsList = new ArrayList(10);
fonts = f;
nextCustomIndexNumber = customFormatStartIndex;
}
/**
* Adds an extended formatting record to the list. If the XF record passed
* in has not been initialized, its index is determined based on the
* xfRecords list, and
* this position is passed to the XF records initialize method
*
* @param xf the xf record to add
* @throws NumFormatRecordsException
*/
public final void addStyle(XFRecord xf)
throws NumFormatRecordsException {
if (!xf.isInitialized()) {
int pos = xfRecords.size();
xf.initialize(pos, this, fonts);
xfRecords.add(xf);
} else {
// The XF record has probably been read in. If the index is greater
// Than the size of the list, then it is not a preset format,
// so add it
if (xf.getXFIndex() >= xfRecords.size()) {
xfRecords.add(xf);
}
}
}
/**
* Adds a cell format to the hash map, keyed on its index. If the format
* record is not initialized, then its index number is determined and its
* initialize method called. If the font is not a built in format, then it
* is added to the list of formats for writing out
*
* @param fr the format record
*/
public final void addFormat(DisplayFormat fr)
throws NumFormatRecordsException {
// Handle the case the where the index number in the read Excel
// file exhibits some major weirdness
if (fr.isInitialized() &&
fr.getFormatIndex() >= maxFormatRecordsIndex) {
logger.warn("Format index exceeds Excel maximum - assigning custom " +
"number");
fr.initialize(nextCustomIndexNumber);
nextCustomIndexNumber++;
}
// Initialize the format record with a custom index number
if (!fr.isInitialized()) {
fr.initialize(nextCustomIndexNumber);
nextCustomIndexNumber++;
}
if (nextCustomIndexNumber > maxFormatRecordsIndex) {
nextCustomIndexNumber = maxFormatRecordsIndex;
throw new NumFormatRecordsException();
}
if (fr.getFormatIndex() >= nextCustomIndexNumber) {
nextCustomIndexNumber = fr.getFormatIndex() + 1;
}
if (!fr.isBuiltIn()) {
formatsList.add(fr);
formats.put(new Integer(fr.getFormatIndex()), fr);
}
}
/**
* Sees if the extended formatting record at the specified position
* represents a date. First checks against the built in formats, and
* then checks against the hash map of FormatRecords
*
* @param pos the xf format index
* @return TRUE if this format index is formatted as a Date
*/
public final boolean isDate(int pos) {
XFRecord xfr = (XFRecord) xfRecords.get(pos);
if (xfr.isDate()) {
return true;
}
FormatRecord fr = (FormatRecord)
formats.get(new Integer(xfr.getFormatRecord()));
return fr != null && fr.isDate();
}
/**
* Gets the DateFormat used to format the cell.
*
* @param pos the xf format index
* @return the DateFormat object used to format the date in the original
* excel cell
*/
public final DateFormat getDateFormat(int pos) {
XFRecord xfr = (XFRecord) xfRecords.get(pos);
if (xfr.isDate()) {
return xfr.getDateFormat();
}
FormatRecord fr = (FormatRecord)
formats.get(new Integer(xfr.getFormatRecord()));
if (fr == null) {
return null;
}
return fr.isDate() ? fr.getDateFormat() : null;
}
/**
* Gets the NumberFormat used to format the cell.
*
* @param pos the xf format index
* @return the DateFormat object used to format the date in the original
* excel cell
*/
public final NumberFormat getNumberFormat(int pos) {
XFRecord xfr = (XFRecord) xfRecords.get(pos);
if (xfr.isNumber()) {
return xfr.getNumberFormat();
}
FormatRecord fr = (FormatRecord)
formats.get(new Integer(xfr.getFormatRecord()));
if (fr == null) {
return null;
}
return fr.isNumber() ? fr.getNumberFormat() : null;
}
/**
* Gets the format record
*
* @param index the formatting record index to retrieve
* @return the format record at the specified index
*/
FormatRecord getFormatRecord(int index) {
return (FormatRecord)
formats.get(new Integer(index));
}
/**
* Writes out all the format records and the XF records
*
* @param outputFile the file to write to
* @throws IOException
*/
public void write(File outputFile) throws IOException {
// Write out all the formats
Iterator i = formatsList.iterator();
FormatRecord fr = null;
while (i.hasNext()) {
fr = (FormatRecord) i.next();
outputFile.write(fr);
}
// Write out the styles
i = xfRecords.iterator();
XFRecord xfr = null;
while (i.hasNext()) {
xfr = (XFRecord) i.next();
outputFile.write(xfr);
}
// Write out the style records
BuiltInStyle style = new BuiltInStyle(0x10, 3);
outputFile.write(style);
style = new BuiltInStyle(0x11, 6);
outputFile.write(style);
style = new BuiltInStyle(0x12, 4);
outputFile.write(style);
style = new BuiltInStyle(0x13, 7);
outputFile.write(style);
style = new BuiltInStyle(0x0, 0);
outputFile.write(style);
style = new BuiltInStyle(0x14, 5);
outputFile.write(style);
}
/**
* Accessor for the fonts used by this workbook
*
* @return the fonts container
*/
protected final Fonts getFonts() {
return fonts;
}
/**
* Gets the XFRecord for the specified index. Used when copying individual
* cells
*
* @param index the XF record to retrieve
* @return the XF record at the specified index
*/
public final XFRecord getXFRecord(int index) {
return (XFRecord) xfRecords.get(index);
}
/**
* Gets the number of formatting records on the list. This is used by the
* writable subclass because there is an upper limit on the amount of
* format records that are allowed to be present in an excel sheet
*
* @return the number of format records present
*/
protected final int getNumberOfFormatRecords() {
return formatsList.size();
}
/**
* Rationalizes all the fonts, removing duplicate entries
*
* @return the list of new font index number
*/
public IndexMapping rationalizeFonts() {
return fonts.rationalize();
}
/**
* Rationalizes the cell formats. Duplicate
* formats are removed and the format indexed of the cells
* adjusted accordingly
*
* @param fontMapping the font mapping index numbers
* @param formatMapping the format mapping index numbers
* @return the list of new font index number
*/
public IndexMapping rationalize(IndexMapping fontMapping,
IndexMapping formatMapping) {
// Update the index codes for the XF records using the format
// mapping and the font mapping
// at the same time
XFRecord xfr = null;
for (Iterator it = xfRecords.iterator(); it.hasNext(); ) {
xfr = (XFRecord) it.next();
if (xfr.getFormatRecord() >= customFormatStartIndex) {
xfr.setFormatIndex(formatMapping.getNewIndex(xfr.getFormatRecord()));
}
xfr.setFontIndex(fontMapping.getNewIndex(xfr.getFontIndex()));
}
ArrayList newrecords = new ArrayList(minXFRecords);
IndexMapping mapping = new IndexMapping(xfRecords.size());
int numremoved = 0;
int numXFRecords = Math.min(minXFRecords, xfRecords.size());
// Copy across the fundamental styles
for (int i = 0; i < numXFRecords; i++) {
newrecords.add(xfRecords.get(i));
mapping.setMapping(i, i);
}
if (numXFRecords < minXFRecords) {
logger.warn("There are less than the expected minimum number of " +
"XF records");
return mapping;
}
// Iterate through the old list
for (int i = minXFRecords; i < xfRecords.size(); i++) {
XFRecord xf = (XFRecord) xfRecords.get(i);
// Compare against formats already on the list
boolean duplicate = false;
for (Iterator it = newrecords.iterator();
it.hasNext() && !duplicate; ) {
XFRecord xf2 = (XFRecord) it.next();
if (xf2.equals(xf)) {
duplicate = true;
mapping.setMapping(i, mapping.getNewIndex(xf2.getXFIndex()));
numremoved++;
}
}
// If this format is not a duplicate then add it to the new list
if (!duplicate) {
newrecords.add(xf);
mapping.setMapping(i, i - numremoved);
}
}
// It is sufficient to merely change the xf index field on all XFRecords
// In this case, CellValues which refer to defunct format records
// will nevertheless be written out with the correct index number
for (Iterator i = xfRecords.iterator(); i.hasNext(); ) {
XFRecord xf = (XFRecord) i.next();
xf.rationalize(mapping);
}
// Set the new list
xfRecords = newrecords;
return mapping;
}
/**
* Rationalizes the display formats. Duplicate
* formats are removed and the format indices of the cells
* adjusted accordingly. It is invoked immediately prior to writing
* writing out the sheet
*
* @return the index mapping between the old display formats and the
* rationalized ones
*/
public IndexMapping rationalizeDisplayFormats() {
ArrayList newformats = new ArrayList();
int numremoved = 0;
IndexMapping mapping = new IndexMapping(nextCustomIndexNumber);
// Iterate through the old list
Iterator i = formatsList.iterator();
DisplayFormat df = null;
DisplayFormat df2 = null;
boolean duplicate = false;
while (i.hasNext()) {
df = (DisplayFormat) i.next();
Assert.verify(!df.isBuiltIn());
// Compare against formats already on the list
Iterator i2 = newformats.iterator();
duplicate = false;
while (i2.hasNext() && !duplicate) {
df2 = (DisplayFormat) i2.next();
if (df2.equals(df)) {
duplicate = true;
mapping.setMapping(df.getFormatIndex(),
mapping.getNewIndex(df2.getFormatIndex()));
numremoved++;
}
}
// If this format is not a duplicate then add it to the new list
if (!duplicate) {
newformats.add(df);
int indexnum = df.getFormatIndex() - numremoved;
if (indexnum > maxFormatRecordsIndex) {
logger.warn("Too many number formats - using default format.");
indexnum = 0; // the default number format index
}
mapping.setMapping(df.getFormatIndex(),
df.getFormatIndex() - numremoved);
}
}
// Set the new list
formatsList = newformats;
// Update the index codes for the remaining formats
i = formatsList.iterator();
while (i.hasNext()) {
df = (DisplayFormat) i.next();
df.initialize(mapping.getNewIndex(df.getFormatIndex()));
}
return mapping;
}
/**
* Accessor for the colour palette
*
* @return the palette
*/
public PaletteRecord getPalette() {
return palette;
}
/**
* Called from the WorkbookParser to set the colour palette
*
* @param pr the palette
*/
public void setPalette(PaletteRecord pr) {
palette = pr;
}
/**
* Sets the RGB value for the specified colour for this workbook
*
* @param c the colour whose RGB value is to be overwritten
* @param r the red portion to set (0-255)
* @param g the green portion to set (0-255)
* @param b the blue portion to set (0-255)
*/
public void setColourRGB(Colour c, int r, int g, int b) {
if (palette == null) {
palette = new PaletteRecord();
}
palette.setColourRGB(c, r, g, b);
}
/**
* Accessor for the RGB value for the specified colour
*
* @return the RGB for the specified colour
*/
public RGB getColourRGB(Colour c) {
if (palette == null) {
return c.getDefaultRGB();
}
return palette.getColourRGB(c);
}
}

@ -0,0 +1,39 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.Cell;
import jxl.biff.formula.FormulaException;
/**
* Interface which is used for copying formulas from a read only
* to a writable spreadsheet
*/
public interface FormulaData extends Cell {
/**
* Gets the raw bytes for the formula. This will include the
* parsed tokens array EXCLUDING the standard cell information
* (row, column, xfindex)
*
* @return the raw record data
* @throws FormulaException
*/
byte[] getFormulaData() throws FormulaException;
}

@ -0,0 +1,615 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan, Eric Jung
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
/**
* Class which represents an Excel header or footer. Information for this
* class came from Microsoft Knowledge Base Article 142136
* (previously Q142136).
* <p>
* This class encapsulates three internal structures representing the header
* or footer contents which appear on the left, right or central part of the
* page
*/
public abstract class HeaderFooter {
/**
* Turns bold printing on or off
*/
private static final String BOLD_TOGGLE = "&B";
// Codes to format text
/**
* Turns underline printing on or off
*/
private static final String UNDERLINE_TOGGLE = "&U";
/**
* Turns italic printing on or off
*/
private static final String ITALICS_TOGGLE = "&I";
/**
* Turns strikethrough printing on or off
*/
private static final String STRIKETHROUGH_TOGGLE = "&S";
/**
* Turns double-underline printing on or off
*/
private static final String DOUBLE_UNDERLINE_TOGGLE = "&E";
/**
* Turns superscript printing on or off
*/
private static final String SUPERSCRIPT_TOGGLE = "&X";
/**
* Turns subscript printing on or off
*/
private static final String SUBSCRIPT_TOGGLE = "&Y";
/**
* Turns outline printing on or off (Macintosh only)
*/
private static final String OUTLINE_TOGGLE = "&O";
/**
* Turns shadow printing on or off (Macintosh only)
*/
private static final String SHADOW_TOGGLE = "&H";
/**
* Left-aligns the characters that follow
*/
private static final String LEFT_ALIGN = "&L";
/**
* Centres the characters that follow
*/
private static final String CENTRE = "&C";
/**
* Right-aligns the characters that follow
*/
private static final String RIGHT_ALIGN = "&R";
/**
* Prints the page number
*/
private static final String PAGENUM = "&P";
// Codes to insert specific data
/**
* Prints the total number of pages in the document
*/
private static final String TOTAL_PAGENUM = "&N";
/**
* Prints the current date
*/
private static final String DATE = "&D";
/**
* Prints the current time
*/
private static final String TIME = "&T";
/**
* Prints the name of the workbook
*/
private static final String WORKBOOK_NAME = "&F";
/**
* Prints the name of the worksheet
*/
private static final String WORKSHEET_NAME = "&A";
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(HeaderFooter.class);
/**
* The left aligned header/footer contents
*/
private Contents left;
/**
* The right aligned header/footer contents
*/
private Contents right;
/**
* The centrally aligned header/footer contents
*/
private Contents centre;
/**
* Default constructor.
*/
protected HeaderFooter() {
left = createContents();
right = createContents();
centre = createContents();
}
/**
* Copy constructor
*
* @param c the item to copy
*/
protected HeaderFooter(HeaderFooter hf) {
left = createContents(hf.left);
right = createContents(hf.right);
centre = createContents(hf.centre);
}
/**
* Constructor used when reading workbooks to separate the left, right
* a central part of the strings into their constituent parts
*/
protected HeaderFooter(String s) {
if (s == null || s.length() == 0) {
left = createContents();
right = createContents();
centre = createContents();
return;
}
int leftPos = s.indexOf(LEFT_ALIGN);
int rightPos = s.indexOf(RIGHT_ALIGN);
int centrePos = s.indexOf(CENTRE);
if (leftPos == -1 && rightPos == -1 && centrePos == -1) {
// When no part is specified, it is the center part
centre = createContents(s);
} else {
// Left part?
if (leftPos != -1) {
// We have a left part, find end of left part
int endLeftPos = s.length();
if (centrePos > leftPos) {
// Case centre part behind left part
endLeftPos = centrePos;
if (rightPos > leftPos && endLeftPos > rightPos) {
// LRC case
endLeftPos = rightPos;
} else {
// LCR case
}
} else {
// Case centre part before left part
if (rightPos > leftPos) {
// LR case
endLeftPos = rightPos;
} else {
// *L case
// Left pos is last
}
}
left = createContents(s.substring(leftPos + 2, endLeftPos));
}
// Right part?
if (rightPos != -1) {
// Find end of right part
int endRightPos = s.length();
if (centrePos > rightPos) {
// centre part behind right part
endRightPos = centrePos;
if (leftPos > rightPos && endRightPos > leftPos) {
// RLC case
endRightPos = leftPos;
} else {
// RCL case
}
} else {
if (leftPos > rightPos) {
// RL case
endRightPos = leftPos;
} else {
// *R case
// Right pos is last
}
}
right = createContents(s.substring(rightPos + 2, endRightPos));
}
// Centre part?
if (centrePos != -1) {
// Find end of centre part
int endCentrePos = s.length();
if (rightPos > centrePos) {
// right part behind centre part
endCentrePos = rightPos;
if (leftPos > centrePos && endCentrePos > leftPos) {
// CLR case
endCentrePos = leftPos;
} else {
// CRL case
}
} else {
if (leftPos > centrePos) {
// CL case
endCentrePos = leftPos;
} else {
// *C case
// Centre pos is last
}
}
centre = createContents(s.substring(centrePos + 2, endCentrePos));
}
}
if (left == null) {
left = createContents();
}
if (centre == null) {
centre = createContents();
}
if (right == null) {
right = createContents();
}
}
/**
* Retrieves a <code>String</code>ified
* version of this object
*
* @return the header string
*/
public String toString() {
StringBuffer hf = new StringBuffer();
if (!left.empty()) {
hf.append(LEFT_ALIGN);
hf.append(left.getContents());
}
if (!centre.empty()) {
hf.append(CENTRE);
hf.append(centre.getContents());
}
if (!right.empty()) {
hf.append(RIGHT_ALIGN);
hf.append(right.getContents());
}
return hf.toString();
}
/**
* Accessor for the contents which appear on the right hand side of the page
*
* @return the right aligned contents
*/
protected Contents getRightText() {
return right;
}
/**
* Accessor for the contents which in the centre of the page
*
* @return the centrally aligned contents
*/
protected Contents getCentreText() {
return centre;
}
/**
* Accessor for the contents which appear on the left hand side of the page
*
* @return the left aligned contents
*/
protected Contents getLeftText() {
return left;
}
/**
* Clears the contents of the header/footer
*/
protected void clear() {
left.clear();
right.clear();
centre.clear();
}
/**
* Creates internal class of the appropriate type
*/
protected abstract Contents createContents();
/**
* Creates internal class of the appropriate type
*/
protected abstract Contents createContents(String s);
/**
* Creates internal class of the appropriate type
*/
protected abstract Contents createContents(Contents c);
/**
* The contents - a simple wrapper around a string buffer
*/
protected static class Contents {
/**
* The buffer containing the header/footer string
*/
private StringBuffer contents;
/**
* The constructor
*/
protected Contents() {
contents = new StringBuffer();
}
/**
* Constructor used when reading worksheets. The string contains all
* the formatting (but not alignment characters
*
* @param s the format string
*/
protected Contents(String s) {
contents = new StringBuffer(s);
}
/**
* Copy constructor
*
* @param copy the contents to copy
*/
protected Contents(Contents copy) {
contents = new StringBuffer(copy.getContents());
}
/**
* Retrieves a <code>String</code>ified
* version of this object
*
* @return the header string
*/
protected String getContents() {
return contents != null ? contents.toString() : "";
}
/**
* Internal method which appends the text to the string buffer
*
* @param txt
*/
private void appendInternal(String txt) {
if (contents == null) {
contents = new StringBuffer();
}
contents.append(txt);
}
/**
* Internal method which appends the text to the string buffer
*
* @param ch
*/
private void appendInternal(char ch) {
if (contents == null) {
contents = new StringBuffer();
}
contents.append(ch);
}
/**
* Appends the text to the string buffer
*
* @param txt
*/
protected void append(String txt) {
appendInternal(txt);
}
/**
* Turns bold printing on or off. Bold printing
* is initially off. Text subsequently appended to
* this object will be bolded until this method is
* called again.
*/
protected void toggleBold() {
appendInternal(BOLD_TOGGLE);
}
/**
* Turns underline printing on or off. Underline printing
* is initially off. Text subsequently appended to
* this object will be underlined until this method is
* called again.
*/
protected void toggleUnderline() {
appendInternal(UNDERLINE_TOGGLE);
}
/**
* Turns italics printing on or off. Italics printing
* is initially off. Text subsequently appended to
* this object will be italicized until this method is
* called again.
*/
protected void toggleItalics() {
appendInternal(ITALICS_TOGGLE);
}
/**
* Turns strikethrough printing on or off. Strikethrough printing
* is initially off. Text subsequently appended to
* this object will be striked out until this method is
* called again.
*/
protected void toggleStrikethrough() {
appendInternal(STRIKETHROUGH_TOGGLE);
}
/**
* Turns double-underline printing on or off. Double-underline printing
* is initially off. Text subsequently appended to
* this object will be double-underlined until this method is
* called again.
*/
protected void toggleDoubleUnderline() {
appendInternal(DOUBLE_UNDERLINE_TOGGLE);
}
/**
* Turns superscript printing on or off. Superscript printing
* is initially off. Text subsequently appended to
* this object will be superscripted until this method is
* called again.
*/
protected void toggleSuperScript() {
appendInternal(SUPERSCRIPT_TOGGLE);
}
/**
* Turns subscript printing on or off. Subscript printing
* is initially off. Text subsequently appended to
* this object will be subscripted until this method is
* called again.
*/
protected void toggleSubScript() {
appendInternal(SUBSCRIPT_TOGGLE);
}
/**
* Turns outline printing on or off (Macintosh only).
* Outline printing is initially off. Text subsequently appended
* to this object will be outlined until this method is
* called again.
*/
protected void toggleOutline() {
appendInternal(OUTLINE_TOGGLE);
}
/**
* Turns shadow printing on or off (Macintosh only).
* Shadow printing is initially off. Text subsequently appended
* to this object will be shadowed until this method is
* called again.
*/
protected void toggleShadow() {
appendInternal(SHADOW_TOGGLE);
}
/**
* Sets the font of text subsequently appended to this
* object.. Previously appended text is not affected.
* <p/>
* <strong>Note:</strong> no checking is performed to
* determine if fontName is a valid font.
*
* @param fontName name of the font to use
*/
protected void setFontName(String fontName) {
// Font name must be in quotations
appendInternal("&\"");
appendInternal(fontName);
appendInternal('\"');
}
/**
* Sets the font size of text subsequently appended to this
* object. Previously appended text is not affected.
* <p/>
* Valid point sizes are between 1 and 99 (inclusive). If
* size is outside this range, this method returns false
* and does not change font size. If size is within this
* range, the font size is changed and true is returned.
*
* @param size The size in points. Valid point sizes are
* between 1 and 99 (inclusive).
* @return true if the font size was changed, false if font
* size was not changed because 1 > size > 99.
*/
protected boolean setFontSize(int size) {
if (size < 1 || size > 99) {
return false;
}
// A two digit number should be used -- even if the
// leading number is just a zero.
String fontSize;
if (size < 10) {
// single-digit -- make two digit
fontSize = "0" + size;
} else {
fontSize = Integer.toString(size);
}
appendInternal('&');
appendInternal(fontSize);
return true;
}
/**
* Appends the page number
*/
protected void appendPageNumber() {
appendInternal(PAGENUM);
}
/**
* Appends the total number of pages
*/
protected void appendTotalPages() {
appendInternal(TOTAL_PAGENUM);
}
/**
* Appends the current date
*/
protected void appendDate() {
appendInternal(DATE);
}
/**
* Appends the current time
*/
protected void appendTime() {
appendInternal(TIME);
}
/**
* Appends the workbook name
*/
protected void appendWorkbookName() {
appendInternal(WORKBOOK_NAME);
}
/**
* Appends the worksheet name
*/
protected void appendWorkSheetName() {
appendInternal(WORKSHEET_NAME);
}
/**
* Clears the contents of this portion
*/
protected void clear() {
contents = null;
}
/**
* Queries if the contents are empty
*
* @return TRUE if the contents are empty, FALSE otherwise
*/
protected boolean empty() {
return contents == null || contents.length() == 0;
}
}
}

@ -0,0 +1,68 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
/**
* This class is a wrapper for a list of mappings between indices.
* It is used when removing duplicate records and specifies the new
* index for cells which have the duplicate format
*/
public final class IndexMapping {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(IndexMapping.class);
/**
* The array of new indexes for an old one
*/
private final int[] newIndices;
/**
* Constructor
*
* @param size the number of index numbers to be mapped
*/
public IndexMapping(int size) {
newIndices = new int[size];
}
/**
* Sets a mapping
*
* @param oldIndex the old index
* @param newIndex the new index
*/
public void setMapping(int oldIndex, int newIndex) {
newIndices[oldIndex] = newIndex;
}
/**
* Gets the new cell format index
*
* @param oldIndex the existing index number
* @return the new index number
*/
public int getNewIndex(int oldIndex) {
return newIndices[oldIndex];
}
}

@ -0,0 +1,140 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Converts excel byte representations into integers
*/
public final class IntegerHelper {
/**
* Private constructor disables the instantiation of this object
*/
private IntegerHelper() {
}
/**
* Gets an int from two bytes
*
* @param b2 the second byte
* @param b1 the first byte
* @return The integer value
*/
public static int getInt(byte b1, byte b2) {
int i1 = b1 & 0xff;
int i2 = b2 & 0xff;
int val = i2 << 8 | i1;
return val;
}
/**
* Gets an short from two bytes
*
* @param b2 the second byte
* @param b1 the first byte
* @return The short value
*/
public static short getShort(byte b1, byte b2) {
short i1 = (short) (b1 & 0xff);
short i2 = (short) (b2 & 0xff);
short val = (short) (i2 << 8 | i1);
return val;
}
/**
* Gets an int from four bytes, doing all the necessary swapping
*
* @param b1 a byte
* @param b2 a byte
* @param b3 a byte
* @param b4 a byte
* @return the integer value represented by the four bytes
*/
public static int getInt(byte b1, byte b2, byte b3, byte b4) {
int i1 = getInt(b1, b2);
int i2 = getInt(b3, b4);
int val = i2 << 16 | i1;
return val;
}
/**
* Gets a two byte array from an integer
*
* @param i the integer
* @return the two bytes
*/
public static byte[] getTwoBytes(int i) {
byte[] bytes = new byte[2];
bytes[0] = (byte) (i & 0xff);
bytes[1] = (byte) ((i & 0xff00) >> 8);
return bytes;
}
/**
* Gets a four byte array from an integer
*
* @param i the integer
* @return a four byte array
*/
public static byte[] getFourBytes(int i) {
byte[] bytes = new byte[4];
int i1 = i & 0xffff;
int i2 = (i & 0xffff0000) >> 16;
getTwoBytes(i1, bytes, 0);
getTwoBytes(i2, bytes, 2);
return bytes;
}
/**
* Converts an integer into two bytes, and places it in the array at the
* specified position
*
* @param target the array to place the byte data into
* @param pos the position at which to place the data
* @param i the integer value to convert
*/
public static void getTwoBytes(int i, byte[] target, int pos) {
target[pos] = (byte) (i & 0xff);
target[pos + 1] = (byte) ((i & 0xff00) >> 8);
}
/**
* Converts an integer into four bytes, and places it in the array at the
* specified position
*
* @param target the array which is to contain the converted data
* @param pos the position in the array in which to place the data
* @param i the integer to convert
*/
public static void getFourBytes(int i, byte[] target, int pos) {
byte[] bytes = getFourBytes(i);
target[pos] = bytes[0];
target[pos + 1] = bytes[1];
target[pos + 2] = bytes[2];
target[pos + 3] = bytes[3];
}
}

@ -0,0 +1,35 @@
/*********************************************************************
*
* Copyright (C) 2009 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.JXLException;
/**
* A properly typed exception in case consumers of the API specifically
* wish to handle the case when the workbook is password protected
*/
public class NameRangeException extends JXLException {
/**
* Constructor
*/
public NameRangeException() {
super("");
}
}

@ -0,0 +1,34 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* Excel places a constraint on the number of format records that
* are allowed. This exception is thrown when that number is exceeded
* This is a static exception and should be handled internally
*/
public class NumFormatRecordsException extends Exception {
/**
* Constructor
*/
public NumFormatRecordsException() {
super("Internal error: max number of FORMAT records exceeded");
}
}

@ -0,0 +1,207 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.format.Colour;
import jxl.format.RGB;
import jxl.read.biff.Record;
/**
* A record representing the RGB colour palette
*/
public class PaletteRecord extends WritableRecordData {
/**
* The number of colours in the palette
*/
private static final int numColours = 56;
/**
* The list of bespoke rgb colours used by this sheet
*/
private final RGB[] rgbColours = new RGB[numColours];
/**
* A dirty flag indicating that this palette has been tampered with
* in some way
*/
private boolean dirty;
/**
* Flag indicating that the palette was read in
*/
private final boolean read;
/**
* Initialized flag
*/
private boolean initialized;
/**
* Constructor
*
* @param t the raw bytes
*/
public PaletteRecord(Record t) {
super(t);
initialized = false;
dirty = false;
read = true;
}
/**
* Default constructor - used when there is no palette specified
*/
public PaletteRecord() {
super(Type.PALETTE);
initialized = true;
dirty = false;
read = false;
// Initialize the array with all the default colours
Colour[] colours = Colour.getAllColours();
for (int i = 0; i < colours.length; i++) {
Colour c = colours[i];
setColourRGB(c,
c.getDefaultRGB().getRed(),
c.getDefaultRGB().getGreen(),
c.getDefaultRGB().getBlue());
}
}
/**
* Accessor for the binary data - used when copying
*
* @return the binary data
*/
public byte[] getData() {
// Palette was read in, but has not been changed
if (read && !dirty) {
return getRecord().getData();
}
byte[] data = new byte[numColours * 4 + 2];
int pos = 0;
// Set the number of records
IntegerHelper.getTwoBytes(numColours, data, pos);
// Set the rgb content
for (int i = 0; i < numColours; i++) {
pos = i * 4 + 2;
data[pos] = (byte) rgbColours[i].getRed();
data[pos + 1] = (byte) rgbColours[i].getGreen();
data[pos + 2] = (byte) rgbColours[i].getBlue();
}
return data;
}
/**
* Initialize the record data
*/
private void initialize() {
byte[] data = getRecord().getData();
int numrecords = IntegerHelper.getInt(data[0], data[1]);
for (int i = 0; i < numrecords; i++) {
int pos = i * 4 + 2;
int red = IntegerHelper.getInt(data[pos], (byte) 0);
int green = IntegerHelper.getInt(data[pos + 1], (byte) 0);
int blue = IntegerHelper.getInt(data[pos + 2], (byte) 0);
rgbColours[i] = new RGB(red, green, blue);
}
initialized = true;
}
/**
* Accessor for the dirty flag, which indicates if this palette has been
* modified
*
* @return TRUE if the palette has been modified, FALSE if it is the default
*/
public boolean isDirty() {
return dirty;
}
/**
* Sets the RGB value for the specified colour for this workbook
*
* @param c the colour whose RGB value is to be overwritten
* @param r the red portion to set (0-255)
* @param g the green portion to set (0-255)
* @param b the blue portion to set (0-255)
*/
public void setColourRGB(Colour c, int r, int g, int b) {
// Only colours on the standard palette with values 8-64 are acceptable
int pos = c.getValue() - 8;
if (pos < 0 || pos >= numColours) {
return;
}
if (!initialized) {
initialize();
}
// Force the colours into the range 0-255
r = setValueRange(r, 0, 0xff);
g = setValueRange(g, 0, 0xff);
b = setValueRange(b, 0, 0xff);
rgbColours[pos] = new RGB(r, g, b);
// Indicate that the palette has been modified
dirty = true;
}
/**
* Gets the colour RGB from the palette
*
* @param c the colour
* @return an RGB structure
*/
public RGB getColourRGB(Colour c) {
// Only colours on the standard palette with values 8-64 are acceptable
int pos = c.getValue() - 8;
if (pos < 0 || pos >= numColours) {
return c.getDefaultRGB();
}
if (!initialized) {
initialize();
}
return rgbColours[pos];
}
/**
* Forces the value passed in to be between the range passed in
*
* @param val the value to constrain
* @param min the minimum acceptable value
* @param max the maximum acceptable value
* @return the constrained value
*/
private int setValueRange(int val, int min, int max) {
val = Math.max(val, min);
val = Math.min(val, max);
return val;
}
}

@ -0,0 +1,157 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.Cell;
import jxl.Range;
import jxl.Sheet;
import jxl.common.Logger;
/**
* Implementation class for the Range interface. This merely
* holds the raw range information, and when the time comes, it
* interrogates the workbook for the object.
* This does not keep handles to the objects for performance reasons,
* as this could impact garbage collection on larger spreadsheets
*/
public class RangeImpl implements Range {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(RangeImpl.class);
/**
* A handle to the workbook
*/
private final WorkbookMethods workbook;
/**
* The sheet index containing the column at the top left
*/
private final int sheet1;
/**
* The column number of the cell at the top left of the range
*/
private final int column1;
/**
* The row number of the cell at the top left of the range
*/
private final int row1;
/**
* The sheet index of the cell at the bottom right
*/
private final int sheet2;
/**
* The column index of the cell at the bottom right
*/
private final int column2;
/**
* The row index of the cell at the bottom right
*/
private final int row2;
/**
* Constructor
*
* @param w the workbook
* @param es the external sheet
* @param s1 the sheet of the top left cell of the range
* @param c1 the column number of the top left cell of the range
* @param r1 the row number of the top left cell of the range
* @param s2 the sheet of the bottom right cell
* @param c2 the column number of the bottom right cell of the range
* @param r2 the row number of the bottomr right cell of the range
*/
public RangeImpl(WorkbookMethods w,
int s1, int c1, int r1,
int s2, int c2, int r2) {
workbook = w;
sheet1 = s1;
sheet2 = s2;
row1 = r1;
row2 = r2;
column1 = c1;
column2 = c2;
}
/**
* Gets the cell at the top left of this range
*
* @return the cell at the top left
*/
public Cell getTopLeft() {
Sheet s = workbook.getReadSheet(sheet1);
if (column1 < s.getColumns() &&
row1 < s.getRows()) {
return s.getCell(column1, row1);
} else {
return new EmptyCell(column1, row1);
}
}
/**
* Gets the cell at the bottom right of this range
*
* @return the cell at the bottom right
*/
public Cell getBottomRight() {
Sheet s = workbook.getReadSheet(sheet2);
if (column2 < s.getColumns() &&
row2 < s.getRows()) {
return s.getCell(column2, row2);
} else {
return new EmptyCell(column2, row2);
}
}
/**
* Gets the index of the first sheet in the range
*
* @return the index of the first sheet in the range
*/
public int getFirstSheetIndex() {
return sheet1;
}
/**
* Gets the index of the last sheet in the range
*
* @return the index of the last sheet in the range
*/
public int getLastSheetIndex() {
return sheet2;
}
}

@ -0,0 +1,83 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.read.biff.Record;
/**
* The record data within a record
*/
public abstract class RecordData {
/**
* The raw data
*/
private Record record;
/**
* The Biff code for this record. This is set up when the record is
* used for writing
*/
private final int code;
/**
* Constructs this object from the raw data
*
* @param r the raw data
*/
protected RecordData(Record r) {
record = r;
code = r.getCode();
}
/**
* Constructor used by the writable records
*
* @param t the type
*/
protected RecordData(Type t) {
code = t.value;
}
/**
* Returns the raw data to its subclasses
*
* @return the raw data
*/
protected Record getRecord() {
return record;
}
/**
* Accessor for the code
*
* @return the code
*/
protected final int getCode() {
return code;
}
}

@ -0,0 +1,293 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.Cell;
import jxl.Range;
import jxl.Sheet;
/**
* Implementation class for the Range interface. This merely
* holds the raw range information. This implementation is used
* for ranges which are present on the current working sheet, so the
* getSheetIndex merely returns -1
*/
public class SheetRangeImpl implements Range {
/**
* A handle to the sheet containing this range
*/
private final Sheet sheet;
/**
* The column number of the cell at the top left of the range
*/
private int column1;
/**
* The row number of the cell at the top left of the range
*/
private int row1;
/**
* The column index of the cell at the bottom right
*/
private int column2;
/**
* The row index of the cell at the bottom right
*/
private int row2;
/**
* Constructor
*
* @param s the sheet containing the range
* @param c1 the column number of the top left cell of the range
* @param r1 the row number of the top left cell of the range
* @param c2 the column number of the bottom right cell of the range
* @param r2 the row number of the bottomr right cell of the range
*/
public SheetRangeImpl(Sheet s, int c1, int r1,
int c2, int r2) {
sheet = s;
row1 = r1;
row2 = r2;
column1 = c1;
column2 = c2;
}
/**
* A copy constructor used for copying ranges between sheets
*
* @param c the range to copy from
* @param s the writable sheet
*/
public SheetRangeImpl(SheetRangeImpl c, Sheet s) {
sheet = s;
row1 = c.row1;
row2 = c.row2;
column1 = c.column1;
column2 = c.column2;
}
/**
* Gets the cell at the top left of this range
*
* @return the cell at the top left
*/
public Cell getTopLeft() {
// If the print area exceeds the bounds of the sheet, then handle
// it here. The sheet implementation will give a NPE
if (column1 >= sheet.getColumns() ||
row1 >= sheet.getRows()) {
return new EmptyCell(column1, row1);
}
return sheet.getCell(column1, row1);
}
/**
* Gets the cell at the bottom right of this range
*
* @return the cell at the bottom right
*/
public Cell getBottomRight() {
// If the print area exceeds the bounds of the sheet, then handle
// it here. The sheet implementation will give a NPE
if (column2 >= sheet.getColumns() ||
row2 >= sheet.getRows()) {
return new EmptyCell(column2, row2);
}
return sheet.getCell(column2, row2);
}
/**
* Not supported. Returns -1, indicating that it refers to the current
* sheet
*
* @return -1
*/
public int getFirstSheetIndex() {
return -1;
}
/**
* Not supported. Returns -1, indicating that it refers to the current
* sheet
*
* @return -1
*/
public int getLastSheetIndex() {
return -1;
}
/**
* Sees whether there are any intersections between this range and the
* range passed in. This method is used internally by the WritableSheet to
* verify the integrity of merged cells, hyperlinks etc. Ranges are
* only ever compared for the same sheet
*
* @param range the range to compare against
* @return TRUE if the ranges intersect, FALSE otherwise
*/
public boolean intersects(SheetRangeImpl range) {
if (range == this) {
return true;
}
return row2 >= range.row1 &&
row1 <= range.row2 &&
column2 >= range.column1 &&
column1 <= range.column2;
}
/**
* To string method - primarily used during debugging
*
* @return the string version of this object
*/
public String toString() {
StringBuffer sb = new StringBuffer();
CellReferenceHelper.getCellReference(column1, row1, sb);
sb.append('-');
CellReferenceHelper.getCellReference(column2, row2, sb);
return sb.toString();
}
/**
* A row has been inserted, so adjust the range objects accordingly
*
* @param r the row which has been inserted
*/
public void insertRow(int r) {
if (r > row2) {
return;
}
if (r <= row1) {
row1++;
}
if (r <= row2) {
row2++;
}
}
/**
* A column has been inserted, so adjust the range objects accordingly
*
* @param c the column which has been inserted
*/
public void insertColumn(int c) {
if (c > column2) {
return;
}
if (c <= column1) {
column1++;
}
if (c <= column2) {
column2++;
}
}
/**
* A row has been removed, so adjust the range objects accordingly
*
* @param r the row which has been inserted
*/
public void removeRow(int r) {
if (r > row2) {
return;
}
if (r < row1) {
row1--;
}
if (r < row2) {
row2--;
}
}
/**
* A column has been removed, so adjust the range objects accordingly
*
* @param c the column which has been removed
*/
public void removeColumn(int c) {
if (c > column2) {
return;
}
if (c < column1) {
column1--;
}
if (c < column2) {
column2--;
}
}
/**
* Standard hash code method
*
* @return the hash code
*/
public int hashCode() {
return 0xffff ^ row1 ^ row2 ^ column1 ^ column2;
}
/**
* Standard equals method
*
* @param o the object to compare
* @return TRUE if the two objects are the same, FALSE otherwise
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof SheetRangeImpl)) {
return false;
}
SheetRangeImpl compare = (SheetRangeImpl) o;
return (column1 == compare.column1 &&
column2 == compare.column2 &&
row1 == compare.row1 &&
row2 == compare.row2);
}
}

@ -0,0 +1,199 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import java.io.UnsupportedEncodingException;
import jxl.WorkbookSettings;
import jxl.common.Logger;
/**
* Helper function to convert Java string objects to and from the byte
* representations
*/
public final class StringHelper {
// Due to a a Sun bug in some versions of JVM 1.4, the UnicodeLittle
// encoding doesn't always work. Making this a public static field
// enables client code access to this (but in an undocumented and
// unsupported fashion). Suggested alternative values for this
// are "UTF-16LE" or "UnicodeLittleUnmarked"
public static String UNICODE_ENCODING = "UnicodeLittle";
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(StringHelper.class);
/**
* Private default constructor to prevent instantiation
*/
private StringHelper() {
}
/**
* Gets the bytes of the specified string. This will simply return the ASCII
* values of the characters in the string
*
* @param s the string to convert into bytes
* @return the ASCII values of the characters in the string
* @deprecated
*/
public static byte[] getBytes(String s) {
return s.getBytes();
}
/**
* Gets the bytes of the specified string. This will simply return the ASCII
* values of the characters in the string
*
* @param s the string to convert into bytes
* @return the ASCII values of the characters in the string
*/
public static byte[] getBytes(String s, WorkbookSettings ws) {
try {
return s.getBytes(ws.getEncoding());
} catch (UnsupportedEncodingException e) {
// fail silently
return null;
}
}
/**
* Converts the string into a little-endian array of Unicode bytes
*
* @param s the string to convert
* @return the unicode values of the characters in the string
*/
public static byte[] getUnicodeBytes(String s) {
try {
byte[] b = s.getBytes(UNICODE_ENCODING);
// Sometimes this method writes out the unicode
// identifier
if (b.length == (s.length() * 2 + 2)) {
byte[] b2 = new byte[b.length - 2];
System.arraycopy(b, 2, b2, 0, b2.length);
b = b2;
}
return b;
} catch (UnsupportedEncodingException e) {
// Fail silently
return null;
}
}
/**
* Gets the ASCII bytes from the specified string and places them in the
* array at the specified position
*
* @param pos the position at which to place the converted data
* @param s the string to convert
* @param d the byte array which will contain the converted string data
*/
public static void getBytes(String s, byte[] d, int pos) {
byte[] b = getBytes(s);
System.arraycopy(b, 0, d, pos, b.length);
}
/**
* Inserts the unicode byte representation of the specified string into the
* array passed in
*
* @param pos the position at which to insert the converted data
* @param s the string to convert
* @param d the byte array which will hold the string data
*/
public static void getUnicodeBytes(String s, byte[] d, int pos) {
byte[] b = getUnicodeBytes(s);
System.arraycopy(b, 0, d, pos, b.length);
}
/**
* Gets a string from the data array using the character encoding for
* this workbook
*
* @param pos The start position of the string
* @param length The number of bytes to transform into a string
* @param d The byte data
* @param ws the workbook settings
* @return the string built up from the raw bytes
*/
public static String getString(byte[] d, int length, int pos,
WorkbookSettings ws) {
if (length == 0) {
return ""; // Reduces number of new Strings
}
try {
return new String(d, pos, length, ws.getEncoding());
// byte[] b = new byte[length];
// System.arraycopy(d, pos, b, 0, length);
// return new String(b, ws.getEncoding());
} catch (UnsupportedEncodingException e) {
logger.warn(e.toString());
return "";
}
}
/**
* Gets a string from the data array
*
* @param pos The start position of the string
* @param length The number of characters to be converted into a string
* @param d The byte data
* @return the string built up from the unicode characters
*/
public static String getUnicodeString(byte[] d, int length, int pos) {
try {
byte[] b = new byte[length * 2];
System.arraycopy(d, pos, b, 0, length * 2);
return new String(b, UNICODE_ENCODING);
} catch (UnsupportedEncodingException e) {
// Fail silently
return "";
}
}
/**
* Replaces all instances of search with replace in the input.
* Even though later versions of java can use string.replace()
* this is included Java 1.2 compatibility
*
* @param input the format string
* @param search the Excel character to be replaced
* @param replace the java equivalent
* @return the input string with the specified substring replaced
*/
public static final String replace(String input,
String search,
String replace) {
String fmtstr = input;
int pos = fmtstr.indexOf(search);
while (pos != -1) {
StringBuffer tmp = new StringBuffer(fmtstr.substring(0, pos));
tmp.append(replace);
tmp.append(fmtstr.substring(pos + search.length()));
fmtstr = tmp.toString();
pos = fmtstr.indexOf(search, pos + replace.length());
}
return fmtstr;
}
}

@ -0,0 +1,612 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
/**
* An enumeration class which contains the biff types
*/
public final class Type {
/**
*
*/
public static final Type BOF = new Type(0x809);
/**
*
*/
public static final Type EOF = new Type(0x0a);
/**
*
*/
public static final Type BOUNDSHEET = new Type(0x85);
/**
*
*/
public static final Type SUPBOOK = new Type(0x1ae);
/**
*
*/
public static final Type EXTERNSHEET = new Type(0x17);
/**
*
*/
public static final Type DIMENSION = new Type(0x200);
/**
*
*/
public static final Type BLANK = new Type(0x201);
/**
*
*/
public static final Type MULBLANK = new Type(0xbe);
/**
*
*/
public static final Type ROW = new Type(0x208);
/**
*
*/
public static final Type NOTE = new Type(0x1c);
/**
*
*/
public static final Type TXO = new Type(0x1b6);
/**
*
*/
public static final Type RK = new Type(0x7e);
/**
*
*/
public static final Type RK2 = new Type(0x27e);
/**
*
*/
public static final Type MULRK = new Type(0xbd);
/**
*
*/
public static final Type INDEX = new Type(0x20b);
/**
*
*/
public static final Type DBCELL = new Type(0xd7);
/**
*
*/
public static final Type SST = new Type(0xfc);
/**
*
*/
public static final Type COLINFO = new Type(0x7d);
/**
*
*/
public static final Type EXTSST = new Type(0xff);
/**
*
*/
public static final Type CONTINUE = new Type(0x3c);
/**
*
*/
public static final Type LABEL = new Type(0x204);
/**
*
*/
public static final Type RSTRING = new Type(0xd6);
/**
*
*/
public static final Type LABELSST = new Type(0xfd);
/**
*
*/
public static final Type NUMBER = new Type(0x203);
/**
*
*/
public static final Type NAME = new Type(0x18);
/**
*
*/
public static final Type TABID = new Type(0x13d);
/**
*
*/
public static final Type ARRAY = new Type(0x221);
/**
*
*/
public static final Type STRING = new Type(0x207);
/**
*
*/
public static final Type FORMULA = new Type(0x406);
/**
*
*/
public static final Type FORMULA2 = new Type(0x6);
/**
*
*/
public static final Type SHAREDFORMULA = new Type(0x4bc);
/**
*
*/
public static final Type FORMAT = new Type(0x41e);
/**
*
*/
public static final Type XF = new Type(0xe0);
/**
*
*/
public static final Type BOOLERR = new Type(0x205);
/**
*
*/
public static final Type INTERFACEHDR = new Type(0xe1);
/**
*
*/
public static final Type SAVERECALC = new Type(0x5f);
/**
*
*/
public static final Type INTERFACEEND = new Type(0xe2);
/**
*
*/
public static final Type XCT = new Type(0x59);
/**
*
*/
public static final Type CRN = new Type(0x5a);
/**
*
*/
public static final Type DEFCOLWIDTH = new Type(0x55);
/**
*
*/
public static final Type DEFAULTROWHEIGHT = new Type(0x225);
/**
*
*/
public static final Type WRITEACCESS = new Type(0x5c);
/**
*
*/
public static final Type WSBOOL = new Type(0x81);
/**
*
*/
public static final Type CODEPAGE = new Type(0x42);
/**
*
*/
public static final Type DSF = new Type(0x161);
/**
*
*/
public static final Type FNGROUPCOUNT = new Type(0x9c);
/**
*
*/
public static final Type FILTERMODE = new Type(0x9b);
/**
*
*/
public static final Type AUTOFILTERINFO = new Type(0x9d);
/**
*
*/
public static final Type AUTOFILTER = new Type(0x9e);
/**
*
*/
public static final Type COUNTRY = new Type(0x8c);
/**
*
*/
public static final Type PROTECT = new Type(0x12);
/**
*
*/
public static final Type SCENPROTECT = new Type(0xdd);
/**
*
*/
public static final Type OBJPROTECT = new Type(0x63);
/**
*
*/
public static final Type PRINTHEADERS = new Type(0x2a);
/**
*
*/
public static final Type HEADER = new Type(0x14);
/**
*
*/
public static final Type FOOTER = new Type(0x15);
/**
*
*/
public static final Type HCENTER = new Type(0x83);
/**
*
*/
public static final Type VCENTER = new Type(0x84);
/**
*
*/
public static final Type FILEPASS = new Type(0x2f);
/**
*
*/
public static final Type SETUP = new Type(0xa1);
/**
*
*/
public static final Type PRINTGRIDLINES = new Type(0x2b);
/**
*
*/
public static final Type GRIDSET = new Type(0x82);
/**
*
*/
public static final Type GUTS = new Type(0x80);
/**
*
*/
public static final Type WINDOWPROTECT = new Type(0x19);
/**
*
*/
public static final Type PROT4REV = new Type(0x1af);
/**
*
*/
public static final Type PROT4REVPASS = new Type(0x1bc);
/**
*
*/
public static final Type PASSWORD = new Type(0x13);
/**
*
*/
public static final Type REFRESHALL = new Type(0x1b7);
/**
*
*/
public static final Type WINDOW1 = new Type(0x3d);
/**
*
*/
public static final Type WINDOW2 = new Type(0x23e);
/**
*
*/
public static final Type BACKUP = new Type(0x40);
/**
*
*/
public static final Type HIDEOBJ = new Type(0x8d);
/**
*
*/
public static final Type NINETEENFOUR = new Type(0x22);
/**
*
*/
public static final Type PRECISION = new Type(0xe);
/**
*
*/
public static final Type BOOKBOOL = new Type(0xda);
/**
*
*/
public static final Type FONT = new Type(0x31);
/**
*
*/
public static final Type MMS = new Type(0xc1);
/**
*
*/
public static final Type CALCMODE = new Type(0x0d);
/**
*
*/
public static final Type CALCCOUNT = new Type(0x0c);
/**
*
*/
public static final Type REFMODE = new Type(0x0f);
/**
*
*/
public static final Type TEMPLATE = new Type(0x60);
/**
*
*/
public static final Type OBJPROJ = new Type(0xd3);
/**
*
*/
public static final Type DELTA = new Type(0x10);
/**
*
*/
public static final Type MERGEDCELLS = new Type(0xe5);
/**
*
*/
public static final Type ITERATION = new Type(0x11);
/**
*
*/
public static final Type STYLE = new Type(0x293);
/**
*
*/
public static final Type USESELFS = new Type(0x160);
/**
*
*/
public static final Type VERTICALPAGEBREAKS = new Type(0x1a);
/**
*
*/
public static final Type HORIZONTALPAGEBREAKS = new Type(0x1b);
/**
*
*/
public static final Type SELECTION = new Type(0x1d);
/**
*
*/
public static final Type HLINK = new Type(0x1b8);
/**
*
*/
public static final Type OBJ = new Type(0x5d);
/**
*
*/
public static final Type MSODRAWING = new Type(0xec);
/**
*
*/
public static final Type MSODRAWINGGROUP = new Type(0xeb);
/**
*
*/
public static final Type LEFTMARGIN = new Type(0x26);
/**
*
*/
public static final Type RIGHTMARGIN = new Type(0x27);
/**
*
*/
public static final Type TOPMARGIN = new Type(0x28);
/**
*
*/
public static final Type BOTTOMMARGIN = new Type(0x29);
/**
*
*/
public static final Type EXTERNNAME = new Type(0x23);
/**
*
*/
public static final Type PALETTE = new Type(0x92);
/**
*
*/
public static final Type PLS = new Type(0x4d);
/**
*
*/
public static final Type SCL = new Type(0xa0);
/**
*
*/
public static final Type PANE = new Type(0x41);
/**
*
*/
public static final Type WEIRD1 = new Type(0xef);
/**
*
*/
public static final Type SORT = new Type(0x90);
/**
*
*/
public static final Type CONDFMT = new Type(0x1b0);
/**
*
*/
public static final Type CF = new Type(0x1b1);
/**
*
*/
public static final Type DV = new Type(0x1be);
/**
*
*/
public static final Type DVAL = new Type(0x1b2);
/**
*
*/
public static final Type BUTTONPROPERTYSET = new Type(0x1ba);
/**
*
*/
public static final Type EXCEL9FILE = new Type(0x1c0);
/**
*
*/
public static final Type FONTX = new Type(0x1026);
/**
*
*/
public static final Type IFMT = new Type(0x104e);
/**
*
*/
public static final Type FBI = new Type(0x1060);
/**
*
*/
public static final Type ALRUNS = new Type(0x1050);
/**
*
*/
public static final Type SERIES = new Type(0x1003);
/**
*
*/
public static final Type SERIESLIST = new Type(0x1016);
/**
*
*/
public static final Type SBASEREF = new Type(0x1048);
/**
*
*/
public static final Type UNKNOWN = new Type(0xffff);
/**
*
*/
// public static final Type R = new Type(0xffff);
// Unknown types
public static final Type U1C0 = new Type(0x1c0);
public static final Type U1C1 = new Type(0x1c1);
// Chart types
/**
* An array of all types
*/
private static Type[] types = new Type[0];
private static final ArbitraryType arbitrary = new ArbitraryType();
/**
* The biff value for this type
*/
public final int value;
/**
* Constructor
* Sets the biff value and adds this type to the array of all types
*
* @param v the biff code for the type
*/
private Type(int v) {
value = v;
// Add to the list of available types
Type[] newTypes = new Type[types.length + 1];
System.arraycopy(types, 0, newTypes, 0, types.length);
newTypes[types.length] = this;
types = newTypes;
}
/**
* Constructor used for the creation of arbitrary types
*/
private Type(int v, ArbitraryType arb) {
value = v;
}
/**
* Gets the type object from its integer value
*
* @param v the internal code
* @return the type
*/
public static Type getType(int v) {
for (int i = 0; i < types.length; i++) {
if (types[i].value == v) {
return types[i];
}
}
return UNKNOWN;
}
/**
* Used to create an arbitrary record type. This method is only
* used during bespoke debugging process. The creation of an
* arbitrary type does not add it to the static list of known types
*/
public static Type createType(int v) {
return new Type(v, arbitrary);
}
/**
* Standard hash code method
*
* @return the hash code
*/
public int hashCode() {
return value;
}
// Pivot stuff
/**
* Standard equals method
*
* @param o the object to compare
* @return TRUE if the objects are equal, FALSE otherwise
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Type)) {
return false;
}
Type t = (Type) o;
return value == t.value;
}
private static class ArbitraryType {
}
}

@ -0,0 +1,54 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.Sheet;
/**
* An interface containing some common workbook methods. This so that
* objects which are re-used for both readable and writable workbooks
* can still make the same method calls on a workbook
*/
public interface WorkbookMethods {
/**
* Gets the specified sheet within this workbook
*
* @param index the zero based index of the required sheet
* @return The sheet specified by the index
*/
Sheet getReadSheet(int index);
/**
* Gets the name at the specified index
*
* @param index the index into the name table
* @return the name of the cell
* @throws NameRangeException
*/
String getName(int index) throws NameRangeException;
/**
* Gets the index of the name record for the name
*
* @param name the name
* @return the index in the name table
*/
int getNameIndex(String name);
}

@ -0,0 +1,143 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* A record detailing whether the sheet is protected
*/
public class WorkspaceInformationRecord extends WritableRecordData {
// the masks
private static final int FIT_TO_PAGES = 0x100;
private static final int SHOW_ROW_OUTLINE_SYMBOLS = 0x400;
private static final int SHOW_COLUMN_OUTLINE_SYMBOLS = 0x800;
private static final int DEFAULT_OPTIONS = 0x4c1;
// the logger
private static final Logger logger =
Logger.getLogger(WorkspaceInformationRecord.class);
/**
* The options byte
*/
private int wsoptions;
/**
* The row outlines
*/
private boolean rowOutlines;
/**
* The column outlines
*/
private boolean columnOutlines;
/**
* The fit to pages flag
*/
private boolean fitToPages;
/**
* Constructs this object from the raw data
*
* @param t the raw data
*/
public WorkspaceInformationRecord(Record t) {
super(t);
byte[] data = getRecord().getData();
wsoptions = IntegerHelper.getInt(data[0], data[1]);
fitToPages = (wsoptions | FIT_TO_PAGES) != 0;
rowOutlines = (wsoptions | SHOW_ROW_OUTLINE_SYMBOLS) != 0;
columnOutlines = (wsoptions | SHOW_COLUMN_OUTLINE_SYMBOLS) != 0;
}
/**
* Constructs this object from the raw data
*/
public WorkspaceInformationRecord() {
super(Type.WSBOOL);
wsoptions = DEFAULT_OPTIONS;
}
/**
* Gets the fit to pages flag
*
* @return TRUE if fit to pages is set
*/
public boolean getFitToPages() {
return fitToPages;
}
/**
* Sets the fit to page flag
*
* @param b fit to page indicator
*/
public void setFitToPages(boolean b) {
fitToPages = b;
}
/**
* Sets the outlines
*/
public void setRowOutlines(boolean ro) {
rowOutlines = true;
}
/**
* Sets the outlines
*/
public void setColumnOutlines(boolean ro) {
rowOutlines = true;
}
/**
* Gets the binary data for output to file
*
* @return the binary data
*/
public byte[] getData() {
byte[] data = new byte[2];
if (fitToPages) {
wsoptions |= FIT_TO_PAGES;
}
if (rowOutlines) {
wsoptions |= SHOW_ROW_OUTLINE_SYMBOLS;
}
if (columnOutlines) {
wsoptions |= SHOW_COLUMN_OUTLINE_SYMBOLS;
}
IntegerHelper.getTwoBytes(wsoptions, data, 0);
return data;
}
}

@ -0,0 +1,139 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.common.Logger;
import jxl.read.biff.Record;
/**
* Extension of the standard RecordData which is used to support those
* records which, once read, may also be written
*/
public abstract class WritableRecordData extends RecordData
implements ByteData {
/**
* The maximum length allowed by Excel for any record length
*/
protected static final int maxRecordLength = 8228;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(WritableRecordData.class);
/**
* Constructor used by the writable records
*
* @param t the biff type of this record
*/
protected WritableRecordData(Type t) {
super(t);
}
/**
* Constructor used when reading a record
*
* @param t the raw data read from the biff file
*/
protected WritableRecordData(Record t) {
super(t);
}
/**
* Used when writing out records. This portion of the method handles the
* biff code and the length of the record and appends on the data retrieved
* from the subclasses
*
* @return the full record data to be written out to the compound file
*/
public final byte[] getBytes() {
byte[] data = getData();
int dataLength = data.length;
// Don't the call the automatic continuation code for now
// Assert.verify(dataLength <= maxRecordLength - 4);
// If the bytes length is greater than the max record length
// then split out the data set into continue records
if (data.length > maxRecordLength - 4) {
dataLength = maxRecordLength - 4;
data = handleContinueRecords(data);
}
byte[] bytes = new byte[data.length + 4];
System.arraycopy(data, 0, bytes, 4, data.length);
IntegerHelper.getTwoBytes(getCode(), bytes, 0);
IntegerHelper.getTwoBytes(dataLength, bytes, 2);
return bytes;
}
/**
* The number of bytes for this record exceeds the maximum record
* length, so a continue is required
*
* @param data the raw data
* @return the continued data
*/
private byte[] handleContinueRecords(byte[] data) {
// Deduce the number of continue records
int continuedData = data.length - (maxRecordLength - 4);
int numContinueRecords = continuedData / (maxRecordLength - 4) + 1;
// Create the new byte array, allowing for the continue records
// code and length
byte[] newdata = new byte[data.length + numContinueRecords * 4];
// Copy the bona fide record data into the beginning of the super
// record
System.arraycopy(data, 0, newdata, 0, maxRecordLength - 4);
int oldarraypos = maxRecordLength - 4;
int newarraypos = maxRecordLength - 4;
// Now handle all the continue records
for (int i = 0; i < numContinueRecords; i++) {
// The number of bytes to add into the new array
int length = Math.min(data.length - oldarraypos, maxRecordLength - 4);
// Add in the continue record code
IntegerHelper.getTwoBytes(Type.CONTINUE.value, newdata, newarraypos);
IntegerHelper.getTwoBytes(length, newdata, newarraypos + 2);
// Copy in as much of the new data as possible
System.arraycopy(data, oldarraypos, newdata, newarraypos + 4, length);
// Update the position counters
oldarraypos += length;
newarraypos += length + 4;
}
return newdata;
}
/**
* Abstract method called by the getBytes method. Subclasses implement
* this method to incorporate their specific binary data - excluding the
* biff code and record length, which is handled by this class
*
* @return subclass specific biff data
*/
protected abstract byte[] getData();
}

@ -0,0 +1,48 @@
/*********************************************************************
*
* Copyright (C) 2009 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff;
import jxl.read.biff.Record;
/**
* A record representing the XCT record
*/
public class XCTRecord extends WritableRecordData {
/**
* Constructor
*
* @param t the raw bytes
*/
public XCTRecord(Record t) {
super(t);
}
/**
* Accessor for the binary data - used when copying
*
* @return the binary data
*/
public byte[] getData() {
return getRecord().getData();
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,86 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.common.Logger;
/**
* A BStoreContainer escher record
*/
class BStoreContainer extends EscherContainer {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(BStoreContainer.class);
/**
* The number of blips inside this container
*/
private int numBlips;
/**
* Constructor used to instantiate this object when reading from an
* escher stream
*
* @param erd the escher data
*/
public BStoreContainer(EscherRecordData erd) {
super(erd);
numBlips = getInstance();
}
/**
* Constructor used when writing out an escher record
*/
public BStoreContainer() {
super(EscherRecordType.BSTORE_CONTAINER);
}
/**
* Accessor for the number of blips
*
* @return the number of blips
*/
public int getNumBlips() {
return numBlips;
}
/**
* Sets the number of drawings in this container
*
* @param count the number of blips
*/
void setNumBlips(int count) {
numBlips = count;
setInstance(numBlips);
}
/**
* Accessor for the drawing
*
* @param i the index number of the drawing to return
* @return the drawing
*/
public BlipStoreEntry getDrawing(int i) {
EscherRecord[] children = getChildren();
BlipStoreEntry bse = (BlipStoreEntry) children[i];
return bse;
}
}

@ -0,0 +1,195 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.biff.IntegerHelper;
import jxl.common.Assert;
import jxl.common.Logger;
/**
* The data for this blip store entry. Typically this is the raw image data
*/
class BlipStoreEntry extends EscherAtom {
/**
* The start of the image data within this blip entry
*/
private static final int IMAGE_DATA_OFFSET = 61;
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(BlipStoreEntry.class);
/**
* The type of the blip
*/
private final BlipType type;
/**
* The image data read in
*/
private byte[] data;
/**
* The length of the image data
*/
private int imageDataLength;
/**
* The reference count on this blip
*/
private int referenceCount;
/**
* Flag to indicate that this entry was specified by the API, and not
* read in
*/
private final boolean write;
/**
* Constructor
*
* @param erd the escher record data
*/
public BlipStoreEntry(EscherRecordData erd) {
super(erd);
type = BlipType.getType(getInstance());
write = false;
byte[] bytes = getBytes();
referenceCount = IntegerHelper.getInt(bytes[24], bytes[25],
bytes[26], bytes[27]);
}
/**
* Constructor
*
* @param d the drawing
* @throws IOException
*/
public BlipStoreEntry(Drawing d) throws IOException {
super(EscherRecordType.BSE);
type = BlipType.PNG;
setVersion(2);
setInstance(type.getValue());
byte[] imageData = d.getImageBytes();
imageDataLength = imageData.length;
data = new byte[imageDataLength + IMAGE_DATA_OFFSET];
System.arraycopy(imageData, 0, data, IMAGE_DATA_OFFSET, imageDataLength);
referenceCount = d.getReferenceCount();
write = true;
}
/**
* Accessor for the blip type
*
* @return the blip type
*/
public BlipType getBlipType() {
return type;
}
/**
* Gets the data for this blip so that it can be written out
*
* @return the data for the blip
*/
public byte[] getData() {
if (write) {
// Drawing has been specified by API
// Type on win32
data[0] = (byte) type.getValue();
// Type on MacOs
data[1] = (byte) type.getValue();
// The blip identifier
// IntegerHelper.getTwoBytes(0xfce1, data, 2);
// Unused tags - 18 bytes
// System.arraycopy(stuff, 0, data, 2, stuff.length);
// The size of the file
IntegerHelper.getFourBytes(imageDataLength + 8 + 17, data, 20);
// The reference count on the blip
IntegerHelper.getFourBytes(referenceCount, data, 24);
// Offset in the delay stream
IntegerHelper.getFourBytes(0, data, 28);
// Usage byte
data[32] = (byte) 0;
// Length of the blip name
data[33] = (byte) 0;
// Last two bytes unused
data[34] = (byte) 0x7e;
data[35] = (byte) 0x01;
// The blip itself
data[36] = (byte) 0;
data[37] = (byte) 0x6e;
// The blip identifier
IntegerHelper.getTwoBytes(0xf01e, data, 38);
// The length of the blip. This is the length of the image file plus
// 16 bytes
IntegerHelper.getFourBytes(imageDataLength + 17, data, 40);
// Unknown stuff
// System.arraycopy(stuff, 0, data, 44, stuff.length);
} else {
// drawing has been read in
data = getBytes();
}
return setHeaderData(data);
}
/**
* Reduces the reference count in this blip. Called when a drawing is
* removed
*/
void dereference() {
referenceCount--;
Assert.verify(referenceCount >= 0);
}
/**
* Accessor for the reference count on the blip
*
* @return the reference count on the blip
*/
int getReferenceCount() {
return referenceCount;
}
/**
* Accessor for the image data.
*
* @return the image data
*/
byte[] getImageData() {
byte[] allData = getBytes();
byte[] imageData = new byte[allData.length - IMAGE_DATA_OFFSET];
System.arraycopy(allData, IMAGE_DATA_OFFSET,
imageData, 0, imageData.length);
return imageData;
}
}

@ -0,0 +1,106 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
/**
* Enumeration for the BLIP type
*/
final class BlipType {
public static final BlipType ERROR = new BlipType(0, "Error");
// An error occured during loading
public static final BlipType UNKNOWN = new BlipType(1, "Unknown");
// An unknown blip type
public static final BlipType EMF = new BlipType(2, "EMF");
// Windows Enhanced Metafile
public static final BlipType WMF = new BlipType(3, "WMF");
// Windows Metafile
public static final BlipType PICT = new BlipType(4, "PICT");
// Macintosh PICT
public static final BlipType JPEG = new BlipType(5, "JPEG"); // JFIF
public static final BlipType PNG = new BlipType(6, "PNG"); // PNG
public static final BlipType DIB = new BlipType(7, "DIB"); // Windows DIB
public static final BlipType FIRST_CLIENT = new BlipType(32, "FIRST");
// First client defined blip type
public static final BlipType LAST_CLIENT = new BlipType(255, "LAST");
/**
* All blip types
*/
private static BlipType[] types = new BlipType[0];
/**
* The blip type code
*/
private final int value;
/**
* The blip type description
*/
private final String desc;
/**
* Constructor
*
* @param val the code
* @param d the description
*/
private BlipType(int val, String d) {
value = val;
desc = d;
BlipType[] newtypes = new BlipType[types.length + 1];
System.arraycopy(types, 0, newtypes, 0, types.length);
newtypes[types.length] = this;
types = newtypes;
}
/**
* Gets the blip type given the value
*
* @param val get the value
* @return the blip type
*/
public static BlipType getType(int val) {
BlipType type = UNKNOWN;
for (int i = 0; i < types.length; i++) {
if (types[i].value == val) {
type = types[i];
break;
}
}
return type;
}
/**
* Accessor for the description
*
* @return the description
*/
public String getDescription() {
return desc;
}
/**
* Accessor for the value
*
* @return the value
*/
public int getValue() {
return value;
}
// Last client defined blip type
}

@ -0,0 +1,790 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.WorkbookSettings;
import jxl.biff.ContinueRecord;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to copy a Button (from the
* Form toolbox) between workbook
*/
public class Button implements DrawingGroupObject {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Button.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The spContainer that was generated
*/
private EscherContainer spContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private final MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the drawing
*/
private final ObjRecord objRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The shape id
*/
private int shapeId;
/**
* The column
*/
private int column;
/**
* The row position of the image
*/
private int row;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private final DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The drawing position on the sheet
*/
private final int drawingNumber;
/**
* An mso drawing record, which sometimes appears
*/
private MsoDrawingRecord mso;
/**
* The text object record
*/
private TextObjectRecord txo;
/**
* Text data from the first continue record
*/
private ContinueRecord text;
/**
* Formatting data from the second continue record
*/
private ContinueRecord formatting;
/**
* The comment text
*/
private String commentText;
/**
* The workbook settings
*/
private final WorkbookSettings workbookSettings;
/**
* Constructor used when reading images
*
* @param msodr the drawing record
* @param obj the object record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
* @param ws the workbook settings
*/
public Button(MsoDrawingRecord msodr,
ObjRecord obj,
DrawingData dd,
DrawingGroup dg,
WorkbookSettings ws) {
drawingGroup = dg;
msoDrawingRecord = msodr;
drawingData = dd;
objRecord = obj;
initialized = false;
workbookSettings = ws;
origin = Origin.READ;
drawingData.addData(msoDrawingRecord.getData());
drawingNumber = drawingData.getNumDrawings() - 1;
drawingGroup.addDrawing(this);
Assert.verify(msoDrawingRecord != null && objRecord != null);
initialize();
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
* @param ws the workbook settings
*/
public Button(DrawingGroupObject dgo,
DrawingGroup dg,
WorkbookSettings ws) {
Button d = (Button) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
objRecord = d.objRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
mso = d.mso;
txo = d.txo;
text = d.text;
formatting = d.formatting;
workbookSettings = ws;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
readSpContainer = drawingData.getSpContainer(drawingNumber);
Assert.verify(readSpContainer != null);
EscherRecord[] children = readSpContainer.getChildren();
Sp sp = (Sp) readSpContainer.getChildren()[0];
objectId = objRecord.getObjectId();
shapeId = sp.getShapeId();
type = ShapeType.getType(sp.getShapeType());
if (type == ShapeType.UNKNOWN) {
logger.warn("Unknown shape type");
}
ClientAnchor clientAnchor = null;
for (int i = 0; i < children.length && clientAnchor == null; i++) {
if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) {
clientAnchor = (ClientAnchor) children[i];
}
}
if (clientAnchor == null) {
logger.warn("Client anchor not found");
} else {
column = (int) clientAnchor.getX1() - 1;
row = (int) clientAnchor.getY1() + 1;
}
initialized = true;
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the object id
*/
public final int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
if (origin == Origin.READ) {
return getReadSpContainer();
}
Assert.verify(false);
/*
if (spContainer == null)
{
spContainer = new SpContainer();
Sp sp = new Sp(type, shapeId, 2560);
spContainer.add(sp);
Opt opt = new Opt();
opt.addProperty(344, false, false, 0); // ?
opt.addProperty(385, false, false, 134217808); // fill colour
opt.addProperty(387, false, false, 134217808); // background colour
opt.addProperty(959, false, false, 131074); // hide
spContainer.add(opt);
ClientAnchor clientAnchor = new ClientAnchor(column + 1.3,
Math.max(0, row - 0.6),
column+3, row + 4);
spContainer.add(clientAnchor);
ClientData clientData = new ClientData();
spContainer.add(clientData);
ClientTextBox clientTextBox = new ClientTextBox();
spContainer.add(clientTextBox);
}
*/
return spContainer;
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return column;
}
/**
* Sets the column position of this drawing. Used when inserting/removing
* columns from the spreadsheet
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
column = (int) x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return row;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
row = (int) y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Sets the text object
*
* @param t the text object record
*/
public void setTextObject(TextObjectRecord t) {
txo = t;
}
/**
* Sets the formatting
*
* @param t continue record
*/
public void setFormatting(ContinueRecord t) {
formatting = t;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() {
Assert.verify(false);
return null;
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
Assert.verify(false);
return null;
}
/**
* The drawing record
*
* @param d the drawing record
*/
public void addMso(MsoDrawingRecord d) {
mso = d;
drawingData.addRawData(mso.getData());
}
/**
* Writes out any additional records
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(objRecord);
if (mso != null) {
outputFile.write(mso);
}
outputFile.write(txo);
outputFile.write(text);
if (formatting != null) {
outputFile.write(formatting);
}
return;
}
Assert.verify(false);
// Create the obj record
ObjRecord objrec = new ObjRecord(objectId,
ObjRecord.EXCELNOTE);
outputFile.write(objrec);
// Create the mso data record. Write the text box record again,
// although it is already included in the SpContainer
ClientTextBox textBox = new ClientTextBox();
MsoDrawingRecord msod = new MsoDrawingRecord(textBox.getData());
outputFile.write(msod);
TextObjectRecord tor = new TextObjectRecord(getText());
outputFile.write(tor);
// Data for the first continue record
byte[] textData = new byte[commentText.length() * 2 + 1];
textData[0] = 0x1; // unicode indicator
StringHelper.getUnicodeBytes(commentText, textData, 1);
//StringHelper.getBytes(commentText, textData, 1);
ContinueRecord textContinue = new ContinueRecord(textData);
outputFile.write(textContinue);
// Data for the formatting runs
byte[] frData = new byte[16];
// First txo run (the user)
IntegerHelper.getTwoBytes(0, frData, 0); // index to the first character
IntegerHelper.getTwoBytes(0, frData, 2); // index to the font(default)
// Mandatory last txo run
IntegerHelper.getTwoBytes(commentText.length(), frData, 8);
IntegerHelper.getTwoBytes(0, frData, 10); // index to the font(default)
ContinueRecord frContinue = new ContinueRecord(frData);
outputFile.write(frContinue);
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Writes out all the note records
*
* @param outputFile the output file
*/
public void writeTailRecords(File outputFile) {
}
/**
* Accessor for the row. As buttons are not associated with a cell,
* does nothing here
*
* @return the row number
*/
public int getRow() {
return 0;
}
/**
* Accessor for the column. As buttons are not associated with a cell,
* does nothing here
*
* @return the column number
*/
public int getColumn() {
return 0;
}
/**
* Accessor for the text on the button
*
* @return the button text
*/
public String getText() {
if (commentText == null) {
Assert.verify(text != null);
byte[] td = text.getData();
if (td[0] == 0) {
commentText = StringHelper.getString
(td, td.length - 1, 1, workbookSettings);
} else {
commentText = StringHelper.getUnicodeString
(td, (td.length - 1) / 2, 1);
}
}
return commentText;
}
/**
* Sets the text data
*
* @param t continuation record
*/
public void setText(ContinueRecord t) {
text = t;
}
/**
* Hashing algorithm
*
* @return the hash code
*/
public int hashCode() {
return commentText.hashCode();
}
/**
* Called when the comment text is changed during the sheet copy process
*
* @param t the new text
*/
public void setButtonText(String t) {
commentText = t;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return mso.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return true;
}
}

@ -0,0 +1,249 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.WorkbookSettings;
import jxl.biff.ByteData;
import jxl.biff.IndexMapping;
import jxl.biff.IntegerHelper;
import jxl.biff.Type;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.read.biff.File;
/**
* Contains the various biff records used to insert a chart into a
* worksheet
*/
public class Chart implements ByteData, EscherStream {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Chart.class);
/**
* The MsoDrawingRecord associated with the chart
*/
private final MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the chart
*/
private final ObjRecord objRecord;
/**
* The start pos of the chart bof stream in the data file
*/
private final int startpos;
/**
* The start pos of the chart bof stream in the data file
*/
private final int endpos;
/**
* A handle to the Excel file
*/
private final File file;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The drawing number
*/
private int drawingNumber;
/**
* The chart byte data
*/
private byte[] data;
/**
* Flag which indicates that the byte data has been initialized
*/
private boolean initialized;
/**
* The workbook settings
*/
private final WorkbookSettings workbookSettings;
/**
* Constructor
*
* @param mso a <code>MsoDrawingRecord</code> value
* @param obj an <code>ObjRecord</code> value
* @param dd the drawing data
* @param sp an <code>int</code> value
* @param ep an <code>int</code> value
* @param f a <code>File</code> value
* @param ws the workbook settings
*/
public Chart(MsoDrawingRecord mso,
ObjRecord obj,
DrawingData dd,
int sp, int ep, File f, WorkbookSettings ws) {
msoDrawingRecord = mso;
objRecord = obj;
startpos = sp;
endpos = ep;
file = f;
workbookSettings = ws;
// msoDrawingRecord is null if the entire sheet consists of just the
// chart. In this case, as there is only one drawing on the page,
// it isn't necessary to add to the drawing data record anyway
if (msoDrawingRecord != null) {
drawingData = dd;
drawingData.addData(msoDrawingRecord.getRecord().getData());
drawingNumber = drawingData.getNumDrawings() - 1;
}
initialized = false;
// Note: mso and obj values can be null if we are creating a chart
// which takes up an entire worksheet. Check that both are null or both
// not null though
Assert.verify((mso != null && obj != null) ||
(mso == null && obj == null));
}
/**
* Gets the entire binary record for the chart as a chunk of binary data
*
* @return the bytes
*/
public byte[] getBytes() {
if (!initialized) {
initialize();
}
return data;
}
/**
* Implementation of the EscherStream method
*
* @return the data
*/
public byte[] getData() {
return msoDrawingRecord.getRecord().getData();
}
/**
* Initializes the charts byte data
*/
private void initialize() {
data = file.read(startpos, endpos - startpos);
initialized = true;
}
/**
* Rationalizes the sheet's xf index mapping
*
* @param xfMapping the index mapping for XFRecords
* @param fontMapping the index mapping for fonts
* @param formatMapping the index mapping for formats
*/
public void rationalize(IndexMapping xfMapping,
IndexMapping fontMapping,
IndexMapping formatMapping) {
if (!initialized) {
initialize();
}
// Read through the array, looking for the data types
// This is a total hack bodge for now - it will eventually need to be
// integrated properly
int pos = 0;
int code = 0;
int length = 0;
Type type = null;
while (pos < data.length) {
code = IntegerHelper.getInt(data[pos], data[pos + 1]);
length = IntegerHelper.getInt(data[pos + 2], data[pos + 3]);
type = Type.getType(code);
if (type == Type.FONTX) {
int fontind = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
IntegerHelper.getTwoBytes(fontMapping.getNewIndex(fontind),
data, pos + 4);
} else if (type == Type.FBI) {
int fontind = IntegerHelper.getInt(data[pos + 12], data[pos + 13]);
IntegerHelper.getTwoBytes(fontMapping.getNewIndex(fontind),
data, pos + 12);
} else if (type == Type.IFMT) {
int formind = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
IntegerHelper.getTwoBytes(formatMapping.getNewIndex(formind),
data, pos + 4);
} else if (type == Type.ALRUNS) {
int numRuns = IntegerHelper.getInt(data[pos + 4], data[pos + 5]);
int fontPos = pos + 6;
for (int i = 0; i < numRuns; i++) {
int fontind = IntegerHelper.getInt(data[fontPos + 2],
data[fontPos + 3]);
IntegerHelper.getTwoBytes(fontMapping.getNewIndex(fontind),
data, fontPos + 2);
fontPos += 4;
}
}
pos += length + 4;
}
}
/**
* Gets the SpContainer containing the charts drawing information
*
* @return the spContainer
*/
EscherContainer getSpContainer() {
EscherContainer spContainer = drawingData.getSpContainer(drawingNumber);
return spContainer;
}
/**
* Accessor for the mso drawing record
*
* @return the drawing record
*/
MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Accessor for the obj record
*
* @return the obj record
*/
ObjRecord getObjRecord() {
return objRecord;
}
}

@ -0,0 +1,716 @@
/*********************************************************************
*
* Copyright (C) 2009 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.WorkbookSettings;
import jxl.biff.ContinueRecord;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to copy a CheckBox (from the
* Form toolbox) between workbook
*/
public class CheckBox implements DrawingGroupObject {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(CheckBox.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The spContainer that was generated
*/
private EscherContainer spContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the drawing
*/
private ObjRecord objRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The shape id
*/
private int shapeId;
/**
* The column
*/
private int column;
/**
* The row position of the image
*/
private int row;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The drawing position on the sheet
*/
private int drawingNumber;
/**
* An mso drawing record, which sometimes appears
*/
private MsoDrawingRecord mso;
/**
* The text object record
*/
private TextObjectRecord txo;
/**
* Text data from the first continue record
*/
private ContinueRecord text;
/**
* Formatting data from the second continue record
*/
private ContinueRecord formatting;
/**
* The workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* Constructor used when reading images
*
* @param mso the drawing record
* @param obj the object record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
* @param ws the workbook settings
*/
public CheckBox(MsoDrawingRecord mso, ObjRecord obj, DrawingData dd,
DrawingGroup dg, WorkbookSettings ws) {
drawingGroup = dg;
msoDrawingRecord = mso;
drawingData = dd;
objRecord = obj;
initialized = false;
workbookSettings = ws;
origin = Origin.READ;
drawingData.addData(msoDrawingRecord.getData());
drawingNumber = drawingData.getNumDrawings() - 1;
drawingGroup.addDrawing(this);
Assert.verify(mso != null && obj != null);
initialize();
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
* @param ws the workbook settings
*/
public CheckBox(DrawingGroupObject dgo,
DrawingGroup dg,
WorkbookSettings ws) {
CheckBox d = (CheckBox) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
objRecord = d.objRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
mso = d.mso;
txo = d.txo;
text = d.text;
formatting = d.formatting;
workbookSettings = ws;
}
/**
* Constructor invoked when writing images
*/
public CheckBox() {
initialized = true;
origin = Origin.WRITE;
referenceCount = 1;
type = ShapeType.HOST_CONTROL;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
readSpContainer = drawingData.getSpContainer(drawingNumber);
Assert.verify(readSpContainer != null);
EscherRecord[] children = readSpContainer.getChildren();
Sp sp = (Sp) readSpContainer.getChildren()[0];
objectId = objRecord.getObjectId();
shapeId = sp.getShapeId();
type = ShapeType.getType(sp.getShapeType());
if (type == ShapeType.UNKNOWN) {
logger.warn("Unknown shape type");
}
ClientAnchor clientAnchor = null;
for (int i = 0; i < children.length && clientAnchor == null; i++) {
if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) {
clientAnchor = (ClientAnchor) children[i];
}
}
if (clientAnchor == null) {
logger.warn("Client anchor not found");
} else {
column = (int) clientAnchor.getX1();
row = (int) clientAnchor.getY1();
}
initialized = true;
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the object id
*/
public final int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
if (origin == Origin.READ) {
return getReadSpContainer();
}
SpContainer spc = new SpContainer();
Sp sp = new Sp(type, shapeId, 2560);
spc.add(sp);
Opt opt = new Opt();
opt.addProperty(127, false, false, 17039620);
opt.addProperty(191, false, false, 524296);
opt.addProperty(511, false, false, 524288);
opt.addProperty(959, false, false, 131072);
// opt.addProperty(260, true, false, blipId);
// opt.addProperty(261, false, false, 36);
spc.add(opt);
ClientAnchor clientAnchor = new ClientAnchor(column,
row,
column + 1,
row + 1,
0x1);
spc.add(clientAnchor);
ClientData clientData = new ClientData();
spc.add(clientData);
return spc;
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return column;
}
/**
* Sets the column position of this drawing. Used when inserting/removing
* columns from the spreadsheet
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
column = (int) x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return row;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
row = (int) y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() {
Assert.verify(false);
return null;
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
Assert.verify(false);
return null;
}
/**
* Writes out the additional records for a combo box
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(objRecord);
if (mso != null) {
outputFile.write(mso);
}
outputFile.write(txo);
outputFile.write(text);
if (formatting != null) {
outputFile.write(formatting);
}
return;
}
// Create the obj record
ObjRecord objrec = new ObjRecord(objectId,
ObjRecord.CHECKBOX);
outputFile.write(objrec);
logger.warn("Writing of additional records for checkboxes not " +
"implemented");
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Writes out all the note records
*
* @param outputFile the output file
*/
public void writeTailRecords(File outputFile) {
}
/**
* Accessor for the row
*
* @return the row
*/
public int getRow() {
return 0;
}
/**
* Accessor for the column
*
* @return the column
*/
public int getColumn() {
return 0;
}
/**
* Hashing algorithm
*
* @return the hash code
*/
public int hashCode() {
return getClass().getName().hashCode();
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return msoDrawingRecord.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return false;
}
/**
* Sets the text object
*
* @param t the text object record
*/
public void setTextObject(TextObjectRecord t) {
txo = t;
}
/**
* Sets the text data
*
* @param t continuation record
*/
public void setText(ContinueRecord t) {
text = t;
}
/**
* Sets the formatting
*
* @param t continue record
*/
public void setFormatting(ContinueRecord t) {
formatting = t;
}
/**
* The drawing record
*
* @param d the drawing record
*/
public void addMso(MsoDrawingRecord d) {
mso = d;
drawingData.addRawData(mso.getData());
}
}

@ -0,0 +1,40 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
class Chunk {
private final int pos;
private final int length;
private final ChunkType type;
private final byte[] data;
public Chunk(int p, int l, ChunkType ct, byte[] d) {
pos = p;
length = l;
type = ct;
data = new byte[length];
System.arraycopy(d, pos, data, 0, length);
}
public byte[] getData() {
return data;
}
}

@ -0,0 +1,64 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.util.Arrays;
/**
* Enumeration for the various chunk types
*/
class ChunkType {
public static ChunkType IHDR = new ChunkType(0x49, 0x48, 0x44, 0x52, "IHDR");
public static ChunkType IEND = new ChunkType(0x49, 0x45, 0x4e, 0x44, "IEND");
public static ChunkType PHYS = new ChunkType(0x70, 0x48, 0x59, 0x73, "pHYs");
public static ChunkType UNKNOWN = new ChunkType(0xff, 0xff, 0xff, 0xff, "UNKNOWN");
private static ChunkType[] chunkTypes = new ChunkType[0];
private final byte[] id;
private final String name;
private ChunkType(int d1, int d2, int d3, int d4, String n) {
id = new byte[]{(byte) d1, (byte) d2, (byte) d3, (byte) d4};
name = n;
ChunkType[] ct = new ChunkType[chunkTypes.length + 1];
System.arraycopy(chunkTypes, 0, ct, 0, chunkTypes.length);
ct[chunkTypes.length] = this;
chunkTypes = ct;
}
public static ChunkType getChunkType(byte d1, byte d2, byte d3, byte d4) {
byte[] cmp = new byte[]{d1, d2, d3, d4};
boolean found = false;
ChunkType chunk = ChunkType.UNKNOWN;
for (int i = 0; i < chunkTypes.length && !found; i++) {
if (Arrays.equals(chunkTypes[i].id, cmp)) {
chunk = chunkTypes[i];
found = true;
}
}
return chunk;
}
public String getName() {
return name;
}
}

@ -0,0 +1,201 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.biff.IntegerHelper;
import jxl.common.Logger;
/**
* The client anchor record
*/
class ClientAnchor extends EscherAtom {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(ClientAnchor.class);
/**
* The binary data
*/
private byte[] data;
/**
* The properties
*/
private final int properties;
/**
* The x1 position
*/
private final double x1;
/**
* The y1 position
*/
private final double y1;
/**
* The x2 position
*/
private final double x2;
/**
* The y2 position
*/
private final double y2;
/**
* Constructor
*
* @param erd the escher record data
*/
public ClientAnchor(EscherRecordData erd) {
super(erd);
byte[] bytes = getBytes();
// The properties
properties = IntegerHelper.getInt(bytes[0], bytes[1]);
// The x1 cell
int x1Cell = IntegerHelper.getInt(bytes[2], bytes[3]);
int x1Fraction = IntegerHelper.getInt(bytes[4], bytes[5]);
x1 = x1Cell + (double) x1Fraction / (double) 1024;
// The y1 cell
int y1Cell = IntegerHelper.getInt(bytes[6], bytes[7]);
int y1Fraction = IntegerHelper.getInt(bytes[8], bytes[9]);
y1 = y1Cell + (double) y1Fraction / (double) 256;
// The x2 cell
int x2Cell = IntegerHelper.getInt(bytes[10], bytes[11]);
int x2Fraction = IntegerHelper.getInt(bytes[12], bytes[13]);
x2 = x2Cell + (double) x2Fraction / (double) 1024;
// The y1 cell
int y2Cell = IntegerHelper.getInt(bytes[14], bytes[15]);
int y2Fraction = IntegerHelper.getInt(bytes[16], bytes[17]);
y2 = y2Cell + (double) y2Fraction / (double) 256;
}
/**
* Constructor
*
* @param x1 the x1 position
* @param y1 the y1 position
* @param x2 the x2 position
* @param y2 the y2 position
* @param props the anchor properties
*/
public ClientAnchor(double x1, double y1, double x2, double y2, int props) {
super(EscherRecordType.CLIENT_ANCHOR);
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
properties = props;
}
/**
* Gets the client anchor data
*
* @return the data
*/
byte[] getData() {
data = new byte[18];
IntegerHelper.getTwoBytes(properties, data, 0);
// The x1 cell
IntegerHelper.getTwoBytes((int) x1, data, 2);
// The x1 fraction into the cell 0-1024
int x1fraction = (int) ((x1 - (int) x1) * 1024);
IntegerHelper.getTwoBytes(x1fraction, data, 4);
// The y1 cell
IntegerHelper.getTwoBytes((int) y1, data, 6);
// The y1 fraction into the cell 0-256
int y1fraction = (int) ((y1 - (int) y1) * 256);
IntegerHelper.getTwoBytes(y1fraction, data, 8);
// The x2 cell
IntegerHelper.getTwoBytes((int) x2, data, 10);
// The x2 fraction into the cell 0-1024
int x2fraction = (int) ((x2 - (int) x2) * 1024);
IntegerHelper.getTwoBytes(x2fraction, data, 12);
// The y2 cell
IntegerHelper.getTwoBytes((int) y2, data, 14);
// The y2 fraction into the cell 0-256
int y2fraction = (int) ((y2 - (int) y2) * 256);
IntegerHelper.getTwoBytes(y2fraction, data, 16);
return setHeaderData(data);
}
/**
* Accessor for the x1 position
*
* @return the x1 position
*/
double getX1() {
return x1;
}
/**
* Accessor for the y1 position
*
* @return the y1 position
*/
double getY1() {
return y1;
}
/**
* Accessor for the x2 position
*
* @return the x2 position
*/
double getX2() {
return x2;
}
/**
* Accessor for the y2 position
*
* @return the y2 position
*/
double getY2() {
return y2;
}
/**
* Accessor for the anchor properties
*/
int getProperties() {
return properties;
}
}

@ -0,0 +1,63 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.common.Logger;
/**
* The client data
*/
class ClientData extends EscherAtom {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(ClientData.class);
/**
* The raw data
*/
private byte[] data;
/**
* Constructor
*
* @param erd the record data
*/
public ClientData(EscherRecordData erd) {
super(erd);
}
/**
* Constructor
*/
public ClientData() {
super(EscherRecordType.CLIENT_DATA);
}
/**
* Accessor for the raw data
*
* @return the binary data
*/
byte[] getData() {
data = new byte[0];
return setHeaderData(data);
}
}

@ -0,0 +1,63 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.common.Logger;
/**
* ???
*/
class ClientTextBox extends EscherAtom {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(ClientTextBox.class);
/**
* The raw data
*/
private byte[] data;
/**
* Constructor
*
* @param erd
*/
public ClientTextBox(EscherRecordData erd) {
super(erd);
}
/**
* Constructor
*/
public ClientTextBox() {
super(EscherRecordType.CLIENT_TEXT_BOX);
}
/**
* Accessor for the raw data
*
* @return
*/
byte[] getData() {
data = new byte[0];
return setHeaderData(data);
}
}

@ -0,0 +1,641 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.WorkbookSettings;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to copy a ComboBox (from the
* Form toolbox) between workbook
*/
public class ComboBox implements DrawingGroupObject {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(ComboBox.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The spContainer that was generated
*/
private EscherContainer spContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the drawing
*/
private ObjRecord objRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The shape id
*/
private int shapeId;
/**
* The column
*/
private int column;
/**
* The row position of the image
*/
private int row;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The drawing position on the sheet
*/
private int drawingNumber;
/**
* The workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* Constructor used when reading images
*
* @param mso the drawing record
* @param obj the object record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
* @param ws the workbook settings
*/
public ComboBox(MsoDrawingRecord mso, ObjRecord obj, DrawingData dd,
DrawingGroup dg, WorkbookSettings ws) {
drawingGroup = dg;
msoDrawingRecord = mso;
drawingData = dd;
objRecord = obj;
initialized = false;
workbookSettings = ws;
origin = Origin.READ;
drawingData.addData(msoDrawingRecord.getData());
drawingNumber = drawingData.getNumDrawings() - 1;
drawingGroup.addDrawing(this);
Assert.verify(mso != null && obj != null);
initialize();
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
* @param ws the workbook settings
*/
public ComboBox(DrawingGroupObject dgo,
DrawingGroup dg,
WorkbookSettings ws) {
ComboBox d = (ComboBox) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
objRecord = d.objRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
workbookSettings = ws;
}
/**
* Constructor invoked when writing images
*/
public ComboBox() {
initialized = true;
origin = Origin.WRITE;
referenceCount = 1;
type = ShapeType.HOST_CONTROL;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
readSpContainer = drawingData.getSpContainer(drawingNumber);
Assert.verify(readSpContainer != null);
EscherRecord[] children = readSpContainer.getChildren();
Sp sp = (Sp) readSpContainer.getChildren()[0];
objectId = objRecord.getObjectId();
shapeId = sp.getShapeId();
type = ShapeType.getType(sp.getShapeType());
if (type == ShapeType.UNKNOWN) {
logger.warn("Unknown shape type");
}
ClientAnchor clientAnchor = null;
for (int i = 0; i < children.length && clientAnchor == null; i++) {
if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) {
clientAnchor = (ClientAnchor) children[i];
}
}
if (clientAnchor == null) {
logger.warn("Client anchor not found");
} else {
column = (int) clientAnchor.getX1();
row = (int) clientAnchor.getY1();
}
initialized = true;
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the object id
*/
public final int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
if (origin == Origin.READ) {
return getReadSpContainer();
}
SpContainer spc = new SpContainer();
Sp sp = new Sp(type, shapeId, 2560);
spc.add(sp);
Opt opt = new Opt();
opt.addProperty(127, false, false, 17039620);
opt.addProperty(191, false, false, 524296);
opt.addProperty(511, false, false, 524288);
opt.addProperty(959, false, false, 131072);
// opt.addProperty(260, true, false, blipId);
// opt.addProperty(261, false, false, 36);
spc.add(opt);
ClientAnchor clientAnchor = new ClientAnchor(column,
row,
column + 1,
row + 1,
0x1);
spc.add(clientAnchor);
ClientData clientData = new ClientData();
spc.add(clientData);
return spc;
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return column;
}
/**
* Sets the column position of this drawing. Used when inserting/removing
* columns from the spreadsheet
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
column = (int) x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return row;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
row = (int) y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() {
Assert.verify(false);
return null;
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
Assert.verify(false);
return null;
}
/**
* Writes out the additional records for a combo box
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(objRecord);
return;
}
// Create the obj record
ObjRecord objrec = new ObjRecord(objectId,
ObjRecord.COMBOBOX);
outputFile.write(objrec);
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Writes out all the note records
*
* @param outputFile the output file
*/
public void writeTailRecords(File outputFile) {
}
/**
* Accessor for the row
*
* @return the row
*/
public int getRow() {
return 0;
}
/**
* Accessor for the column
*
* @return the column
*/
public int getColumn() {
return 0;
}
/**
* Hashing algorithm
*
* @return the hash code
*/
public int hashCode() {
return getClass().getName().hashCode();
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return msoDrawingRecord.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return false;
}
}

@ -0,0 +1,829 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.WorkbookSettings;
import jxl.biff.ContinueRecord;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to insert a cell note into a
* worksheet
*/
public class Comment implements DrawingGroupObject {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Comment.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The spContainer that was generated
*/
private EscherContainer spContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the drawing
*/
private ObjRecord objRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The shape id
*/
private int shapeId;
/**
* The column
*/
private int column;
/**
* The row position of the image
*/
private int row;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The drawing position on the sheet
*/
private int drawingNumber;
/**
* An mso drawing record, which sometimes appears
*/
private MsoDrawingRecord mso;
/**
* The text object record
*/
private TextObjectRecord txo;
/**
* The note record
*/
private NoteRecord note;
/**
* Text data from the first continue record
*/
private ContinueRecord text;
/**
* Formatting data from the second continue record
*/
private ContinueRecord formatting;
/**
* The comment text
*/
private String commentText;
/**
* The workbook settings
*/
private WorkbookSettings workbookSettings;
/**
* Constructor used when reading images
*
* @param msorec the drawing record
* @param obj the object record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
* @param ws the workbook settings
*/
public Comment(MsoDrawingRecord msorec, ObjRecord obj, DrawingData dd,
DrawingGroup dg, WorkbookSettings ws) {
drawingGroup = dg;
msoDrawingRecord = msorec;
drawingData = dd;
objRecord = obj;
initialized = false;
workbookSettings = ws;
origin = Origin.READ;
drawingData.addData(msoDrawingRecord.getData());
drawingNumber = drawingData.getNumDrawings() - 1;
drawingGroup.addDrawing(this);
Assert.verify(msoDrawingRecord != null && objRecord != null);
if (!initialized) {
initialize();
}
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
* @param ws the workbook settings
*/
/*protected*/
public Comment(DrawingGroupObject dgo,
DrawingGroup dg,
WorkbookSettings ws) {
Comment d = (Comment) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
objRecord = d.objRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
mso = d.mso;
txo = d.txo;
text = d.text;
formatting = d.formatting;
note = d.note;
width = d.width;
height = d.height;
workbookSettings = ws;
}
/**
* Constructor invoked when writing the images
*
* @param txt the comment text
* @param c the column
* @param r the row
*/
public Comment(String txt, int c, int r) {
initialized = true;
origin = Origin.WRITE;
column = c;
row = r;
referenceCount = 1;
type = ShapeType.TEXT_BOX;
commentText = txt;
width = 3;
height = 4;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
readSpContainer = drawingData.getSpContainer(drawingNumber);
Assert.verify(readSpContainer != null);
EscherRecord[] children = readSpContainer.getChildren();
Sp sp = (Sp) readSpContainer.getChildren()[0];
objectId = objRecord.getObjectId();
shapeId = sp.getShapeId();
type = ShapeType.getType(sp.getShapeType());
if (type == ShapeType.UNKNOWN) {
logger.warn("Unknown shape type");
}
ClientAnchor clientAnchor = null;
for (int i = 0; i < children.length && clientAnchor == null; i++) {
if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) {
clientAnchor = (ClientAnchor) children[i];
}
}
if (clientAnchor == null) {
logger.warn("client anchor not found");
} else {
column = (int) clientAnchor.getX1() - 1;
row = (int) clientAnchor.getY1() + 1;
width = clientAnchor.getX2() - clientAnchor.getX1();
height = clientAnchor.getY2() - clientAnchor.getY1();
}
initialized = true;
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the object id
*/
public final int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
if (origin == Origin.READ) {
return getReadSpContainer();
}
if (spContainer == null) {
spContainer = new SpContainer();
Sp sp = new Sp(type, shapeId, 2560);
spContainer.add(sp);
Opt opt = new Opt();
opt.addProperty(344, false, false, 0); // ?
opt.addProperty(385, false, false, 134217808); // fill colour
opt.addProperty(387, false, false, 134217808); // background colour
opt.addProperty(959, false, false, 131074); // hide
spContainer.add(opt);
ClientAnchor clientAnchor = new ClientAnchor(column + 1.3,
Math.max(0, row - 0.6),
column + 1.3 + width,
row + height,
0x1);
spContainer.add(clientAnchor);
ClientData clientData = new ClientData();
spContainer.add(clientData);
ClientTextBox clientTextBox = new ClientTextBox();
spContainer.add(clientTextBox);
}
return spContainer;
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return column;
}
/**
* Sets the column position of this drawing. Used when inserting/removing
* columns from the spreadsheet
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
column = (int) x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return row;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
row = (int) y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Sets the text object
*
* @param t the text object
*/
public void setTextObject(TextObjectRecord t) {
txo = t;
}
/**
* Sets the note object
*
* @param t the note record
*/
public void setNote(NoteRecord t) {
note = t;
}
/**
* Sets the formatting
*
* @param t the formatting record
*/
public void setFormatting(ContinueRecord t) {
formatting = t;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() {
Assert.verify(false);
return null;
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
Assert.verify(false);
return null;
}
/**
* Adds an mso record to this object
*
* @param d the mso record
*/
public void addMso(MsoDrawingRecord d) {
mso = d;
drawingData.addRawData(mso.getData());
}
/**
* Writes out the additional comment records
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(objRecord);
if (mso != null) {
outputFile.write(mso);
}
outputFile.write(txo);
outputFile.write(text);
if (formatting != null) {
outputFile.write(formatting);
}
return;
}
// Create the obj record
ObjRecord objrec = new ObjRecord(objectId,
ObjRecord.EXCELNOTE);
outputFile.write(objrec);
// Create the mso data record. Write the text box record again,
// although it is already included in the SpContainer
ClientTextBox textBox = new ClientTextBox();
MsoDrawingRecord msod = new MsoDrawingRecord(textBox.getData());
outputFile.write(msod);
TextObjectRecord txorec = new TextObjectRecord(getText());
outputFile.write(txorec);
// Data for the first continue record
byte[] textData = new byte[commentText.length() * 2 + 1];
textData[0] = 0x1; // unicode indicator
StringHelper.getUnicodeBytes(commentText, textData, 1);
//StringHelper.getBytes(commentText, textData, 1);
ContinueRecord textContinue = new ContinueRecord(textData);
outputFile.write(textContinue);
// Data for the formatting runs
byte[] frData = new byte[16];
// First txo run (the user)
IntegerHelper.getTwoBytes(0, frData, 0); // index to the first character
IntegerHelper.getTwoBytes(0, frData, 2); // index to the font(default)
// Mandatory last txo run
IntegerHelper.getTwoBytes(commentText.length(), frData, 8);
IntegerHelper.getTwoBytes(0, frData, 10); // index to the font(default)
ContinueRecord frContinue = new ContinueRecord(frData);
outputFile.write(frContinue);
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Writes out all the note records
*
* @param outputFile the output file
* @throws IOException
*/
public void writeTailRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(note);
return;
}
// The note record
NoteRecord noteRecord = new NoteRecord(column, row, objectId);
outputFile.write(noteRecord);
}
/**
* Accessor for the row
*
* @return the row
*/
public int getRow() {
return note.getRow();
}
/**
* Accessor for the column
*
* @return the column
*/
public int getColumn() {
return note.getColumn();
}
/**
* Accessor for the comment text
*
* @return the comment text
*/
public String getText() {
if (commentText == null) {
Assert.verify(text != null);
byte[] td = text.getData();
if (td[0] == 0) {
commentText = StringHelper.getString
(td, td.length - 1, 1, workbookSettings);
} else {
commentText = StringHelper.getUnicodeString
(td, (td.length - 1) / 2, 1);
}
}
return commentText;
}
/**
* Sets the text data
*
* @param t the text data
*/
public void setText(ContinueRecord t) {
text = t;
}
/**
* Hashing algorithm
*
* @return the hash code
*/
public int hashCode() {
return commentText.hashCode();
}
/**
* Called when the comment text is changed during the sheet copy process
*
* @param t the new text
*/
public void setCommentText(String t) {
commentText = t;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return msoDrawingRecord.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over several records and require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return true;
}
}

@ -0,0 +1,105 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.biff.IntegerHelper;
/**
* The Drawing Group
*/
class Dg extends EscherAtom {
/**
* The data
*/
private byte[] data;
/**
* The id of this drawing
*/
private final int drawingId;
/**
* The number of shapes
*/
private final int shapeCount;
/**
* The seed for drawing ids
*/
private final int seed;
/**
* Constructor invoked when reading in an escher stream
*
* @param erd the escher record
*/
public Dg(EscherRecordData erd) {
super(erd);
drawingId = getInstance();
byte[] bytes = getBytes();
shapeCount = IntegerHelper.getInt(bytes[0], bytes[1], bytes[2], bytes[3]);
seed = IntegerHelper.getInt(bytes[4], bytes[5], bytes[6], bytes[7]);
}
/**
* Constructor invoked when writing out an escher stream
*
* @param numDrawings the number of drawings
*/
public Dg(int numDrawings) {
super(EscherRecordType.DG);
drawingId = 1;
shapeCount = numDrawings + 1;
seed = 1024 + shapeCount + 1;
setInstance(drawingId);
}
/**
* Gets the drawing id
*
* @return the drawing id
*/
public int getDrawingId() {
return drawingId;
}
/**
* Gets the shape count
*
* @return the shape count
*/
int getShapeCount() {
return shapeCount;
}
/**
* Used to generate the drawing data
*
* @return the data
*/
byte[] getData() {
data = new byte[8];
IntegerHelper.getFourBytes(shapeCount, data, 0);
IntegerHelper.getFourBytes(seed, data, 4);
return setHeaderData(data);
}
}

@ -0,0 +1,32 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
/**
* A Dg Container
*/
class DgContainer extends EscherContainer {
/**
* Constructor
*/
public DgContainer() {
super(EscherRecordType.DG_CONTAINER);
}
}

@ -0,0 +1,203 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.util.ArrayList;
import jxl.biff.IntegerHelper;
import jxl.common.Logger;
/**
* Dgg record
*/
class Dgg extends EscherAtom {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Dgg.class);
/**
* The binary data
*/
private byte[] data;
/**
* The number of clusters
*/
private int numClusters;
/**
* The maximum shape id
*/
private int maxShapeId;
/**
* The number of shapes saved
*/
private final int shapesSaved;
/**
* The number of drawings saved
*/
private final int drawingsSaved;
/**
* The clusters
*/
private final ArrayList clusters;
/**
* Constructor
*
* @param erd the read in data
*/
public Dgg(EscherRecordData erd) {
super(erd);
clusters = new ArrayList();
byte[] bytes = getBytes();
maxShapeId = IntegerHelper.getInt
(bytes[0], bytes[1], bytes[2], bytes[3]);
numClusters = IntegerHelper.getInt
(bytes[4], bytes[5], bytes[6], bytes[7]);
shapesSaved = IntegerHelper.getInt
(bytes[8], bytes[9], bytes[10], bytes[11]);
drawingsSaved = IntegerHelper.getInt
(bytes[12], bytes[13], bytes[14], bytes[15]);
int pos = 16;
for (int i = 0; i < numClusters; i++) {
int dgId = IntegerHelper.getInt(bytes[pos], bytes[pos + 1]);
int sids = IntegerHelper.getInt(bytes[pos + 2], bytes[pos + 3]);
Cluster c = new Cluster(dgId, sids);
clusters.add(c);
pos += 4;
}
}
/**
* Constructor
*
* @param numShapes the number of shapes
* @param numDrawings the number of drawings
*/
public Dgg(int numShapes, int numDrawings) {
super(EscherRecordType.DGG);
shapesSaved = numShapes;
drawingsSaved = numDrawings;
clusters = new ArrayList();
}
/**
* Adds a cluster to this record
*
* @param dgid the id
* @param sids the sid
*/
void addCluster(int dgid, int sids) {
Cluster c = new Cluster(dgid, sids);
clusters.add(c);
}
/**
* Gets the data for writing out
*
* @return the binary data
*/
byte[] getData() {
numClusters = clusters.size();
data = new byte[16 + numClusters * 4];
// The max shape id
IntegerHelper.getFourBytes(1024 + shapesSaved, data, 0);
// The number of clusters
IntegerHelper.getFourBytes(numClusters, data, 4);
// The number of shapes saved
IntegerHelper.getFourBytes(shapesSaved, data, 8);
// The number of drawings saved
// IntegerHelper.getFourBytes(drawingsSaved, data, 12);
IntegerHelper.getFourBytes(1, data, 12);
int pos = 16;
for (int i = 0; i < numClusters; i++) {
Cluster c = (Cluster) clusters.get(i);
IntegerHelper.getTwoBytes(c.drawingGroupId, data, pos);
IntegerHelper.getTwoBytes(c.shapeIdsUsed, data, pos + 2);
pos += 4;
}
return setHeaderData(data);
}
/**
* Accessor for the number of shapes saved
*
* @return the number of shapes saved
*/
int getShapesSaved() {
return shapesSaved;
}
/**
* Accessor for the number of drawings saved
*
* @return the number of drawings saved
*/
int getDrawingsSaved() {
return drawingsSaved;
}
/**
* Accessor for a particular cluster
*
* @param i the cluster number
* @return the cluster
*/
Cluster getCluster(int i) {
return (Cluster) clusters.get(i);
}
/**
* The cluster structure
*/
static final class Cluster {
/**
* The drawing group id
*/
int drawingGroupId;
/**
* The something or other
*/
int shapeIdsUsed;
/**
* Constructor
*
* @param dgId the drawing group id
* @param sids the sids
*/
Cluster(int dgId, int sids) {
drawingGroupId = dgId;
shapeIdsUsed = sids;
}
}
}

@ -0,0 +1,32 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
/**
* Container for Dgg objects
*/
class DggContainer extends EscherContainer {
/**
* Constructor
*/
public DggContainer() {
super(EscherRecordType.DGG_CONTAINER);
}
}

@ -0,0 +1,990 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.FileInputStream;
import java.io.IOException;
import jxl.CellView;
import jxl.Image;
import jxl.Sheet;
import jxl.common.Assert;
import jxl.common.LengthConverter;
import jxl.common.LengthUnit;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to insert a drawing into a
* worksheet
*/
public class Drawing implements DrawingGroupObject, Image {
/**
* The default font size for columns
*/
private static final double DEFAULT_FONT_SIZE = 10;
// The image anchor properties
public static ImageAnchorProperties MOVE_AND_SIZE_WITH_CELLS =
new ImageAnchorProperties(1);
public static ImageAnchorProperties MOVE_WITH_CELLS =
new ImageAnchorProperties(2);
public static ImageAnchorProperties NO_MOVE_OR_SIZE_WITH_CELLS =
new ImageAnchorProperties(3);
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Drawing.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private MsoDrawingRecord msoDrawingRecord;
/**
* The ObjRecord associated with the drawing
*/
private ObjRecord objRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The file containing the image
*/
private java.io.File imageFile;
/**
* The raw image data, used instead of an image file
*/
private byte[] imageData;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The column position of the image
*/
private double x;
/**
* The row position of the image
*/
private double y;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The shape id
*/
private int shapeId;
/**
* The drawing position on the sheet
*/
private int drawingNumber;
/**
* A reference to the sheet containing this drawing. Used to calculate
* the drawing dimensions in pixels
*/
private Sheet sheet;
/**
* Reader for the raw image data
*/
private PNGReader pngReader;
/**
* The client anchor properties
*/
private ImageAnchorProperties imageAnchorProperties;
/**
* Constructor used when reading images
*
* @param mso the drawing record
* @param obj the object record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
*/
public Drawing(MsoDrawingRecord mso,
ObjRecord obj,
DrawingData dd,
DrawingGroup dg,
Sheet s) {
drawingGroup = dg;
msoDrawingRecord = mso;
drawingData = dd;
objRecord = obj;
sheet = s;
initialized = false;
origin = Origin.READ;
drawingData.addData(msoDrawingRecord.getData());
drawingNumber = drawingData.getNumDrawings() - 1;
drawingGroup.addDrawing(this);
Assert.verify(mso != null && obj != null);
initialize();
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
*/
protected Drawing(DrawingGroupObject dgo, DrawingGroup dg) {
Drawing d = (Drawing) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
objRecord = d.objRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
}
/**
* Constructor invoked when writing the images
*
* @param x the column
* @param y the row
* @param w the width in cells
* @param h the height in cells
* @param image the image file
*/
public Drawing(double x,
double y,
double w,
double h,
java.io.File image) {
imageFile = image;
initialized = true;
origin = Origin.WRITE;
this.x = x;
this.y = y;
this.width = w;
this.height = h;
referenceCount = 1;
imageAnchorProperties = MOVE_WITH_CELLS;
type = ShapeType.PICTURE_FRAME;
}
/**
* Constructor invoked when writing the images
*
* @param x the column
* @param y the row
* @param w the width in cells
* @param h the height in cells
* @param image the image data
*/
public Drawing(double x,
double y,
double w,
double h,
byte[] image) {
imageData = image;
initialized = true;
origin = Origin.WRITE;
this.x = x;
this.y = y;
this.width = w;
this.height = h;
referenceCount = 1;
imageAnchorProperties = MOVE_WITH_CELLS;
type = ShapeType.PICTURE_FRAME;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
readSpContainer = drawingData.getSpContainer(drawingNumber);
Assert.verify(readSpContainer != null);
EscherRecord[] children = readSpContainer.getChildren();
Sp sp = (Sp) readSpContainer.getChildren()[0];
shapeId = sp.getShapeId();
objectId = objRecord.getObjectId();
type = ShapeType.getType(sp.getShapeType());
if (type == ShapeType.UNKNOWN) {
logger.warn("Unknown shape type");
}
Opt opt = (Opt) readSpContainer.getChildren()[1];
if (opt.getProperty(260) != null) {
blipId = opt.getProperty(260).value;
}
if (opt.getProperty(261) != null) {
imageFile = new java.io.File(opt.getProperty(261).stringValue);
} else {
if (type == ShapeType.PICTURE_FRAME) {
logger.warn("no filename property for drawing");
imageFile = new java.io.File(Integer.toString(blipId));
}
}
ClientAnchor clientAnchor = null;
for (int i = 0; i < children.length && clientAnchor == null; i++) {
if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) {
clientAnchor = (ClientAnchor) children[i];
}
}
if (clientAnchor == null) {
logger.warn("client anchor not found");
} else {
x = clientAnchor.getX1();
y = clientAnchor.getY1();
width = clientAnchor.getX2() - x;
height = clientAnchor.getY2() - y;
imageAnchorProperties = ImageAnchorProperties.getImageAnchorProperties
(clientAnchor.getProperties());
}
if (blipId == 0) {
logger.warn("linked drawings are not supported");
}
initialized = true;
}
/**
* Accessor for the image file
*
* @return the image file
*/
public java.io.File getImageFile() {
return imageFile;
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
if (imageFile == null) {
// return the blip id, if it exists
return blipId != 0 ? Integer.toString(blipId) : "__new__image__";
}
return imageFile.getPath();
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the shape id
*/
public int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
if (origin == Origin.READ) {
return getReadSpContainer();
}
SpContainer spContainer = new SpContainer();
Sp sp = new Sp(type, shapeId, 2560);
spContainer.add(sp);
Opt opt = new Opt();
opt.addProperty(260, true, false, blipId);
if (type == ShapeType.PICTURE_FRAME) {
String filePath = imageFile != null ? imageFile.getPath() : "";
opt.addProperty(261, true, true, filePath.length() * 2, filePath);
opt.addProperty(447, false, false, 65536);
opt.addProperty(959, false, false, 524288);
spContainer.add(opt);
}
ClientAnchor clientAnchor = new ClientAnchor
(x, y, x + width, y + height,
imageAnchorProperties.getValue());
spContainer.add(clientAnchor);
ClientData clientData = new ClientData();
spContainer.add(clientData);
return spContainer;
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return x;
}
/**
* Sets the column position of this drawing
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
this.x = x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return y;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
this.y = y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() throws IOException {
if (origin == Origin.READ || origin == Origin.READ_WRITE) {
return getImageData();
}
Assert.verify(origin == Origin.WRITE);
if (imageFile == null) {
Assert.verify(imageData != null);
return imageData;
}
byte[] data = new byte[(int) imageFile.length()];
FileInputStream fis = new FileInputStream(imageFile);
fis.read(data, 0, data.length);
fis.close();
return data;
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Writes any other records associated with this drawing group object
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
if (origin == Origin.READ) {
outputFile.write(objRecord);
return;
}
// Create the obj record
ObjRecord objrec = new ObjRecord(objectId,
ObjRecord.PICTURE);
outputFile.write(objrec);
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Does nothing here
*
* @param outputFile the output file
*/
public void writeTailRecords(File outputFile) throws IOException {
// does nothing
}
/**
* Interface method
*
* @return the column number at which the image is positioned
*/
public double getColumn() {
return getX();
}
/**
* Interface method
*
* @return the row number at which the image is positions
*/
public double getRow() {
return getY();
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return msoDrawingRecord.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return false;
}
/**
* Removes a row
*
* @param r the row to be removed
*/
public void removeRow(int r) {
if (y > r) {
setY(r);
}
}
/**
* Accessor for the image dimensions. See technotes for Bill's explanation
* of the calculation logic
*
* @return approximate drawing size in pixels
*/
private double getWidthInPoints() {
if (sheet == null) {
logger.warn("calculating image width: sheet is null");
return 0;
}
// The start and end row numbers
int firstCol = (int) x;
int lastCol = (int) Math.ceil(x + width) - 1;
// **** MAGIC NUMBER ALERT ***
// multiply the point size of the font by 0.59 to give the point size
// I know of no explanation for this yet, other than that it seems to
// give the right answer
// Get the width of the image within the first col, allowing for
// fractional offsets
CellView cellView = sheet.getColumnView(firstCol);
int firstColWidth = cellView.getSize();
double firstColImageWidth = (1 - (x - firstCol)) * firstColWidth;
double pointSize = (cellView.getFormat() != null) ?
cellView.getFormat().getFont().getPointSize() : DEFAULT_FONT_SIZE;
double firstColWidthInPoints = firstColImageWidth * 0.59 * pointSize / 256;
// Get the height of the image within the last row, allowing for
// fractional offsets
int lastColWidth = 0;
double lastColImageWidth = 0;
double lastColWidthInPoints = 0;
if (lastCol != firstCol) {
cellView = sheet.getColumnView(lastCol);
lastColWidth = cellView.getSize();
lastColImageWidth = (x + width - lastCol) * lastColWidth;
pointSize = (cellView.getFormat() != null) ?
cellView.getFormat().getFont().getPointSize() : DEFAULT_FONT_SIZE;
lastColWidthInPoints = lastColImageWidth * 0.59 * pointSize / 256;
}
// Now get all the columns in between
double width = 0;
for (int i = 0; i < lastCol - firstCol - 1; i++) {
cellView = sheet.getColumnView(firstCol + 1 + i);
pointSize = (cellView.getFormat() != null) ?
cellView.getFormat().getFont().getPointSize() : DEFAULT_FONT_SIZE;
width += cellView.getSize() * 0.59 * pointSize / 256;
}
// Add on the first and last row contributions to get the height in twips
double widthInPoints = width +
firstColWidthInPoints + lastColWidthInPoints;
return widthInPoints;
}
/**
* Accessor for the image dimensions. See technotes for Bill's explanation
* of the calculation logic
*
* @return approximate drawing size in pixels
*/
private double getHeightInPoints() {
if (sheet == null) {
logger.warn("calculating image height: sheet is null");
return 0;
}
// The start and end row numbers
int firstRow = (int) y;
int lastRow = (int) Math.ceil(y + height) - 1;
// Get the height of the image within the first row, allowing for
// fractional offsets
int firstRowHeight = sheet.getRowView(firstRow).getSize();
double firstRowImageHeight = (1 - (y - firstRow)) * firstRowHeight;
// Get the height of the image within the last row, allowing for
// fractional offsets
int lastRowHeight = 0;
double lastRowImageHeight = 0;
if (lastRow != firstRow) {
lastRowHeight = sheet.getRowView(lastRow).getSize();
lastRowImageHeight = (y + height - lastRow) * lastRowHeight;
}
// Now get all the rows in between
double height = 0;
for (int i = 0; i < lastRow - firstRow - 1; i++) {
height += sheet.getRowView(firstRow + 1 + i).getSize();
}
// Add on the first and last row contributions to get the height in twips
double heightInTwips = height + firstRowHeight + lastRowHeight;
// Now divide by the magic number to converts twips into pixels and
// return the value
double heightInPoints = heightInTwips / 20.0;
return heightInPoints;
}
/**
* Get the width of this image as rendered within Excel
*
* @param unit the unit of measurement
* @return the width of the image within Excel
*/
public double getWidth(LengthUnit unit) {
double widthInPoints = getWidthInPoints();
return widthInPoints * LengthConverter.getConversionFactor
(LengthUnit.POINTS, unit);
}
/**
* Get the height of this image as rendered within Excel
*
* @param unit the unit of measurement
* @return the height of the image within Excel
*/
public double getHeight(LengthUnit unit) {
double heightInPoints = getHeightInPoints();
return heightInPoints * LengthConverter.getConversionFactor
(LengthUnit.POINTS, unit);
}
/**
* Gets the width of the image. Note that this is the width of the
* underlying image, and does not take into account any size manipulations
* that may have occurred when the image was added into Excel
*
* @return the image width in pixels
*/
public int getImageWidth() {
return getPngReader().getWidth();
}
/**
* Gets the height of the image. Note that this is the height of the
* underlying image, and does not take into account any size manipulations
* that may have occurred when the image was added into Excel
*
* @return the image width in pixels
*/
public int getImageHeight() {
return getPngReader().getHeight();
}
/**
* Gets the horizontal resolution of the image, if that information
* is available.
*
* @return the number of dots per unit specified, if available, 0 otherwise
*/
public double getHorizontalResolution(LengthUnit unit) {
int res = getPngReader().getHorizontalResolution();
return res / LengthConverter.getConversionFactor(LengthUnit.METRES, unit);
}
/**
* Gets the vertical resolution of the image, if that information
* is available.
*
* @return the number of dots per unit specified, if available, 0 otherwise
*/
public double getVerticalResolution(LengthUnit unit) {
int res = getPngReader().getVerticalResolution();
return res / LengthConverter.getConversionFactor(LengthUnit.METRES, unit);
}
private PNGReader getPngReader() {
if (pngReader != null) {
return pngReader;
}
byte[] imdata = null;
if (origin == Origin.READ || origin == Origin.READ_WRITE) {
imdata = getImageData();
} else {
try {
imdata = getImageBytes();
} catch (IOException e) {
logger.warn("Could not read image file");
imdata = new byte[0];
}
}
pngReader = new PNGReader(imdata);
pngReader.read();
return pngReader;
}
/**
* Accessor for the anchor properties
*/
protected ImageAnchorProperties getImageAnchor() {
if (!initialized) {
initialize();
}
return imageAnchorProperties;
}
/**
* Accessor for the anchor properties
*/
protected void setImageAnchor(ImageAnchorProperties iap) {
imageAnchorProperties = iap;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
// Enumeration type for the image anchor properties
protected static class ImageAnchorProperties {
private static ImageAnchorProperties[] o = new ImageAnchorProperties[0];
private final int value;
ImageAnchorProperties(int v) {
value = v;
ImageAnchorProperties[] oldArray = o;
o = new ImageAnchorProperties[oldArray.length + 1];
System.arraycopy(oldArray, 0, o, 0, oldArray.length);
o[oldArray.length] = this;
}
static ImageAnchorProperties getImageAnchorProperties(int val) {
ImageAnchorProperties iap = MOVE_AND_SIZE_WITH_CELLS;
int pos = 0;
while (pos < o.length) {
if (o[pos].getValue() == val) {
iap = o[pos];
break;
} else {
pos++;
}
}
return iap;
}
int getValue() {
return value;
}
}
}

@ -0,0 +1,629 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.FileInputStream;
import java.io.IOException;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.write.biff.File;
/**
* Contains the various biff records used to insert a drawing into a
* worksheet. This type of image does not have an associated object
* record
*/
public class Drawing2 implements DrawingGroupObject {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(Drawing.class);
/**
* The spContainer that was read in
*/
private EscherContainer readSpContainer;
/**
* The MsoDrawingRecord associated with the drawing
*/
private MsoDrawingRecord msoDrawingRecord;
/**
* Initialized flag
*/
private boolean initialized = false;
/**
* The file containing the image
*/
private java.io.File imageFile;
/**
* The raw image data, used instead of an image file
*/
private byte[] imageData;
/**
* The object id, assigned by the drawing group
*/
private int objectId;
/**
* The blip id
*/
private int blipId;
/**
* The column position of the image
*/
private double x;
/**
* The row position of the image
*/
private double y;
/**
* The width of the image in cells
*/
private double width;
/**
* The height of the image in cells
*/
private double height;
/**
* The number of places this drawing is referenced
*/
private int referenceCount;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* Where this image came from (read, written or a copy)
*/
private Origin origin;
/**
* The drawing group for all the images
*/
private DrawingGroup drawingGroup;
/**
* The drawing data
*/
private DrawingData drawingData;
/**
* The type of this drawing object
*/
private ShapeType type;
/**
* The shape id
*/
private int shapeId;
/**
* The drawing position on the sheet
*/
private int drawingNumber;
/**
* Constructor used when reading images
*
* @param mso the drawing record
* @param dd the drawing data for all drawings on this sheet
* @param dg the drawing group
*/
public Drawing2(MsoDrawingRecord mso,
DrawingData dd,
DrawingGroup dg) {
drawingGroup = dg;
msoDrawingRecord = mso;
drawingData = dd;
initialized = false;
origin = Origin.READ;
// there is no drawing number associated with this drawing
drawingData.addRawData(msoDrawingRecord.getData());
drawingGroup.addDrawing(this);
Assert.verify(mso != null);
initialize();
}
/**
* Copy constructor used to copy drawings from read to write
*
* @param dgo the drawing group object
* @param dg the drawing group
*/
protected Drawing2(DrawingGroupObject dgo, DrawingGroup dg) {
Drawing2 d = (Drawing2) dgo;
Assert.verify(d.origin == Origin.READ);
msoDrawingRecord = d.msoDrawingRecord;
initialized = false;
origin = Origin.READ;
drawingData = d.drawingData;
drawingGroup = dg;
drawingNumber = d.drawingNumber;
drawingGroup.addDrawing(this);
}
/**
* Constructor invoked when writing the images
*
* @param x the column
* @param y the row
* @param w the width in cells
* @param h the height in cells
* @param image the image file
*/
public Drawing2(double x,
double y,
double w,
double h,
java.io.File image) {
imageFile = image;
initialized = true;
origin = Origin.WRITE;
this.x = x;
this.y = y;
this.width = w;
this.height = h;
referenceCount = 1;
type = ShapeType.PICTURE_FRAME;
}
/**
* Constructor invoked when writing the images
*
* @param x the column
* @param y the row
* @param w the width in cells
* @param h the height in cells
* @param image the image data
*/
public Drawing2(double x,
double y,
double w,
double h,
byte[] image) {
imageData = image;
initialized = true;
origin = Origin.WRITE;
this.x = x;
this.y = y;
this.width = w;
this.height = h;
referenceCount = 1;
type = ShapeType.PICTURE_FRAME;
}
/**
* Initializes the member variables from the Escher stream data
*/
private void initialize() {
initialized = true;
}
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
public final void setObjectId(int objid, int bip, int sid) {
objectId = objid;
blipId = bip;
shapeId = sid;
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
}
}
/**
* Accessor for the object id
*
* @return the object id
*/
public final int getObjectId() {
if (!initialized) {
initialize();
}
return objectId;
}
/**
* Accessor for the shape id
*
* @return the shape id
*/
public int getShapeId() {
if (!initialized) {
initialize();
}
return shapeId;
}
/**
* Accessor for the blip id
*
* @return the blip id
*/
public final int getBlipId() {
if (!initialized) {
initialize();
}
return blipId;
}
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
public MsoDrawingRecord getMsoDrawingRecord() {
return msoDrawingRecord;
}
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
public EscherContainer getSpContainer() {
if (!initialized) {
initialize();
}
Assert.verify(origin == Origin.READ);
return getReadSpContainer();
}
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
public DrawingGroup getDrawingGroup() {
return drawingGroup;
}
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
public void setDrawingGroup(DrawingGroup dg) {
drawingGroup = dg;
}
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
public Origin getOrigin() {
return origin;
}
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
public int getReferenceCount() {
return referenceCount;
}
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
public void setReferenceCount(int r) {
referenceCount = r;
}
/**
* Accessor for the column of this drawing
*
* @return the column
*/
public double getX() {
if (!initialized) {
initialize();
}
return x;
}
/**
* Sets the column position of this drawing
*
* @param x the column
*/
public void setX(double x) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
this.x = x;
}
/**
* Accessor for the row of this drawing
*
* @return the row
*/
public double getY() {
if (!initialized) {
initialize();
}
return y;
}
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
public void setY(double y) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
this.y = y;
}
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
public double getWidth() {
if (!initialized) {
initialize();
}
return width;
}
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
public void setWidth(double w) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
width = w;
}
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
public double getHeight() {
if (!initialized) {
initialize();
}
return height;
}
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
public void setHeight(double h) {
if (origin == Origin.READ) {
if (!initialized) {
initialize();
}
origin = Origin.READ_WRITE;
}
height = h;
}
/**
* Gets the SpContainer that was read in
*
* @return the read sp container
*/
private EscherContainer getReadSpContainer() {
if (!initialized) {
initialize();
}
return readSpContainer;
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageData() {
Assert.verify(false);
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
if (!initialized) {
initialize();
}
return drawingGroup.getImageData(blipId);
}
/**
* Accessor for the image data
*
* @return the image data
*/
public byte[] getImageBytes() throws IOException {
Assert.verify(false);
if (origin == Origin.READ || origin == Origin.READ_WRITE) {
return getImageData();
}
Assert.verify(origin == Origin.WRITE);
if (imageFile == null) {
Assert.verify(imageData != null);
return imageData;
}
byte[] data = new byte[(int) imageFile.length()];
FileInputStream fis = new FileInputStream(imageFile);
fis.read(data, 0, data.length);
fis.close();
return data;
}
/**
* Accessor for the type
*
* @return the type
*/
public ShapeType getType() {
return type;
}
/**
* Writes any other records associated with this drawing group object
*
* @param outputFile the output file
* @throws IOException
*/
public void writeAdditionalRecords(File outputFile) throws IOException {
// no records to write
}
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
* Does nothing here
*
* @param outputFile the output file
* @throws IOException
*/
public void writeTailRecords(File outputFile) throws IOException {
// does nothing
}
/**
* Interface method
*
* @return the column number at which the image is positioned
*/
public double getColumn() {
return getX();
}
/**
* Interface method
*
* @return the row number at which the image is positions
*/
public double getRow() {
return getY();
}
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
public boolean isFirst() {
return msoDrawingRecord.isFirst();
}
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
public boolean isFormObject() {
return false;
}
/**
* Removes a row
*
* @param r the row to be removed
*/
public void removeRow(int r) {
if (y > r) {
setY(r);
}
}
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
public String getImageFilePath() {
Assert.verify(false);
return null;
}
}

@ -0,0 +1,206 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.util.ArrayList;
import jxl.common.Assert;
import jxl.common.Logger;
/**
* Class used to concatenate all the data for the various drawing objects
* into one continuous stream
*/
public class DrawingData implements EscherStream {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(DrawingData.class);
/**
* The drawing data
*/
private byte[] drawingData;
/**
* The number of drawings
*/
private int numDrawings;
/**
* Initialized flag
*/
private boolean initialized;
/**
* The spgr container. The contains the SpContainer for each drawing
*/
private EscherRecord[] spContainers;
/**
* Constructor
*/
public DrawingData() {
numDrawings = 0;
drawingData = null;
initialized = false;
}
/**
* Initialization
*/
private void initialize() {
EscherRecordData er = new EscherRecordData(this, 0);
Assert.verify(er.isContainer());
EscherContainer dgContainer = new EscherContainer(er);
EscherRecord[] children = dgContainer.getChildren();
children = dgContainer.getChildren();
// Dg dg = (Dg) children[0];
EscherContainer spgrContainer = null;
for (int i = 0; i < children.length && spgrContainer == null; i++) {
EscherRecord child = children[i];
if (child.getType() == EscherRecordType.SPGR_CONTAINER) {
spgrContainer = (EscherContainer) child;
}
}
Assert.verify(spgrContainer != null);
EscherRecord[] spgrChildren = spgrContainer.getChildren();
// See if any of the spgrChildren are SpgrContainer
boolean nestedContainers = false;
for (int i = 0; i < spgrChildren.length && !nestedContainers; i++) {
if (spgrChildren[i].getType() == EscherRecordType.SPGR_CONTAINER) {
nestedContainers = true;
}
}
// If there are no nested containers, simply set the spContainer list
// to be the list of children
if (!nestedContainers) {
spContainers = spgrChildren;
} else {
// Go through the hierarchy and dig out all the Sp containers
ArrayList sps = new ArrayList();
getSpContainers(spgrContainer, sps);
spContainers = new EscherRecord[sps.size()];
spContainers = (EscherRecord[]) sps.toArray(spContainers);
}
initialized = true;
}
/**
* Gets the sp container from the internal data
*
* @param spgrContainer the spgr container
* @param sps the list of sp records
*/
private void getSpContainers(EscherContainer spgrContainer, ArrayList sps) {
EscherRecord[] spgrChildren = spgrContainer.getChildren();
for (int i = 0; i < spgrChildren.length; i++) {
if (spgrChildren[i].getType() == EscherRecordType.SP_CONTAINER) {
sps.add(spgrChildren[i]);
} else if (spgrChildren[i].getType() == EscherRecordType.SPGR_CONTAINER) {
getSpContainers((EscherContainer) spgrChildren[i], sps);
} else {
logger.warn("Spgr Containers contains a record other than Sp/Spgr " +
"containers");
}
}
}
/**
* Adds the byte stream to the drawing data
*
* @param data the data to add
*/
public void addData(byte[] data) {
addRawData(data);
numDrawings++;
}
/**
* Adds the data to the array without incrementing the drawing number.
* This is used by comments, which for some bizarre and inexplicable
* reason split out the data
*
* @param data the data to add
*/
public void addRawData(byte[] data) {
if (drawingData == null) {
drawingData = data;
return;
}
// Resize the array
byte[] newArray = new byte[drawingData.length + data.length];
System.arraycopy(drawingData, 0, newArray, 0, drawingData.length);
System.arraycopy(data, 0, newArray, drawingData.length, data.length);
drawingData = newArray;
// Dirty up this object
initialized = false;
}
/**
* Accessor for the number of drawings
*
* @return the current count of drawings
*/
final int getNumDrawings() {
return numDrawings;
}
/**
* Gets the sp container for the specified drawing number
*
* @param drawingNum the drawing number for which to return the spContainer
* @return the spcontainer
*/
EscherContainer getSpContainer(int drawingNum) {
if (!initialized) {
initialize();
}
if ((drawingNum + 1) >= spContainers.length) {
throw new DrawingDataException();
}
EscherContainer spContainer =
(EscherContainer) spContainers[drawingNum + 1];
Assert.verify(spContainer != null);
return spContainer;
}
/**
* Gets the data which was read in for the drawings
*
* @return the drawing data
*/
public byte[] getData() {
return drawingData;
}
}

@ -0,0 +1,35 @@
/*********************************************************************
*
* Copyright (C) 2006 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
/**
* Checked exception thrown when the drawing data is corrupt eg. when
* the drawing number exceeds the number of SpContainers. This exception
* is handled within the drawing package, and usually causes drawings to be
* disabled for the remainder of the workbook
*/
public class DrawingDataException extends RuntimeException {
private static final String message =
"Drawing number exceeds available SpContainers";
DrawingDataException() {
super(message);
}
}

@ -0,0 +1,534 @@
/*********************************************************************
*
* Copyright (C) 2004 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import jxl.common.Assert;
import jxl.common.Logger;
import jxl.read.biff.Record;
import jxl.write.biff.File;
/**
* This class contains the Excel picture data in Escher format for the
* entire workbook
*/
public class DrawingGroup implements EscherStream {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(DrawingGroup.class);
/**
* The escher data read in from file
*/
private byte[] drawingData;
/**
* The top level escher container
*/
private EscherContainer escherData;
/**
* The Bstore container, which contains all the drawing data
*/
private BStoreContainer bstoreContainer;
/**
* The initialized flag
*/
private boolean initialized;
/**
* The list of user added drawings
*/
private final ArrayList drawings;
/**
* The number of blips
*/
private int numBlips;
/**
* The number of charts
*/
private int numCharts;
/**
* The number of shape ids used on the second Dgg cluster
*/
private int drawingGroupId;
/**
* Flag which indicates that at least one of the drawings has been omitted
* from the worksheet
*/
private boolean drawingsOmitted;
/**
* The origin of this drawing group
*/
private Origin origin;
/**
* A hash map of images keyed on the file path, containing the
* reference count
*/
private final HashMap imageFiles;
/**
* A count of the next available object id
*/
private int maxObjectId;
/**
* The maximum shape id so far encountered
*/
private int maxShapeId;
/**
* Constructor
*
* @param o the origin of this drawing group
*/
public DrawingGroup(Origin o) {
origin = o;
initialized = o == Origin.WRITE;
drawings = new ArrayList();
imageFiles = new HashMap();
drawingsOmitted = false;
maxObjectId = 1;
maxShapeId = 1024;
}
/**
* Copy constructor
* Uses a shallow copy for most things, since as soon as anything
* is changed, the drawing group is invalidated and all the data blocks
* regenerated
*
* @param dg the drawing group to copy
*/
public DrawingGroup(DrawingGroup dg) {
drawingData = dg.drawingData;
escherData = dg.escherData;
bstoreContainer = dg.bstoreContainer;
initialized = dg.initialized;
drawingData = dg.drawingData;
escherData = dg.escherData;
bstoreContainer = dg.bstoreContainer;
numBlips = dg.numBlips;
numCharts = dg.numCharts;
drawingGroupId = dg.drawingGroupId;
drawingsOmitted = dg.drawingsOmitted;
origin = dg.origin;
imageFiles = (HashMap) dg.imageFiles.clone();
maxObjectId = dg.maxObjectId;
maxShapeId = dg.maxShapeId;
// Create this as empty, because all drawings will get added later
// as part of the sheet copy process
drawings = new ArrayList();
}
/**
* /**
* Adds in a drawing group record to this drawing group. The binary
* data is extracted from the drawing group and added to a single
* byte array
*
* @param mso the drawing group record to add
*/
public void add(MsoDrawingGroupRecord mso) {
addData(mso.getData());
}
/**
* Adds a continue record to this drawing group. the binary data is
* extracted and appended to the byte array
*
* @param cont the continue record
*/
public void add(Record cont) {
addData(cont.getData());
}
/**
* Adds the mso record data to the drawing data
*
* @param msodata the raw mso data
*/
private void addData(byte[] msodata) {
if (drawingData == null) {
drawingData = new byte[msodata.length];
System.arraycopy(msodata, 0, drawingData, 0, msodata.length);
return;
}
// Grow the array
byte[] newdata = new byte[drawingData.length + msodata.length];
System.arraycopy(drawingData, 0, newdata, 0, drawingData.length);
System.arraycopy(msodata, 0, newdata, drawingData.length, msodata.length);
drawingData = newdata;
}
/**
* Adds a drawing to the drawing group
*
* @param d the drawing to add
*/
final void addDrawing(DrawingGroupObject d) {
drawings.add(d);
maxObjectId = Math.max(maxObjectId, d.getObjectId());
maxShapeId = Math.max(maxShapeId, d.getShapeId());
}
/**
* Adds a chart to the drawing group
*
* @param c the chart
*/
public void add(Chart c) {
numCharts++;
}
/**
* Adds a drawing from the public, writable interface
*
* @param d the drawing to add
*/
public void add(DrawingGroupObject d) {
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
BStoreContainer bsc = getBStoreContainer(); // force initialization
Dgg dgg = (Dgg) escherData.getChildren()[0];
drawingGroupId = dgg.getCluster(1).drawingGroupId - numBlips - 1;
numBlips = bsc != null ? bsc.getNumBlips() : 0;
if (bsc != null) {
Assert.verify(numBlips == bsc.getNumBlips());
}
}
if (!(d instanceof Drawing)) {
// Assign a new object id and add it to the list
// drawings.add(d);
maxObjectId++;
maxShapeId++;
d.setDrawingGroup(this);
d.setObjectId(maxObjectId, numBlips + 1, maxShapeId);
if (drawings.size() > maxObjectId) {
logger.warn("drawings length " + drawings.size() +
" exceeds the max object id " + maxObjectId);
}
// numBlips++;
return;
}
Drawing drawing = (Drawing) d;
// See if this is referenced elsewhere
Drawing refImage =
(Drawing) imageFiles.get(d.getImageFilePath());
if (refImage == null) {
// There are no other references to this drawing, so assign
// a new object id and put it on the hash map
maxObjectId++;
maxShapeId++;
drawings.add(drawing);
drawing.setDrawingGroup(this);
drawing.setObjectId(maxObjectId, numBlips + 1, maxShapeId);
numBlips++;
imageFiles.put(drawing.getImageFilePath(), drawing);
} else {
// This drawing is used elsewhere in the workbook. Increment the
// reference count on the drawing, and set the object id of the drawing
// passed in
refImage.setReferenceCount(refImage.getReferenceCount() + 1);
drawing.setDrawingGroup(this);
drawing.setObjectId(refImage.getObjectId(),
refImage.getBlipId(),
refImage.getShapeId());
}
}
/**
* Interface method to remove a drawing from the group
*
* @param d the drawing to remove
*/
public void remove(DrawingGroupObject d) {
// Unless there are real images or some such, it is possible that
// a BStoreContainer will not be present. In that case simply return
if (getBStoreContainer() == null) {
return;
}
if (origin == Origin.READ) {
origin = Origin.READ_WRITE;
numBlips = getBStoreContainer().getNumBlips();
Dgg dgg = (Dgg) escherData.getChildren()[0];
drawingGroupId = dgg.getCluster(1).drawingGroupId - numBlips - 1;
}
// Get the blip
EscherRecord[] children = getBStoreContainer().getChildren();
BlipStoreEntry bse = (BlipStoreEntry) children[d.getBlipId() - 1];
bse.dereference();
if (bse.getReferenceCount() == 0) {
// Remove the blip
getBStoreContainer().remove(bse);
// Adjust blipId on the other blips
for (Iterator i = drawings.iterator(); i.hasNext(); ) {
DrawingGroupObject drawing = (DrawingGroupObject) i.next();
if (drawing.getBlipId() > d.getBlipId()) {
drawing.setObjectId(drawing.getObjectId(),
drawing.getBlipId() - 1,
drawing.getShapeId());
}
}
numBlips--;
}
}
/**
* Initializes the drawing data from the escher record read in
*/
private void initialize() {
EscherRecordData er = new EscherRecordData(this, 0);
Assert.verify(er.isContainer());
escherData = new EscherContainer(er);
Assert.verify(escherData.getLength() == drawingData.length);
Assert.verify(escherData.getType() == EscherRecordType.DGG_CONTAINER);
initialized = true;
}
/**
* Gets hold of the BStore container from the Escher data
*
* @return the BStore container
*/
private BStoreContainer getBStoreContainer() {
if (bstoreContainer == null) {
if (!initialized) {
initialize();
}
EscherRecord[] children = escherData.getChildren();
if (children.length > 1 &&
children[1].getType() == EscherRecordType.BSTORE_CONTAINER) {
bstoreContainer = (BStoreContainer) children[1];
}
}
return bstoreContainer;
}
/**
* Gets hold of the binary data
*
* @return the data
*/
public byte[] getData() {
return drawingData;
}
/**
* Writes the drawing group to the output file
*
* @param outputFile the file to write to
* @throws IOException
*/
public void write(File outputFile) throws IOException {
if (origin == Origin.WRITE) {
DggContainer dggContainer = new DggContainer();
Dgg dgg = new Dgg(numBlips + numCharts + 1, numBlips);
dgg.addCluster(1, 0);
dgg.addCluster(numBlips + 1, 0);
dggContainer.add(dgg);
int drawingsAdded = 0;
BStoreContainer bstoreCont = new BStoreContainer();
// Create a blip entry for each drawing
for (Iterator i = drawings.iterator(); i.hasNext(); ) {
Object o = i.next();
if (o instanceof Drawing) {
Drawing d = (Drawing) o;
BlipStoreEntry bse = new BlipStoreEntry(d);
bstoreCont.add(bse);
drawingsAdded++;
}
}
if (drawingsAdded > 0) {
bstoreCont.setNumBlips(drawingsAdded);
dggContainer.add(bstoreCont);
}
Opt opt = new Opt();
dggContainer.add(opt);
SplitMenuColors splitMenuColors = new SplitMenuColors();
dggContainer.add(splitMenuColors);
drawingData = dggContainer.getData();
} else if (origin == Origin.READ_WRITE) {
DggContainer dggContainer = new DggContainer();
Dgg dgg = new Dgg(numBlips + numCharts + 1, numBlips);
dgg.addCluster(1, 0);
dgg.addCluster(drawingGroupId + numBlips + 1, 0);
dggContainer.add(dgg);
BStoreContainer bstoreCont = new BStoreContainer();
bstoreCont.setNumBlips(numBlips);
// Create a blip entry for each drawing that was read in
BStoreContainer readBStoreContainer = getBStoreContainer();
if (readBStoreContainer != null) {
EscherRecord[] children = readBStoreContainer.getChildren();
for (int i = 0; i < children.length; i++) {
BlipStoreEntry bse = (BlipStoreEntry) children[i];
bstoreCont.add(bse);
}
}
// Create a blip entry for each drawing that has been added
for (Iterator i = drawings.iterator(); i.hasNext(); ) {
DrawingGroupObject dgo = (DrawingGroupObject) i.next();
if (dgo instanceof Drawing) {
Drawing d = (Drawing) dgo;
if (d.getOrigin() == Origin.WRITE) {
BlipStoreEntry bse = new BlipStoreEntry(d);
bstoreCont.add(bse);
}
}
}
dggContainer.add(bstoreCont);
Opt opt = new Opt();
opt.addProperty(191, false, false, 524296);
opt.addProperty(385, false, false, 134217737);
opt.addProperty(448, false, false, 134217792);
dggContainer.add(opt);
SplitMenuColors splitMenuColors = new SplitMenuColors();
dggContainer.add(splitMenuColors);
drawingData = dggContainer.getData();
}
MsoDrawingGroupRecord msodg = new MsoDrawingGroupRecord(drawingData);
outputFile.write(msodg);
}
/**
* Accessor for the number of blips in the drawing group
*
* @return the number of blips
*/
final int getNumberOfBlips() {
return numBlips;
}
/**
* Gets the drawing data for the given blip id. Called by the Drawing
* object
*
* @param blipId the blipId
* @return the drawing data
*/
byte[] getImageData(int blipId) {
numBlips = getBStoreContainer().getNumBlips();
Assert.verify(blipId <= numBlips);
Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE);
// Get the blip
EscherRecord[] children = getBStoreContainer().getChildren();
BlipStoreEntry bse = (BlipStoreEntry) children[blipId - 1];
return bse.getImageData();
}
/**
* Indicates that at least one of the drawings has been omitted from
* the worksheet
*
* @param mso the mso record
* @param obj the obj record
*/
public void setDrawingsOmitted(MsoDrawingRecord mso, ObjRecord obj) {
drawingsOmitted = true;
if (obj != null) {
maxObjectId = Math.max(maxObjectId, obj.getObjectId());
}
}
/**
* Accessor for the drawingsOmitted flag
*
* @return TRUE if a drawing has been omitted, FALSE otherwise
*/
public boolean hasDrawingsOmitted() {
return drawingsOmitted;
}
/**
* Updates this with the appropriate data from the drawing group passed in
* This is called during the copy process: this is first initialised as
* an empty object, but during the copy, the source DrawingGroup may
* change. After the copy process, this method is then called to update
* the relevant fields. Unfortunately, the copy process required the
* presence of a drawing group
*
* @param dg the drawing group containing the updated data
*/
public void updateData(DrawingGroup dg) {
drawingsOmitted = dg.drawingsOmitted;
maxObjectId = dg.maxObjectId;
maxShapeId = dg.maxShapeId;
}
}

@ -0,0 +1,231 @@
/*********************************************************************
*
* Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import java.io.IOException;
import jxl.write.biff.File;
/**
* Interface for the various object types that can be added to a drawing
* group
*/
public interface DrawingGroupObject {
/**
* Sets the object id. Invoked by the drawing group when the object is
* added to id
*
* @param objid the object id
* @param bip the blip id
* @param sid the shape id
*/
void setObjectId(int objid, int bip, int sid);
/**
* Accessor for the object id
*
* @return the object id
*/
int getObjectId();
/**
* Accessor for the blip id
*
* @return the blip id
*/
int getBlipId();
/**
* Accessor for the shape id
*
* @return the shape id
*/
int getShapeId();
/**
* Gets the drawing record which was read in
*
* @return the drawing record
*/
MsoDrawingRecord getMsoDrawingRecord();
/**
* Creates the main Sp container for the drawing
*
* @return the SP container
*/
EscherContainer getSpContainer();
/**
* Accessor for the drawing group
*
* @return the drawing group
*/
DrawingGroup getDrawingGroup();
/**
* Sets the drawing group for this drawing. Called by the drawing group
* when this drawing is added to it
*
* @param dg the drawing group
*/
void setDrawingGroup(DrawingGroup dg);
/**
* Gets the origin of this drawing
*
* @return where this drawing came from
*/
Origin getOrigin();
/**
* Accessor for the reference count on this drawing
*
* @return the reference count
*/
int getReferenceCount();
/**
* Sets the new reference count on the drawing
*
* @param r the new reference count
*/
void setReferenceCount(int r);
/**
* Accessor for the column of this drawing
*
* @return the column
*/
double getX();
/**
* Sets the column position of this drawing
*
* @param x the column
*/
void setX(double x);
/**
* Accessor for the row of this drawing
*
* @return the row
*/
double getY();
/**
* Accessor for the row of the drawing
*
* @param y the row
*/
void setY(double y);
/**
* Accessor for the width of this drawing
*
* @return the number of columns spanned by this image
*/
double getWidth();
/**
* Accessor for the width
*
* @param w the number of columns to span
*/
void setWidth(double w);
/**
* Accessor for the height of this drawing
*
* @return the number of rows spanned by this image
*/
double getHeight();
/**
* Accessor for the height of this drawing
*
* @param h the number of rows spanned by this image
*/
void setHeight(double h);
/**
* Accessor for the type
*
* @return the type
*/
ShapeType getType();
/**
* Accessor for the image data
*
* @return the image data
*/
byte[] getImageData();
/**
* Accessor for the image data
*
* @return the image data
*/
byte[] getImageBytes() throws IOException;
/**
* Accessor for the image file path. Normally this is the absolute path
* of a file on the directory system, but if this drawing was constructed
* using an byte[] then the blip id is returned
*
* @return the image file path, or the blip id
*/
String getImageFilePath();
/**
* Writes any other records associated with this drawing group object
*/
void writeAdditionalRecords(File outputFile) throws IOException;
/**
* Writes any records that need to be written after all the drawing group
* objects have been written
*/
void writeTailRecords(File outputFile) throws IOException;
/**
* Accessor for the first drawing on the sheet. This is used when
* copying unmodified sheets to indicate that this drawing contains
* the first time Escher gubbins
*
* @return TRUE if this MSORecord is the first drawing on the sheet
*/
boolean isFirst();
/**
* Queries whether this object is a form object. Form objects have their
* drawings records spread over TXO and CONTINUE records and
* require special handling
*
* @return TRUE if this is a form object, FALSE otherwise
*/
boolean isFormObject();
}

@ -0,0 +1,63 @@
/*********************************************************************
*
* Copyright (C) 2003 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/
package jxl.biff.drawing;
import jxl.common.Logger;
/**
* Class for atoms. This may be instantiated as is for unknown/uncared about
* atoms, or subclassed if we have some semantic interest in the contents
*/
class EscherAtom extends EscherRecord {
/**
* The logger
*/
private static final Logger logger = Logger.getLogger(EscherAtom.class);
/**
* Constructor
*
* @param erd the escher record data
*/
public EscherAtom(EscherRecordData erd) {
super(erd);
}
/**
* Constructor
*
* @param type the type
*/
protected EscherAtom(EscherRecordType type) {
super(type);
}
/**
* Gets the data for writing
*
* @return the data
*/
byte[] getData() {
logger.warn("escher atom getData called on object of type " +
getClass().getName() + " code " +
Integer.toString(getType().getValue(), 16));
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save