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