Trim trailing white spaces.
[geeqie.git] / src / jpeg_parser.c
index f1b5e0c..9918aab 100644 (file)
@@ -1,8 +1,19 @@
-
-#include "main.h" 
+/*
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2011 The Geeqie Team
+ *
+ * Author: Vladimir Nadvornik
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#include "main.h"
 #include "jpeg_parser.h"
 
-gboolean jpeg_segment_find(guchar *data, guint size,
+gboolean jpeg_segment_find(const guchar *data, guint size,
                            guchar app_marker, const gchar *magic, guint magic_len,
                            guint *seg_offset, guint *seg_length)
 {
@@ -10,8 +21,7 @@ gboolean jpeg_segment_find(guchar *data, guint size,
        guint offset = 0;
        guint length = 0;
 
-       while (marker != app_marker &&
-              marker != JPEG_MARKER_EOI)
+       while (marker != JPEG_MARKER_EOI)
                {
                offset += length;
                length = 2;
@@ -25,19 +35,18 @@ gboolean jpeg_segment_find(guchar *data, guint size,
                        {
                        if (offset + 4 >= size) return FALSE;
                        length += ((guint)data[offset + 2] << 8) + data[offset + 3];
-                       }
-               }
 
-       if (marker == app_marker &&
-           offset + length < size &&
-           length >= 4 + magic_len &&
-           memcmp(data + offset + 4, magic, magic_len) == 0)
-               {
-               *seg_offset = offset + 4;
-               *seg_length = length - 4;
-               return TRUE;
+                       if (marker == app_marker &&
+                           offset + length < size &&
+                           length >= 4 + magic_len &&
+                           memcmp(data + offset + 4, magic, magic_len) == 0)
+                               {
+                               *seg_offset = offset + 4;
+                               *seg_length = length - 4;
+                               return TRUE;
+                               }
+                       }
                }
-
        return FALSE;
 }
 
@@ -55,7 +64,7 @@ typedef enum {
 
 
 
-guint16 tiff_byte_get_int16(guchar *f, TiffByteOrder bo)
+guint16 tiff_byte_get_int16(const guchar *f, TiffByteOrder bo)
 {
        guint16 align_buf;
 
@@ -67,7 +76,7 @@ guint16 tiff_byte_get_int16(guchar *f, TiffByteOrder bo)
                return GUINT16_FROM_BE(align_buf);
 }
 
-guint32 tiff_byte_get_int32(guchar *f, TiffByteOrder bo)
+guint32 tiff_byte_get_int32(const guchar *f, TiffByteOrder bo)
 {
        guint32 align_buf;
 
@@ -111,7 +120,7 @@ void tiff_byte_put_int32(guchar *f, guint32 n, TiffByteOrder bo)
        memcpy(f, &align_buf, sizeof(guint32));
 }
 
-gint tiff_directory_offset(guchar *data, const guint len,
+gint tiff_directory_offset(const guchar *data, const guint len,
                                guint *offset, TiffByteOrder *bo)
 {
        if (len < 8) return FALSE;
@@ -139,12 +148,12 @@ gint tiff_directory_offset(guchar *data, const guint len,
        return (*offset < len);
 }
 
-typedef gint (* FuncParseIFDEntry)(guchar *tiff, guint offset,
+typedef gint (* FuncParseIFDEntry)(const guchar *tiff, guint offset,
                                 guint size, TiffByteOrder bo,
                                 gpointer data);
 
 
-gint tiff_parse_IFD_table(guchar *tiff, guint offset,
+gint tiff_parse_IFD_table(const guchar *tiff, guint offset,
                          guint size, TiffByteOrder bo,
                          guint *next_offset,
                          FuncParseIFDEntry parse_entry, gpointer data)
@@ -159,7 +168,6 @@ gint tiff_parse_IFD_table(guchar *tiff, guint offset,
 
        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;
 
@@ -169,13 +177,12 @@ printf("count %d\n", count);
                }
        
        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,
+static gint mpo_parse_Index_IFD_entry(const guchar *tiff, guint offset,
                                 guint size, TiffByteOrder bo,
                                 gpointer data)
 {
@@ -192,16 +199,18 @@ static gint mpo_parse_Index_IFD_entry(guchar *tiff, guint offset,
        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;
-               }
+       DEBUG_1("   tag %x format %x count %x data_val %x", tag, format, count, data_val);
+
+       if (tag == 0xb000)
+               {
+               mpo->version = data_val;
+               DEBUG_1("    mpo version %x", mpo->version);
+               }
+       else if (tag == 0xb001)
+               {
+               mpo->num_images = data_val;
+               DEBUG_1("    num images %x", mpo->num_images);
+               }
        else if (tag == 0xb002)
                {
                guint i;
@@ -229,55 +238,150 @@ printf("tag %x format %x count %x data_val %x\n", tag, format, count, data_val);
                        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) 
+                       if (i == 0)
                                {
                                mpo->images[i].offset = 0;
                                }
                        else
                                {
-                               mpo->images[i].offset += mpo->mpo_offset;
-                               }
+                               mpo->images[i].offset += mpo->mpo_offset;
+                               }
                                
-                       printf("img %x %x %x\n", image_attr, mpo->images[i].length, mpo->images[i].offset);
+                       DEBUG_1("   image %x %x %x", image_attr, mpo->images[i].length, mpo->images[i].offset);
                        }
                }
 
        return 0;
 }
 
-MPOData *jpeg_get_mpo_data(guchar *data, guint size)
+static gint mpo_parse_Attributes_IFD_entry(const guchar *tiff, guint offset,
+                                guint size, TiffByteOrder bo,
+                                gpointer data)
+{
+       guint tag;
+       guint format;
+       guint count;
+       guint data_val;
+
+       MPOEntry *mpe = 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);
+       DEBUG_1("   tag %x format %x count %x data_val %x", tag, format, count, data_val);
+
+       switch (tag)
+               {
+               case 0xb000:
+                       mpe->MPFVersion = data_val;
+                       DEBUG_1("    mpo version %x", data_val);
+                       break;
+               case 0xb101:
+                       mpe->MPIndividualNum = data_val;
+                       DEBUG_1("    Individual Image Number %x", mpe->MPIndividualNum);
+                       break;
+               case 0xb201:
+                       mpe->PanOrientation = data_val;
+                       break;
+/*
+
+FIXME:
+Panorama Scanning Orientation PanOrientation 45569 B201 LONG 1
+Panorama Horizontal Overlap PanOverlap_H 45570 B202 RATIONAL 1
+Panorama Vertical Overlap PanOverlap_V 45571 B203 RATIONAL 1
+Base Viewpoint Number BaseViewpointNum 45572 B204 LONG 1
+Convergence Angle ConvergenceAngle 45573 B205 SRATIONAL 1
+Baseline Length BaselineLength 45574 B206 RATIONAL 1
+Divergence Angle VerticalDivergence 45575 B207 SRATIONAL 1
+Horizontal Axis Distance AxisDistance_X 45576 B208 SRATIONAL 1
+Vertical Axis Distance AxisDistance_Y 45577 B209 SRATIONAL 1
+Collimation Axis Distance AxisDistance_Z 45578 B20A SRATIONAL 1
+Yaw Angle YawAngle 45579 B20B SRATIONAL 1
+Pitch Angle PitchAngle 45580 B20C SRATIONAL 1
+Roll Angle RollAngle 45581 B20D
+  */
+               default:
+                       break;
+               }
+
+       return 0;
+}
+
+MPOData *jpeg_get_mpo_data(const 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;
+               guint next_offset;
                TiffByteOrder bo;
                MPOData *mpo;
                guint i;
 
-               printf("mpo signature found at %x\n", seg_offset); 
-               data += seg_offset + 4;
+               DEBUG_1("mpo signature found at %x", seg_offset);
+               seg_offset += 4;
                seg_size -= 4;
                
-               if (!tiff_directory_offset(data, seg_size, &offset, &bo)) return NULL;
+               if (!tiff_directory_offset(data + seg_offset, seg_size, &offset, &bo)) return NULL;
 
                mpo = g_new0(MPOData, 1);
-               mpo->mpo_offset = seg_offset + 4;
+               mpo->mpo_offset = seg_offset;
                
-               tiff_parse_IFD_table(data,  offset , seg_size, bo, NULL, mpo_parse_Index_IFD_entry, (gpointer)mpo);
+               tiff_parse_IFD_table(data + seg_offset,  offset , seg_size, bo, &next_offset, 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);
+                               DEBUG_1("MPO file truncated to %d valid images, %d %d", i, mpo->images[i].offset + mpo->images[i].length, size);
                                break;
                                }
                        }
