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));
+    }
 }

Reply via email to