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