From c546114c635f93ff254b4d479a1b6370377d054b Mon Sep 17 00:00:00 2001 From: Vladimir Nadvornik Date: Sun, 27 Mar 2011 10:57:08 +0200 Subject: [PATCH] added mpo parser --- src/image_load_jpeg.c | 2 + src/jpeg_parser.c | 241 ++++++++++++++++++++++++++++++++++++++++++ src/jpeg_parser.h | 25 +++++ 3 files changed, 268 insertions(+) diff --git a/src/image_load_jpeg.c b/src/image_load_jpeg.c index 7fb60901..80622782 100644 --- a/src/image_load_jpeg.c +++ b/src/image_load_jpeg.c @@ -2,6 +2,7 @@ #include "main.h" #include "image-load.h" #include "image_load_jpeg.h" +#include "jpeg_parser.h" #include #include @@ -156,6 +157,7 @@ static gboolean image_loader_jpeg_load (gpointer loader, const guchar *buf, gsiz struct error_handler_data jerr; // stdio_src_ptr src; + MPOData *mpo = jpeg_get_mpo_data(buf, count); /* setup error handler */ cinfo.err = jpeg_std_error (&jerr.pub); diff --git a/src/jpeg_parser.c b/src/jpeg_parser.c index bedf00af..f1b5e0c3 100644 --- a/src/jpeg_parser.c +++ b/src/jpeg_parser.c @@ -40,3 +40,244 @@ gboolean jpeg_segment_find(guchar *data, guint size, return FALSE; } + + +typedef enum { + TIFF_BYTE_ORDER_INTEL, + TIFF_BYTE_ORDER_MOTOROLA +} TiffByteOrder; + +#define TIFF_TIFD_OFFSET_TAG 0 +#define TIFF_TIFD_OFFSET_FORMAT 2 +#define TIFF_TIFD_OFFSET_COUNT 4 +#define TIFF_TIFD_OFFSET_DATA 8 +#define TIFF_TIFD_SIZE 12 + + + +guint16 tiff_byte_get_int16(guchar *f, TiffByteOrder bo) +{ + guint16 align_buf; + + memcpy(&align_buf, f, sizeof(guint16)); + + if (bo == TIFF_BYTE_ORDER_INTEL) + return GUINT16_FROM_LE(align_buf); + else + return GUINT16_FROM_BE(align_buf); +} + +guint32 tiff_byte_get_int32(guchar *f, TiffByteOrder bo) +{ + guint32 align_buf; + + memcpy(&align_buf, f, sizeof(guint32)); + + if (bo == TIFF_BYTE_ORDER_INTEL) + return GUINT32_FROM_LE(align_buf); + else + return GUINT32_FROM_BE(align_buf); +} + +void tiff_byte_put_int16(guchar *f, guint16 n, TiffByteOrder bo) +{ + guint16 align_buf; + + if (bo == TIFF_BYTE_ORDER_INTEL) + { + align_buf = GUINT16_TO_LE(n); + } + else + { + align_buf = GUINT16_TO_BE(n); + } + + memcpy(f, &align_buf, sizeof(guint16)); +} + +void tiff_byte_put_int32(guchar *f, guint32 n, TiffByteOrder bo) +{ + guint32 align_buf; + + if (bo == TIFF_BYTE_ORDER_INTEL) + { + align_buf = GUINT32_TO_LE(n); + } + else + { + align_buf = GUINT32_TO_BE(n); + } + + memcpy(f, &align_buf, sizeof(guint32)); +} + +gint tiff_directory_offset(guchar *data, const guint len, + guint *offset, TiffByteOrder *bo) +{ + if (len < 8) return FALSE; + + if (memcmp(data, "II", 2) == 0) + { + *bo = TIFF_BYTE_ORDER_INTEL; + } + else if (memcmp(data, "MM", 2) == 0) + { + *bo = TIFF_BYTE_ORDER_MOTOROLA; + } + else + { + return FALSE; + } + + if (tiff_byte_get_int16(data + 2, *bo) != 0x002A) + { + return FALSE; + } + + *offset = tiff_byte_get_int32(data + 4, *bo); + + return (*offset < len); +} + +typedef gint (* FuncParseIFDEntry)(guchar *tiff, guint offset, + guint size, TiffByteOrder bo, + gpointer data); + + +gint tiff_parse_IFD_table(guchar *tiff, guint offset, + guint size, TiffByteOrder bo, + guint *next_offset, + FuncParseIFDEntry parse_entry, gpointer data) +{ + guint count; + guint i; + guint next; + + + /* We should be able to read number of entries in IFD0) */ + if (size < offset + 2) return -1; + + count = tiff_byte_get_int16(tiff + offset, bo); + offset += 2; +printf("count %d\n", count); + /* Entries and next IFD offset must be readable */ + if (size < offset + count * TIFF_TIFD_SIZE + 4) return -1; + + for (i = 0; i < count; i++) + { + parse_entry(tiff, offset + i * TIFF_TIFD_SIZE, size, bo, data); + } + + next = tiff_byte_get_int32(tiff + offset + count * TIFF_TIFD_SIZE, bo); +printf("next %d\n", next); + if (next_offset) *next_offset = next; + + return 0; +} + +static gint mpo_parse_Index_IFD_entry(guchar *tiff, guint offset, + guint size, TiffByteOrder bo, + gpointer data) +{ + guint tag; + guint format; + guint count; + guint data_val; + guint data_offset; + guint data_length; + + MPOData *mpo = data; + + tag = tiff_byte_get_int16(tiff + offset + TIFF_TIFD_OFFSET_TAG, bo); + format = tiff_byte_get_int16(tiff + offset + TIFF_TIFD_OFFSET_FORMAT, bo); + count = tiff_byte_get_int32(tiff + offset + TIFF_TIFD_OFFSET_COUNT, bo); + data_val = tiff_byte_get_int32(tiff + offset + TIFF_TIFD_OFFSET_DATA, bo); +printf("tag %x format %x count %x data_val %x\n", tag, format, count, data_val); + + if (tag == 0xb000) + { + mpo->version = data_val; + } + else if (tag == 0xb001) + { + mpo->num_images = data_val; + } + else if (tag == 0xb002) + { + guint i; + data_offset = data_val; + data_length = count; + if (size < data_offset || size < data_offset + data_length) + { + return -1; + } + if (count != mpo->num_images * 16) + { + return -1; + } + + mpo->images = g_new0(MPOEntry, mpo->num_images); + + for (i = 0; i < mpo->num_images; i++) { + guint image_attr = tiff_byte_get_int32(tiff + data_offset + i * 16, bo); + mpo->images[i].type_code = image_attr & 0xffffff; + mpo->images[i].representative = !!(image_attr & 0x20000000); + mpo->images[i].dependent_child = !!(image_attr & 0x40000000); + mpo->images[i].dependent_parent = !!(image_attr & 0x80000000); + mpo->images[i].length = tiff_byte_get_int32(tiff + data_offset + i * 16 + 4, bo); + mpo->images[i].offset = tiff_byte_get_int32(tiff + data_offset + i * 16 + 8, bo); + mpo->images[i].dep1 = tiff_byte_get_int16(tiff + data_offset + i * 16 + 12, bo); + mpo->images[i].dep2 = tiff_byte_get_int16(tiff + data_offset + i * 16 + 14, bo); + + if (i == 0) + { + mpo->images[i].offset = 0; + } + else + { + mpo->images[i].offset += mpo->mpo_offset; + } + + printf("img %x %x %x\n", image_attr, mpo->images[i].length, mpo->images[i].offset); + } + } + + return 0; +} + +MPOData *jpeg_get_mpo_data(guchar *data, guint size) +{ + guint seg_offset; + guint seg_size; + if (jpeg_segment_find(data, size, JPEG_MARKER_APP2, "MPF\x00", 4, &seg_offset, &seg_size) && seg_size >16) + { + guint offset; + TiffByteOrder bo; + MPOData *mpo; + guint i; + + printf("mpo signature found at %x\n", seg_offset); + data += seg_offset + 4; + seg_size -= 4; + + if (!tiff_directory_offset(data, seg_size, &offset, &bo)) return NULL; + + mpo = g_new0(MPOData, 1); + mpo->mpo_offset = seg_offset + 4; + + tiff_parse_IFD_table(data, offset , seg_size, bo, NULL, mpo_parse_Index_IFD_entry, (gpointer)mpo); + if (!mpo->images) mpo->num_images = 0; + + for (i = 0; i < mpo->num_images; i++) + { + if (mpo->images[i].offset + mpo->images[i].length > size) + { + mpo->num_images = i; + DEBUG_1("MPO file truncated to %d valid images", i); + break; + } + } + return mpo; + } + return NULL; +} diff --git a/src/jpeg_parser.h b/src/jpeg_parser.h index 767b3e9a..0f342ecf 100644 --- a/src/jpeg_parser.h +++ b/src/jpeg_parser.h @@ -23,4 +23,29 @@ gboolean jpeg_segment_find(guchar *data, guint size, guchar app_marker, const gchar *magic, guint magic_len, guint *seg_offset, guint *seg_length); + +typedef struct _MPOData MPOData; +typedef struct _MPOEntry MPOEntry; + +struct _MPOEntry { + guint type_code; + gboolean representative; + gboolean dependent_child; + gboolean dependent_parent; + guint offset; + guint length; + guint dep1; + guint dep2; +}; + + +struct _MPOData { + guint mpo_offset; + + guint version; + guint num_images; + MPOEntry *images; +}; + +MPOData* jpeg_get_mpo_data(guchar *data, guint size); #endif \ No newline at end of file -- 2.20.1