+               
+               for (i = 0; i < mpo->num_images; i++)
+                       {
+                       if (i == 0)
+                               {
+                               offset = next_offset;
+                               }
+                       else
+                               {
+                               if (!jpeg_segment_find(data + mpo->images[i].offset, mpo->images[i].length, JPEG_MARKER_APP2, "MPF\x00", 4, &seg_offset, &seg_size) || seg_size <=16)
+                                       {
+                                       DEBUG_1("MPO image %d: MPO signature not found", i);
+                                       continue;
+                                       }
+                               
+                               seg_offset += 4;
+                               seg_size -= 4;
+                               if (!tiff_directory_offset(data + mpo->images[i].offset + seg_offset, seg_size, &offset, &bo))
+                                       {
+                                       DEBUG_1("MPO image %d: invalid directory offset", i);
+                                       continue;
+                                       }
+
+                               }
+                       tiff_parse_IFD_table(data + mpo->images[i].offset + seg_offset,  offset , seg_size, bo, NULL, mpo_parse_Attributes_IFD_entry, (gpointer)&mpo->images[i]);
+                       }
+               
                return mpo;
                }
        return NULL;
 }
+
+void jpeg_mpo_data_free(MPOData *mpo)
+{
+       if (mpo)
+               {
+               if (mpo->images) g_free(mpo->images);
+               g_free(mpo);
+               }
+}
+
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */