From: Nick Burch Date: Sun, 18 May 2008 16:25:00 +0000 (+0000) Subject: Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-63924... X-Git-Tag: REL_3_5_BETA2~84 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d0fec10d56efe5047151c7c6e7f795581abfde43;p=poi.git Merged revisions 638786-638802,638805-638811,638813-638814,638816-639230,639233-639241,639243-639253,639255-639486,639488-639601,639603-639835,639837-639917,639919-640056,640058-640710,640712-641156,641158-641184,641186-641795,641797-641798,641800-641933,641935-641963,641965-641966,641968-641995,641997-642230,642232-642562,642564-642565,642568-642570,642572-642573,642576-642736,642739-642877,642879,642881-642890,642892-642903,642905-642945,642947-643624,643626-643653,643655-643669,643671,643673-643830,643832-643833,643835-644342,644344-644472,644474-644508,644510-645347,645349-645351,645353-645559,645561-645565,645568-645951,645953-646193,646195-646311,646313-646404,646406-646665,646667-646853,646855-646869,646871-647151,647153-647185,647187-647277,647279-647566,647568-647573,647575,647578-647711,647714-647737,647739-647823,647825-648155,648157-648202,648204-648273,648275,648277-648302,648304-648333,648335-648588,648590-648622,648625-648673,648675-649141,649144,649146-649556,649558-649795,649799,649801-649910,649912-649913,649915-650128,650131-650132,650134-650137,650140-650914,650916-651991,651993-652284,652286-652287,652289,652291,652293-652297,652299-652328,652330-652425,652427-652445,652447-652560,652562-652933,652935,652937-652993,652995-653116,653118-653124,653126-653483,653487-653519,653522-653550,653552-653607,653609-653667,653669-653674,653676-653814,653817-653830,653832-653891,653893-653944,653946-654055,654057-654355,654357-654365,654367-654648,654651-655215,655217-655277,655279-655281,655283-655911,655913-656212,656214,656216-656251,656253-656698,656700-656756,656758-656892,656894-657135,657137-657578 via svnmerge from https://svn.apache.org:443/repos/asf/poi/trunk ........ r657166 | josh | 2008-05-16 19:46:04 +0100 (Fri, 16 May 2008) | 1 line Simplification of BiffViewer. Made easier to send results to file. ........ r657167 | josh | 2008-05-16 19:55:02 +0100 (Fri, 16 May 2008) | 1 line Fix for bug 40414 - update selected/active sheet after removing sheet from workbook ........ r657180 | josh | 2008-05-16 20:24:47 +0100 (Fri, 16 May 2008) | 1 line fixed bug number in junit msg - from r656893 bug 44523 ........ r657355 | yegor | 2008-05-17 15:00:30 +0100 (Sat, 17 May 2008) | 1 line added HSSFName.isDeleted() to check if the name points to cell that no longer exists ........ r657358 | yegor | 2008-05-17 15:03:27 +0100 (Sat, 17 May 2008) | 1 line misc bug fixes ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@657579 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index b2dea5c407..380ecb923c 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -44,6 +44,8 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx + 24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists + 40414 - fixed selected/active sheet after removing sheet from workbook 44523 - fixed workbook sheet selection and focus 45000 - Fixed NPE in ListLevel when numberText is null 44985 - Properly update TextSpecInfoAtom when the parent text is changed diff --git a/src/documentation/content/xdocs/spreadsheet/quick-guide.xml b/src/documentation/content/xdocs/spreadsheet/quick-guide.xml index cdad1392be..7523f500d8 100644 --- a/src/documentation/content/xdocs/spreadsheet/quick-guide.xml +++ b/src/documentation/content/xdocs/spreadsheet/quick-guide.xml @@ -1284,6 +1284,20 @@ Examples: Cell c = r.getCell(crefs[j].getCol()); // Do something with this corner cell } + } + +

+ Note, when a cell is deleted, Excel does not delete the + attached named range. As result, workbook can contain + named ranges that point to cells that no longer exist. + You should check the validity of a reference before + constructing AreaReference +

