From d4a1239efa7b81c3200c789a9aedf68f08ba76ae Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Fri, 18 Jul 2014 15:59:55 +0000 Subject: [PATCH] #56737 Sometimes Excel writes an internal reference to a local name in an odd way, without an ExternalNameRecord, try to detect and work around those git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1611681 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hssf/model/InternalWorkbook.java | 61 +++++++++++++++++-- .../org/apache/poi/hssf/model/LinkTable.java | 43 ++++++++++--- .../poi/hssf/record/ExternSheetRecord.java | 15 ++++- .../apache/poi/hssf/model/TestLinkTable.java | 15 ++++- .../apache/poi/hssf/usermodel/TestBugs.java | 1 - 5 files changed, 116 insertions(+), 19 deletions(-) diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java index e54d6c5d8..9ecbdb97b 100644 --- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java +++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java @@ -26,8 +26,61 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; -import org.apache.poi.ddf.*; -import org.apache.poi.hssf.record.*; +import org.apache.poi.ddf.EscherBSERecord; +import org.apache.poi.ddf.EscherBoolProperty; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherDgRecord; +import org.apache.poi.ddf.EscherDggRecord; +import org.apache.poi.ddf.EscherOptRecord; +import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.ddf.EscherRGBProperty; +import org.apache.poi.ddf.EscherRecord; +import org.apache.poi.ddf.EscherSimpleProperty; +import org.apache.poi.ddf.EscherSpRecord; +import org.apache.poi.ddf.EscherSplitMenuColorsRecord; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BackupRecord; +import org.apache.poi.hssf.record.BookBoolRecord; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.CodepageRecord; +import org.apache.poi.hssf.record.CountryRecord; +import org.apache.poi.hssf.record.DSFRecord; +import org.apache.poi.hssf.record.DateWindow1904Record; +import org.apache.poi.hssf.record.DrawingGroupRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.EscherAggregate; +import org.apache.poi.hssf.record.ExtSSTRecord; +import org.apache.poi.hssf.record.ExtendedFormatRecord; +import org.apache.poi.hssf.record.ExternSheetRecord; +import org.apache.poi.hssf.record.FileSharingRecord; +import org.apache.poi.hssf.record.FnGroupCountRecord; +import org.apache.poi.hssf.record.FontRecord; +import org.apache.poi.hssf.record.FormatRecord; +import org.apache.poi.hssf.record.HideObjRecord; +import org.apache.poi.hssf.record.HyperlinkRecord; +import org.apache.poi.hssf.record.InterfaceEndRecord; +import org.apache.poi.hssf.record.InterfaceHdrRecord; +import org.apache.poi.hssf.record.MMSRecord; +import org.apache.poi.hssf.record.NameCommentRecord; +import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.PaletteRecord; +import org.apache.poi.hssf.record.PasswordRecord; +import org.apache.poi.hssf.record.PasswordRev4Record; +import org.apache.poi.hssf.record.PrecisionRecord; +import org.apache.poi.hssf.record.ProtectRecord; +import org.apache.poi.hssf.record.ProtectionRev4Record; +import org.apache.poi.hssf.record.RecalcIdRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RefreshAllRecord; +import org.apache.poi.hssf.record.SSTRecord; +import org.apache.poi.hssf.record.StyleRecord; +import org.apache.poi.hssf.record.SupBookRecord; +import org.apache.poi.hssf.record.TabIdRecord; +import org.apache.poi.hssf.record.UseSelFSRecord; +import org.apache.poi.hssf.record.WindowOneRecord; +import org.apache.poi.hssf.record.WindowProtectRecord; +import org.apache.poi.hssf.record.WriteAccessRecord; +import org.apache.poi.hssf.record.WriteProtectRecord; import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName; @@ -1776,7 +1829,7 @@ public final class InternalWorkbook { return new ExternalSheet(extNames[0], extNames[1]); } public ExternalName getExternalName(int externSheetIndex, int externNameIndex) { - String nameName = linkTable.resolveNameXText(externSheetIndex, externNameIndex); + String nameName = linkTable.resolveNameXText(externSheetIndex, externNameIndex, this); if(nameName == null) { return null; } @@ -2299,7 +2352,7 @@ public final class InternalWorkbook { * @return the string representation of the defined or external name */ public String resolveNameXText(int refIndex, int definedNameIndex) { - return linkTable.resolveNameXText(refIndex, definedNameIndex); + return linkTable.resolveNameXText(refIndex, definedNameIndex, this); } /** diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java index 6e203ef1d..9735d61c8 100644 --- a/src/java/org/apache/poi/hssf/model/LinkTable.java +++ b/src/java/org/apache/poi/hssf/model/LinkTable.java @@ -31,6 +31,7 @@ import org.apache.poi.hssf.record.NameCommentRecord; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SupBookRecord; +import org.apache.poi.ss.formula.SheetNameFormatter; import org.apache.poi.ss.formula.ptg.Area3DPtg; import org.apache.poi.ss.formula.ptg.ErrPtg; import org.apache.poi.ss.formula.ptg.NameXPtg; @@ -206,7 +207,7 @@ final class LinkTable { // collect zero or more DEFINEDNAMEs id=0x18, // with their comments if present while(true) { - Class nextClass = rs.peekNextClass(); + Class nextClass = rs.peekNextClass(); if (nextClass == NameRecord.class) { NameRecord nr = (NameRecord)rs.getNext(); _definedNames.add(nr); @@ -280,10 +281,9 @@ final class LinkTable { * @param sheetNumber 1-based sheet number */ public NameRecord getSpecificBuiltinRecord(byte builtInCode, int sheetNumber) { - - Iterator iterator = _definedNames.iterator(); + Iterator iterator = _definedNames.iterator(); while (iterator.hasNext()) { - NameRecord record = ( NameRecord ) iterator.next(); + NameRecord record = iterator.next(); //print areas are one based if (record.getBuiltInName() == builtInCode && record.getSheetNumber() == sheetNumber) { @@ -471,10 +471,37 @@ final class LinkTable { } return -1; } - - public String resolveNameXText(int refIndex, int definedNameIndex) { - int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex); - return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex); + + public String resolveNameXText(int refIndex, int definedNameIndex, InternalWorkbook workbook) { + int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex); + int firstTabIndex = _externSheetRecord.getFirstSheetIndexFromRefIndex(refIndex); + if (firstTabIndex == -1) { + // The referenced sheet could not be found + throw new RuntimeException("Referenced sheet could not be found"); + } + + // Does it exist via the external book block? + if (_externalBookBlocks.length > extBookIndex) { + return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex); + } else if (firstTabIndex == -2) { + // Workbook scoped name, not actually external after all + NameRecord nr = getNameRecord(definedNameIndex); + int sheetNumber = nr.getSheetNumber(); + + StringBuffer text = new StringBuffer(); + if (sheetNumber > 0) { + String sheetName = workbook.getSheetName(sheetNumber-1); + SheetNameFormatter.appendFormat(text, sheetName); + text.append("!"); + } + text.append(nr.getNameText()); + return text.toString(); + } else { + throw new ArrayIndexOutOfBoundsException( + "Ext Book Index relative but beyond the supported length, was " + + extBookIndex + " but maximum is " + _externalBookBlocks.length + ); + } } public int resolveNameXIx(int refIndex, int definedNameIndex) { int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex); diff --git a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java index 0ff062b08..5d59b36c9 100644 --- a/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java +++ b/src/java/org/apache/poi/hssf/record/ExternSheetRecord.java @@ -200,9 +200,13 @@ public class ExternSheetRecord extends StandardRecord { return sid; } - public int getExtbookIndexFromRefIndex(int refIndex) { - return getRef(refIndex).getExtBookIndex(); - } + /** + * Returns the index of the SupBookRecord for this index + */ + public int getExtbookIndexFromRefIndex(int refIndex) { + RefSubRecord refRec = getRef(refIndex); + return refRec.getExtBookIndex(); + } /** * @return -1 if not found @@ -217,6 +221,11 @@ public class ExternSheetRecord extends StandardRecord { return -1; } + /** + * Returns the first sheet that the reference applies to, or + * -1 if the referenced sheet can't be found, or -2 if the + * reference is workbook scoped. + */ public int getFirstSheetIndexFromRefIndex(int extRefIndex) { return getRef(extRefIndex).getFirstSheetIndex(); } diff --git a/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java b/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java index d62a80d72..48c81ea0b 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java +++ b/src/testcases/org/apache/poi/hssf/model/TestLinkTable.java @@ -27,7 +27,16 @@ import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.apache.poi.hssf.HSSFTestDataSamples; -import org.apache.poi.hssf.record.*; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.CountryRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.ExternSheetRecord; +import org.apache.poi.hssf.record.ExternalNameRecord; +import org.apache.poi.hssf.record.NameCommentRecord; +import org.apache.poi.hssf.record.NameRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SSTRecord; +import org.apache.poi.hssf.record.SupBookRecord; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.formula.ptg.NameXPtg; @@ -230,7 +239,7 @@ public final class TestLinkTable extends TestCase { //check that assertEquals(0, tbl.resolveNameXIx(namex1.getSheetRefIndex(), namex1.getNameIndex())); - assertEquals("ISODD", tbl.resolveNameXText(namex1.getSheetRefIndex(), namex1.getNameIndex())); + assertEquals("ISODD", tbl.resolveNameXText(namex1.getSheetRefIndex(), namex1.getNameIndex(), null)); assertNull(tbl.getNameXPtg("ISEVEN")); NameXPtg namex2 = tbl.addNameXPtg("ISEVEN"); // adds two new rercords @@ -256,7 +265,7 @@ public final class TestLinkTable extends TestCase { assertTrue(wrl.get(7) instanceof EOFRecord); assertEquals(0, tbl.resolveNameXIx(namex2.getSheetRefIndex(), namex2.getNameIndex())); - assertEquals("ISEVEN", tbl.resolveNameXText(namex2.getSheetRefIndex(), namex2.getNameIndex())); + assertEquals("ISEVEN", tbl.resolveNameXText(namex2.getSheetRefIndex(), namex2.getNameIndex(), null)); } } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index 5d03b45d3..f9fac83d8 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -2619,7 +2619,6 @@ public final class TestBugs extends BaseTestBugzillaIssues { * Currently failing with * java.lang.RuntimeException: Unexpected eval class (org.apache.poi.ss.formula.eval.NameXEval) */ - @Ignore @Test public void bug56737() throws IOException { Workbook wb = openSample("56737.xls");