+ 51415 - Fixed Workbook.createSheet(sheetName) to truncate names longer than 31 characters
51332 - Fixed internal IDs of shapes generated by HSSFPatriarch when there are more than 1023 drawing objects
48408 - Improved documentation for Sheet.setColumnWidth
51390 - Added handling of additional properties to HWPF ParagraphSprmCompressor
diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
index 62796a62f2..e781675efa 100644
--- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
+++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
@@ -89,6 +89,7 @@ import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@@ -579,6 +580,10 @@ public final class InternalWorkbook {
*/
public void setSheetName(int sheetnum, String sheetname) {
checkSheets(sheetnum);
+
+ // YK: Mimic Excel and silently truncate sheet names longer than 31 characters
+ if(sheetname.length() > 31) sheetname = sheetname.substring(0, 31);
+
BoundSheetRecord sheet = boundsheets.get(sheetnum);
sheet.setSheetname(sheetname);
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index a0007fcee7..863e160b30 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -543,15 +543,20 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
}
/**
- * 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.
+ * Set the sheet name.
*
- * @param sheetIx number (0 based)
+ * @param sheet number (0 based)
+ * @throws IllegalArgumentException if the name is null or invalid
+ * or workbook already contains a sheet with this name
+ * @see {@link #createSheet(String)}
+ * @see {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+ * for a safe way to create valid names
*/
public void setSheetName(int sheetIx, String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("sheetName must not be null");
+ }
+
if (workbook.doesContainsSheetName(name, sheetIx)) {
throw new IllegalArgumentException("The workbook already contains a sheet with this name");
}
@@ -757,20 +762,55 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
}
/**
- * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and
- * returns the high level representation. Use this to create new sheets.
+ * Create a new sheet for this Workbook and return the high level representation.
+ * Use this to create new sheets.
*
- * @param sheetname the name for the new sheet. Note - certain length limits
- * apply. See {@link #setSheetName(int, String)}.
- * @see org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)
- * for a safe way to create valid names
- * @return HSSFSheet representing the new sheet.
- * @throws IllegalArgumentException
- * if there is already a sheet present with a case-insensitive
- * match for the specified name.
+ *
+ * Note that Excel allows sheet names up to 31 chars in length but other applications
+ * (such as OpenOffice) allow more. Some versions of Excel crash with names longer than 31 chars,
+ * others - truncate such names to 31 character.
+ *
+ *
+ * POI's SpreadsheetAPI silently truncates the input argument to 31 characters.
+ * Example:
+ *
+ *
+ * Sheet sheet = workbook.createSheet("My very long sheet name which is longer than 31 chars"); // will be truncated
+ * assert 31 == sheet.getSheetName().length();
+ * assert "My very long sheet name which i" == sheet.getSheetName();
+ *
+ *
+ *
+ * Except the 31-character constraint, Excel applies some other rules:
+ *
+ * Sheet name MUST be unique in the workbook and MUST NOT contain the any of the following characters:
+ *
+ * - 0x0000
+ * - 0x0003
+ * - colon (:)
+ * - backslash (\)
+ * - asterisk (*)
+ * - question mark (?)
+ * - forward slash (/)
+ * - opening square bracket ([)
+ * - closing square bracket (])
+ *
+ * The string MUST NOT begin or end with the single quote (') character.
+ *
+ *
+ * @param sheetname sheetname to set for the sheet.
+ * @return Sheet representing the new sheet.
+ * @throws IllegalArgumentException if the name is null or invalid
+ * or workbook already contains a sheet with this name
+ * @see {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+ * for a safe way to create valid names
*/
public HSSFSheet createSheet(String sheetname)
{
+ if (sheetname == null) {
+ throw new IllegalArgumentException("sheetName must not be null");
+ }
+
if (workbook.doesContainsSheetName( sheetname, _sheets.size() ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
diff --git a/src/java/org/apache/poi/ss/usermodel/Workbook.java b/src/java/org/apache/poi/ss/usermodel/Workbook.java
index 03a349d3fa..9312eba797 100644
--- a/src/java/org/apache/poi/ss/usermodel/Workbook.java
+++ b/src/java/org/apache/poi/ss/usermodel/Workbook.java
@@ -131,12 +131,16 @@ public interface Workbook {
* Set the sheet name.
*
* @param sheet number (0 based)
- * @throws IllegalArgumentException if the name is greater than 31 chars or contains /\?*[]
+ * @throws IllegalArgumentException if the name is null or invalid
+ * or workbook already contains a sheet with this name
+ * @see {@link #createSheet(String)}
+ * @see {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+ * for a safe way to create valid names
*/
void setSheetName(int sheet, String name);
/**
- * Set the sheet name
+ * Get the sheet name
*
* @param sheet sheet number (0 based)
* @return Sheet name
@@ -168,12 +172,48 @@ public interface Workbook {
Sheet createSheet();
/**
- * Create an Sheet for this Workbook, adds it to the sheets and returns
- * the high level representation. Use this to create new sheets.
+ * Create a new sheet for this Workbook and return the high level representation.
+ * Use this to create new sheets.
+ *
+ *
+ * Note that Excel allows sheet names up to 31 chars in length but other applications
+ * (such as OpenOffice) allow more. Some versions of Excel crash with names longer than 31 chars,
+ * others - truncate such names to 31 character.
+ *
+ *
+ * POI's SpreadsheetAPI silently truncates the input argument to 31 characters.
+ * Example:
+ *
+ *
+ * Sheet sheet = workbook.createSheet("My very long sheet name which is longer than 31 chars"); // will be truncated
+ * assert 31 == sheet.getSheetName().length();
+ * assert "My very long sheet name which i" == sheet.getSheetName();
+ *
+ *
+ *
+ * Except the 31-character constraint, Excel applies some other rules:
+ *
+ * Sheet name MUST be unique in the workbook and MUST NOT contain the any of the following characters:
+ *
+ * - 0x0000
+ * - 0x0003
+ * - colon (:)
+ * - backslash (\)
+ * - asterisk (*)
+ * - question mark (?)
+ * - forward slash (/)
+ * - opening square bracket ([)
+ * - closing square bracket (])
+ *
+ * The string MUST NOT begin or end with the single quote (') character.
+ *
*
* @param sheetname sheetname to set for the sheet.
* @return Sheet representing the new sheet.
- * @throws IllegalArgumentException if the name is greater than 31 chars or contains /\?*[]
+ * @throws IllegalArgumentException if the name is null or invalid
+ * or workbook already contains a sheet with this name
+ * @see {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+ * for a safe way to create valid names
*/
Sheet createSheet(String sheetname);
diff --git a/src/java/org/apache/poi/ss/util/WorkbookUtil.java b/src/java/org/apache/poi/ss/util/WorkbookUtil.java
index 8ab44b9ce4..767e1327e2 100644
--- a/src/java/org/apache/poi/ss/util/WorkbookUtil.java
+++ b/src/java/org/apache/poi/ss/util/WorkbookUtil.java
@@ -104,9 +104,11 @@ public class WorkbookUtil {
throw new IllegalArgumentException("sheetName must not be null");
}
int len = sheetName.length();
- if (len < 1) {
- throw new IllegalArgumentException("sheetName must not be empty string");
+ if (len < 1 || len > 31) {
+ throw new IllegalArgumentException("sheetName '" + sheetName
+ + "' is invalid - character count MUST be greater than or equal to 1 and less than or equal to 31");
}
+
for (int i=0; i
+ * Note that Excel allows sheet names up to 31 chars in length but other applications
+ * (such as OpenOffice) allow more. Some versions of Excel crash with names longer than 31 chars,
+ * others - truncate such names to 31 character.
+ *
+ *
+ * POI's SpreadsheetAPI silently truncates the input argument to 31 characters.
+ * Example:
+ *
+ *
+ * Sheet sheet = workbook.createSheet("My very long sheet name which is longer than 31 chars"); // will be truncated
+ * assert 31 == sheet.getSheetName().length();
+ * assert "My very long sheet name which i" == sheet.getSheetName();
+ *
+ *
+ *
+ * Except the 31-character constraint, Excel applies some other rules:
+ *
+ * Sheet name MUST be unique in the workbook and MUST NOT contain the any of the following characters:
+ *
+ * - 0x0000
+ * - 0x0003
+ * - colon (:)
+ * - backslash (\)
+ * - asterisk (*)
+ * - question mark (?)
+ * - forward slash (/)
+ * - opening square bracket ([)
+ * - closing square bracket (])
+ *
+ * The string MUST NOT begin or end with the single quote (') character.
+ *
+ *
+ * @param sheetname sheetname to set for the sheet.
+ * @return Sheet representing the new sheet.
+ * @throws IllegalArgumentException if the name is null or invalid
+ * or workbook already contains a sheet with this name
+ * @see {@link org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
+ * for a safe way to create valid names
*/
public XSSFSheet createSheet(String sheetname) {
+ if (sheetname == null) {
+ throw new IllegalArgumentException("sheetName must not be null");
+ }
+
if (containsSheet( sheetname, sheets.size() ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name");
+ // YK: Mimic Excel and silently truncate sheet names longer than 31 characters
+ if(sheetname.length() > 31) sheetname = sheetname.substring(0, 31);
+ WorkbookUtil.validateSheetName(sheetname);
+
CTSheet sheet = addSheet(sheetname);
int sheetNumber = 1;
@@ -525,8 +569,6 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable 31) sheetname = sheetname.substring(0, 31);
+ WorkbookUtil.validateSheetName(sheetname);
+
+ if (containsSheet(sheetname, sheetIndex ))
throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
XSSFFormulaUtils utils = new XSSFFormulaUtils(this);
- utils.updateSheetName(sheetIndex, name);
+ utils.updateSheetName(sheetIndex, sheetname);
- workbook.getSheets().getSheetArray(sheetIndex).setName(name);
+ workbook.getSheets().getSheetArray(sheetIndex).setName(sheetname);
}
/**
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
index a4a8d29cc8..9ba714c748 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestWorkbook.java
@@ -99,6 +99,22 @@ public abstract class BaseTestWorkbook extends TestCase {
// expected during successful test
}
+ //try to assign an invalid name to the 2nd sheet
+ try {
+ wb.createSheet(null);
+ fail("should have thrown exceptiuon due to invalid sheet name");
+ } catch (IllegalArgumentException e) {
+ // expected during successful test
+ }
+
+ try {
+ wb.setSheetName(2, null);
+
+ fail("should have thrown exceptiuon due to invalid sheet name");
+ } catch (IllegalArgumentException e) {
+ // expected during successful test
+ }
+
//check
assertEquals(0, wb.getSheetIndex("sheet0"));
assertEquals(1, wb.getSheetIndex("sheet1"));
@@ -129,9 +145,14 @@ public abstract class BaseTestWorkbook extends TestCase {
Workbook wb = _testDataProvider.createWorkbook();
String sheetName1 = "My very long sheet name which is longer than 31 chars";
+ String truncatedSheetName1 = sheetName1.substring(0, 31);
Sheet sh1 = wb.createSheet(sheetName1);
- assertEquals(sheetName1, sh1.getSheetName());
- assertSame(sh1, wb.getSheet(sheetName1));
+ assertEquals(truncatedSheetName1, sh1.getSheetName());
+ assertSame(sh1, wb.getSheet(truncatedSheetName1));
+ // now via wb.setSheetName
+ wb.setSheetName(0, sheetName1);
+ assertEquals(truncatedSheetName1, sh1.getSheetName());
+ assertSame(sh1, wb.getSheet(truncatedSheetName1));
String sheetName2 = "My very long sheet name which is longer than 31 chars " +
"and sheetName2.substring(0, 31) == sheetName1.substring(0, 31)";
@@ -144,15 +165,16 @@ public abstract class BaseTestWorkbook extends TestCase {
}
String sheetName3 = "POI allows creating sheets with names longer than 31 characters";
+ String truncatedSheetName3 = sheetName3.substring(0, 31);
Sheet sh3 = wb.createSheet(sheetName3);
- assertEquals(sheetName3, sh3.getSheetName());
- assertSame(sh3, wb.getSheet(sheetName3));
+ assertEquals(truncatedSheetName3, sh3.getSheetName());
+ assertSame(sh3, wb.getSheet(truncatedSheetName3));
//serialize and read again
wb = _testDataProvider.writeOutAndReadBack(wb);
assertEquals(2, wb.getNumberOfSheets());
- assertEquals(0, wb.getSheetIndex(sheetName1));
- assertEquals(1, wb.getSheetIndex(sheetName3));
+ assertEquals(0, wb.getSheetIndex(truncatedSheetName1));
+ assertEquals(1, wb.getSheetIndex(truncatedSheetName3));
}
public void testRemoveSheetAt() {
--
2.39.5