GraphicsMagick: JP2: Assure that the designated decoder is used ...

GraphicsMagick Commits <[email protected]>
Newsgroups gmane.comp.video.graphicsmagick.cvs
Message-ID <mailman.86248.1625516095.1299.graphicsmagick-commit@lists.sourceforge.net>
changeset 9753d715e6db in /hg/GraphicsMagick
details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=9753d715e6db
summary: JP2: Assure that the designated decoder is used rather than using autodetection and possibly using a different decoder than intended.

diffstat:

 ChangeLog                              |    9 +
 VisualMagick/installer/inc/version.isx |    4 +-
 coders/jp2.c                           |  292 ++++++++++++++++++++------------
 configure                              |    2 +-
 configure.ac                           |    2 +-
 magick/magick_config.h.in              |    3 +
 magick/version.h                       |    4 +-
 www/Changelog.html                     |    8 +
 8 files changed, 211 insertions(+), 113 deletions(-)

diffs (truncated from 605 to 500 lines):

diff -r 78b3bea5b3c8 -r 9753d715e6db ChangeLog
--- a/ChangeLog	Sun Jun 27 17:10:41 2021 -0500
+++ b/ChangeLog	Mon Jul 05 15:14:27 2021 -0500
@@ -1,3 +1,12 @@
+2021-07-05  Bob Friesenhahn  <[email protected]>
+
+        * coders/jp2.c: Assure that the designated decoder is used rather
+        than using autodetection and possibly using a different decoder
+        than intended. Added experimental support for JasPer
+        HAVE_JAS_INIT_CUSTOM feature, but leave disabled by default.  Fix
+        a stream manager bug noticed with the madams-callbacks branch of
+        JasPer.
+
 2021-06-27  Bob Friesenhahn  <[email protected]>
 
         * coders/msl.c (ProcessMSLScript): Fix possible use of freed
diff -r 78b3bea5b3c8 -r 9753d715e6db VisualMagick/installer/inc/version.isx
--- a/VisualMagick/installer/inc/version.isx	Sun Jun 27 17:10:41 2021 -0500
+++ b/VisualMagick/installer/inc/version.isx	Mon Jul 05 15:14:27 2021 -0500
@@ -10,5 +10,5 @@
 
 #define public MagickPackageName "GraphicsMagick"
 #define public MagickPackageVersion "1.4"
-#define public MagickPackageVersionAddendum ".020210627"
-#define public MagickPackageReleaseDate "snapshot-20210627"
+#define public MagickPackageVersionAddendum ".020210705"
+#define public MagickPackageReleaseDate "snapshot-20210705"
diff -r 78b3bea5b3c8 -r 9753d715e6db coders/jp2.c
--- a/coders/jp2.c	Sun Jun 27 17:10:41 2021 -0500
+++ b/coders/jp2.c	Mon Jul 05 15:14:27 2021 -0500
@@ -1,5 +1,5 @@
 /*
-% Copyright (C) 2003-2020 GraphicsMagick Group
+% Copyright (C) 2003-2021 GraphicsMagick Group
 % Copyright (C) 2002 ImageMagick Studio
 %
 % This program is covered by multiple licenses, which are described in
@@ -47,60 +47,57 @@
 #include "magick/resource.h"
 #include "magick/utility.h"
 #if defined(HasJP2)
-#if !defined(uchar)
-#define uchar  unsigned char
-#endif
-#if !defined(ushort)
-#define ushort  unsigned short
-#endif
-#if !defined(uint)
-#define uint  unsigned int
-#endif
-#if !defined(longlong)
-#define longlong  long long
-#endif
-#if !defined(ulonglong)
-#define ulonglong  unsigned long long
-#endif
+#  if !defined(uchar)
+#    define uchar  unsigned char
+#  endif
+#  if !defined(ushort)
+#    define ushort  unsigned short
+#  endif
+#  if !defined(uint)
+#    define uint  unsigned int
+#  endif
+#  if !defined(longlong)
+#    define longlong  long long
+#  endif
+#  if !defined(ulonglong)
+#    define ulonglong  unsigned long long
+#  endif
 
-#ifdef __VMS
-#define JAS_VERSION 1.700.0
-#define PACKAGE jasper
-#define VERSION 1.700.0
-#endif
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#include "jasper/jasper.h"
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#endif
+#  ifdef __VMS
+#    define JAS_VERSION 1.700.0
+#    define PACKAGE jasper
+#    define VERSION 1.700.0
+#  endif /* ifdef __VMS */
+#  undef PACKAGE_NAME
+#  undef PACKAGE_STRING
+#  undef PACKAGE_TARNAME
+#  undef PACKAGE_VERSION
+#  include "jasper/jasper.h"
+#  undef PACKAGE_NAME
+#  undef PACKAGE_STRING
+#  undef PACKAGE_TARNAME
+#  undef PACKAGE_VERSION
 /*
   Old JasPer uses non-persistent '!defined(EXCLUDE_FOO_SUPPORT)' and
   modern JasPer uses persistent 'if defined(JAS_INCLUDE_FOO_CODEC)'
   in jas_image.h
 */
