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