150f88c2d90d4d9147490e287e559fb87f027d92
[geeqie.git] / src / format_raw.c
1 /*
2  *  GQView
3  *  (C) 2005 John Ellis
4  *
5  *  Authors:
6  *    Original version 2005 Lars Ellenberg, base on dcraw by David coffin.
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #  include "config.h"
15 #endif
16
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24
25 #include <glib.h>
26
27 #include "intl.h"
28
29 #include "format_raw.h"
30
31 #include "format_canon.h"
32 #include "format_fuji.h"
33 #include "format_nikon.h"
34
35
36 /* so that debugging is honored */
37 extern gint debug;
38
39
40 typedef struct _FormatRawEntry FormatRawEntry;
41 struct _FormatRawEntry {
42         const gchar *extension;
43         FormatRawMatchType magic_type;
44         const guint magic_offset;
45         const void *magic_pattern;
46         const guint magic_length;
47         const gchar *description;
48         FormatRawParseFunc func_parse;
49 };
50
51 static FormatRawEntry format_raw_list[] = {
52         FORMAT_RAW_CANON,
53         FORMAT_RAW_FUJI,
54         FORMAT_RAW_NIKON,
55         { NULL, 0, 0, NULL, 0, NULL, NULL }
56 };
57
58
59 typedef struct _FormatExifEntry FormatExifEntry;
60 struct _FormatExifEntry {
61         FormatExifMatchType header_type;
62         const void *header_pattern;
63         const guint header_length;
64         const gchar *description;
65         FormatExifParseFunc func_parse;
66 };
67
68 static FormatExifEntry format_exif_list[] = {
69         FORMAT_EXIF_CANON,
70         FORMAT_EXIF_FUJI,
71         FORMAT_EXIF_NIKON,
72         { 0, NULL, 0, NULL }
73 };
74
75
76 static guint tiff_table(unsigned char *data, const guint len, guint offset, ExifByteOrder bo,
77                         guint tag, ExifFormatType type,
78                         guint *result_offset, guint *result_count)
79 {
80         guint count;
81         guint i;
82
83         if (len < offset + 2) return 0;
84         if (type < 0 || type > EXIF_FORMAT_COUNT) return 0;
85
86         count = exif_byte_get_int16(data + offset, bo);
87         offset += 2;
88         if (len < offset + count * 12 + 4) return 0;
89
90         for (i = 0; i < count; i++)
91                 {
92                 guint segment;
93
94                 segment = offset + i * 12;
95                 if (exif_byte_get_int16(data + segment, bo) == tag &&
96                     exif_byte_get_int16(data + segment + 2, bo) == type)
97                         {
98                         guint chunk_count;
99                         guint chunk_offset;
100                         guint chunk_length;
101
102                         chunk_count = exif_byte_get_int32(data + segment + 4, bo);
103                         chunk_length = ExifFormatList[type].size * chunk_count;
104
105                         if (chunk_length > 4)
106                                 {
107                                 chunk_offset = exif_byte_get_int32(data + segment + 8, bo);
108                                 }
109                         else
110                                 {
111                                 chunk_offset = segment + 8;
112                                 }
113
114                         if (chunk_offset + chunk_length <= len)
115                                 {
116                                 *result_offset = chunk_offset;
117                                 *result_count = chunk_count;
118                                 }
119
120                         return 0;
121                         }
122                 }
123
124         return exif_byte_get_int32(data + offset + count * 12, bo);
125 }
126
127 static gint format_tiff_find_tag_data(unsigned char *data, const guint len,
128                                       guint tag, ExifFormatType type,
129                                       guint *result_offset, guint *result_count)
130 {
131         ExifByteOrder bo;
132         guint offset;
133
134         if (len < 8) return FALSE;
135
136         if (memcmp(data, "II", 2) == 0)
137                 {
138                 bo = EXIF_BYTE_ORDER_INTEL;
139                 }
140         else if (memcmp(data, "MM", 2) == 0)
141                 {
142                 bo = EXIF_BYTE_ORDER_MOTOROLA;
143                 }
144         else
145                 {
146                 return FALSE;
147                 }
148
149         if (exif_byte_get_int16(data + 2, bo) != 0x002A)
150                 {
151                 return FALSE;
152                 }
153
154         offset = exif_byte_get_int32(data + 4, bo);
155
156         while (offset != 0)
157                 {
158                 guint ro = 0;
159                 guint rc = 0;
160
161                 offset = tiff_table(data, len, offset, bo, tag, type, &ro, &rc);
162                 if (ro != 0)
163                         {
164                         *result_offset = ro;
165                         *result_count = rc;
166                         return TRUE;
167                         }
168                 }
169
170         return FALSE;
171 }
172
173 static FormatRawEntry *format_raw_find(unsigned char *data, const guint len)
174 {
175         gint n;
176         gint tiff;
177         guint make_count = 0;
178         guint make_offset = 0;
179
180         tiff = (len > 8 &&
181                 (memcmp(data, "II\x2a\x00", 4) == 0 ||
182                  memcmp(data, "MM\x00\x2a", 4) == 0));
183
184         n = 0;
185         while (format_raw_list[n].magic_pattern)
186                 {
187                 FormatRawEntry *entry = &format_raw_list[n];
188
189                 switch (entry->magic_type)
190                         {
191                         case FORMAT_RAW_MATCH_MAGIC:
192                                 if (entry->magic_length + entry->magic_offset <= len &&
193                                     memcmp(data + entry->magic_offset,
194                                            entry->magic_pattern, entry->magic_length) == 0)
195                                         {
196                                         return entry;
197                                         }
198                                 break;
199                         case FORMAT_RAW_MATCH_TIFF_MAKE:
200                                 if (tiff &&
201                                     make_offset == 0 &&
202                                     !format_tiff_find_tag_data(data, len, 0x10f, EXIF_FORMAT_STRING,
203                                                                &make_offset, &make_count))
204                                         {
205                                         tiff = FALSE;
206                                         }
207                                 if (make_offset != 0 &&
208                                     make_count >= entry->magic_offset + entry->magic_length &&
209                                     memcmp(entry->magic_pattern,
210                                            data + make_offset + entry->magic_offset, entry->magic_length) == 0)
211                                         {
212                                         return entry;
213                                         }
214                                 break;
215                         default:
216                                 break;
217                         }
218                 n++;
219                 }
220
221         return NULL;
222 }
223
224 static gint format_raw_parse(FormatRawEntry *entry,
225                              unsigned char *data, const guint len,
226                              guint *image_offset, guint *exif_offset)
227 {
228         guint io = 0;
229         guint eo = 0;
230         gint found;
231
232         if (!entry || !entry->func_parse) return FALSE;
233
234         if (debug) printf("RAW using file parser for %s\n", entry->description);
235
236         found = entry->func_parse(data, len, &io, &eo);
237
238         if (!found ||
239             io >= len - 4 ||
240             eo >= len)
241                 {
242                 return FALSE;
243                 }
244
245         if (image_offset) *image_offset = io;
246         if (exif_offset) *exif_offset = eo;
247
248         return TRUE;
249 }
250
251 gint format_raw_img_exif_offsets(unsigned char *data, const guint len,
252                                  guint *image_offset, guint *exif_offset)
253 {
254         FormatRawEntry *entry;
255
256         if (!data || len < 1) return FALSE;
257
258         entry = format_raw_find(data, len);
259
260         if (!entry || !entry->func_parse) return FALSE;
261
262         return format_raw_parse(entry, data, len, image_offset, exif_offset);
263 }
264
265
266 gint format_raw_img_exif_offsets_fd(int fd, const gchar *path,
267                                     unsigned char *header_data, const guint header_len,
268                                     guint *image_offset, guint *exif_offset)
269 {
270         FormatRawEntry *entry;
271         void *map_data = NULL;
272         size_t map_len = 0;
273         struct stat st;
274         gint success;
275
276         if (!header_data || fd < 0) return FALSE;
277
278         /* given image pathname, first do simple (and fast) file extension test */
279         if (path)
280                 {
281                 const gchar *ext;
282                 gint match = FALSE;
283                 gint i;
284
285                 ext = strrchr(path, '.');
286                 if (!ext) return FALSE;
287                 ext++;
288
289                 i = 0;
290                 while (!match && format_raw_list[i].magic_pattern)
291                         {
292                         if (format_raw_list[i].extension &&
293                             strcasecmp(format_raw_list[i].extension, ext) == 0)
294                                 {
295                                 match = TRUE;
296                                 }
297                         i++;
298                         }
299
300                 if (!match) return FALSE;
301
302                 if (debug) printf("RAW file parser extension match\n");
303                 }
304
305         entry = format_raw_find(header_data, header_len);
306
307         if (!entry || !entry->func_parse) return FALSE;
308
309         if (fstat(fd, &st) == -1)
310                 {
311                 printf("Failed to stat file %d\n", fd);
312                 return FALSE;
313                 }
314         map_len = st.st_size;
315         map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
316         if (map_data == MAP_FAILED)
317                 {
318                 printf("Failed to mmap file %d\n", fd);
319                 return FALSE;
320                 }
321
322         success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset);
323
324         if (munmap(map_data, map_len) == -1)
325                 {
326                 printf("Failed to unmap file %d\n", fd);
327                 }
328
329         if (success && image_offset)
330                 {
331                 if (lseek(fd, *image_offset, SEEK_SET) != *image_offset)
332                         {
333                         printf("Failed to seek to embedded image\n");
334
335                         *image_offset = 0;
336                         if (*exif_offset) *exif_offset = 0;
337                         success = FALSE;
338                         }
339                 }
340
341         return success;
342 }
343
344
345 static FormatExifEntry *format_exif_makernote_find(ExifData *exif, unsigned char *tiff,
346                                                    guint offset, guint size)
347 {
348         ExifItem *make;
349         gint n;
350
351         make = exif_get_item(exif, "Make");
352
353         n = 0;
354         while (format_exif_list[n].header_pattern)
355                 {
356                 switch (format_exif_list[n].header_type)
357                         {
358                         case FORMAT_EXIF_MATCH_MAKERNOTE:
359                                 if (format_exif_list[n].header_length + offset < size &&
360                                     memcmp(tiff + offset, format_exif_list[n].header_pattern,
361                                                           format_exif_list[n].header_length) == 0)
362                                         {
363                                         return &format_exif_list[n];
364                                         }
365                                 break;
366                         case FORMAT_EXIF_MATCH_MAKE:
367                                 if (make &&
368                                     make->data_len >= format_exif_list[n].header_length &&
369                                     memcmp(make->data, format_exif_list[n].header_pattern,
370                                                        format_exif_list[n].header_length) == 0)
371                                         {
372                                         return &format_exif_list[n];
373                                         }
374                                 break;
375                         }
376                 n++;
377                 }
378
379         return FALSE;
380 }
381
382 gint format_exif_makernote_parse(ExifData *exif, unsigned char *tiff, guint offset,
383                                  guint size, ExifByteOrder bo)
384 {
385         FormatExifEntry *entry;
386
387         entry = format_exif_makernote_find(exif, tiff, offset, size);
388
389         if (!entry || !entry->func_parse) return FALSE;
390
391         if (debug) printf("EXIF using makernote parser for %s\n", entry->description);
392
393         return entry->func_parse(exif, tiff, offset, size, bo);
394 }
395
396