This is an automated email from the ASF dual-hosted git repository. tballison pushed a commit to branch TIKA-4785 in repository https://gitbox.apache.org/repos/asf/tika.git
commit 452779408f2d534df939b8ca7c4f5e598d3c4af6 Author: tallison <[email protected]> AuthorDate: Fri Jul 10 13:46:37 2026 -0400 TIKA-4785 --- .../org/apache/tika/parser/pkg/PackageParser.java | 11 +++- .../apache/tika/parser/pkg/PackageParserTest.java | 64 ++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java index 8db2714264..613e7b4432 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/PackageParser.java @@ -449,8 +449,15 @@ public class PackageParser extends AbstractEncodingDetectorParser { entry.getSize(), xhtml); if (extractor.shouldParseEmbedded(entryMetadata)) { - try (InputStream entryStream = zipFile.getInputStream(entry)) { - extractor.parseEmbedded(entryStream, xhtml, entryMetadata, true); + // Detectors (e.g. POIFSContainerDetector.isOleHeader) mark/reset the stream, but + // ZipFile.getInputStream(entry) returns a non-markable InflaterInputStream. Wrap it + // in a mark/reset-supporting TikaInputStream first, mirroring the ArchiveInputStream + // path in parseEntry (TIKA-4785). entryStream is closed by the try-with-resources; + // like parseEntry we don't close the TikaInputStream (that would double-close it). + try (InputStream entryStream = zipFile.getInputStream(entry); + TemporaryResources tmp = new TemporaryResources()) { + TikaInputStream tis = TikaInputStream.get(entryStream, tmp, entryMetadata); + extractor.parseEmbedded(tis, xhtml, entryMetadata, true); } catch (UnsupportedZipFeatureException e) { EmbeddedDocumentUtil.recordEmbeddedStreamException(e, parentMetadata); if (name != null && name.length() > 0) { diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/pkg/PackageParserTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/pkg/PackageParserTest.java index bec188b8d8..f4d7b1efe4 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/pkg/PackageParserTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/src/test/java/org/apache/tika/parser/pkg/PackageParserTest.java @@ -16,13 +16,29 @@ */ package org.apache.tika.parser.pkg; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; +import org.xml.sax.ContentHandler; +import org.xml.sax.helpers.DefaultHandler; import org.apache.tika.TikaTest; +import org.apache.tika.extractor.EmbeddedDocumentExtractor; +import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.TikaCoreProperties; +import org.apache.tika.parser.AutoDetectParser; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.Parser; public class PackageParserTest extends TikaTest { @@ -38,4 +54,52 @@ public class PackageParserTest extends TikaTest { assertContains("文章", metadataList.get(1).get(TikaCoreProperties.RESOURCE_NAME_KEY)); assertContains("文章", metadataList.get(2).get(TikaCoreProperties.RESOURCE_NAME_KEY)); } + + /** + * TIKA-4785: PackageParser must hand embedded-document extractors a mark/reset-supporting + * stream. A .sxc (application/vnd.sun.xml.calc) is a zip that OpenDocumentParser does not + * claim, so it is handled here; the 3.x ZipFile fast-path (parseZipEntry) regressed by + * passing the raw, non-markable InflaterInputStream from ZipFile.getInputStream(entry). A + * file-backed input routes through that fast-path. The default extractor wraps the stream + * defensively, so we install a custom extractor to observe the stream Tika hands out. + */ + @Test + public void embeddedStreamSupportsMarkReset() throws Exception { + List<Boolean> markSupported = new ArrayList<>(); + Parser parser = new AutoDetectParser(); + ParseContext context = new ParseContext(); + context.set(Parser.class, parser); + context.set(EmbeddedDocumentExtractor.class, new EmbeddedDocumentExtractor() { + @Override + public boolean shouldParseEmbedded(Metadata metadata) { + return true; + } + + @Override + public void parseEmbedded(InputStream stream, ContentHandler handler, + Metadata metadata, boolean outputHtml) { + markSupported.add(stream.markSupported()); + } + }); + + Metadata metadata = new Metadata(); + Path tmpFile = Files.createTempFile("tika4785", ".sxc"); + try { + try (InputStream is = + getResourceAsStream("/test-documents/testStarOffice-6.0-calc.sxc")) { + Files.copy(is, tmpFile, StandardCopyOption.REPLACE_EXISTING); + } + try (TikaInputStream tis = TikaInputStream.get(tmpFile)) { + parser.parse(tis, new DefaultHandler(), metadata, context); + } + } finally { + Files.deleteIfExists(tmpFile); + } + + assertEquals("application/vnd.sun.xml.calc", metadata.get(Metadata.CONTENT_TYPE)); + assertFalse(markSupported.isEmpty(), "expected at least one embedded entry to be parsed"); + for (boolean supported : markSupported) { + assertTrue(supported, "embedded stream must support mark/reset (TIKA-4785)"); + } + } }