-#if defined(EXCLUDE_JP2_SUPPORT)
-#  undef HAVE_JP2_DECODE
-#endif
-#if defined(EXCLUDE_JPC_SUPPORT)
-#  undef HAVE_JPC_DECODE
-#endif
-#if defined(EXCLUDE_PGX_SUPPORT)
-#  undef HAVE_PGX_DECODE
-#endif
+#  if defined(EXCLUDE_JP2_SUPPORT)
+#    undef HAVE_JP2_DECODE
+#  endif
+#  if defined(EXCLUDE_JPC_SUPPORT)
+#    undef HAVE_JPC_DECODE
+#  endif
+#  if defined(EXCLUDE_PGX_SUPPORT)
+#    undef HAVE_PGX_DECODE
+#  endif
 
 
 /*
   Forward declarations.
 */
-#if defined(HasJP2)
 static unsigned int
   WriteJP2Image(const ImageInfo *,Image *);
-#endif
 
 static MagickBool jasper_initialized=MagickFalse;
 static const char jasper_options[][11] =
@@ -281,7 +278,6 @@
 %    o exception: return any errors or warnings in this structure.
 %
 */
-#if defined(HasJP2)
 
 typedef struct _StreamManager
 {
@@ -311,7 +307,7 @@
   JasPer library using the C pre-processor.
  */
 #if !defined(MAGICK_JP2_OLD_STREAM_INTERFACE)
-#define MAGICK_JP2_OLD_STREAM_INTERFACE 0
+#  define MAGICK_JP2_OLD_STREAM_INTERFACE 0
 #endif /* if !defined(MAGICK_JP2_OLD_STREAM_INTERFACE) */
 
 #if MAGICK_JP2_OLD_STREAM_INTERFACE
@@ -360,7 +356,7 @@
     *source = (StreamManager *) object;
 
   CloseBlob(source->image);
-  MagickFreeMemory(source);
+  jas_free(source);
   return (0);
 }
 
@@ -373,15 +369,15 @@
   StreamManager
     *source;
 
-  stream=MagickAllocateMemory(jas_stream_t *,sizeof(jas_stream_t));
+  stream=(jas_stream_t *) jas_malloc(sizeof(jas_stream_t));
   if (stream == (jas_stream_t *) NULL)
     return((jas_stream_t *) NULL);
   (void) memset(stream,0,sizeof(jas_stream_t));
   stream->rwlimit_=(-1);
-  stream->obj_=MagickAllocateMemory(jas_stream_obj_t *,sizeof(StreamManager));
+  stream->obj_=(jas_stream_obj_t *) jas_malloc(sizeof(StreamManager));
   if (stream->obj_ == (jas_stream_obj_t *) NULL)
     {
-      MagickFreeMemory(stream);
+      jas_free(stream);
       return((jas_stream_t *) NULL);
     }
   stream->ops_=stream_ops;
@@ -409,6 +405,55 @@
   ThrowReaderException(code_,reason_,image_); \
 }
 
