diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index bc9fb9da0..1d561f809 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 48936 - Avoid writing malformed CDATA blocks in sharedStrings.xml 49026 - Added implementation for TEXT() 49025 - Added implementation for TRUNC() 49147 - Properly close internal InputStream in ExtractorFactory#createExtractor(File) diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java index ac648c142..3d402ea43 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java @@ -84,7 +84,7 @@ public class SharedStringsTable extends POIXMLDocumentPart { */ private int uniqueCount; - private SstDocument _sstDoc; + public SstDocument _sstDoc; public SharedStringsTable() { super(); @@ -195,6 +195,10 @@ public class SharedStringsTable extends POIXMLDocumentPart { */ public void writeTo(OutputStream out) throws IOException { XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS); + // the following two lines turn off writing CDATA + // see Bugzilla 48936 + options.setSaveCDataLengthThreshold(1000000); + options.setSaveCDataEntityCountThreshold(-1); //re-create the sst table every time saving a workbook CTSst sst = _sstDoc.getSst(); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestSharedStringsTable.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestSharedStringsTable.java index 15d71c3d4..0298b0517 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/model/TestSharedStringsTable.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestSharedStringsTable.java @@ -18,12 +18,18 @@ package org.apache.poi.xssf.model; import java.util.List; +import java.util.ArrayList; +import java.io.*; import junit.framework.TestCase; import org.apache.poi.xssf.XSSFTestDataSamples; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.POIDataSamples; +import org.apache.poi.POIXMLException; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst; @@ -125,4 +131,49 @@ public final class TestSharedStringsTable extends TestCase { assertEquals(st1.toString(), st2.toString()); } } + + /** + * Test for Bugzilla 48936 + * + * A specific sequence of strings can result in broken CDATA section in sharedStrings.xml file. + * + * @author Philippe Laflamme + */ + public void testBug48936() throws IOException { + Workbook w = new XSSFWorkbook(); + Sheet s = w.createSheet(); + int i = 0; + List lst = readStrings("48936-strings.txt"); + for (String str : lst) { + s.createRow(i++).createCell(0).setCellValue(str); + } + + try { + w = XSSFTestDataSamples.writeOutAndReadBack(w); + } catch (POIXMLException e){ + fail("Detected Bug #48936"); + } + s = w.getSheetAt(0); + i = 0; + for (String str : lst) { + String val = s.getRow(i++).getCell(0).getStringCellValue(); + assertEquals(str, val); + } + } + + private List readStrings(String filename) throws IOException { + List strs = new ArrayList(); + POIDataSamples samples = POIDataSamples.getSpreadSheetInstance(); + BufferedReader br = new BufferedReader( + new InputStreamReader(samples.openResourceAsStream(filename))); + String s; + while ((s = br.readLine()) != null) { + if (s.trim().length() > 0) { + strs.add(s.trim()); + } + } + br.close(); + return strs; + } + } diff --git a/test-data/spreadsheet/48936-strings.txt b/test-data/spreadsheet/48936-strings.txt new file mode 100644 index 000000000..2ceefe386 --- /dev/null +++ b/test-data/spreadsheet/48936-strings.txt @@ -0,0 +1,81 @@ +[IntegrityCheck-ERROR[MALE[50.0 < x < 199.0], FEMALE[50.0 < x < 199.0]], IntegrityCheck-WARNING[MALE[61.0 < x < 126.0], FEMALE[47.0 < x < 119.0]]] +Computing[($1 + $2 + $3)/3,[Instrument[BloodPressure, RES_FIRST_DIASTOLIC_BP], Instrument[BloodPressure, RES_SEC_DIASTOLIC_BP], Instrument[BloodPressure, RES_THIRD_DIASTOLIC_BP]]] +COMPUTED +BloodPressure +BloodPressure +Average Pulse Rate +Moyenne des lectures de pouls +Computing[($1 + $2 + $3)/3,[Instrument[BloodPressure, RES_FIRST_PULSE_RATE], Instrument[BloodPressure, RES_SEC_PULSE_RATE], Instrument[BloodPressure, RES_THIRD_PULSE_RATE]]] +COMPUTED +BloodPressure +BloodPressure +Average Systolic Blood Pressure +Pression artérielle systolique moyenne +Computing[($1 + $2 + $3)/3,[Instrument[BloodPressure, RES_FIRST_SYSTOLIC_BP], Instrument[BloodPressure, RES_SEC_SYSTOLIC_BP], Instrument[BloodPressure, RES_THIRD_SYSTOLIC_BP]]] +COMPUTED +BloodPressure +BloodPressure +BloodPressure +BloodPressure +BloodPressure +BloodPressure +BloodPressure +BloodPressure +BloodPressure +Armband size used +Taille du brassard utilisé +MANUAL +Small +Petit +Medium +Moyen +Large +Grand +Extra Large +Très grand +BloodPressure +BloodPressure +Arm suggested to be used for measurement +Bras suggéré pour la mesure +Variable[Onyx.CIPreliminaryQuestionnaire.BP_ARM_CHOSEN] +AUTOMATIC +false +BloodPressure +BloodPressure +What arm was actually used for the measurements? +Quel bras a été utilisé pour les mesures? +MANUAL +Left +Gauche +Right +Droit +BloodPressure +BloodPressure +Circumference of upper arm at midpoint +Circonférence du haut du bras +[IntegrityCheck-ERROR[MALE[17.0 < x < 50.0], FEMALE[17.0 < x < 50.0]]] +MANUAL +BloodPressure +BloodPressure +Diastolic Blood Pressure reading (1) +Lecture de la pression artérielle diastolique (1) +[IntegrityCheck-ERROR[MALE[30 < x < 200 || ], FEMALE[30 < x < 200 || ]], IntegrityCheck-WARNING[MALE[51 < x < 96 || ], FEMALE[51 < x < 96 || ]], IntegrityCheck-ERROR[x < RES_FIRST_SYSTOLIC_BP]] +MANUAL +BloodPressure +BloodPressure +Pulse Rate reading (1) +Lecture de pouls (1) +[IntegrityCheck-ERROR[MALE[30 < x < 200 || ], FEMALE[30 < x < 200 || ]], IntegrityCheck-WARNING[MALE[40 < x < 100 || ], FEMALE[40 < x < 100 || ]]] +MANUAL +BloodPressure +BloodPressure +Systolic Blood Pressure reading (1) +Lecture de la pression artérielle systolique (1) +[IntegrityCheck-ERROR[MALE[30 < x < 300 || ], FEMALE[30 < x < 300 || ]], IntegrityCheck-WARNING[MALE[77 < x < 192 || ], FEMALE[77 < x < 192 || ]]] +MANUAL +BloodPressure +BloodPressure +Diastolic Blood Pressure reading (2) +Lecture de la pression artérielle diastolique (2) +[IntegrityCheck-ERROR[MALE[30 < x < 200 || ], FEMALE[30 < x < 200 || ]], IntegrityCheck-WARNING[MALE[51 < x < 96 || ], FEMALE[51 < x < 96 || ]], IntegrityCheck-ERROR[x < RES_SEC_SYSTOLIC_BP]] +