[gs-commits] ghostpdl branch, pdfi, updated. jbig2dec-0.14-2334-gc430982

[email protected] (Ken Sharp) Mon, 14 Oct 2019 14:11:17 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, pdfi has been updated
       via  c4309825a1e77b5d54bc66de804d88c0b9b9fc48 (commit)
       via  9b217f52c5693a22af282f1b218cc7b9bc36936c (commit)
      from  709c4cba1e30d84f5b2ca3f389446d11897325a0 (commit)

----------------------------------------------------------------------
commit c4309825a1e77b5d54bc66de804d88c0b9b9fc48
Author: Ken Sharp <[email protected]>
Date:   Mon Oct 14 15:10:24 2019 +0100

    Use SubFileDecode to limit bytes read from an ObjStm
    
    Inspired by a customer file.... An object in an ObjStm is not delimited
    with x y obj...endobj, its a naked object. Some object types are
    self-delimiting such as dictionaries and arrays, but other types are
    not.
    
    In particular null objects and numbers are not delimited. Because the
    objects in an ObjStm need not have any white space, this can lead to
    errors if we are try to read tokens. Consider two number 123 and 456
    which are stored consecutively in an ObjStm, the offset array would
    contain something like x 0 y 3, so that the offset of object x is 0,
    and the offset of object y is 3, but the actual decompressed stream
    content would be '123456'. We have to know that the initial object
    contains only 3 bytes and stop after that.
    
    We were not previously doing this.
    
    This commit adds a SubFileDecode around the entire ObjStm stream object
    using the /Length key to lilmit the number of bytes which can be read.
    This is because the offsets array only contains offsets to each object
    and so cannot be used to find the length of the last object in the
    stream.
    
    When reading an object, except for the last one in the stream, we apply
    another SubFileDeocde to the compressed stream to limit the amount of
    uncompressed data we read to the difference between the offsets of
    two consecutive objects.
    
    This prevents us running past the end of an object, even if it is not
    delimited in the stream.

diff --git a/pdf/pdf_int.c b/pdf/pdf_int.c
index 6e87b9e..2835692 100644
--- a/pdf/pdf_int.c
+++ b/pdf/pdf_int.c
@@ -408,9 +408,9 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
 
             xref_entry *compressed_entry = &ctx->xref_table->xref[entry->u.compressed.compressed_stream_num];
             pdf_dict *compressed_object;
-            pdf_stream *compressed_stream;
+            pdf_stream *compressed_stream, *SubFile_stream, *Object_stream;
             char Buffer[256];
-            int i = 0;
+            int i = 0, object_length = 0;
             int64_t num_entries;
             gs_offset_t offset = 0;
 
@@ -481,7 +481,20 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
                 return code;
             }
 
