Skip to content

Commit 52cfea2

Browse files
Implemented import option to ignore invalid row/column dimensions
1 parent d20639a commit 52cfea2

File tree

9 files changed

+176
-5
lines changed

9 files changed

+176
-5
lines changed

NanoXLSX4j.Lib/src/main/java/ch/rabanti/nanoxlsx4j/ImportOptions.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ public enum ColumnType {
101101
private boolean enforceDateTimesAsNumbers = false;
102102
private boolean enforceEmptyValuesAsString = false;
103103
private boolean enforcePhoneticCharacterImport = false;
104+
private boolean enforceValidColumnDimensions = true;
105+
private boolean enforceValidRowDimensions;
104106
private final Map<Integer, ColumnType> enforcedColumnTypes = new HashMap<>();
105107
private int enforcingStartRowNumber = 0;
106108
private GlobalType globalEnforcingType = GlobalType.Default;
@@ -221,6 +223,52 @@ public void setEnforceEmptyValuesAsString(boolean enforceEmptyValuesAsString) {
221223
this.enforceEmptyValuesAsString = enforceEmptyValuesAsString;
222224
}
223225

226+
/**
227+
* Gets whether invalid column dimensions (larger than {@link Worksheet#MAX_COLUMN_WIDTH} or smaller than
228+
* {@link Worksheet#MIN_COLUMN_WIDTH}) will throw an exception
229+
*
230+
* @return If true, invalid column dimensions will trow an exception. If false, such invalid values will be ignored
231+
* and set to {@link Worksheet#MAX_COLUMN_WIDTH} or {@link Worksheet#MIN_COLUMN_WIDTH}. Default is true
232+
*/
233+
public boolean isEnforceValidColumnDimensions() {
234+
return enforceValidColumnDimensions;
235+
}
236+
237+
/**
238+
* Sets whether invalid column dimensions (larger than {@link Worksheet#MAX_COLUMN_WIDTH} or smaller than
239+
* {@link Worksheet#MIN_COLUMN_WIDTH}) will throw an exception
240+
*
241+
* @param enforceValidColumnDimensions If true, invalid column dimensions will trow an exception. If false, such
242+
* invalid values will be ignored and set to {@link Worksheet#MAX_COLUMN_WIDTH}
243+
* or {@link Worksheet#MIN_COLUMN_WIDTH}. Default is true
244+
*/
245+
public void setEnforceValidColumnDimensions(boolean enforceValidColumnDimensions) {
246+
this.enforceValidColumnDimensions = enforceValidColumnDimensions;
247+
}
248+
249+
/**
250+
* Gets whether invalid row dimensions (larger than {@link Worksheet#MAX_ROW_HEIGHT} or smaller than
251+
* {@link Worksheet#MIN_ROW_HEIGHT}) will throw an exception
252+
*
253+
* @return If true, invalid row dimensions will trow an exception. If false, such invalid values will be ignored and
254+
* set to {@link Worksheet#MAX_ROW_HEIGHT} or {@link Worksheet#MIN_ROW_HEIGHT}. Default is true
255+
*/
256+
public boolean isEnforceValidRowDimensions() {
257+
return enforceValidRowDimensions;
258+
}
259+
260+
/**
261+
* Sets whether invalid row dimensions (larger than {@link Worksheet#MAX_ROW_HEIGHT} or smaller than
262+
* {@link Worksheet#MIN_ROW_HEIGHT}) will throw an exception
263+
*
264+
* @param enforceValidRowDimensions If true, invalid row dimensions will trow an exception. If false, such invalid
265+
* values will be ignored and set to {@link Worksheet#MAX_ROW_HEIGHT} or
266+
* {@link Worksheet#MIN_ROW_HEIGHT}. Default is true
267+
*/
268+
public void setEnforceValidRowDimensions(boolean enforceValidRowDimensions) {
269+
this.enforceValidRowDimensions = enforceValidRowDimensions;
270+
}
271+
224272
/**
225273
* Gets the global strategy to handle cell values. The default will not enforce any general casting, beside defined
226274
* values of {@link ImportOptions#setEnforceDateTimesAsNumbers(boolean)},

NanoXLSX4j.Lib/src/main/java/ch/rabanti/nanoxlsx4j/lowLevel/WorksheetReader.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import ch.rabanti.nanoxlsx4j.ImportOptions;
1414
import ch.rabanti.nanoxlsx4j.Range;
1515
import ch.rabanti.nanoxlsx4j.Worksheet;
16+
import ch.rabanti.nanoxlsx4j.exceptions.WorksheetException;
1617
import ch.rabanti.nanoxlsx4j.styles.Style;
1718

1819
import java.io.IOException;
@@ -595,7 +596,7 @@ private void getColumns(XmlDocument xmlDocument) {
595596
}
596597
for (int index : indices) {
597598
Column column = new Column(index - 1); // transform to zero-based
598-
column.setWidth(width);
599+
column.setWidth(getValidatedWidth(width));
599600
column.setHidden(hidden);
600601
if (defaultStyle != null) {
601602
column.setDefaultColumnStyle(defaultStyle);
@@ -628,8 +629,8 @@ private void readCell(XmlDocument.XmlNode rowChild) {
628629
value = valueNode.getInnerText();
629630
}
630631
if (valueNode.getName().equalsIgnoreCase("is")) {
631-
if (valueNode.getChildNodes().hasNext()){
632-
value = valueNode.getChildNodes().next().getInnerText();
632+
if (valueNode.getChildNodes().hasNext()) {
633+
value = valueNode.getChildNodes().next().getInnerText();
633634
}
634635
}
635636
}
@@ -663,7 +664,7 @@ else if (checkType(type, "str")) {
663664
importedType = Cell.CellType.FORMULA;
664665
rawValue = raw;
665666
}
666-
else if (checkType(type, "inlineStr")){
667+
else if (checkType(type, "inlineStr")) {
667668
importedType = Cell.CellType.STRING;
668669
rawValue = raw;
669670
}
@@ -1325,6 +1326,37 @@ private static Long tryParseLong(String value) {
13251326
}
13261327
}
13271328

1329+
/**
1330+
* Gets the column width according to {@link ImportOptions#isEnforceValidColumnDimensions()}
1331+
*
1332+
* @param rawValue Raw column value
1333+
* @return Modified column width in case
1334+
* {@link ImportOptions#isEnforceValidColumnDimensions() is set to false, and the raw value was invalid
1335+
* @throws Throws a WorksheetException if the raw value was invalid and
1336+
* {@link ImportOptions#isEnforceValidColumnDimensions() is set to true
1337+
*/
1338+
private float getValidatedWidth(float rawValue) throws WorksheetException {
1339+
if (rawValue < Worksheet.MIN_COLUMN_WIDTH) {
1340+
if (importOptions.isEnforceValidColumnDimensions()) {
1341+
throw new WorksheetException(String.format("The worksheet contains an invalid column width (too small: %f) value. Consider using the ImportOption 'setEnforceValidColumnDimensions' to ignore this error.", rawValue));
1342+
}
1343+
else {
1344+
return Worksheet.MIN_COLUMN_WIDTH;
1345+
}
1346+
}
1347+
else if (rawValue > Worksheet.MAX_COLUMN_WIDTH) {
1348+
if (importOptions.isEnforceValidColumnDimensions()) {
1349+
throw new WorksheetException(String.format("The worksheet contains an invalid column width (too large: %f) value. Consider using the ImportOption 'setEnforceValidColumnDimensions' to ignore this error.", rawValue));
1350+
}
1351+
else {
1352+
return Worksheet.MAX_COLUMN_WIDTH;
1353+
}
1354+
}
1355+
else {
1356+
return rawValue;
1357+
}
1358+
}
1359+
13281360
/**
13291361
* Tries to resolve a shared string from its ID
13301362
*

NanoXLSX4j.Lib/src/main/java/ch/rabanti/nanoxlsx4j/lowLevel/XlsxReader.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import ch.rabanti.nanoxlsx4j.Workbook;
1515
import ch.rabanti.nanoxlsx4j.Worksheet;
1616
import ch.rabanti.nanoxlsx4j.exceptions.IOException;
17+
import ch.rabanti.nanoxlsx4j.exceptions.WorksheetException;
1718
import ch.rabanti.nanoxlsx4j.styles.Style;
1819
import ch.rabanti.nanoxlsx4j.styles.StyleRepository;
1920

@@ -263,7 +264,7 @@ public Workbook getWorkbook() {
263264
ws.addHiddenRow(row.getKey());
264265
}
265266
if (row.getValue().getHeight() != null) {
266-
ws.setRowHeight(row.getKey(), row.getValue().getHeight());
267+
ws.setRowHeight(row.getKey(), getValidatedHeight(row.getValue().getHeight()));
267268
}
268269
}
269270
for (Column column : reader.getValue().getColumns()) {
@@ -343,4 +344,35 @@ else if (pane.isYSplitDefined() && pane.isXSplitDefined()) {
343344
return wb;
344345
}
345346

347+
/**
348+
* Gets the row height according to {@link ImportOptions#isEnforceValidRowDimensions()}
349+
*
350+
* @param rawValue Raw row value
351+
* @return Modified row height in case
352+
* {@link ImportOptions#isEnforceValidRowDimensions() is set to false, and the raw value was invalid
353+
* @throws Throws a WorksheetException if the raw value was invalid and
354+
* {@link ImportOptions#isEnforceValidRownDimensions() is set to true
355+
*/
356+
private float getValidatedHeight(float rawValue) throws WorksheetException {
357+
if (rawValue < Worksheet.MIN_ROW_HEIGHT) {
358+
if (importOptions.isEnforceValidRowDimensions()) {
359+
throw new WorksheetException(String.format("The worksheet contains an invalid row height (too small: %f) value. Consider using the ImportOption 'setEnforceValidRowDimensions' to ignore this error.", rawValue));
360+
}
361+
else {
362+
return Worksheet.MIN_ROW_HEIGHT;
363+
}
364+
}
365+
else if (rawValue > Worksheet.MAX_ROW_HEIGHT) {
366+
if (importOptions.isEnforceValidRowDimensions()) {
367+
throw new WorksheetException(String.format("The worksheet contains an invalid row height (too large: %f) value. Consider using the ImportOption 'setEnforceValidRowDimensions' to ignore this error.", rawValue));
368+
}
369+
else {
370+
return Worksheet.MAX_ROW_HEIGHT;
371+
}
372+
}
373+
else {
374+
return rawValue;
375+
}
376+
}
377+
346378
}

