Fix for bug 45876 - allowed BoundSheetRecord to take sheet names longer than 31 chars

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@700280 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-09-29 22:04:20 +00:00
parent 857ead338e
commit d14991ed02
7 changed files with 63 additions and 31 deletions

View File

@ -37,6 +37,7 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.2-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45876 - fixed BoundSheetRecord to allow sheet names longer than 31 chars</action>
<action dev="POI-DEVELOPERS" type="add">45890 - fixed HSSFSheet.shiftRows to also update conditional formats</action>
<action dev="POI-DEVELOPERS" type="add">45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas</action>
<action dev="POI-DEVELOPERS" type="add">Optimised the FormulaEvaluator to take cell dependencies into account</action>

View File

@ -34,6 +34,7 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.2-alpha1" date="2008-??-??">
<action dev="POI-DEVELOPERS" type="fix">45876 - fixed BoundSheetRecord to allow sheet names longer than 31 chars</action>
<action dev="POI-DEVELOPERS" type="add">45890 - fixed HSSFSheet.shiftRows to also update conditional formats</action>
<action dev="POI-DEVELOPERS" type="add">45865 modified Formula Parser/Evaluator to handle cross-worksheet formulas</action>
<action dev="POI-DEVELOPERS" type="add">Optimised the FormulaEvaluator to take cell dependencies into account</action>

View File

@ -55,6 +55,12 @@ import org.apache.poi.util.POILogger;
* @version 1.0-pre
*/
public final class Workbook implements Model {
/**
* Excel silently truncates long sheet names to 31 chars.
* This constant is used to ensure uniqueness in the first 31 chars
*/
private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31;
private static final int DEBUG = POILogger.DEBUG;
/**
@ -488,32 +494,43 @@ public final class Workbook implements Model {
/**
* sets the name for a given sheet. If the boundsheet record doesn't exist and
* its only one more than we have, go ahead and create it. If its > 1 more than
* its only one more than we have, go ahead and create it. If it's > 1 more than
* we have, except
*
* @param sheetnum the sheet number (0 based)
* @param sheetname the name for the sheet
*/
public void setSheetName(int sheetnum, String sheetname ) {
public void setSheetName(int sheetnum, String sheetname) {
checkSheets(sheetnum);
BoundSheetRecord sheet = (BoundSheetRecord)boundsheets.get( sheetnum );
sheet.setSheetname(sheetname);
}
/**
* Determines whether a workbook contains the provided sheet name.
* Determines whether a workbook contains the provided sheet name. For the purpose of
* comparison, long names are truncated to 31 chars.
*
* @param name the name to test (case insensitive match)
* @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
* @return true if the sheet contains the name, false otherwise.
*/
public boolean doesContainsSheetName( String name, int excludeSheetIdx )
{
for ( int i = 0; i < boundsheets.size(); i++ )
{
public boolean doesContainsSheetName(String name, int excludeSheetIdx) {
String aName = name;
if (aName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
aName = aName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
}
for (int i = 0; i < boundsheets.size(); i++) {
BoundSheetRecord boundSheetRecord = getBoundSheetRec(i);
if (excludeSheetIdx != i && name.equalsIgnoreCase(boundSheetRecord.getSheetname()))
if (excludeSheetIdx == i) {
continue;
}
String bName = boundSheetRecord.getSheetname();
if (bName.length() > MAX_SENSITIVE_SHEET_NAME_LEN) {
bName = bName.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN);
}
if (aName.equalsIgnoreCase(bName)) {
return true;
}
}
return false;
}
@ -1954,9 +1971,9 @@ public final class Workbook implements Model {
return (short)getOrCreateLinkTable().checkExternSheet(sheetNumber);
}
public int getExternalSheetIndex(String workbookName, String sheetName) {
return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName);
}
public int getExternalSheetIndex(String workbookName, String sheetName) {
return getOrCreateLinkTable().getExternalSheetIndex(workbookName, sheetName);
}
/** gets the total number of names

View File

@ -116,9 +116,8 @@ public final class BoundSheetRecord extends Record {
throw new IllegalArgumentException("sheetName must not be null");
}
int len = sheetName.length();
if (len < 1 || len > 31) {
throw new IllegalArgumentException("sheetName '" + sheetName
+ "' is invalid - must be 1-30 characters long");
if (len < 1) {
throw new IllegalArgumentException("sheetName must not be empty string");
}
for (int i=0; i<len; i++) {
char ch = sheetName.charAt(i);

View File

@ -515,15 +515,17 @@ public class HSSFWorkbook extends POIDocument
}
/**
* set the sheet name.
* Will throw IllegalArgumentException if the name is greater than 31 chars
* or contains /\?*[]
* Sets the sheet name.
* Will throw IllegalArgumentException if the name is duplicated or contains /\?*[]
* Note - Excel allows sheet names up to 31 chars in length but other applications allow more.
* Excel does not crash with names longer than 31 chars, but silently truncates such names to
* 31 chars. POI enforces uniqueness on the first 31 chars.
*
* @param sheetIx number (0 based)
*/
public void setSheetName(int sheetIx, String name)
{
if (workbook.doesContainsSheetName( name, sheetIx )) {
throw new IllegalArgumentException( "The workbook already contains a sheet with this name" );
public void setSheetName(int sheetIx, String name) {
if (workbook.doesContainsSheetName(name, sheetIx)) {
throw new IllegalArgumentException("The workbook already contains a sheet with this name");
}
validateSheetIndex(sheetIx);
workbook.setSheetName(sheetIx, name);
@ -726,14 +728,14 @@ public class HSSFWorkbook extends POIDocument
* create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and
* returns the high level representation. Use this to create new sheets.
*
* @param sheetname
* sheetname to set for the sheet.
* @param sheetname the name for the new sheet. Note - certain length limits
* apply. See {@link #setSheetName(int, String)}.
*
* @return HSSFSheet representing the new sheet.
* @throws IllegalArgumentException
* if there is already a sheet present with a case-insensitive
* match for the specified name.
*/
public HSSFSheet createSheet(String sheetname)
{
if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))

View File

@ -45,13 +45,6 @@ public final class TestBoundSheetRecord extends TestCase {
public void testName() {
BoundSheetRecord record = new BoundSheetRecord("1234567890223456789032345678904");
try {
record.setSheetname("12345678902234567890323456789042");
throw new AssertionFailedError("Should have thrown IllegalArgumentException, but didnt");
} catch (IllegalArgumentException e) {
// expected
}
try {
record.setSheetname("s//*s");
throw new AssertionFailedError("Should have thrown IllegalArgumentException, but didnt");

View File

@ -891,4 +891,23 @@ public final class TestHSSFSheet extends TestCase {
//TODO: check shapeId in the cloned sheet
}
/**
* POI now (Sep 2008) allows sheet names longer than 31 chars (for other apps besides Excel).
* Since Excel silently truncates to 31, make sure that POI enforces uniqueness on the first
* 31 chars.
*/
public void testLongSheetNames() {
HSSFWorkbook wb = new HSSFWorkbook();
final String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars
wb.createSheet(SAME_PREFIX + "Dxxxx");
try {
wb.createSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char
throw new AssertionFailedError("Expected exception not thrown");
} catch (IllegalArgumentException e) {
assertEquals("The workbook already contains a sheet of this name", e.getMessage());
}
wb.createSheet(SAME_PREFIX + "Exxxx"); // OK - differs in the 31st char
}
}