-            code = pdfi_filter(ctx, compressed_object, ctx->main_stream, &compressed_stream, false);
+            code = pdfi_dict_get_type(ctx, compressed_object, "Length", PDF_INT, &o);
+            if (code < 0) {
+                pdfi_countdown(compressed_object);
+                (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
+                return code;
+            }
+
+            code = pdfi_apply_SubFileDecode_filter(ctx, ((pdf_num *)o)->value.i, NULL, ctx->main_stream, &SubFile_stream, false);
+            if (code < 0) {
+                (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
+                return code;
+            }
+
+            code = pdfi_filter(ctx, compressed_object, SubFile_stream, &compressed_stream, false);
             if (code < 0) {
                 pdfi_countdown(compressed_object);
                 (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
@@ -523,9 +536,12 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
                 }
                 if (i == entry->u.compressed.object_index)
                     offset = ((pdf_num *)o)->value.i;
+                if (i == entry->u.compressed.object_index + 1)
+                    object_length = ((pdf_num *)o)->value.i - offset;
                 pdfi_pop(ctx, 1);
             }
 
+            /* Skip to the offset of the object we want to read */
             for (i=0;i < offset;i++)
             {
                 code = pdfi_read_bytes(ctx, (byte *)&Buffer[0], 1, 1, compressed_stream);
@@ -535,9 +551,26 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
                 }
             }
 
-            code = pdfi_read_token(ctx, compressed_stream);
+            /* If object_length is not 0, then we want to apply a SubFileDecode filter to limit
+             * the number of bytes we read to the declared size of the object (difference between
+             * the offsets of the object we want to read, and the next object). If it is 0 then
+             * we're reading the last object in the stream, so we just rely on the SubFileDecode
+             * we set up when we created compressed_stream to limit the bytes to the length of
+             * that stream.
+             */
+            if (object_length > 0) {
+                code = pdfi_apply_SubFileDecode_filter(ctx, object_length, NULL, compressed_stream, &Object_stream, false);
+                if (code < 0) {
+                    (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
+                    return code;
+                }
+            } else {
+                Object_stream = compressed_stream;
+            }
+
+            code = pdfi_read_token(ctx, Object_stream);
             if (code < 0) {
-                pdfi_close_file(ctx, compressed_stream);
+                pdfi_close_file(ctx, Object_stream);
                 pdfi_countdown(compressed_object);
                 (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
                 return code;
@@ -547,15 +580,15 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
 
                 /* Need to read all the elements from COS objects */
                 do {
-                    code = pdfi_read_token(ctx, compressed_stream);
+                    code = pdfi_read_token(ctx, Object_stream);
                     if (code < 0) {
-                        pdfi_close_file(ctx, compressed_stream);
+                        pdfi_close_file(ctx, Object_stream);
                         pdfi_countdown(compressed_object);
                         (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
                         return code;
                     }
                     if (compressed_stream->eof == true) {
-                        pdfi_close_file(ctx, compressed_stream);
+                        pdfi_close_file(ctx, Object_stream);
                         pdfi_countdown(compressed_object);
                         (void)pdfi_seek(ctx, ctx->main_stream, saved_stream_offset, SEEK_SET);
                         return_error(gs_error_ioerror);
@@ -563,7 +596,7 @@ int pdfi_dereference(pdf_context *ctx, uint64_t obj, uint64_t gen, pdf_obj **obj
                 }while ((ctx->stack_top[-1]->type != PDF_ARRAY && ctx->stack_top[-1]->type != PDF_DICT) || pdfi_count_stack(ctx) > start_depth);
             }
 
-            pdfi_close_file(ctx, compressed_stream);
+            pdfi_close_file(ctx, Object_stream);
 
             *object = ctx->stack_top[-1];
             /* For compressed objects we don't get a 'obj gen obj' sequence which is what sets

----------------------------------------------------------------------
commit 9b217f52c5693a22af282f1b218cc7b9bc36936c
Author: Ken Sharp <[email protected]>
Date:   Mon Oct 14 15:02:11 2019 +0100

    Update SubFileDecode to work with a length as well as a string
    
    The SubFileDecode filter was only half-implemented, while we used the
    EOD string and length, we did not use EODCount, which meant we always
    stopped on the first occurence of EOD and we could not specify just the
    length of the stream by setting EODCount but with a string length of 0.
    
    
    Fix pdfi_read_bytes so that any buffered data is returned even at EOF
    
    We tested the stream EOF before returning any buffered data which could
    lead to us losing any data which had been returned to the stream
    buffer by pdf_unread_bytes(). We now check that unread_size is 0
    and return any unread bytes even at EOF. We don't return 0 until we
    have reached EOF and there are no unread bytes.

diff --git a/pdf/pdf_file.c b/pdf/pdf_file.c
index 231687e..5192ef9 100644
--- a/pdf/pdf_file.c
+++ b/pdf/pdf_file.c
@@ -949,16 +949,20 @@ int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, pdf_name *EO
     int code;
     stream_SFD_state state;
     stream *new_s = NULL;
-    int min_size = EODString->length;
+    int min_size = EODCount;
 
     *new_stream = NULL;
 
     if (s_SFD_template.set_defaults)
         s_SFD_template.set_defaults((stream_state *)&state);
 
-    state.eod.data = EODString->data;
-    state.eod.size = EODString->length;
+    if (EODString != NULL) {
+        state.eod.data = EODString->data;
+        state.eod.size = EODString->length;
+        min_size = EODString->length;
+    }
 
+    state.count = EODCount;
 
     code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_SFD_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s);
     if (code < 0)
@@ -1205,7 +1209,7 @@ int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t coun
     uint32_t bytes = 0;
     int32_t code;
 
-    if (s->eof)
+    if (s->eof && s->unread_size == 0)
         return 0;
 
     if (s->unread_size) {
@@ -1222,6 +1226,8 @@ int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t coun
             Buffer += s->unread_size;
             i = s->unread_size;
             s->unread_size = 0;
+            if (s->eof)
+                return i;
         }
     }
     if (total) {


Summary of changes:
 pdf/pdf_file.c | 14 ++++++++++----
 pdf/pdf_int.c  | 51 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 52 insertions(+), 13 deletions(-)