Simplify vflist_get_formatted()
[geeqie.git] / src / format_raw.c
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: Lars Ellenberg
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #ifndef HAVE_EXIV2
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34
35 #include <glib.h>
36
37 #include "intl.h"
38
39 #include "main.h"
40 #include "format_raw.h"
41
42 #include "format_canon.h"
43 #include "format_fuji.h"
44 #include "format_nikon.h"
45 #include "format_olympus.h"
46
47
48 typedef struct _FormatRawEntry FormatRawEntry;
49 struct _FormatRawEntry {
50         const gchar *extension;
51         FormatRawMatchType magic_type;
52         const guint magic_offset;
53         gconstpointer magic_pattern;
54         const guint magic_length;
55         const FormatRawExifType exif_type;
56         FormatRawExifParseFunc exif_func;
57         const gchar *description;
58         FormatRawParseFunc func_parse;
59 };
60
61 static FormatRawEntry format_raw_list[] = {
62 #if DEBUG_RAW_TIFF
63         FORMAT_RAW_DEBUG_TIFF,
64 #endif
65         FORMAT_RAW_CANON,
66         FORMAT_RAW_FUJI,
67         FORMAT_RAW_NIKON,
68         FORMAT_RAW_OLYMPUS,
69         FORMAT_RAW_PENTAX,
70         FORMAT_RAW_SAMSUNG,
71         { NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL }
72 };
73
74
75 typedef struct _FormatExifEntry FormatExifEntry;
76 struct _FormatExifEntry {
77         FormatExifMatchType header_type;
78         gconstpointer header_pattern;
79         const guint header_length;
80         const gchar *description;
81         FormatExifParseFunc func_parse;
82 };
83
84 static FormatExifEntry format_exif_list[] = {
85         FORMAT_EXIF_CANON,
86         FORMAT_EXIF_FUJI,
87         FORMAT_EXIF_NIKON,
88         FORMAT_EXIF_OLYMPUS,
89         { 0, NULL, 0, NULL, NULL }
90 };
91
92
93 static guint tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
94                         guint tag, ExifFormatType type,
95                         guint *result_offset, guint *result_count)
96 {
97         guint count;
98         guint i;
99
100         if (len < offset + 2) return 0;
101         if (type > EXIF_FORMAT_COUNT) return 0;
102
103         count = exif_byte_get_int16(data + offset, bo);
104         offset += 2;
105         if (len < offset + count * 12 + 4) return 0;
106
107         for (i = 0; i < count; i++)
108                 {
109                 guint segment;
110
111                 segment = offset + i * 12;
112                 if (exif_byte_get_int16(data + segment, bo) == tag &&
113                     exif_byte_get_int16(data + segment + 2, bo) == type)
114                         {
115                         guint chunk_count;
116                         guint chunk_offset;
117                         guint chunk_length;
118
119                         chunk_count = exif_byte_get_int32(data + segment + 4, bo);
120                         chunk_length = ExifFormatList[type].size * chunk_count;
121
122                         if (chunk_length > 4)
123                                 {
124                                 chunk_offset = exif_byte_get_int32(data + segment + 8, bo);
125                                 }
126                         else
127                                 {
128                                 chunk_offset = segment + 8;
129                                 }
130
131                         if (chunk_offset + chunk_length <= len)
132                                 {
133                                 *result_offset = chunk_offset;
134                                 *result_count = chunk_count;
135                                 }
136
137                         return 0;
138                         }
139                 }
140
141         return exif_byte_get_int32(data + offset + count * 12, bo);
142 }
143
144 static gboolean format_tiff_find_tag_data(guchar *data, const guint len,
145                                           guint tag, ExifFormatType type,
146                                           guint *result_offset, guint *result_count)
147 {
148         ExifByteOrder bo;
149         guint offset;
150
151         if (len < 8) return FALSE;
152
153         if (memcmp(data, "II", 2) == 0)
154                 {
155                 bo = EXIF_BYTE_ORDER_INTEL;
156                 }
157         else if (memcmp(data, "MM", 2) == 0)
158                 {
159                 bo = EXIF_BYTE_ORDER_MOTOROLA;
160                 }
161         else
162                 {
163                 return FALSE;
164                 }
165
166         if (exif_byte_get_int16(data + 2, bo) != 0x002A)
167                 {
168                 return FALSE;
169                 }
170
171         offset = exif_byte_get_int32(data + 4, bo);
172
173         while (offset != 0)
174                 {
175                 guint ro = 0;
176                 guint rc = 0;
177
178                 offset = tiff_table(data, len, offset, bo, tag, type, &ro, &rc);
179                 if (ro != 0)
180                         {
181                         *result_offset = ro;
182                         *result_count = rc;
183                         return TRUE;
184                         }
185                 }
186
187         return FALSE;
188 }
189
190 static FormatRawEntry *format_raw_find(guchar *data, const guint len)
191 {
192         gint n;
193         gboolean tiff;
194         guint make_count = 0;
195         guint make_offset = 0;
196
197         tiff = (len > 8 &&
198                 (memcmp(data, "II\x2a\x00", 4) == 0 ||
199                  memcmp(data, "MM\x00\x2a", 4) == 0));
200
201         n = 0;
202         while (format_raw_list[n].magic_pattern)
203                 {
204                 FormatRawEntry *entry = &format_raw_list[n];
205
206                 switch (entry->magic_type)
207                         {
208                         case FORMAT_RAW_MATCH_MAGIC:
209                                 if (entry->magic_length + entry->magic_offset <= len &&
210                                     memcmp(data + entry->magic_offset,
211                                            entry->magic_pattern, entry->magic_length) == 0)
212                                         {
213                                         return entry;
214                                         }
215                                 break;
216                         case FORMAT_RAW_MATCH_TIFF_MAKE:
217                                 if (tiff &&
218                                     make_offset == 0 &&
219                                     !format_tiff_find_tag_data(data, len, 0x10f, EXIF_FORMAT_STRING,
220                                                                &make_offset, &make_count))
221                                         {
222                                         tiff = FALSE;
223                                         }
224                                 if (make_offset != 0 &&
225                                     make_count >= entry->magic_offset + entry->magic_length &&
226                                     memcmp(entry->magic_pattern,
227                                            data + make_offset + entry->magic_offset, entry->magic_length) == 0)
228                                         {
229                                         return entry;
230                                         }
231                                 break;
232                         default:
233                                 break;
234                         }
235                 n++;
236                 }
237
238         return NULL;
239 }
240
241 static gboolean format_raw_parse(FormatRawEntry *entry,
242                                  guchar *data, const guint len,
243                                  guint *image_offset, guint *exif_offset)
244 {
245         guint io = 0;
246         guint eo = 0;
247         gboolean found;
248
249         if (!entry || !entry->func_parse) return FALSE;
250
251         DEBUG_1("RAW using file parser for %s", entry->description);
252
253         found = entry->func_parse(data, len, &io, &eo);
254
255         if (!found ||
256             io >= len - 4 ||
257             eo >= len)
258                 {
259                 return FALSE;
260                 }
261
262         if (image_offset) *image_offset = io;
263         if (exif_offset) *exif_offset = eo;
264
265         return TRUE;
266 }
267
268 gboolean format_raw_img_exif_offsets(guchar *data, const guint len,
269                                      guint *image_offset, guint *exif_offset)
270 {
271         FormatRawEntry *entry;
272
273         if (!data || len < 1) return FALSE;
274
275         entry = format_raw_find(data, len);
276
277         if (!entry || !entry->func_parse) return FALSE;
278
279         return format_raw_parse(entry, data, len, image_offset, exif_offset);
280 }
281
282
283 FormatRawExifType format_raw_exif_offset(guchar *data, const guint len, guint *exif_offset,
284                                          FormatRawExifParseFunc *exif_parse_func)
285 {
286         FormatRawEntry *entry;
287
288         if (!data || len < 1) return FALSE;
289
290         entry = format_raw_find(data, len);
291
292         if (!entry || !entry->func_parse) return FALSE;
293
294         if (!format_raw_parse(entry, data, len, NULL, exif_offset)) return FORMAT_RAW_EXIF_NONE;
295
296         if (entry->exif_type == FORMAT_RAW_EXIF_PROPRIETARY && exif_parse_func)
297                 {
298                 *exif_parse_func = entry->exif_func;
299                 }
300
301         return entry->exif_type;
302 }
303
304
305 gboolean format_raw_img_exif_offsets_fd(gint fd, const gchar *path,
306                                         guchar *header_data, const guint header_len,
307                                         guint *image_offset, guint *exif_offset)
308 {
309         FormatRawEntry *entry;
310         gpointer map_data = NULL;
311         size_t map_len = 0;
312         struct stat st;
313         gboolean success;
314
315         if (!header_data || fd < 0) return FALSE;
316
317         /* given image pathname, first do simple (and fast) file extension test */
318         if (path)
319                 {
320                 const gchar *ext;
321                 gboolean match = FALSE;
322                 gint i;
323
324                 ext = strrchr(path, '.');
325                 if (!ext) return FALSE;
326                 ext++;
327
328                 i = 0;
329                 while (!match && format_raw_list[i].magic_pattern)
330                         {
331                         if (format_raw_list[i].extension &&
332                             g_ascii_strcasecmp(format_raw_list[i].extension, ext) == 0)
333                                 {
334                                 match = TRUE;
335                                 }
336                         i++;
337                         }
338
339                 if (!match) return FALSE;
340
341                 DEBUG_1("RAW file parser extension match");
342                 }
343
344         /**
345          * @FIXME when the target is a tiff file it should be mmaped prior to format_raw_find as
346          * the make field data may not always be within header_data + header_len
347          */
348         entry = format_raw_find(header_data, header_len);
349
350         if (!entry || !entry->func_parse) return FALSE;
351
352         if (fstat(fd, &st) == -1)
353                 {
354                 log_printf("Failed to stat file %d\n", fd);
355                 return FALSE;
356                 }
357         map_len = st.st_size;
358         map_data = mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
359         if (map_data == MAP_FAILED)
360                 {
361                 log_printf("Failed to mmap file %d\n", fd);
362                 return FALSE;
363                 }
364
365         success = format_raw_parse(entry, map_data, map_len, image_offset, exif_offset);
366
367         if (munmap(map_data, map_len) == -1)
368                 {
369                 log_printf("Failed to unmap file %d\n", fd);
370                 }
371
372         if (success && image_offset)
373                 {
374                 if (lseek(fd, *image_offset, SEEK_SET) != (off_t) *image_offset)
375                         {
376                         log_printf("Failed to seek to embedded image\n");
377
378                         *image_offset = 0;
379                         if (*exif_offset) *exif_offset = 0;
380                         success = FALSE;
381                         }
382                 }
383
384         return success;
385 }
386
387
388 static FormatExifEntry *format_exif_makernote_find(ExifData *exif, guchar *tiff,
389                                                    guint offset, guint size)
390 {
391         ExifItem *make;
392         gint n;
393
394         make = exif_get_item(exif, "Exif.Image.Make");
395
396         n = 0;
397         while (format_exif_list[n].header_pattern)
398                 {
399                 switch (format_exif_list[n].header_type)
400                         {
401                         case FORMAT_EXIF_MATCH_MAKERNOTE:
402                                 if (format_exif_list[n].header_length + offset < size &&
403                                     memcmp(tiff + offset, format_exif_list[n].header_pattern,
404                                                           format_exif_list[n].header_length) == 0)
405                                         {
406                                         return &format_exif_list[n];
407                                         }
408                                 break;
409                         case FORMAT_EXIF_MATCH_MAKE:
410                                 if (make &&
411                                     make->data_len >= format_exif_list[n].header_length &&
412                                     memcmp(make->data, format_exif_list[n].header_pattern,
413                                                        format_exif_list[n].header_length) == 0)
414                                         {
415                                         return &format_exif_list[n];
416                                         }
417                                 break;
418                         }
419                 n++;
420                 }
421
422         return FALSE;
423 }
424
425 gboolean format_exif_makernote_parse(ExifData *exif, guchar *tiff, guint offset,
426                                      guint size, ExifByteOrder bo)
427 {
428         FormatExifEntry *entry;
429
430         entry = format_exif_makernote_find(exif, tiff, offset, size);
431
432         if (!entry || !entry->func_parse) return FALSE;
433
434         DEBUG_1("EXIF using makernote parser for %s", entry->description);
435
436         return entry->func_parse(exif, tiff, offset, size, bo);
437 }
438
439 /*
440  *-----------------------------------------------------------------------------
441  * Basic TIFF debugger, prints all IFD entries within tiff file
442  *-----------------------------------------------------------------------------
443  */
444 #if DEBUG_RAW_TIFF
445
446 static guint format_debug_tiff_table(guchar *data, const guint len, guint offset,
447                                      ExifByteOrder bo, gint level);
448
449 static void format_debug_tiff_entry(guchar *data, const guint len, guint offset,
450                                     ExifByteOrder bo, gint level)
451 {
452         guint tag;
453         guint type;
454         guint count;
455         guint segment;
456         guint seg_len;
457
458         tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
459         type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
460         count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);
461
462         seg_len = ExifFormatList[type].size * count;
463         if (seg_len > 4)
464                 {
465                 segment = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
466                 if (segment + seg_len > len) return;
467                 }
468         else
469                 {
470                 segment = offset + EXIF_TIFD_OFFSET_DATA;
471                 }
472
473         log_printf("%*stag:0x%04X (%05d), type:%2d %9s, len:%6d [%02X %02X %02X %02X] @ offset:%d\n",
474                 level, "", tag, tag, type,
475                 (type < EXIF_FORMAT_COUNT) ? ExifFormatList[type].short_name : "???", count,
476                 data[segment], data[segment + 1], data[segment + 2], data[segment + 3], segment);
477
478         if (tag == 0x8769 || tag == 0x14a)
479                 {
480                 gint i;
481
482                 log_printf("%*s~~~ found %s table\n", level, "", (tag == 0x14a) ? "subIFD" : "EXIF" );
483
484                 for (i = 0; i < count; i++)
485                         {
486                         guint subset;
487
488                         subset = exif_byte_get_int32(data + segment + i * 4, bo);
489                         format_debug_tiff_table(data, len, subset, bo, level + 1);
490                         }
491                 }
492         else if (tag == 0x8773 && type == EXIF_FORMAT_UNDEFINED)
493                 {
494                 log_printf("%*s~~~ found ICC color profile at offset %d, length %d\n", level, "", segment, seg_len);
495                 }
496         else if (tag == 0x201 && (type == EXIF_FORMAT_LONG_UNSIGNED || type == EXIF_FORMAT_LONG))
497                 {
498                 guint subset = exif_byte_get_int32(data + segment, bo);
499                 log_printf("%*s~~~ found jpeg data at offset %d\n", level, "", subset);
500                 }
501         else if (tag == 0x202 && (type == EXIF_FORMAT_LONG_UNSIGNED || type == EXIF_FORMAT_LONG))
502                 {
503                 guint subset = exif_byte_get_int32(data + segment, bo);
504                 log_printf("%*s~~~ found jpeg data length of %d\n", level, "", subset);
505                 }
506 }
507
508 static guint format_debug_tiff_table(guchar *data, const guint len, guint offset,
509                                      ExifByteOrder bo, gint level)
510 {
511         guint count;
512         guint i;
513
514         if (level > EXIF_TIFF_MAX_LEVELS) return 0;
515
516         if (len < offset + 2) return FALSE;
517
518         count = exif_byte_get_int16(data + offset, bo);
519         offset += 2;
520         if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
521
522         log_printf("%*s== tiff table #%d has %d entries ==\n", level, "", level, count);
523
524         for (i = 0; i < count; i++)
525                 {
526                 format_debug_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo, level);
527                 }
528
529         log_printf("%*s----------- end of #%d ------------\n", level, "", level);
530
531         return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
532 }
533
534 gboolean format_debug_tiff_raw(guchar *data, const guint len,
535                                guint *image_offset, guint *exif_offset)
536 {
537         ExifByteOrder bo;
538         gint level;
539         guint offset;
540
541         if (len < 8) return FALSE;
542
543         /* for debugging, we are more relaxed as to magic header */
544         if (memcmp(data, "II", 2) == 0)
545                 {
546                 bo = EXIF_BYTE_ORDER_INTEL;
547                 }
548         else if (memcmp(data, "MM", 2) == 0)
549                 {
550                 bo = EXIF_BYTE_ORDER_MOTOROLA;
551                 }
552         else
553                 {
554                 return FALSE;
555                 }
556
557         log_printf("*** debug parsing tiff\n");
558
559         offset = exif_byte_get_int32(data + 4, bo);
560         level = 0;
561         while (offset && level < EXIF_TIFF_MAX_LEVELS)
562                 {
563                 offset = format_debug_tiff_table(data, len, offset, bo, 0);
564                 level++;
565                 }
566
567         log_printf("*** end\n");
568
569         /* we are debugging, not trying to return any data */
570         return FALSE;
571 }
572 #endif
573
574 #endif
575 /* not HAVE_EXIV2 */
576 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */