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

Reply via email to