Oh, and with the patch this time.

Riccardo Magliocchetti wrote:
Hi,

jpeg decoding is a hot topic again, or better, having fun crashing the
dsjpeg library is :) So the attached patch refresh the ijg libjpeg based
decoder patch i've already posted there.

The changelog:

- some changes to swfdec/Makefile.am were missing

- added the same check added to dsjpeg to avoid crashing against
cookiemon.jpg

- made swfdec_jpeg_decode_argb a bit prettier than last time removing the
soi cleanup loops and removing one for eoi too: a simpler check for soi is
done in swfdec_jpeg_fill_input_buffer() as in gnash.

image-lossless-alpha.swf test is expected to fail, which is the jpeg with
alpha channel and i don't know how and if it is possible to fix that.

Comments are appreciated.

cheers,
riccardo

diff --git a/configure.ac b/configure.ac
index d0fe495..f2b8d65 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,12 +264,17 @@ else
 fi
 AM_CONDITIONAL(HAVE_VIVI, [test "x$HAVE_VIVI" = xyes])
 
+dnl Test for libjpeg
+AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, HAVE_JPEG=yes, HAVE_JPEG=no)
+if test "$HAVE_JPEG" = no; then
+  AC_MSG_ERROR([Couldn't find libjpeg.])
+fi
 
 AC_SUBST(GLOBAL_CFLAGS)
 AC_SUBST(GLOBAL_CFLAGS)
 
 SWFDEC_CFLAGS="-I\$(top_srcdir) $GLIB_CFLAGS $CAIRO_CFLAGS"
-SWFDEC_LIBS="\$(top_builddir)/swfdec/libswfdec-$SWFDEC_MAJORMINOR.la $GLIB_LIBS $CAIRO_LIBS -lz -lm"
+SWFDEC_LIBS="\$(top_builddir)/swfdec/libswfdec-$SWFDEC_MAJORMINOR.la $GLIB_LIBS $CAIRO_LIBS -lz -lm -ljpeg"
 AC_SUBST(SWFDEC_LIBS)
 AC_SUBST(SWFDEC_CFLAGS)
 
@@ -302,7 +307,6 @@ data/swfdec-gtk.pc
 doc/Makefile
 swfdec/Makefile
 swfdec/swfdec_version.h
-swfdec/jpeg/Makefile
 swfdec-gtk/Makefile
 player/Makefile
 test/Makefile
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 2ad2dd5..b51c670 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -1,5 +1,3 @@
-SUBDIRS = jpeg
-
 CODEC_FILES =
 
 if HAVE_GST
@@ -185,7 +183,7 @@ [EMAIL PROTECTED]@_la_SOURCES = \
 
 [EMAIL PROTECTED]@_la_CFLAGS = \
 	$(GLOBAL_CFLAGS) $(CAIRO_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) \
-	-I$(top_srcdir) -I$(srcdir)/jpeg/ $(LIBOIL_CFLAGS) \
+	-I$(top_srcdir) $(LIBOIL_CFLAGS) \
 	$(GST_CFLAGS) $(FFMPEG_CFLAGS) $(MAD_CFLAGS) \
 	-DG_LOG_DOMAIN=\"Swfdec\"
 [EMAIL PROTECTED]@_la_LDFLAGS = \
@@ -221,8 +219,6 @@ public_headers = \
 	swfdec_system.h \
 	swfdec_url.h
 
[EMAIL PROTECTED]@_la_LIBADD = jpeg/libjpeg.la 
-
 [EMAIL PROTECTED]@includedir = $(includedir)/[EMAIL PROTECTED]@/swfdec
 [EMAIL PROTECTED]@include_HEADERS = $(public_headers) swfdec_enums.h
 [EMAIL PROTECTED]@include_HEADERS = swfdec_version.h
diff --git a/swfdec/swfdec_image.c b/swfdec/swfdec_image.c
index 92bef53..a33a7b3 100644
--- a/swfdec/swfdec_image.c
+++ b/swfdec/swfdec_image.c
@@ -26,8 +26,11 @@
 #include <stdio.h>
 #include <zlib.h>
 #include <string.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+#include <stdint.h>
 
-#include "jpeg.h"
 #include "swfdec_image.h"
 #include "swfdec_cache.h"
 #include "swfdec_cached_image.h"
@@ -37,6 +40,24 @@
 
 G_DEFINE_TYPE (SwfdecImage, swfdec_image, SWFDEC_TYPE_CHARACTER)
 
+#define JPEG_BUF_SIZE 4096
+
+typedef struct {
+  struct jpeg_source_mgr pub;
+  unsigned char * infile;
+  JOCTET * buffer;
+  gboolean start_of_file;
+} swfdecJpegSourceMgr;
+
+typedef swfdecJpegSourceMgr * swfdec_jpeg_src_ptr;
+
+struct swfdecJpegErrorMgr {
+  struct jpeg_error_mgr pub;
+  jmp_buf setjmp_buffer;
+};
+
+typedef struct swfdecJpegErrorMgr * swfdec_jpeg_error_ptr;
+
 static void
 swfdec_image_dispose (GObject *object)
 {
@@ -132,6 +153,160 @@ swfdec_image_validate_size (SwfdecRenderer *renderer, guint width, guint height)
   return TRUE;
 }
 
+static void
+G_GNUC_NORETURN
+swfdec_jpeg_error_exit (j_common_ptr cinfo)
+{
+  swfdec_jpeg_error_ptr err = (swfdec_jpeg_error_ptr) cinfo->err;
+  char buffer[JMSG_LENGTH_MAX];
+
+  (*cinfo->err->format_message) (cinfo, buffer);
+  SWFDEC_ERROR ("Error decoding JPEG image: %s", buffer);
+  longjmp (err->setjmp_buffer, 1);
+}
+
+static void
+swfdec_jpeg_error_set (j_common_ptr cinfo, int msg_code)
+{
+  cinfo->err->msg_code = msg_code;
+}
+
+static void
+swfdec_jpeg_init_source (j_decompress_ptr cinfo)
+{
+  swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+  src->start_of_file = TRUE;
+}
+
+static gboolean
+swfdec_jpeg_fill_input_buffer (j_decompress_ptr cinfo)
+{
+  swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+  size_t nbytes;
+
+  nbytes = MIN (sizeof (*src->infile), JPEG_BUF_SIZE);
+  memcpy (src->buffer, src->infile, nbytes);
+
+  if (nbytes <= 0) {
+    /* Insert a fake EOI marker */
+    src->buffer[0] = (JOCTET) 0xff;
+    src->buffer[1] = (JOCTET) JPEG_EOI;
+    nbytes = 2;
+  }
+
+  /* Workaround for bogus jpeg header */
+  if (src->start_of_file && nbytes >= 4) {
+    if (src->buffer[0] == 0xff
+        && src->buffer[1] == JPEG_EOI
+        && src->buffer[2] == 0xff
+        && src->buffer[3] == 0xd8) {
+      src->buffer[1] = 0xd8;
+      src->buffer[3] = JPEG_EOI;
+    }
+  }
+
+  src->pub.next_input_byte = src->buffer;
+  src->pub.bytes_in_buffer = nbytes;
+  src->infile += nbytes;
+  src->start_of_file = FALSE;
+
+  return TRUE;
+}
+
+static void
+swfdec_jpeg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+
+  if (num_bytes > 0) {
+    while (num_bytes > (long) src->pub.bytes_in_buffer) {
+      num_bytes -= (long) src->pub.bytes_in_buffer;
+      (void) swfdec_jpeg_fill_input_buffer (cinfo);
+    }
+    src->pub.next_input_byte += (size_t) num_bytes;
+    src->pub.bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+static void
+swfdec_jpeg_term_source (j_decompress_ptr cinfo)
+{
+}
+
+static void
+swfdec_jpeg_rgb_to_argb (struct jpeg_decompress_struct *cinfo,
+                         JSAMPROW *rgb, uint32_t *argb)
+{
+  guint size = cinfo->output_width * cinfo->output_components;
+
+  for (guint i = 0, j = 0; i < size; i += 3, j++)
+    argb[j] = SWFDEC_COLOR_COMBINE(rgb[0][i], rgb[0][i+1], rgb[0][i+2], 0xff);
+}
+
+static gboolean
+swfdec_jpeg_decode (unsigned char *data, int length,
+    uint32_t **outdata, guint *width, guint *height)
+{
+  struct jpeg_decompress_struct cinfo;
+  struct swfdecJpegErrorMgr jerr;
+  swfdec_jpeg_src_ptr src;
+  JSAMPROW buf[1];
+  uint32_t *image;
+
+  cinfo.err = jpeg_std_error (&jerr.pub);
+  jerr.pub.error_exit = swfdec_jpeg_error_exit;
+
+  if (setjmp(jerr.setjmp_buffer)) {
+    jpeg_destroy_decompress (&cinfo);
+    return FALSE;
+  }
+
+  jpeg_create_decompress (&cinfo);
+
+  cinfo.src = (struct jpeg_source_mgr *)
+      (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+                                  sizeof (swfdecJpegSourceMgr));
+  src = (swfdec_jpeg_src_ptr) cinfo.src;
+  src->buffer = (JOCTET *)
+      (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+                                  JPEG_BUF_SIZE * sizeof (JOCTET));
+  src->pub.init_source = swfdec_jpeg_init_source;
+  src->pub.fill_input_buffer = swfdec_jpeg_fill_input_buffer;
+  src->pub.skip_input_data = swfdec_jpeg_skip_input_data;
+  src->pub.resync_to_restart = jpeg_resync_to_restart;
+  src->pub.term_source = swfdec_jpeg_term_source;
+  src->infile = data;
+  src->pub.bytes_in_buffer = 0;
+  src->pub.next_input_byte = NULL;
+
+  jpeg_read_header (&cinfo, TRUE);
+  jpeg_start_decompress (&cinfo);
+
+  *height = cinfo.output_height;
+  *width = cinfo.output_width;
+
+  if ((1 << 30) / cinfo.output_width / cinfo.output_height < sizeof (uint32_t)) {
+    swfdec_jpeg_error_set ((j_common_ptr) &cinfo, JERR_OUT_OF_MEMORY);
+    swfdec_jpeg_error_exit ((j_common_ptr) &cinfo);
+  }
+
+  buf[0] = g_malloc (cinfo.output_width * cinfo.output_components);
+  image = g_malloc (cinfo.output_width * cinfo.output_height * sizeof (uint32_t));
+  *outdata = image;
+  
+  while (cinfo.output_scanline < cinfo.image_height) {
+    jpeg_read_scanlines(&cinfo, buf, 1);
+    swfdec_jpeg_rgb_to_argb (&cinfo, buf, image);
+    image += cinfo.output_width;
+  }
+
+  g_free (buf[0]);
+  jpeg_finish_decompress (&cinfo); 
+  jpeg_destroy_decompress (&cinfo);
+
+  return TRUE;
+}
+
 /**
  * swfdec_jpeg_decode_argb:
  *
@@ -146,24 +321,33 @@ swfdec_jpeg_decode_argb (SwfdecRenderer *renderer,
     unsigned char *data2, int length2,
     void *outdata, guint *width, guint *height)
 {
-  gboolean ret;
-
-  if (data2) {
-    unsigned char *tmpdata;
-    int tmplength;
+  unsigned char *data;
+  int length;
+  gboolean ret = FALSE;
+
+  if (data1 && !data2) {
+    ret = swfdec_jpeg_decode (data1, length1, outdata, width, height);
+  } else if (!data1 && data2) {
+    ret = swfdec_jpeg_decode (data2, length2, outdata, width, height);
+  } else if (data1 && data2) {
+    while (length1 >= 2 && data1[length1-2] == 0xff &&
+        (data1[length1-1] == 0xd9 || data1[length1-1] == 0xd8)) {
+      length1 -= 2;
+    }
 
-    tmplength = length1 + length2;
-    tmpdata = g_malloc (tmplength);
+    while (length2 >= 2 && data2[0] == 0xff &&
+        (data2[1] == 0xd8 || data2[1] == 0xd9)) {
+      data2 += 2;
+      length2 -= 2;
+    }
 
-    memcpy (tmpdata, data1, length1);
-    memcpy (tmpdata + length1, data2, length2);
-    ret = jpeg_decode_argb (tmpdata, tmplength, outdata, width, height);
+    length = length1 + length2;
+    data = g_malloc (length);
+    memcpy (data, data1, length1);
+    memcpy (data + length1, data2, length2);
 
-    g_free (tmpdata);
-  } else if (data1) {
-    ret = jpeg_decode_argb (data1, length1, outdata, width, height);
-  } else {
-    ret = FALSE;
+    ret = swfdec_jpeg_decode (data, length, outdata, width, height);
+    g_free (data);
   }
 
   if (ret)
_______________________________________________
Swfdec mailing list
Swfdec@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/swfdec

Reply via email to