This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new a387b8b05f stop EnviHeaderParser and IDMLParser carrying state across
parses (#3406)
a387b8b05f is described below
commit a387b8b05f284402e8750db91260267cdf501c6d
Author: Naveed <[email protected]>
AuthorDate: Fri Oct 23 19:18:30 2026 +0530
stop EnviHeaderParser and IDMLParser carrying state across parses (#3406)
Both parsers are shared @TikaComponent instances but kept per-document
state in fields. EnviHeaderParser held its XHTMLContentHandler and the
multi-line field accumulator, and never cleared the accumulator, so a
second brace-delimited field was reported under the first field's key
and a later document inherited the previous document's description.
IDMLParser accumulated page counts across parses. Both now keep that
state local to the parse.
Generated-by: Claude Code
---
.../apache/tika/parser/envi/EnviHeaderParser.java | 28 ++++++-------
.../tika/parser/envi/EnviHeaderParserTest.java | 40 +++++++++++++++++++
.../apache/tika/parser/indesign/IDMLParser.java | 46 +++++++++++-----------
.../tika/parser/indesign/IDMLParserTest.java | 11 ++++++
4 files changed, 87 insertions(+), 38 deletions(-)
diff --git
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java
index 31f9a78778..2afb845162 100644
---
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java
+++
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/main/java/org/apache/tika/parser/envi/EnviHeaderParser.java
@@ -52,10 +52,6 @@ public class EnviHeaderParser extends
AbstractEncodingDetectorParser {
private static final Set<MediaType> SUPPORTED_TYPES =
Collections.singleton(MediaType.application("envi.hdr"));
- private List<String> multiLineFieldValueList = new ArrayList<>();
-
- private transient XHTMLContentHandler xhtml;
-
public EnviHeaderParser() {
super();
}
@@ -84,9 +80,9 @@ public class EnviHeaderParser extends
AbstractEncodingDetectorParser {
Charset charset = reader.getCharset();
// deprecated, see TIKA-431
metadata.set(HttpHeaders.CONTENT_ENCODING, charset.name());
- xhtml = new XHTMLContentHandler(handler, metadata, context);
+ XHTMLContentHandler xhtml = new XHTMLContentHandler(handler,
metadata, context);
xhtml.startDocument();
- readLines(reader, metadata);
+ readLines(reader, metadata, xhtml);
xhtml.endDocument();
} catch (IOException | TikaException e) {
LOG.error("Error reading input data tis.", e);
@@ -96,18 +92,19 @@ public class EnviHeaderParser extends
AbstractEncodingDetectorParser {
}
- private void readLines(AutoDetectReader reader, Metadata metadata)
- throws IOException, SAXException {
+ private void readLines(AutoDetectReader reader, Metadata metadata,
+ XHTMLContentHandler xhtml) throws IOException,
SAXException {
// text contents of the xhtml
String line;
+ List<String> multiLineFieldValueList = new ArrayList<>();
while ((line = reader.readLine()) != null) {
if (line.contains("{") && !line.endsWith("}") || line.startsWith("
")) {
- String completeField = parseMultiLineFieldValue(line);
+ String completeField = parseMultiLineFieldValue(line,
multiLineFieldValueList);
if (completeField != null) {
- writeParagraphAndSetMetadata(completeField, metadata);
+ writeParagraphAndSetMetadata(completeField, metadata,
xhtml);
}
} else {
- writeParagraphAndSetMetadata(line, metadata);
+ writeParagraphAndSetMetadata(line, metadata, xhtml);
}
}
}
@@ -115,7 +112,8 @@ public class EnviHeaderParser extends
AbstractEncodingDetectorParser {
/*
* Write a line to the XHTMLContentHandler and populate the key, value
into the Metadata
*/
- private void writeParagraphAndSetMetadata(String line, Metadata metadata)
throws SAXException {
+ private void writeParagraphAndSetMetadata(String line, Metadata metadata,
+ XHTMLContentHandler xhtml)
throws SAXException {
if (line.length() < 300) {
String[] keyValue = line.split("=", 2);
if (keyValue.length != 1) {
@@ -227,10 +225,12 @@ public class EnviHeaderParser extends
AbstractEncodingDetectorParser {
* check it made to ensure the multi-line contents are contained in
* opening and closing braces.
*/
- private String parseMultiLineFieldValue(String line) {
+ private String parseMultiLineFieldValue(String line, List<String>
multiLineFieldValueList) {
multiLineFieldValueList.add(line);
if (line.endsWith("}")) {
- return String.join("", multiLineFieldValueList);
+ String completeField = String.join("", multiLineFieldValueList);
+ multiLineFieldValueList.clear();
+ return completeField;
} else {
//do nothing
}
diff --git
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/test/java/org/apache/tika/parser/envi/EnviHeaderParserTest.java
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/test/java/org/apache/tika/parser/envi/EnviHeaderParserTest.java
index 736157bce6..b39a27c0a3 100644
---
a/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/test/java/org/apache/tika/parser/envi/EnviHeaderParserTest.java
+++
b/tika-parsers/tika-parsers-extended/tika-parser-scientific-module/src/test/java/org/apache/tika/parser/envi/EnviHeaderParserTest.java
@@ -17,6 +17,8 @@
package org.apache.tika.parser.envi;
import static org.apache.tika.TikaTest.assertContains;
+import static org.apache.tika.TikaTest.assertNotContained;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.ByteArrayOutputStream;
@@ -156,4 +158,42 @@ public class EnviHeaderParserTest {
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
+
+ @Test
+ public void testMultiLineFieldsDoNotLeakAcrossParses() throws Exception {
+ // one instance serves every parse: the first document's multi-line
description
+ // must not surface in the second document's content or metadata
+ parse("/test-documents/envi_test_header.hdr", new
ToXMLContentHandler(), new Metadata());
+ ToXMLContentHandler second = new ToXMLContentHandler();
+ Metadata secondMetadata = new Metadata();
+ parse("/test-documents/ang20150420t182050_corr_v1e_img.hdr", second,
secondMetadata);
+ String content = second.toString();
+ assertNotContained("GEO-TIFF File Imported into ENVI", content);
+ assertContains(
+ "<p>description = { Georeferenced Image built from input GLT.
" +
+ "[Wed Jun 10 04:37:54 2015] [Wed Jun 10 04:48:52
2015]}</p>",
+ content);
+ assertEquals("{ Georeferenced Image built from input GLT. [Wed Jun 10
04:37:54 2015] " +
+ "[Wed Jun 10 04:48:52 2015]}",
secondMetadata.get("envi:description"));
+ }
+
+ @Test
+ public void testSecondMultiLineFieldStartsEmpty() throws Exception {
+ String header = "ENVI\ndescription = {\n first}\nband names = {\n
Band 1,\n Band 2}\n";
+ try (TikaInputStream tis =
TikaInputStream.get(header.getBytes(StandardCharsets.US_ASCII))) {
+ parser.parse(tis, handler, metadata, new ParseContext());
+ }
+ assertContains("<p>band names = { Band 1, Band 2}</p>",
handler.toString());
+ assertEquals("{ first}", metadata.get("envi:description"));
+ assertEquals("{ Band 1, Band 2}", metadata.get("envi:band.names"));
+ }
+
+ private void parse(String resource, ToXMLContentHandler handler, Metadata
metadata)
+ throws Exception {
+ try (TikaInputStream tis = TikaInputStream.get(
+ EnviHeaderParser.class.getResourceAsStream(resource))) {
+ assertNotNull(tis, "Test ENVI file '" + resource + "' not found");
+ parser.parse(tis, handler, metadata, new ParseContext());
+ }
+ }
}
diff --git
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/indesign/IDMLParser.java
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/indesign/IDMLParser.java
index cbd9cdffbb..0b82d6240d 100644
---
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/indesign/IDMLParser.java
+++
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/main/java/org/apache/tika/parser/indesign/IDMLParser.java
@@ -69,16 +69,6 @@ public class IDMLParser implements Parser {
*/
private static final String META_NAME = "META-INF/metadata.xml";
- /**
- * Internal page count.
- */
- private int pageCount = 0;
-
- /**
- * Internal master spread count.
- */
- private int masterSpreadCount = 0;
-
@Override
public Set<MediaType> getSupportedTypes(ParseContext context) {
return SUPPORTED_TYPES;
@@ -102,24 +92,25 @@ public class IDMLParser implements Parser {
XHTMLContentHandler xhtml = new XHTMLContentHandler(baseHandler,
metadata, context);
xhtml.startDocument();
EndDocumentShieldingContentHandler handler = new
EndDocumentShieldingContentHandler(xhtml);
+ PageCounts counts = new PageCounts();
if (zipFile != null) {
try {
- handleZipFile(zipFile, metadata, context, handler);
+ handleZipFile(zipFile, metadata, context, handler, counts);
} finally {
zipFile.close();
}
} else {
try {
- handleZipStream(zipStream, metadata, context, handler);
+ handleZipStream(zipStream, metadata, context, handler, counts);
} finally {
zipStream.close();
}
}
- metadata.set(IDML.SPREAD_PAGE_COUNT, Integer.toString(pageCount));
- metadata.set(IDML.MASTER_SPREAD_PAGE_COUNT,
Integer.toString(masterSpreadCount));
- metadata.set(Office.PAGE_COUNT, Integer.toString(pageCount +
masterSpreadCount));
+ metadata.set(IDML.SPREAD_PAGE_COUNT, Integer.toString(counts.pages));
+ metadata.set(IDML.MASTER_SPREAD_PAGE_COUNT,
Integer.toString(counts.masterSpreadPages));
+ metadata.set(Office.PAGE_COUNT, Integer.toString(counts.pages +
counts.masterSpreadPages));
xhtml.endDocument();
@@ -129,36 +120,37 @@ public class IDMLParser implements Parser {
}
private void handleZipStream(ZipInputStream zipStream, Metadata metadata,
ParseContext context,
- ContentHandler handler) throws IOException,
TikaException, SAXException {
+ ContentHandler handler, PageCounts counts)
+ throws IOException, TikaException, SAXException {
ZipEntry entry = zipStream.getNextEntry();
if (entry == null) {
throw new IOException("No entries found in ZipInputStream");
}
do {
- handleZipEntry(entry, zipStream, metadata, context, handler);
+ handleZipEntry(entry, zipStream, metadata, context, handler,
counts);
entry = zipStream.getNextEntry();
} while (entry != null);
}
- private void handleZipFile(ZipFile zipFile, Metadata metadata,
ParseContext context, ContentHandler handler)
- throws IOException, TikaException, SAXException {
+ private void handleZipFile(ZipFile zipFile, Metadata metadata,
ParseContext context, ContentHandler handler,
+ PageCounts counts) throws IOException,
TikaException, SAXException {
ZipEntry entry = zipFile.getEntry(META_NAME);
if (entry != null) {
- handleZipEntry(entry, zipFile.getInputStream(entry), metadata,
context, handler);
+ handleZipEntry(entry, zipFile.getInputStream(entry), metadata,
context, handler, counts);
}
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
entry = entries.nextElement();
if (!META_NAME.equals(entry.getName())) {
- handleZipEntry(entry, zipFile.getInputStream(entry), metadata,
context, handler);
+ handleZipEntry(entry, zipFile.getInputStream(entry), metadata,
context, handler, counts);
}
}
}
private void handleZipEntry(ZipEntry entry, InputStream zip, Metadata
metadata,
- ParseContext context, ContentHandler handler)
+ ParseContext context, ContentHandler handler,
PageCounts counts)
throws IOException, SAXException, TikaException {
if (entry == null) {
@@ -180,15 +172,21 @@ public class IDMLParser implements Parser {
Metadata embeddedMeta = Metadata.newInstance(context);
ContentAndMetadataExtractor.extract(zip, handler, embeddedMeta,
context);
int spreadCount =
Integer.parseInt(embeddedMeta.get(Office.PAGE_COUNT));
- masterSpreadCount += spreadCount;
+ counts.masterSpreadPages += spreadCount;
} else if (entry.getName().contains("Spreads/Spread")) {
Metadata embeddedMeta = Metadata.newInstance(context);
ContentAndMetadataExtractor.extract(zip, handler, embeddedMeta,
context);
int spreadCount =
Integer.parseInt(embeddedMeta.get(Office.PAGE_COUNT));
- pageCount += spreadCount;
+ counts.pages += spreadCount;
} else if (entry.getName().contains("Stories")) {
ContentAndMetadataExtractor.extract(zip, handler,
Metadata.newInstance(context), context);
}
}
+
+ /** Page totals of one document; the parser instance is shared across
parses. */
+ private static final class PageCounts {
+ int pages;
+ int masterSpreadPages;
+ }
}
diff --git
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/indesign/IDMLParserTest.java
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/indesign/IDMLParserTest.java
index 01535905c4..ac0f16c32a 100644
---
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/indesign/IDMLParserTest.java
+++
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-miscoffice-module/src/test/java/org/apache/tika/parser/indesign/IDMLParserTest.java
@@ -67,4 +67,15 @@ public class IDMLParserTest extends TikaTest {
assertContains("<meta name=\"xmp:CreatorTool\" content=\"Adobe
InDesign CC 14.0 (Windows)\" />", xml);
}
+
+ @Test
+ public void testPageCountsAreNotCarriedAcrossParses() throws Exception {
+ // one instance serves every parse: the totals must start from zero
each time
+ getText("testIndesign.idml", parser, new Metadata());
+ Metadata metadata = new Metadata();
+ getText("testIndesign.idml", parser, metadata);
+ assertEquals("3", metadata.get(Office.PAGE_COUNT));
+ assertEquals("2", metadata.get(IDML.MASTER_SPREAD_PAGE_COUNT));
+ assertEquals("1", metadata.get(IDML.SPREAD_PAGE_COUNT));
+ }
}