+#undef HAVE_JAS_INIT_CUSTOM
+
+#if HAVE_JAS_INIT_CUSTOM
+static void* _MagickReallocateResourceLimitedMemoryTraditional(void *p,const size_t size)
+{
+  return _MagickReallocateResourceLimitedMemory(p,1,size,0);
+}
+#endif /* if HAVE_JAS_INIT_CUSTOM */
+
+/*
+  Initialize Jasper
+*/
+static void initialize_jasper(void)
+{
+  if (!jasper_initialized)
+    {
+#if HAVE_JAS_INIT_CUSTOM
+      jas_allocator_t jas_allocator;
+      jas_conf_t jas_conf;
+
+      (void) memset(&jas_allocator,0,sizeof(jas_allocator));
+      (void) memset(&jas_conf,0,sizeof(jas_conf));
+
+      jas_allocator.alloc = _MagickAllocateResourceLimitedMemory;
+      jas_allocator.free = _MagickFreeResourceLimitedMemory;
+      jas_allocator.realloc = _MagickReallocateResourceLimitedMemoryTraditional;
+
+      jas_conf.dec_default_max_samples = JAS_DEC_DEFAULT_MAX_SAMPLES;
+      (void) jas_init_custom(&jas_allocator,&jas_conf);
+#else
+      jas_init();
+#endif  /* HAVE_JAS_INIT_CUSTOM */
+      jasper_initialized=MagickTrue;
+    }
+}
+
+
+/*
+  Cleanup Jasper
+*/
+static void cleanup_jasper(void)
+{
+  if (jasper_initialized)
+    {
+      jas_cleanup();
+      jasper_initialized=MagickFalse;
+    }
+}
+
 static Image *ReadJP2Image(const ImageInfo *image_info,
                            ExceptionInfo *exception)
 {
@@ -442,9 +487,6 @@
   register PixelPacket
     *q;
 
-  size_t
-    magick_length;
-
   magick_off_t
     pos;
 
@@ -456,25 +498,21 @@
   Quantum
     *channel_lut[4];
 
-  unsigned char
-    magick[16];
-
   char
     options[MaxTextExtent];
 
   unsigned int
     status;
 
+  MagickBool
+    jp2_hdr,
+    jpc_hdr,
+    pgx_hdr;
+
   /*
     Initialize Jasper
   */
-#if defined(HasJP2)
-  if (!jasper_initialized)
-    {
-      jas_init();
-      jasper_initialized=MagickTrue;
-    }
-#endif
+  initialize_jasper();
 
   /*
     Open image file.
@@ -490,25 +528,78 @@
   if (status == False)
     ThrowReaderException(FileOpenError,UnableToOpenFile,image);
 
+  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                        "Requested format is \"%s\"",
+                        image_info->magick);
+
   /*
-    Get the header so we can auto-detect the format.
+    Get the header and auto-detect apparent format.
   */
+  {
+    size_t
+      magick_length;
 
-  /* Get current seek position (normally 0) */
-  pos=TellBlob(image);
+    unsigned char
+      magick[16];
+
+    const MagickInfo
+      *magick_info;
+
+    /* Get current seek position (normally 0) */
+    pos=TellBlob(image);
+
+    /* Read header */
+    if ((magick_length=ReadBlob(image,sizeof(magick),magick)) != sizeof(magick))
+      {
+        ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,
+                             image);
+      }
+
+    /* Restore seek position */
+    if (SeekBlob(image,pos,SEEK_SET) != pos)
+      {
+        ThrowReaderException(BlobError,UnableToSeekToOffset,image);
+      }
 
-  /* Read header */
-  if ((magick_length=ReadBlob(image,sizeof(magick),magick)) != sizeof(magick))
-    {
-      ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,
-                           image);
-    }
+    /* Inspect header to see what it might actually be */
+    jp2_hdr=IsJP2(magick,sizeof(magick));
+    jpc_hdr=IsJPC(magick,sizeof(magick));
+    pgx_hdr=IsPGX(magick,sizeof(magick));
+
+    /*
+      If input format was previously auto-detected or specified, then
+      assure that header matches what was specified.
+    */
+    if (((LocaleCompare(image_info->magick,"JP2") == 0) && !jp2_hdr) ||
+        (((LocaleCompare(image_info->magick,"JPC") == 0) ||
+          (LocaleCompare(image_info->magick,"J2C") == 0)) && !jpc_hdr) ||
+        ((LocaleCompare(image_info->magick,"PGX") == 0) && !pgx_hdr))
+      {
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                              "Not a \"%s\" file!", image_info->magick);
+        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+      }
 
-  /* Restore seek position */
-  if (SeekBlob(image,pos,SEEK_SET) != pos)
-    {
-      ThrowReaderException(BlobError,UnableToSeekToOffset,image);
-    }
+    /*
+      Throw exception if header is not one we expect.
+    */
+    if (!jp2_hdr && !jpc_hdr && !pgx_hdr)
+      {
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                              "Header is not a supported type for this coder");
+        ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
+      }
+
+    /*
+      Check if we are allowed to decode this format.
+    */
+    if (((magick_info = GetMagickInfo(image_info->magick,exception)) ==
+         (const MagickInfo *) NULL) ||
+        (magick_info->decoder == (DecoderHandler) NULL))
+      {
+        ThrowReaderException(DelegateError,UnableToDecodeImageFile,image);
+      }
+  }
 
   /*
     Obtain a JP2 Stream.
@@ -517,7 +608,6 @@
   if (jp2_stream == (jas_stream_t *) NULL)
     ThrowReaderException(DelegateError,UnableToManageJP2Stream,image);
 
-
   {
     /* Pass options argument which specifies "max_samples" to cap memory usage. */
     const magick_uint64_t memory_limit = (magick_uint64_t) GetMagickResourceLimit(MemoryResource);