NanoXLSX4j.Lib/src/test/java/ch/rabanti/nanoxlsx4j/reader/ImportOptionTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import ch.rabanti.nanoxlsx4j.Workbook;
99
import ch.rabanti.nanoxlsx4j.Worksheet;
1010
import ch.rabanti.nanoxlsx4j.styles.BasicStyles;
11+
import org.junit.jupiter.api.Assertions;
1112
import org.junit.jupiter.api.DisplayName;
1213
import org.junit.jupiter.api.Test;
1314
import org.junit.jupiter.params.ParameterizedTest;
@@ -1494,6 +1495,64 @@ void importOptionsGetterTest() {
14941495
assertTrue(options.isEnforceEmptyValuesAsString());
14951496
}
14961497

1498+
1499+
@ParameterizedTest
1500+
@DisplayName("Test of the ImportOption property EnforceValidColumnDimensions")
1501+
@CsvSource({
1502+
"valid_column_row_dimensions.xlsx, true, false",
1503+
"invalid_column_width_min.xlsx, true, true",
1504+
"invalid_column_width_max.xlsx, true, true",
1505+
"invalid_row_height_min.xlsx, true, false",
1506+
"invalid_row_height_max.xlsx, true, false",
1507+
"valid_column_row_dimensions.xlsx, false, false",
1508+
"invalid_column_width_min.xlsx, false, false",
1509+
"invalid_column_width_max.xlsx, false, false",
1510+
"invalid_row_height_min.xlsx, false, false",
1511+
"invalid_row_height_max.xlsx, false, false"
1512+
})
1513+
void enforceValidColumnDimensionsTest(String fileName, boolean givenOptionValue, boolean expectedThrow) throws Exception {
1514+
ImportOptions options = new ImportOptions();
1515+
options.setEnforceValidColumnDimensions(givenOptionValue);
1516+
options.setEnforceValidRowDimensions(false);
1517+
InputStream stream = TestUtils.getResource(fileName);
1518+
1519+
if (expectedThrow) {
1520+
Assertions.assertThrows(Exception.class, () -> Workbook.load(stream, options));
1521+
} else {
1522+
Workbook workbook = Workbook.load(stream, options);
1523+
Assertions.assertNotNull(workbook);
1524+
}
1525+
}
1526+
1527+
@ParameterizedTest
1528+
@DisplayName("Test of the ImportOption property EnforceValidRowDimensions")
1529+
@CsvSource({
1530+
"valid_column_row_dimensions.xlsx, true, false",
1531+
"invalid_row_height_min.xlsx, true, true",
1532+
"invalid_row_height_max.xlsx, true, true",
1533+
"invalid_column_width_min.xlsx, true, false",
1534+
"invalid_column_width_max.xlsx, true, false",
1535+
"valid_column_row_dimensions.xlsx, false, false",
1536+
"invalid_row_height_min.xlsx, false, false",
1537+
"invalid_row_height_max.xlsx, false, false",
1538+
"invalid_column_width_min.xlsx, false, false",
1539+
"invalid_column_width_max.xlsx, false, false"
1540+
})
1541+
void enforceValidRowDimensionsTest(String fileName, boolean givenOptionValue, boolean expectedThrow) throws Exception {
1542+
ImportOptions options = new ImportOptions();
1543+
options.setEnforceValidRowDimensions(givenOptionValue);
1544+
options.setEnforceValidColumnDimensions(false);
1545+
InputStream stream = TestUtils.getResource(fileName);
1546+
1547+
if (expectedThrow) {
1548+
Assertions.assertThrows(Exception.class, () -> Workbook.load(stream, options));
1549+
} else {
1550+
Workbook workbook = Workbook.load(stream, options);
1551+
Assertions.assertNotNull(workbook);
1552+
}
1553+
}
1554+
1555+
14971556
private static <T, D> void assertValues(Map<String, T> givenCells, ImportOptions importOptions, BiConsumer<Object, Object> assertionAction)
14981557
throws Exception {
14991558
assertValues(givenCells, importOptions, assertionAction, null);
4.28 KB
Binary file not shown.
4.28 KB
Binary file not shown.
4.25 KB
Binary file not shown.
4.25 KB
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)