+ + if(hssfName.isDeleted()){ + //named range points to a deleted cell. + } else { + AreaReference ref = new AreaReference(hssfName.getReference()); } diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 75117754bd..ebf869ce95 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -41,6 +41,8 @@ Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx
+ 24207 - added HSSFName.isDeleted() to check if the name points to cell that no longer exists + 40414 - fixed selected/active sheet after removing sheet from workbook 44523 - fixed workbook sheet selection and focus 45000 - Fixed NPE in ListLevel when numberText is null 44985 - Properly update TextSpecInfoAtom when the parent text is changed diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java index 242a85f45f..cd43651912 100644 --- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java +++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java @@ -15,22 +15,20 @@ limitations under the License. ==================================================================== */ -/* - * BiffViewer.java - * - * Created on November 13, 2001, 9:23 AM - */ package org.apache.poi.hssf.dev; -import org.apache.poi.hssf.record.*; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.util.HexDump; - +import java.io.File; import java.io.FileInputStream; -import java.io.IOException; +import java.io.FileOutputStream; import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; import java.util.ArrayList; +import org.apache.poi.hssf.record.*; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.HexDump; + /** * Utillity for reading in BIFF8 records and displaying data from them. * @@ -38,38 +36,26 @@ import java.util.ArrayList; *@author Glen Stampoultzis (glens at apache.org) *@see #main */ - -public class BiffViewer { - String filename; +public final class BiffViewer { + private final File _inputFile; private boolean dump; + private final PrintStream _ps; - /** - * Creates new BiffViewer - * - *@param args - */ - - public BiffViewer(String[] args) { - if (args.length > 0) { - filename = args[0]; - } else { - System.out.println("BIFFVIEWER REQUIRES A FILENAME***"); - } + public BiffViewer(File inFile, PrintStream ps) { + _inputFile = inFile; + _ps = ps; } /** * Method run starts up BiffViewer... */ - public void run() { try { - POIFSFileSystem fs = - new POIFSFileSystem(new FileInputStream(filename)); - InputStream stream = - fs.createDocumentInputStream("Workbook"); - createRecords(stream, dump); + POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(_inputFile)); + InputStream stream = fs.createDocumentInputStream("Workbook"); + createRecords(stream, dump, _ps); } catch (Exception e) { e.printStackTrace(); } @@ -86,451 +72,306 @@ public class BiffViewer { * InputStream *@exception RecordFormatException on error processing the InputStream */ - - public static Record[] createRecords(InputStream in, boolean dump) + public static Record[] createRecords(InputStream in, boolean dump, PrintStream ps) throws RecordFormatException { ArrayList records = new ArrayList(); RecordDetails activeRecord = null; - try { - BiffviewRecordInputStream recStream = new BiffviewRecordInputStream(in); - while (recStream.hasNextRecord()) { + BiffviewRecordInputStream recStream = new BiffviewRecordInputStream(in); + while (recStream.hasNextRecord()) { recStream.nextRecord(); if (recStream.getSid() != 0) { - Record record = createRecord (recStream); + Record record = createRecord (recStream); if (record.getSid() != ContinueRecord.sid) { records.add(record); if (activeRecord != null) - activeRecord.dump(); - activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), (int)recStream.getPos(), record); + activeRecord.dump(ps); + activeRecord = new RecordDetails(recStream.getSid(), recStream.getLength(), (int)recStream.getPos(), record); } if (dump) { - recStream.dumpBytes(); - } + recStream.dumpBytes(ps); } - } - activeRecord.dump(); - } catch (IOException e) { - throw new RecordFormatException("Error reading bytes", e); + } + } + if (activeRecord != null) { + activeRecord.dump(ps); } Record[] retval = new Record[records.size()]; - - retval = (Record[]) records.toArray(retval); + records.toArray(retval); return retval; } - private static void dumpNormal(Record record, int startloc, short rectype, short recsize) - { - System.out.println("Offset 0x" + Integer.toHexString(startloc) + " (" + startloc + ")"); - System.out.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size = " + recsize ); - System.out.println( record.toString() ); - - } /** - * Essentially a duplicate of RecordFactory. Kept seperate as not to screw + * Essentially a duplicate of RecordFactory. Kept separate as not to screw * up non-debug operations. * */ private static Record createRecord( RecordInputStream in ) { - Record retval = null; - switch ( in.getSid() ) { - case ChartRecord.sid: - retval = new ChartRecord( in ); - break; + return new ChartRecord( in ); case ChartFormatRecord.sid: - retval = new ChartFormatRecord( in ); - break; + return new ChartFormatRecord( in ); case SeriesRecord.sid: - retval = new SeriesRecord( in ); - break; + return new SeriesRecord( in ); case BeginRecord.sid: - retval = new BeginRecord( in ); - break; + return new BeginRecord( in ); case EndRecord.sid: - retval = new EndRecord( in ); - break; + return new EndRecord( in ); case BOFRecord.sid: - retval = new BOFRecord( in ); - break; + return new BOFRecord( in ); case InterfaceHdrRecord.sid: - retval = new InterfaceHdrRecord( in ); - break; + return new InterfaceHdrRecord( in ); case MMSRecord.sid: - retval = new MMSRecord( in ); - break; + return new MMSRecord( in ); case InterfaceEndRecord.sid: - retval = new InterfaceEndRecord( in ); - break; + return new InterfaceEndRecord( in ); case WriteAccessRecord.sid: - retval = new WriteAccessRecord( in ); - break; + return new WriteAccessRecord( in ); case CodepageRecord.sid: - retval = new CodepageRecord( in ); - break; + return new CodepageRecord( in ); case DSFRecord.sid: - retval = new DSFRecord( in ); - break; + return new DSFRecord( in ); case TabIdRecord.sid: - retval = new TabIdRecord( in ); - break; + return new TabIdRecord( in ); case FnGroupCountRecord.sid: - retval = new FnGroupCountRecord( in ); - break; + return new FnGroupCountRecord( in ); case WindowProtectRecord.sid: - retval = new WindowProtectRecord( in ); - break; + return new WindowProtectRecord( in ); case ProtectRecord.sid: - retval = new ProtectRecord( in ); - break; + return new ProtectRecord( in ); case PasswordRecord.sid: - retval = new PasswordRecord( in ); - break; + return new PasswordRecord( in ); case ProtectionRev4Record.sid: - retval = new ProtectionRev4Record( in ); - break; + return new ProtectionRev4Record( in ); case PasswordRev4Record.sid: - retval = new PasswordRev4Record( in ); - break; + return new PasswordRev4Record( in ); case WindowOneRecord.sid: - retval = new WindowOneRecord( in ); - break; + return new WindowOneRecord( in ); case BackupRecord.sid: - retval = new BackupRecord( in ); - break; + return new BackupRecord( in ); case HideObjRecord.sid: - retval = new HideObjRecord( in ); - break; + return new HideObjRecord( in ); case DateWindow1904Record.sid: - retval = new DateWindow1904Record( in ); - break; + return new DateWindow1904Record( in ); case PrecisionRecord.sid: - retval = new PrecisionRecord( in ); - break; + return new PrecisionRecord( in ); case RefreshAllRecord.sid: - retval = new RefreshAllRecord( in ); - break; + return new RefreshAllRecord( in ); case BookBoolRecord.sid: - retval = new BookBoolRecord( in ); - break; + return new BookBoolRecord( in ); case FontRecord.sid: - retval = new FontRecord( in ); - break; + return new FontRecord( in ); case FormatRecord.sid: - retval = new FormatRecord( in ); - break; + return new FormatRecord( in ); case ExtendedFormatRecord.sid: - retval = new ExtendedFormatRecord( in ); - break; + return new ExtendedFormatRecord( in ); case StyleRecord.sid: - retval = new StyleRecord( in ); - break; + return new StyleRecord( in ); case UseSelFSRecord.sid: - retval = new UseSelFSRecord( in ); - break; + return new UseSelFSRecord( in ); case BoundSheetRecord.sid: - retval = new BoundSheetRecord( in ); - break; + return new BoundSheetRecord( in ); case CountryRecord.sid: - retval = new CountryRecord( in ); - break; + return new CountryRecord( in ); case SSTRecord.sid: - retval = new SSTRecord( in ); - break; + return new SSTRecord( in ); case ExtSSTRecord.sid: - retval = new ExtSSTRecord( in ); - break; + return new ExtSSTRecord( in ); case EOFRecord.sid: - retval = new EOFRecord( in ); - break; + return new EOFRecord( in ); case IndexRecord.sid: - retval = new IndexRecord( in ); - break; + return new IndexRecord( in ); case CalcModeRecord.sid: - retval = new CalcModeRecord( in ); - break; + return new CalcModeRecord( in ); case CalcCountRecord.sid: - retval = new CalcCountRecord( in ); - break; + return new CalcCountRecord( in ); case RefModeRecord.sid: - retval = new RefModeRecord( in ); - break; + return new RefModeRecord( in ); case IterationRecord.sid: - retval = new IterationRecord( in ); - break; + return new IterationRecord( in ); case DeltaRecord.sid: - retval = new DeltaRecord( in ); - break; + return new DeltaRecord( in ); case SaveRecalcRecord.sid: - retval = new SaveRecalcRecord( in ); - break; + return new SaveRecalcRecord( in ); case PrintHeadersRecord.sid: - retval = new PrintHeadersRecord( in ); - break; + return new PrintHeadersRecord( in ); case PrintGridlinesRecord.sid: - retval = new PrintGridlinesRecord( in ); - break; + return new PrintGridlinesRecord( in ); case GridsetRecord.sid: - retval = new GridsetRecord( in ); - break; + return new GridsetRecord( in ); case DrawingGroupRecord.sid: - retval = new DrawingGroupRecord( in ); - break; + return new DrawingGroupRecord( in ); case DrawingRecordForBiffViewer.sid: - retval = new DrawingRecordForBiffViewer( in ); - break; + return new DrawingRecordForBiffViewer( in ); case DrawingSelectionRecord.sid: - retval = new DrawingSelectionRecord( in ); - break; + return new DrawingSelectionRecord( in ); case GutsRecord.sid: - retval = new GutsRecord( in ); - break; + return new GutsRecord( in ); case DefaultRowHeightRecord.sid: - retval = new DefaultRowHeightRecord( in ); - break; + return new DefaultRowHeightRecord( in ); case WSBoolRecord.sid: - retval = new WSBoolRecord( in ); - break; + return new WSBoolRecord( in ); case HeaderRecord.sid: - retval = new HeaderRecord( in ); - break; + return new HeaderRecord( in ); case FooterRecord.sid: - retval = new FooterRecord( in ); - break; + return new FooterRecord( in ); case HCenterRecord.sid: - retval = new HCenterRecord( in ); - break; + return new HCenterRecord( in ); case VCenterRecord.sid: - retval = new VCenterRecord( in ); - break; + return new VCenterRecord( in ); case PrintSetupRecord.sid: - retval = new PrintSetupRecord( in ); - break; + return new PrintSetupRecord( in ); case DefaultColWidthRecord.sid: - retval = new DefaultColWidthRecord( in ); - break; + return new DefaultColWidthRecord( in ); case DimensionsRecord.sid: - retval = new DimensionsRecord( in ); - break; + return new DimensionsRecord( in ); case RowRecord.sid: - retval = new RowRecord( in ); - break; + return new RowRecord( in ); case LabelSSTRecord.sid: - retval = new LabelSSTRecord( in ); - break; + return new LabelSSTRecord( in ); case RKRecord.sid: - retval = new RKRecord( in ); - break; + return new RKRecord( in ); case NumberRecord.sid: - retval = new NumberRecord( in ); - break; + return new NumberRecord( in ); case DBCellRecord.sid: - retval = new DBCellRecord( in ); - break; + return new DBCellRecord( in ); case WindowTwoRecord.sid: - retval = new WindowTwoRecord( in ); - break; + return new WindowTwoRecord( in ); case SelectionRecord.sid: - retval = new SelectionRecord( in ); - break; + return new SelectionRecord( in ); case ContinueRecord.sid: - retval = new ContinueRecord( in ); - break; + return new ContinueRecord( in ); case LabelRecord.sid: - retval = new LabelRecord( in ); - break; + return new LabelRecord( in ); case MulRKRecord.sid: - retval = new MulRKRecord( in ); - break; + return new MulRKRecord( in ); case MulBlankRecord.sid: - retval = new MulBlankRecord( in ); - break; + return new MulBlankRecord( in ); case BlankRecord.sid: - retval = new BlankRecord( in ); - break; + return new BlankRecord( in ); case BoolErrRecord.sid: - retval = new BoolErrRecord( in ); - break; + return new BoolErrRecord( in ); case ColumnInfoRecord.sid: - retval = new ColumnInfoRecord( in ); - break; + return new ColumnInfoRecord( in ); case MergeCellsRecord.sid: - retval = new MergeCellsRecord( in ); - break; + return new MergeCellsRecord( in ); case AreaRecord.sid: - retval = new AreaRecord( in ); - break; + return new AreaRecord( in ); case DataFormatRecord.sid: - retval = new DataFormatRecord( in ); - break; + return new DataFormatRecord( in ); case BarRecord.sid: - retval = new BarRecord( in ); - break; + return new BarRecord( in ); case DatRecord.sid: - retval = new DatRecord( in ); - break; + return new DatRecord( in ); case PlotGrowthRecord.sid: - retval = new PlotGrowthRecord( in ); - break; + return new PlotGrowthRecord( in ); case UnitsRecord.sid: - retval = new UnitsRecord( in ); - break; + return new UnitsRecord( in ); case FrameRecord.sid: - retval = new FrameRecord( in ); - break; + return new FrameRecord( in ); case ValueRangeRecord.sid: - retval = new ValueRangeRecord( in ); - break; + return new ValueRangeRecord( in ); case SeriesListRecord.sid: - retval = new SeriesListRecord( in ); - break; + return new SeriesListRecord( in ); case FontBasisRecord.sid: - retval = new FontBasisRecord( in ); - break; + return new FontBasisRecord( in ); case FontIndexRecord.sid: - retval = new FontIndexRecord( in ); - break; + return new FontIndexRecord( in ); case LineFormatRecord.sid: - retval = new LineFormatRecord( in ); - break; + return new LineFormatRecord( in ); case AreaFormatRecord.sid: - retval = new AreaFormatRecord( in ); - break; + return new AreaFormatRecord( in ); case LinkedDataRecord.sid: - retval = new LinkedDataRecord( in ); - break; + return new LinkedDataRecord( in ); case FormulaRecord.sid: - retval = new FormulaRecord( in ); - break; + return new FormulaRecord( in ); case SheetPropertiesRecord.sid: - retval = new SheetPropertiesRecord( in ); - break; + return new SheetPropertiesRecord( in ); case DefaultDataLabelTextPropertiesRecord.sid: - retval = new DefaultDataLabelTextPropertiesRecord( in ); - break; + return new DefaultDataLabelTextPropertiesRecord( in ); case TextRecord.sid: - retval = new TextRecord( in ); - break; + return new TextRecord( in ); case AxisParentRecord.sid: - retval = new AxisParentRecord( in ); - break; + return new AxisParentRecord( in ); case AxisLineFormatRecord.sid: - retval = new AxisLineFormatRecord( in ); - break; + return new AxisLineFormatRecord( in ); case SupBookRecord.sid: - retval = new SupBookRecord( in ); - break; + return new SupBookRecord( in ); case ExternSheetRecord.sid: - retval = new ExternSheetRecord( in ); - break; + return new ExternSheetRecord( in ); case SCLRecord.sid: - retval = new SCLRecord( in ); - break; + return new SCLRecord( in ); case SeriesToChartGroupRecord.sid: - retval = new SeriesToChartGroupRecord( in ); - break; + return new SeriesToChartGroupRecord( in ); case AxisUsedRecord.sid: - retval = new AxisUsedRecord( in ); - break; + return new AxisUsedRecord( in ); case AxisRecord.sid: - retval = new AxisRecord( in ); - break; + return new AxisRecord( in ); case CategorySeriesAxisRecord.sid: - retval = new CategorySeriesAxisRecord( in ); - break; + return new CategorySeriesAxisRecord( in ); case AxisOptionsRecord.sid: - retval = new AxisOptionsRecord( in ); - break; + return new AxisOptionsRecord( in ); case TickRecord.sid: - retval = new TickRecord( in ); - break; + return new TickRecord( in ); case SeriesTextRecord.sid: - retval = new SeriesTextRecord( in ); - break; + return new SeriesTextRecord( in ); case ObjectLinkRecord.sid: - retval = new ObjectLinkRecord( in ); - break; + return new ObjectLinkRecord( in ); case PlotAreaRecord.sid: - retval = new PlotAreaRecord( in ); - break; + return new PlotAreaRecord( in ); case SeriesIndexRecord.sid: - retval = new SeriesIndexRecord( in ); - break; + return new SeriesIndexRecord( in ); case LegendRecord.sid: - retval = new LegendRecord( in ); - break; + return new LegendRecord( in ); case LeftMarginRecord.sid: - retval = new LeftMarginRecord( in ); - break; + return new LeftMarginRecord( in ); case RightMarginRecord.sid: - retval = new RightMarginRecord( in ); - break; + return new RightMarginRecord( in ); case TopMarginRecord.sid: - retval = new TopMarginRecord( in ); - break; + return new TopMarginRecord( in ); case BottomMarginRecord.sid: - retval = new BottomMarginRecord( in ); - break; + return new BottomMarginRecord( in ); case PaletteRecord.sid: - retval = new PaletteRecord( in ); - break; + return new PaletteRecord( in ); case StringRecord.sid: - retval = new StringRecord( in ); - break; + return new StringRecord( in ); case NameRecord.sid: - retval = new NameRecord( in ); - break; + return new NameRecord( in ); case PaneRecord.sid: - retval = new PaneRecord( in ); - break; + return new PaneRecord( in ); case SharedFormulaRecord.sid: - retval = new SharedFormulaRecord( in); - break; + return new SharedFormulaRecord( in); case ObjRecord.sid: - retval = new ObjRecord( in); - break; + return new ObjRecord( in); case TextObjectRecord.sid: - retval = new TextObjectRecord( in); - break; + return new TextObjectRecord( in); case HorizontalPageBreakRecord.sid: - retval = new HorizontalPageBreakRecord( in); - break; + return new HorizontalPageBreakRecord( in); case VerticalPageBreakRecord.sid: - retval = new VerticalPageBreakRecord( in); - break; + return new VerticalPageBreakRecord( in); case WriteProtectRecord.sid: - retval = new WriteProtectRecord( in); - break; + return new WriteProtectRecord( in); case FilePassRecord.sid: - retval = new FilePassRecord(in); - break; + return new FilePassRecord(in); case NoteRecord.sid: - retval = new NoteRecord( in ); - break; + return new NoteRecord( in ); case FileSharingRecord.sid: - retval = new FileSharingRecord( in ); - break; + return new FileSharingRecord( in ); case HyperlinkRecord.sid: - retval = new HyperlinkRecord( in ); - break; - default: - retval = new UnknownRecord( in ); + return new HyperlinkRecord( in ); } - return retval; + return new UnknownRecord( in ); } /** * Method setDump - hex dump out data or not. - * - *@param dump */ - public void setDump(boolean dump) { this.dump = dump; } @@ -552,33 +393,44 @@ public class BiffViewer { * */ public static void main(String[] args) { + + System.setProperty("poi.deserialize.escher", "true"); + + if (args.length == 0) { + System.out.println( "Biff viewer needs a filename" ); + return; + } + try { - System.setProperty("poi.deserialize.escher", "true"); + String inFileName = args[0]; + File inputFile = new File(inFileName); + if(!inputFile.exists()) { + throw new RuntimeException("specified inputFile '" + inFileName + "' does not exist"); + } + PrintStream ps; + if (false) { // set to true to output to file + OutputStream os = new FileOutputStream(inFileName + ".out"); + ps = new PrintStream(os); + } else { + ps = System.out; + } + BiffViewer viewer = new BiffViewer(inputFile, ps); - if (args.length == 0) - { - System.out.println( "Biff viewer needs a filename" ); + if (args.length > 1 && args[1].equals("on")) { + viewer.setDump(true); } - else - { - BiffViewer viewer = new BiffViewer(args); - if ((args.length > 1) && args[1].equals("on")) { - viewer.setDump(true); - } - if ((args.length > 1) && args[1].equals("bfd")) { - POIFSFileSystem fs = - new POIFSFileSystem(new FileInputStream(args[0])); - InputStream stream = - fs.createDocumentInputStream("Workbook"); - int size = stream.available(); - byte[] data = new byte[size]; - - stream.read(data); - HexDump.dump(data, 0, System.out, 0); - } else { - viewer.run(); - } + if (args.length > 1 && args[1].equals("bfd")) { + POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile)); + InputStream stream = fs.createDocumentInputStream("Workbook"); + int size = stream.available(); + byte[] data = new byte[size]; + + stream.read(data); + HexDump.dump(data, 0, System.out, 0); + } else { + viewer.run(); } + ps.close(); } catch (Exception e) { e.printStackTrace(); } @@ -587,7 +439,7 @@ public class BiffViewer { /** * This record supports dumping of completed continue records. */ - static class RecordDetails + private static final class RecordDetails { short rectype, recsize; int startloc; @@ -616,18 +468,19 @@ public class BiffViewer { return record; } - public void dump() throws IOException - { - dumpNormal(record, startloc, rectype, recsize); + public void dump(PrintStream ps) { + ps.println("Offset 0x" + Integer.toHexString(startloc) + " (" + startloc + ")"); + ps.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size = " + recsize ); + ps.println( record.toString() ); } } - static class BiffviewRecordInputStream extends RecordInputStream { + private static final class BiffviewRecordInputStream extends RecordInputStream { public BiffviewRecordInputStream(InputStream in) { super(in); } - public void dumpBytes() { - HexDump.dump(this.data, 0, this.currentLength); + public void dumpBytes(PrintStream ps) { + ps.println(HexDump.dump(this.data, 0, this.currentLength)); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java index bd955f8254..31af2b773a 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -140,4 +140,13 @@ public class HSSFName implements Name { } + /** + * Tests if this name points to a cell that no longer exists + * + * @return true if the name refers to a deleted cell, false otherwise + */ + public boolean isDeleted(){ + String ref = getReference(); + return "#REF!".endsWith(ref); + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index b4c3cf3c7d..08ddb9656f 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -157,7 +157,7 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm protected HSSFWorkbook( Workbook book ) { - super(null, null); + super(null, null); workbook = book; sheets = new ArrayList( INITIAL_CAPACITY ); names = new ArrayList( INITIAL_CAPACITY ); @@ -775,14 +775,54 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm } /** - * removes sheet at the given index + * Removes sheet at the given index.

+ * + * Care must be taken if the removed sheet is the currently active or only selected sheet in + * the workbook. There are a few situations when Excel must have a selection and/or active + * sheet. (For example when printing - see Bug 40414).
+ * + * This method makes sure that if the removed sheet was active, another sheet will become + * active in its place. Furthermore, if the removed sheet was the only selected sheet, another + * sheet will become selected. The newly active/selected sheet will have the same index, or + * one less if the removed sheet was the last in the workbook. + * * @param index of the sheet (0-based) */ + public void removeSheetAt(int index) { + validateSheetIndex(index); + boolean wasActive = getSheetAt(index).isActive(); + boolean wasSelected = getSheetAt(index).isSelected(); - public void removeSheetAt(int index) - { sheets.remove(index); workbook.removeSheet(index); + + // set the remaining active/selected sheet + int nSheets = sheets.size(); + if (nSheets < 1) { + // nothing more to do if there are no sheets left + return; + } + // the index of the closest remaining sheet to the one just deleted + int newSheetIndex = index; + if (newSheetIndex >= nSheets) { + newSheetIndex = nSheets-1; + } + if (wasActive) { + setActiveSheet(newSheetIndex); + } + + if (wasSelected) { + boolean someOtherSheetIsStillSelected = false; + for (int i =0; i < nSheets; i++) { + if (getSheetAt(i).isSelected()) { + someOtherSheetIsStillSelected = true; + break; + } + } + if (!someOtherSheetIsStillSelected) { + setSelectedTab(newSheetIndex); + } + } } /** diff --git a/src/testcases/org/apache/poi/hssf/data/24207.xls b/src/testcases/org/apache/poi/hssf/data/24207.xls new file mode 100755 index 0000000000..eca56425ef Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/24207.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/36947.xls b/src/testcases/org/apache/poi/hssf/data/36947.xls new file mode 100755 index 0000000000..4c7bde6c2a Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/36947.xls differ diff --git a/src/testcases/org/apache/poi/hssf/data/39634.xls b/src/testcases/org/apache/poi/hssf/data/39634.xls new file mode 100755 index 0000000000..0f76bffe47 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/39634.xls differ diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 2985278c54..0a55d65087 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -911,4 +911,45 @@ public final class TestBugs extends TestCase { writeOutAndReadBack(wb); assertTrue("no errors writing sample xls", true); } + + /** + * Bug 21334: "File error: data may have been lost" with a file + * that contains macros and this formula: + * {=SUM(IF(FREQUENCY(IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),""),IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),""))>0,1))} + */ + public void test21334() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sh = wb.createSheet(); + HSSFCell cell = sh.createRow(0).createCell((short)0); + String formula = "SUM(IF(FREQUENCY(IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),\"\"),IF(LEN(V4:V220)>0,MATCH(V4:V220,V4:V220,0),\"\"))>0,1))"; + cell.setCellFormula(formula); + + HSSFWorkbook wb_sv = writeOutAndReadBack(wb); + HSSFCell cell_sv = wb_sv.getSheetAt(0).getRow(0).getCell((short)0); + assertEquals(formula, cell_sv.getCellFormula()); + } + + public void test36947() throws Exception { + HSSFWorkbook wb = openSample("36947.xls"); + assertTrue("no errors reading sample xls", true); + writeOutAndReadBack(wb); + assertTrue("no errors writing sample xls", true); + } + + /** + * Bug 42448: Can't parse SUMPRODUCT(A!C7:A!C67, B8:B68) / B69 + */ + public void test42448(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFCell cell = wb.createSheet().createRow(0).createCell((short)0); + cell.setCellFormula("SUMPRODUCT(A!C7:A!C67, B8:B68) / B69"); + assertTrue("no errors parsing formula", true); + } + + public void test39634() throws Exception { + HSSFWorkbook wb = openSample("39634.xls"); + assertTrue("no errors reading sample xls", true); + writeOutAndReadBack(wb); + assertTrue("no errors writing sample xls", true); + } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java index e1afb453bc..cb5b3d3554 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFWorkbook.java @@ -232,11 +232,11 @@ public final class TestHSSFWorkbook extends TestCase { // Demonstrate bug 44525: // Well... not quite, since isActive + isSelected were also added in the same bug fix if (sheet1.isSelected()) { - throw new AssertionFailedError("Identified bug 44525 a"); + throw new AssertionFailedError("Identified bug 44523 a"); } wb.setActiveSheet(1); if (sheet1.isActive()) { - throw new AssertionFailedError("Identified bug 44525 b"); + throw new AssertionFailedError("Identified bug 44523 b"); } confirmActiveSelected(sheet1, false); @@ -299,8 +299,81 @@ public final class TestHSSFWorkbook extends TestCase { } } + + public void testActiveSheetAfterDelete_bug40414() { + HSSFWorkbook wb=new HSSFWorkbook(); + HSSFSheet sheet0 = wb.createSheet("Sheet0"); + HSSFSheet sheet1 = wb.createSheet("Sheet1"); + HSSFSheet sheet2 = wb.createSheet("Sheet2"); + HSSFSheet sheet3 = wb.createSheet("Sheet3"); + HSSFSheet sheet4 = wb.createSheet("Sheet4"); + + // confirm default activation/selection + confirmActiveSelected(sheet0, true); + confirmActiveSelected(sheet1, false); + confirmActiveSelected(sheet2, false); + confirmActiveSelected(sheet3, false); + confirmActiveSelected(sheet4, false); + + wb.setActiveSheet(3); + wb.setSelectedTab(3); + + confirmActiveSelected(sheet0, false); + confirmActiveSelected(sheet1, false); + confirmActiveSelected(sheet2, false); + confirmActiveSelected(sheet3, true); + confirmActiveSelected(sheet4, false); + + wb.removeSheetAt(3); + // after removing the only active/selected sheet, another should be active/selected in its place + if (!sheet4.isSelected()) { + throw new AssertionFailedError("identified bug 40414 a"); + } + if (!sheet4.isActive()) { + throw new AssertionFailedError("identified bug 40414 b"); + } + + confirmActiveSelected(sheet0, false); + confirmActiveSelected(sheet1, false); + confirmActiveSelected(sheet2, false); + confirmActiveSelected(sheet4, true); + + sheet3 = sheet4; // re-align local vars in this test case + + // Some more cases of removing sheets + + // Starting with a multiple selection, and different active sheet + wb.setSelectedTabs(new int[] { 1, 3, }); + wb.setActiveSheet(2); + confirmActiveSelected(sheet0, false, false); + confirmActiveSelected(sheet1, false, true); + confirmActiveSelected(sheet2, true, false); + confirmActiveSelected(sheet3, false, true); + + // removing a sheet that is not active, and not the only selected sheet + wb.removeSheetAt(3); + confirmActiveSelected(sheet0, false, false); + confirmActiveSelected(sheet1, false, true); + confirmActiveSelected(sheet2, true, false); + + // removing the only selected sheet + wb.removeSheetAt(1); + confirmActiveSelected(sheet0, false, false); + confirmActiveSelected(sheet2, true, true); + + // The last remaining sheet should always be active+selected + wb.removeSheetAt(1); + confirmActiveSelected(sheet0, true, true); + } + private static void confirmActiveSelected(HSSFSheet sheet, boolean expected) { - assertEquals(expected, sheet.isActive()); - assertEquals(expected, sheet.isSelected()); + confirmActiveSelected(sheet, expected, expected); + } + + + private static void confirmActiveSelected(HSSFSheet sheet, + boolean expectedActive, boolean expectedSelected) { + assertEquals("active", expectedActive, sheet.isActive()); + assertEquals("selected", expectedSelected, sheet.isSelected()); } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java b/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java index 98500960da..b3d08bf724 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestNamedRange.java @@ -533,4 +533,28 @@ public final class TestNamedRange extends TestCase { String contents = c.getStringCellValue(); assertEquals("Contents of cell retrieved by its named reference", contents, cvalue); } + + public void testDeletedReference() throws Exception { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("24207.xls"); + assertEquals(2, wb.getNumberOfNames()); + + HSSFName name1 = wb.getNameAt(0); + assertEquals("a", name1.getNameName()); + assertEquals("Sheet1!$A$1", name1.getReference()); + AreaReference ref1 = new AreaReference(name1.getReference()); + assertTrue("Successfully constructed first reference", true); + + HSSFName name2 = wb.getNameAt(1); + assertEquals("b", name2.getNameName()); + assertEquals("#REF!", name2.getReference()); + assertTrue(name2.isDeleted()); + try { + AreaReference ref2 = new AreaReference(name2.getReference()); + fail("attempt to supply an invalid reference to AreaReference constructor results in exception"); + } catch (Exception e){ + ; + } + + } + }