@@ -528,33 +618,37 @@
                           "JP2 options = \"%s\"", options);
   }
 
+  /* JP2, JPC, PGX (J2C is an alias for JPC) */
 #if HAVE_JP2_DECODE
-  if (IsJP2(magick,sizeof(magick)))
+  /* JPEG-2000 JP2 File Format Syntax */
+  if (jp2_hdr)
     {
       /* jas_image_t *jp2_decode(jas_stream_t *in, const char *optstr); */
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                             "Decoding JP2...");
       jp2_image=jp2_decode(jp2_stream,options);
     }
-#endif
+#endif /* if HAVE_JP2_DECODE */
 #if HAVE_JPC_DECODE
-  if (IsJPC(magick,sizeof(magick)))
+  /* JPEG-2000 Code Stream Syntax */
+  if (jpc_hdr)
     {
       /* jas_image_t *jpc_decode(jas_stream_t *in, const char *optstr); */
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                             "Decoding JPC...");
       jp2_image=jpc_decode(jp2_stream,options);
     }
-#endif
+#endif /* if HAVE_JPC_DECODE */
 #if HAVE_PGX_DECODE
-  if (IsPGX(magick,sizeof(magick)))
+  /* JPEG-2000 VM Format */
+  if (pgx_hdr)
     {
       /* jas_image_t *pgx_decode(jas_stream_t *in, const char *optstr); */
       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                             "Decoding PGX...");
       jp2_image=pgx_decode(jp2_stream,options);
     }
-#endif
+#endif /* if HAVE_PGX_DECODE */
 
   /*
     Using jas_image_decode() makes us subject to Jasper's own format
@@ -837,7 +931,7 @@
   StopTimer(&image->timer);
   return(image);
 }
-#endif
+#endif /* if defined(HasJP2) */
 
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -864,6 +958,7 @@
 */
 ModuleExport void RegisterJP2Image(void)
 {
+#if defined(HasJP2)
   static char
     version[16];
 
@@ -882,10 +977,8 @@
   entry->adjoin=False;
   entry->seekable_stream=True;
   entry->thread_support=False;
-#if defined(HasJP2)
   entry->decoder=(DecoderHandler) ReadJP2Image;
   entry->encoder=(EncoderHandler) WriteJP2Image;
-#endif
   entry->coder_class=StableCoderClass;
   (void) RegisterMagickInfo(entry);
 #endif /* if HAVE_JPC_DECODE */
@@ -899,10 +992,8 @@
   entry->adjoin=False;
   entry->seekable_stream=True;
   entry->thread_support=False;
-#if defined(HasJP2)
   entry->decoder=(DecoderHandler) ReadJP2Image;
   entry->encoder=(EncoderHandler) WriteJP2Image;
-#endif
   entry->coder_class=StableCoderClass;
   (void) RegisterMagickInfo(entry);
 #endif /* HAVE_JP2_DECODE */
@@ -916,10 +1007,8 @@
   entry->adjoin=False;
   entry->seekable_stream=True;
   entry->thread_support=False;
-#if defined(HasJP2)
   entry->decoder=(DecoderHandler) ReadJP2Image;
   entry->encoder=(EncoderHandler) WriteJP2Image;
-#endif
   entry->coder_class=StableCoderClass;
   (void) RegisterMagickInfo(entry);
 #endif /* if HAVE_JPC_DECODE */
@@ -933,13 +1022,12 @@
   entry->adjoin=False;
   entry->seekable_stream=True;
   entry->thread_support=False;
-#if defined(HasJP2)
   entry->decoder=(DecoderHandler) ReadJP2Image;
   entry->encoder=(EncoderHandler) WriteJP2Image;
-#endif
-  entry->coder_class=StableCoderClass;
+  entry->coder_class=UnstableCoderClass;
   (void) RegisterMagickInfo(entry);
 #endif /* if HAVE_PGX_DECODE */
+#endif /* if defined(HasJP2) */
 }
 
 /*
@@ -963,21 +1051,17 @@
 */
 ModuleExport void UnregisterJP2Image(void)
 {
+#if defined(HasJP2)
   (void) UnregisterMagickInfo("PGX");
   (void) UnregisterMagickInfo("JPC");
   (void) UnregisterMagickInfo("JP2");
   (void) UnregisterMagickInfo("J2C");
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.