/** A record containing the necessary data for the font information */ public class FontRecord extends WritableRecordData implements Font { /** The logger */ private static 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 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; /** Dummy indicators for overloading the constructor */ private static class Biff7 {}; 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; /** * 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 = false; 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; if (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)) { return true; } return false; } /** * 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; } }
/** Parses the biff file passed in, and builds up an internal representation of the spreadsheet */ public class WorkbookParser extends Workbook implements ExternalSheet, WorkbookMethods { /** The logger */ private static Logger logger = Logger.getLogger(WorkbookParser.class); /** The excel file */ private File excelFile; /** The number of open bofs */ private int bofs; /** Indicates whether or not the dates are based around the 1904 date system */ private boolean nineteenFour; /** The shared string table */ private SSTRecord sharedStrings; /** The names of all the worksheets */ private ArrayList boundsheets; /** The xf records */ private FormattingRecords formattingRecords; /** The fonts used by this workbook */ private Fonts fonts; /** The sheets contained in this workbook */ private ArrayList sheets; /** The last sheet accessed */ private SheetImpl lastSheet; /** The index of the last sheet retrieved */ private int lastSheetIndex; /** The named records found in this workbook */ private HashMap namedRecords; /** The list of named records */ private ArrayList nameTable; /** The external sheet record. Used by formulas, and names */ private ExternalSheetRecord externSheet; /** The list of supporting workbooks - used by formulas */ private ArrayList supbooks; /** The bof record for this workbook */ private BOFRecord workbookBof; /** The Mso Drawing Group record for this workbook */ private MsoDrawingGroupRecord msoDrawingGroup; /** The property set record associated with this workbook */ private ButtonPropertySetRecord buttonPropertySet; /** Workbook protected flag */ private boolean wbProtected; /** Contains macros flag */ private boolean containsMacros; /** The workbook settings */ private WorkbookSettings settings; /** The drawings contained in this workbook */ private DrawingGroup drawingGroup; /** * Constructs this object from the raw excel data * * @param f the excel 97 biff file * @param s the workbook settings */ public WorkbookParser(File f, WorkbookSettings s) { super(); excelFile = f; boundsheets = new ArrayList(10); fonts = new Fonts(); formattingRecords = new FormattingRecords(fonts); sheets = new ArrayList(10); supbooks = new ArrayList(10); namedRecords = new HashMap(); lastSheetIndex = -1; wbProtected = false; containsMacros = false; settings = s; } /** * Gets the sheets within this workbook. NOTE: Use of this method for very large worksheets can * cause performance and out of memory problems. Use the alternative method getSheet() to retrieve * each sheet individually * * @return an array of the individual sheets */ public Sheet[] getSheets() { Sheet[] sheetArray = new Sheet[getNumberOfSheets()]; for (int i = 0; i < getNumberOfSheets(); i++) { sheetArray[i] = (Sheet) sheets.get(i); } return sheetArray; } /** * Interface method from 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 */ public Sheet getReadSheet(int index) { return getSheet(index); } /** * Gets the specified sheet within this workbook * * @param index the zero based index of the required sheet * @return The sheet specified by the index */ public Sheet getSheet(int index) { // First see if the last sheet index is the same as this sheet index. // If so, then the same sheet is being re-requested, so simply // return it instead of rereading it if ((lastSheet != null) && lastSheetIndex == index) { return lastSheet; } // Flush out all of the cached data in the last sheet if (lastSheet != null) { lastSheet.clear(); if (!settings.getGCDisabled()) { System.gc(); } } lastSheet = (SheetImpl) sheets.get(index); lastSheetIndex = index; lastSheet.readSheet(); return lastSheet; } /** * Gets the sheet with the specified name from within this workbook * * @param name the sheet name * @return The sheet with the specified name, or null if it is not found */ public Sheet getSheet(String name) { // Iterate through the boundsheet records int pos = 0; boolean found = false; Iterator i = boundsheets.iterator(); BoundsheetRecord br = null; while (i.hasNext() && !found) { br = (BoundsheetRecord) i.next(); if (br.getName().equals(name)) { found = true; } else { pos++; } } return found ? getSheet(pos) : null; } /** * Gets the sheet names * * @return an array of strings containing the sheet names */ public String[] getSheetNames() { String[] names = new String[boundsheets.size()]; BoundsheetRecord br = null; for (int i = 0; i < names.length; i++) { br = (BoundsheetRecord) boundsheets.get(i); names[i] = br.getName(); } return names; } /** * Package protected function which gets the real internal sheet index based upon the external * sheet reference. This is used for extern sheet references which are specified in formulas * * @param index the external sheet reference * @return the actual sheet index */ public int getExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { return index; } Assert.verify(externSheet != null); int firstTab = externSheet.getFirstTabIndex(index); return firstTab; } /** * Package protected function which gets the real internal sheet index based upon the external * sheet reference. This is used for extern sheet references which are specified in formulas * * @param index the external sheet reference * @return the actual sheet index */ public int getLastExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { return index; } Assert.verify(externSheet != null); int lastTab = externSheet.getLastTabIndex(index); return lastTab; } /** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int firstTab = externSheet.getFirstTabIndex(index); if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(firstTab); return br.getName(); } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); sb.append('['); sb.append(sr.getFileName()); sb.append(']'); sb.append(sr.getSheetName(firstTab)); return sb.toString(); } // An unknown supbook - return unkown return "[UNKNOWN]"; } /** * Gets the name of the external sheet specified by the index * * @param index the external sheet index * @return the name of the external sheet */ public String getLastExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); int lastTab = externSheet.getLastTabIndex(index); if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the boundsheets list BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); return br.getName(); } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record StringBuffer sb = new StringBuffer(); sb.append('['); sb.append(sr.getFileName()); sb.append(']'); sb.append(sr.getSheetName(lastTab)); return sb.toString(); } // An unknown supbook - return unkown return "[UNKNOWN]"; } /** * Returns the number of sheets in this workbook * * @return the number of sheets in this workbook */ public int getNumberOfSheets() { return sheets.size(); } /** Closes this workbook, and frees makes any memory allocated available for garbage collection */ public void close() { if (lastSheet != null) { lastSheet.clear(); } excelFile.clear(); if (!settings.getGCDisabled()) { System.gc(); } } /** * Adds the sheet to the end of the array * * @param s the sheet to add */ final void addSheet(Sheet s) { sheets.add(s); } /** * Does the hard work of building up the object graph from the excel bytes * * @exception BiffException * @exception PasswordException if the workbook is password protected */ protected void parse() throws BiffException, PasswordException { Record r = null; BOFRecord bof = new BOFRecord(excelFile.next()); workbookBof = bof; bofs++; if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (!bof.isWorkbookGlobals()) { throw new BiffException(BiffException.expectedGlobals); } ArrayList continueRecords = new ArrayList(); nameTable = new ArrayList(); // Skip to the first worksheet while (bofs == 1) { r = excelFile.next(); if (r.getType() == Type.SST) { continueRecords.clear(); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { continueRecords.add(excelFile.next()); nextrec = excelFile.peek(); } // cast the array Object[] rec = continueRecords.toArray(); Record[] records = new Record[rec.length]; System.arraycopy(rec, 0, records, 0, rec.length); sharedStrings = new SSTRecord(r, records, settings); } else if (r.getType() == Type.FILEPASS) { throw new PasswordException(); } else if (r.getType() == Type.NAME) { NameRecord nr = null; if (bof.isBiff8()) { nr = new NameRecord(r, settings, namedRecords.size()); } else { nr = new NameRecord(r, settings, namedRecords.size(), NameRecord.biff7); } namedRecords.put(nr.getName(), nr); nameTable.add(nr); } else if (r.getType() == Type.FONT) { FontRecord fr = null; if (bof.isBiff8()) { fr = new FontRecord(r, settings); } else { fr = new FontRecord(r, settings, FontRecord.biff7); } fonts.addFont(fr); } else if (r.getType() == Type.PALETTE) { PaletteRecord palette = new PaletteRecord(r); formattingRecords.setPalette(palette); } else if (r.getType() == Type.NINETEENFOUR) { NineteenFourRecord nr = new NineteenFourRecord(r); nineteenFour = nr.is1904(); } else if (r.getType() == Type.FORMAT) { FormatRecord fr = null; if (bof.isBiff8()) { fr = new FormatRecord(r, settings, FormatRecord.biff8); } else { fr = new FormatRecord(r, settings, FormatRecord.biff7); } try { formattingRecords.addFormat(fr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.XF) { XFRecord xfr = null; if (bof.isBiff8()) { xfr = new XFRecord(r, XFRecord.biff8); } else { xfr = new XFRecord(r, XFRecord.biff7); } try { formattingRecords.addStyle(xfr); } catch (NumFormatRecordsException e) { // This should not happen. Bomb out Assert.verify(false, e.getMessage()); } } else if (r.getType() == Type.BOUNDSHEET) { BoundsheetRecord br = null; if (bof.isBiff8()) { br = new BoundsheetRecord(r); } else { br = new BoundsheetRecord(r, BoundsheetRecord.biff7); } if (br.isSheet() || br.isChart()) { boundsheets.add(br); } } else if (r.getType() == Type.EXTERNSHEET) { if (bof.isBiff8()) { externSheet = new ExternalSheetRecord(r, settings); } else { externSheet = new ExternalSheetRecord(r, settings, ExternalSheetRecord.biff7); } } else if (r.getType() == Type.CODEPAGE) { CodepageRecord cr = new CodepageRecord(r); settings.setCharacterSet(cr.getCharacterSet()); } else if (r.getType() == Type.SUPBOOK) { SupbookRecord sr = new SupbookRecord(r, settings); supbooks.add(sr); } else if (r.getType() == Type.PROTECT) { ProtectRecord pr = new ProtectRecord(r); wbProtected = pr.isProtected(); } else if (r.getType() == Type.OBJPROJ) { containsMacros = true; } else if (r.getType() == Type.MSODRAWINGGROUP) { msoDrawingGroup = new MsoDrawingGroupRecord(r); if (drawingGroup == null) { drawingGroup = new DrawingGroup(DrawingGroup.READ); } drawingGroup.add(msoDrawingGroup); Record nextrec = excelFile.peek(); while (nextrec.getType() == Type.CONTINUE) { drawingGroup.add(excelFile.next()); nextrec = excelFile.peek(); } } else if (r.getType() == Type.BUTTONPROPERTYSET) { buttonPropertySet = new ButtonPropertySetRecord(r); } else if (r.getType() == Type.EOF) { bofs--; } } bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } // Only get sheets for which there is a corresponding Boundsheet record while (bof != null && getNumberOfSheets() < boundsheets.size()) { if (!bof.isBiff8() && !bof.isBiff7()) { throw new BiffException(BiffException.unrecognizedBiffVersion); } if (bof.isWorksheet()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else if (bof.isChart()) { // Read the sheet in SheetImpl s = new SheetImpl( excelFile, sharedStrings, formattingRecords, bof, workbookBof, nineteenFour, this); BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else { logger.warn("BOF is unrecognized"); while (excelFile.hasNext() && r.getType() != Type.EOF) { r = excelFile.next(); } } // The next record will normally be a BOF or empty padding until // the end of the block is reached. In exceptionally unlucky cases, // the last EOF will coincide with a block division, so we have to // check there is more data to retrieve. // Thanks to liamg for spotting this bof = null; if (excelFile.hasNext()) { r = excelFile.next(); if (r.getType() == Type.BOF) { bof = new BOFRecord(r); } } } } /** * Accessor for the formattingRecords, used by the WritableWorkbook when creating a copy of this * * @return the formatting records */ public FormattingRecords getFormattingRecords() { return formattingRecords; } /** * Accessor for the externSheet, used by the WritableWorkbook when creating a copy of this * * @return the external sheet record */ public ExternalSheetRecord getExternalSheetRecord() { return externSheet; } /** * Accessor for the MsoDrawingGroup, used by the WritableWorkbook when creating a copy of this * * @return the Mso Drawing Group record */ public MsoDrawingGroupRecord getMsoDrawingGroupRecord() { return msoDrawingGroup; } /** * Accessor for the supbook records, used by the WritableWorkbook when creating a copy of this * * @return the supbook records */ public SupbookRecord[] getSupbookRecords() { SupbookRecord[] sr = new SupbookRecord[supbooks.size()]; for (int i = 0; i < sr.length; i++) { sr[i] = (SupbookRecord) supbooks.get(i); } return sr; } /** * Accessor for the name records. Used by the WritableWorkbook when creating a copy of this * * @return the array of names */ public NameRecord[] getNameRecords() { NameRecord[] na = new NameRecord[nameTable.size()]; for (int i = 0; i < nameTable.size(); i++) { na[i] = (NameRecord) nameTable.get(i); } return na; } /** * Accessor for the fonts, used by the WritableWorkbook when creating a copy of this * * @return the fonts used in this workbook */ public Fonts getFonts() { return fonts; } /** * 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 * * @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 Cell findCellByName(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); if (nr == null) { return null; } NameRecord.NameRange[] ranges = nr.getRanges(); // Go and retrieve the first cell in the first range Sheet s = getSheet(ranges[0].getExternalSheet()); Cell cell = s.getCell(ranges[0].getFirstColumn(), ranges[0].getFirstRow()); return cell; } /** * 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 to find * @return the range of cells */ public Range[] findByName(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); if (nr == null) { return null; } NameRecord.NameRange[] ranges = nr.getRanges(); Range[] cellRanges = new Range[ranges.length]; for (int i = 0; i < ranges.length; i++) { cellRanges[i] = new RangeImpl( this, getExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getFirstColumn(), ranges[i].getFirstRow(), getLastExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getLastColumn(), ranges[i].getLastRow()); } return cellRanges; } /** * Gets the named ranges * * @return the list of named cells within the workbook */ public String[] getRangeNames() { Object[] keys = namedRecords.keySet().toArray(); String[] names = new String[keys.length]; System.arraycopy(keys, 0, names, 0, keys.length); return names; } /** * Method used when parsing formulas to make sure we are trying to parse a supported biff version * * @return the BOF record */ public BOFRecord getWorkbookBof() { return workbookBof; } /** * Determines whether the sheet is protected * * @return whether or not the sheet is protected */ public boolean isProtected() { return wbProtected; } /** * Accessor for the settings * * @return the workbook settings */ public WorkbookSettings getSettings() { return settings; } /** * Accessor/implementation method for the external sheet reference * * @param sheetName the sheet name to look for * @return the external sheet index */ public int getExternalSheetIndex(String sheetName) { return 0; } /** * Accessor/implementation method for the external sheet reference * * @param sheetName the sheet name to look for * @return the external sheet index */ public int getLastExternalSheetIndex(String sheetName) { return 0; } /** * Gets the name at the specified index * * @param index the index into the name table * @return the name of the cell */ public String getName(int index) { Assert.verify(index >= 0 && index < nameTable.size()); return ((NameRecord) nameTable.get(index)).getName(); } /** * Gets the index of the name record for the name * * @param name the name to search for * @return the index in the name table */ public int getNameIndex(String name) { NameRecord nr = (NameRecord) namedRecords.get(name); return nr != null ? nr.getIndex() : 0; } /** Accessor for the drawing group */ public DrawingGroup getDrawingGroup() { return drawingGroup; } /** * Accessor for the CompoundFile. For this feature to return non-null value, the propertySets * feature in WorkbookSettings must be enabled and the workbook must contain additional property * sets. This method is used during the workbook copy * * @return the base compound file if it contains additional data items and property sets are * enabled */ public CompoundFile getCompoundFile() { return excelFile.getCompoundFile(); } /** * Accessor for the containsMacros * * @return TRUE if this workbook contains macros, FALSE otherwise */ public boolean containsMacros() { return containsMacros; } /** Accessor for the button property set, used during copying */ public ButtonPropertySetRecord getButtonPropertySet() { return buttonPropertySet; } }