3 #include "jpeg_parser.h"
5 gboolean jpeg_segment_find(guchar *data, guint size,
6 guchar app_marker, const gchar *magic, guint magic_len,
7 guint *seg_offset, guint *seg_length)
13 while (marker != app_marker &&
14 marker != JPEG_MARKER_EOI)
19 if (offset + 2 >= size ||
20 data[offset] != JPEG_MARKER) return FALSE;
22 marker = data[offset + 1];
23 if (marker != JPEG_MARKER_SOI &&
24 marker != JPEG_MARKER_EOI)
26 if (offset + 4 >= size) return FALSE;
27 length += ((guint)data[offset + 2] << 8) + data[offset + 3];
31 if (marker == app_marker &&
32 offset + length < size &&
33 length >= 4 + magic_len &&
34 memcmp(data + offset + 4, magic, magic_len) == 0)
36 *seg_offset = offset + 4;
37 *seg_length = length - 4;
46 TIFF_BYTE_ORDER_INTEL,
47 TIFF_BYTE_ORDER_MOTOROLA
50 #define TIFF_TIFD_OFFSET_TAG 0
51 #define TIFF_TIFD_OFFSET_FORMAT 2
52 #define TIFF_TIFD_OFFSET_COUNT 4
53 #define TIFF_TIFD_OFFSET_DATA 8
54 #define TIFF_TIFD_SIZE 12
58 guint16 tiff_byte_get_int16(guchar *f, TiffByteOrder bo)
62 memcpy(&align_buf, f, sizeof(guint16));
64 if (bo == TIFF_BYTE_ORDER_INTEL)
65 return GUINT16_FROM_LE(align_buf);
67 return GUINT16_FROM_BE(align_buf);
70 guint32 tiff_byte_get_int32(guchar *f, TiffByteOrder bo)
74 memcpy(&align_buf, f, sizeof(guint32));
76 if (bo == TIFF_BYTE_ORDER_INTEL)
77 return GUINT32_FROM_LE(align_buf);
79 return GUINT32_FROM_BE(align_buf);
82 void tiff_byte_put_int16(guchar *f, guint16 n, TiffByteOrder bo)
86 if (bo == TIFF_BYTE_ORDER_INTEL)
88 align_buf = GUINT16_TO_LE(n);
92 align_buf = GUINT16_TO_BE(n);
95 memcpy(f, &align_buf, sizeof(guint16));
98 void tiff_byte_put_int32(guchar *f, guint32 n, TiffByteOrder bo)
102 if (bo == TIFF_BYTE_ORDER_INTEL)
104 align_buf = GUINT32_TO_LE(n);
108 align_buf = GUINT32_TO_BE(n);
111 memcpy(f, &align_buf, sizeof(guint32));
114 gint tiff_directory_offset(guchar *data, const guint len,
115 guint *offset, TiffByteOrder *bo)
117 if (len < 8) return FALSE;
119 if (memcmp(data, "II", 2) == 0)
121 *bo = TIFF_BYTE_ORDER_INTEL;
123 else if (memcmp(data, "MM", 2) == 0)
125 *bo = TIFF_BYTE_ORDER_MOTOROLA;
132 if (tiff_byte_get_int16(data + 2, *bo) != 0x002A)
137 *offset = tiff_byte_get_int32(data + 4, *bo);
139 return (*offset < len);
142 typedef gint (* FuncParseIFDEntry)(guchar *tiff, guint offset,
143 guint size, TiffByteOrder bo,
147 gint tiff_parse_IFD_table(guchar *tiff, guint offset,
148 guint size, TiffByteOrder bo,
150 FuncParseIFDEntry parse_entry, gpointer data)
157 /* We should be able to read number of entries in IFD0) */
158 if (size < offset + 2) return -1;
160 count = tiff_byte_get_int16(tiff + offset, bo);
162 printf("count %d\n", count);
163 /* Entries and next IFD offset must be readable */
164 if (size < offset + count * TIFF_TIFD_SIZE + 4) return -1;
166 for (i = 0; i < count; i++)
168 parse_entry(tiff, offset + i * TIFF_TIFD_SIZE, size, bo, data);
171 next = tiff_byte_get_int32(tiff + offset + count * TIFF_TIFD_SIZE, bo);
172 printf("next %d\n", next);
173 if (next_offset) *next_offset = next;
178 static gint mpo_parse_Index_IFD_entry(guchar *tiff, guint offset,
179 guint size, TiffByteOrder bo,
191 tag = tiff_byte_get_int16(tiff + offset + TIFF_TIFD_OFFSET_TAG, bo);
192 format = tiff_byte_get_int16(tiff + offset + TIFF_TIFD_OFFSET_FORMAT, bo);
193 count = tiff_byte_get_int32(tiff + offset + TIFF_TIFD_OFFSET_COUNT, bo);
194 data_val = tiff_byte_get_int32(tiff + offset + TIFF_TIFD_OFFSET_DATA, bo);
195 printf("tag %x format %x count %x data_val %x\n", tag, format, count, data_val);
199 mpo->version = data_val;
201 else if (tag == 0xb001)
203 mpo->num_images = data_val;
205 else if (tag == 0xb002)
208 data_offset = data_val;
210 if (size < data_offset || size < data_offset + data_length)
214 if (count != mpo->num_images * 16)
219 mpo->images = g_new0(MPOEntry, mpo->num_images);
221 for (i = 0; i < mpo->num_images; i++) {
222 guint image_attr = tiff_byte_get_int32(tiff + data_offset + i * 16, bo);
223 mpo->images[i].type_code = image_attr & 0xffffff;
224 mpo->images[i].representative = !!(image_attr & 0x20000000);
225 mpo->images[i].dependent_child = !!(image_attr & 0x40000000);
226 mpo->images[i].dependent_parent = !!(image_attr & 0x80000000);
227 mpo->images[i].length = tiff_byte_get_int32(tiff + data_offset + i * 16 + 4, bo);
228 mpo->images[i].offset = tiff_byte_get_int32(tiff + data_offset + i * 16 + 8, bo);
229 mpo->images[i].dep1 = tiff_byte_get_int16(tiff + data_offset + i * 16 + 12, bo);
230 mpo->images[i].dep2 = tiff_byte_get_int16(tiff + data_offset + i * 16 + 14, bo);
234 mpo->images[i].offset = 0;
238 mpo->images[i].offset += mpo->mpo_offset;
241 printf("img %x %x %x\n", image_attr, mpo->images[i].length, mpo->images[i].offset);
248 MPOData *jpeg_get_mpo_data(guchar *data, guint size)
252 if (jpeg_segment_find(data, size, JPEG_MARKER_APP2, "MPF\x00", 4, &seg_offset, &seg_size) && seg_size >16)
259 printf("mpo signature found at %x\n", seg_offset);
260 data += seg_offset + 4;
263 if (!tiff_directory_offset(data, seg_size, &offset, &bo)) return NULL;
265 mpo = g_new0(MPOData, 1);
266 mpo->mpo_offset = seg_offset + 4;
268 tiff_parse_IFD_table(data, offset , seg_size, bo, NULL, mpo_parse_Index_IFD_entry, (gpointer)mpo);
269 if (!mpo->images) mpo->num_images = 0;
271 for (i = 0; i < mpo->num_images; i++)
273 if (mpo->images[i].offset + mpo->images[i].length > size)
276 DEBUG_1("MPO file truncated to %d valid images", i);