This is an automated email from the ASF dual-hosted git repository. tballison pushed a commit to branch placeholder-stream in repository https://gitbox.apache.org/repos/asf/tika.git
commit 92bd7cecf4eac8e22f800182fb565ccfdd8d1011 Author: tallison <[email protected]> AuthorDate: Wed Sep 2 20:42:55 2026 -0400 add a placeholder marker --- CHANGES.txt | 5 +++++ .../src/main/java/org/apache/tika/io/TikaInputSource.java | 8 ++++++++ .../src/main/java/org/apache/tika/io/TikaInputStream.java | 14 +++++++++++++- .../main/java/org/apache/tika/renderer/RenderResult.java | 3 ++- .../apache/tika/parser/microsoft/MetafileRendering.java | 2 +- .../org/apache/tika/parser/microsoft/OfficeParser.java | 11 ++++++++--- .../java/org/apache/tika/parser/pdf/AbstractPDF2XHTML.java | 2 +- .../apache/tika/parser/pdf/image/ImageGraphicsEngine.java | 2 +- 8 files changed, 39 insertions(+), 8 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 80e898aa72..54605e07c1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,10 @@ Release 4.1.0 - unreleased + * Placeholder streams -- the empty stand-ins parsers hand parseEmbedded + for content that is never extracted -- report an unknown length rather + than their own zero, and the macro-failure entry is registered without + parsing its sentinel (TIKA-4874). + * Raster previews for the vector thumbnails of Office documents: the new poi-metafile-renderer draws EMF and WMF images through POI (a PNG of a configurable width; Word's bitmap-in-WMF thumbnails from the bitmap diff --git a/tika-core/src/main/java/org/apache/tika/io/TikaInputSource.java b/tika-core/src/main/java/org/apache/tika/io/TikaInputSource.java index 9e7b4a8d30..78500097c8 100644 --- a/tika-core/src/main/java/org/apache/tika/io/TikaInputSource.java +++ b/tika-core/src/main/java/org/apache/tika/io/TikaInputSource.java @@ -63,6 +63,14 @@ interface TikaInputSource extends Closeable { */ long getLength(); + /** + * Whether this source stands in for content that is never extracted. Spooling one + * measures nothing, so its unknown length must not cost a temp file to confirm. + */ + default boolean isPlaceholder() { + return false; + } + /** * Enables full rewind capability. * <p> diff --git a/tika-core/src/main/java/org/apache/tika/io/TikaInputStream.java b/tika-core/src/main/java/org/apache/tika/io/TikaInputStream.java index b58cd548db..670e2581dd 100644 --- a/tika-core/src/main/java/org/apache/tika/io/TikaInputStream.java +++ b/tika-core/src/main/java/org/apache/tika/io/TikaInputStream.java @@ -158,6 +158,18 @@ public class TikaInputStream extends TaggedInputStream { return new TikaInputStream(inputSource, tmp, ext); } + /** + * An empty stream standing in for content that is never extracted -- a metadata-only + * entry, a rendering carried as an open container. It reports an <em>unknown</em> + * length, so nothing mistakes the placeholder's size for the document's. Pair it with + * {@link org.apache.tika.parser.MetadataOnlyParse} to register an entry without + * parsing it, unless an open container supplies the content. + */ + public static TikaInputStream getPlaceholder() { + TemporaryResources tmp = new TemporaryResources(); + return new TikaInputStream(new PlaceholderSource(tmp), tmp, ""); + } + public static TikaInputStream get(Path path) throws IOException { return get(path, new Metadata()); } @@ -453,7 +465,7 @@ public class TikaInputStream extends TaggedInputStream { return -1; } long len = source.getLength(); - if (len == -1) { + if (len == -1 && !source.isPlaceholder()) { // Force spill to get length getPath(); len = source.getLength(); diff --git a/tika-core/src/main/java/org/apache/tika/renderer/RenderResult.java b/tika-core/src/main/java/org/apache/tika/renderer/RenderResult.java index 25588c45bb..db6ab42bdf 100644 --- a/tika-core/src/main/java/org/apache/tika/renderer/RenderResult.java +++ b/tika-core/src/main/java/org/apache/tika/renderer/RenderResult.java @@ -65,7 +65,8 @@ public class RenderResult implements Closeable { if (result instanceof Path) { return TikaInputStream.get((Path)result, metadata); } else { - TikaInputStream tis = TikaInputStream.get(new byte[0]); + // the rendering rides in the open container, not the stream + TikaInputStream tis = TikaInputStream.getPlaceholder(); tis.setOpenContainer(result); return tis; } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/MetafileRendering.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/MetafileRendering.java index d4efd0a12c..0032c97a64 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/MetafileRendering.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/MetafileRendering.java @@ -119,7 +119,7 @@ final class MetafileRendering { if (source != null && source.hasFile()) { return TikaInputStream.get(source.getPath()); } - return TikaInputStream.get(new byte[0]); + return TikaInputStream.getPlaceholder(); } /** diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParser.java index 423a51f86b..925e688f58 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/main/java/org/apache/tika/parser/microsoft/OfficeParser.java @@ -55,6 +55,7 @@ import org.apache.tika.metadata.HttpHeaders; import org.apache.tika.metadata.Metadata; import org.apache.tika.metadata.TikaCoreProperties; import org.apache.tika.mime.MediaType; +import org.apache.tika.parser.MetadataOnlyParse; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.PasswordProvider; import org.apache.tika.parser.microsoft.ooxml.OOXMLParser; @@ -130,9 +131,13 @@ public class OfficeParser extends AbstractOfficeParser { m.set(HttpHeaders.CONTENT_TYPE, "text/x-vbasic"); EmbeddedDocumentUtil.recordException(e, m, context); if (embeddedDocumentExtractor.shouldParseEmbedded(m, context)) { - embeddedDocumentExtractor.parseEmbedded( - //pass in space character so that we don't trigger a zero-byte exception - TikaInputStream.get(new byte[]{'\u0020'}), xhtml, m, context, true); + // the entry carries the exception, not content: register it without a parse + try (TikaInputStream tis = TikaInputStream.getPlaceholder()) { + context.set(MetadataOnlyParse.class, MetadataOnlyParse.INSTANCE); + embeddedDocumentExtractor.parseEmbedded(tis, xhtml, m, context, true); + } finally { + context.set(MetadataOnlyParse.class, null); + } } return; } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/AbstractPDF2XHTML.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/AbstractPDF2XHTML.java index aa57face74..da4a51ed43 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/AbstractPDF2XHTML.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/AbstractPDF2XHTML.java @@ -640,7 +640,7 @@ class AbstractPDF2XHTML extends PDFTextStripper { new PageRangeRequest(getCurrentPageNo(), getCurrentPageNo()); if (thisRenderer instanceof PDDocumentRenderer) { //do not do autocloseable. We need to leave the pdDocument open! - TikaInputStream tis = TikaInputStream.get(new byte[0]); + TikaInputStream tis = TikaInputStream.getPlaceholder(); tis.setOpenContainer(pdDocument); return thisRenderer.render(tis, pageMetadata, context, pageRangeRequest) .getResults().get(0); diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/image/ImageGraphicsEngine.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/image/ImageGraphicsEngine.java index 1c04c23a44..e4387802f9 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/image/ImageGraphicsEngine.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pdf-module/src/main/java/org/apache/tika/parser/pdf/image/ImageGraphicsEngine.java @@ -451,7 +451,7 @@ public class ImageGraphicsEngine extends PDFGraphicsStreamEngine { metadata.set(TIFF.IMAGE_LENGTH, pdImage.getHeight()); //TODO: what else can we extract from the PDImage without rendering? //Register the image's metadata entry without decoding it (marker skips the parse). - try (TikaInputStream tis = TikaInputStream.get(new byte[0])) { + try (TikaInputStream tis = TikaInputStream.getPlaceholder()) { parseContext.set(MetadataOnlyParse.class, MetadataOnlyParse.INSTANCE); embeddedDocumentExtractor.parseEmbedded(tis, new EmbeddedContentHandler(xhtml), metadata, parseContext, false);
