clang-tidy: bugprone-macro-parentheses
[geeqie.git] / src / format-canon.cc
1 /*
2  * Copyright (C) 2005 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: Daniel M. German <dmgerman@uvic.ca>
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 <unistd.h>
29
30 #include <glib.h>
31
32 #include "intl.h"
33
34 #include "main.h"
35 #include "format-canon.h"
36 #include "format-raw.h"
37
38 #include "exif.h"
39
40
41 /*
42  *-----------------------------------------------------------------------------
43  * Raw (CR2, CRW) embedded jpeg extraction for Canon
44  *-----------------------------------------------------------------------------
45  */
46
47 static gboolean canon_cr2_tiff_entry(guchar *data, const guint len, guint offset, ExifByteOrder bo,
48                                      guint *image_offset, gint *jpeg_encoding)
49 {
50         guint tag;
51         guint type;
52         guint count;
53         guint jpeg_start;
54
55         /* the two (tiff compliant) tags we want are:
56          *  0x0103 image compression type (must be type 6 for jpeg)
57          *  0x0111 jpeg start offset
58          * only use the first segment that contains an actual jpeg - as there
59          * is a another that contains the raw data.
60          */
61         tag = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_TAG, bo);
62         type = exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
63         count = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_COUNT, bo);
64
65         /* tag 0x0103 contains the compression type for this segment's image data */
66         if (tag == 0x0103)
67                 {
68                 if (ExifFormatList[type].size * count == 2 &&
69                     exif_byte_get_int16(data + offset + EXIF_TIFD_OFFSET_DATA, bo) == 6)
70                         {
71                         *jpeg_encoding = TRUE;
72                         }
73                 return FALSE;
74                 }
75
76         /* find and verify jpeg offset */
77         if (tag != 0x0111 ||
78             !jpeg_encoding) return FALSE;
79
80         /* make sure data segment contains 4 bytes */
81         if (ExifFormatList[type].size * count != 4) return FALSE;
82
83         jpeg_start = exif_byte_get_int32(data + offset + EXIF_TIFD_OFFSET_DATA, bo);
84
85         /* verify this is jpeg data */
86         if (len < jpeg_start + 4 ||
87             memcmp(data + jpeg_start, "\xff\xd8", 2) != 0)
88                 {
89                 return FALSE;
90                 }
91
92         *image_offset = jpeg_start;
93         return TRUE;
94 }
95
96 static gint canon_cr2_tiff_table(guchar *data, const guint len, guint offset, ExifByteOrder bo,
97                                  guint *image_offset)
98 {
99         gboolean jpeg_encoding = FALSE;
100         guint count;
101         guint i;
102
103         if (len < offset + 2) return 0;
104
105         count = exif_byte_get_int16(data + offset, bo);
106         offset += 2;
107         if (len < offset + count * EXIF_TIFD_SIZE + 4) return 0;
108
109         for (i = 0; i < count; i++)
110                 {
111                 if (canon_cr2_tiff_entry(data, len, offset + i * EXIF_TIFD_SIZE, bo,
112                                          image_offset, &jpeg_encoding))
113                         {
114                         return 0;
115                         }
116                 }
117
118         return exif_byte_get_int32(data + offset + count * EXIF_TIFD_SIZE, bo);
119 }
120
121 gboolean format_canon_raw_cr2(guchar *data, const guint len,
122                               guint *image_offset, guint *)
123 {
124         guint jpeg_offset = 0;
125         ExifByteOrder bo;
126         guint offset;
127         gint level;
128
129         /* cr2 files are tiff files with a few canon specific directory tags
130          * they are (always ?) in little endian format
131          */
132         if (!exif_tiff_directory_offset(data, len, &offset, &bo)) return FALSE;
133
134         level = 0;
135         while (offset && level < EXIF_TIFF_MAX_LEVELS)
136                 {
137                 offset = canon_cr2_tiff_table(data, len, offset, bo, &jpeg_offset);
138                 level++;
139
140                 if (jpeg_offset != 0)
141                         {
142                         if (image_offset) *image_offset = jpeg_offset;
143                         return TRUE;
144                         }
145                 }
146
147         return FALSE;
148 }
149
150 #define CRW_BYTE_ORDER          EXIF_BYTE_ORDER_INTEL
151 #define CRW_HEADER_SIZE         26
152 #define CRW_DIR_ENTRY_SIZE      10
153
154 gboolean format_canon_raw_crw(guchar *data, const guint len,
155                               guint *image_offset, guint *)
156 {
157         guint block_offset;
158         guint data_length;
159         guint offset;
160         guint count;
161         guint i;
162
163         /* CRW header starts with 2 bytes for byte order (always "II", little endian),
164          * 4 bytes for start of root block,
165          * and 8 bytes of magic for file type and format "HEAPCCDR"
166          * (also 4 bytes for file version, and 8 bytes reserved)
167          *
168          * CIFF specification in pdf format is available on some websites,
169          * search for "CIFFspecV1R03.pdf" or "CIFFspecV1R04.pdf"
170          */
171         if (len < CRW_HEADER_SIZE ||
172             memcmp(data, "II", 2) != 0 ||
173             memcmp(data + 6, "HEAPCCDR", 8) != 0)
174                 {
175                 return FALSE;
176                 }
177
178         block_offset = exif_byte_get_int32(data + 2, CRW_BYTE_ORDER);
179
180         /* the end of the root block equals end of file,
181          * the last 4 bytes of the root block contain the block's data size
182          */
183         offset = len - 4;
184         data_length = exif_byte_get_int32(data + offset, CRW_BYTE_ORDER);
185
186         offset = block_offset + data_length;
187         if (len < offset + 2) return FALSE;
188
189         /* number of directory entries for this block is in
190          * the next two bytes after the data for this block.
191          */
192         count = exif_byte_get_int16(data + offset, CRW_BYTE_ORDER);
193         offset += 2;
194         if (len < offset + count * CRW_DIR_ENTRY_SIZE + 4) return FALSE;
195
196         /* walk the directory entries looking for type jpeg (tag 0x2007),
197          * for reference, other tags are 0x2005 for raw and 0x300a for photo info:
198          */
199         for (i = 0; i < count ; i++)
200                 {
201                 guint entry_offset;
202                 guint record_type;
203                 guint record_offset;
204                 guint record_length;
205
206                 entry_offset = offset + i * CRW_DIR_ENTRY_SIZE;
207
208                 /* entry is 10 bytes (in order):
209                  *  2 for type
210                  *  4 for length of data
211                  *  4 for offset into data segment of this block
212                  */
213                 record_type = exif_byte_get_int16(data + entry_offset, CRW_BYTE_ORDER);
214                 record_length = exif_byte_get_int32(data + entry_offset + 2, CRW_BYTE_ORDER);
215                 record_offset = exif_byte_get_int32(data + entry_offset + 6, CRW_BYTE_ORDER);
216
217                 /* tag we want for jpeg data */
218                 if (record_type == 0x2007)
219                         {
220                         guint jpeg_offset;
221
222                         jpeg_offset = block_offset + record_offset;
223                         if (len < jpeg_offset + record_length ||
224                             record_length < 4 ||
225                             memcmp(data + jpeg_offset, "\xff\xd8\xff\xdb", 4) != 0)
226                                 {
227                                 return FALSE;
228                                 }
229
230                         /* we now know offset and verified jpeg */
231                         *image_offset = jpeg_offset;
232                         return TRUE;
233                         }
234                 }
235
236         return FALSE;
237 }
238
239
240 /*
241  *-----------------------------------------------------------------------------
242  * EXIF Makernote for Canon
243  *-----------------------------------------------------------------------------
244  */
245
246 static ExifTextList CanonSet1MacroMode[] = {
247         { 1,    "macro" },
248         { 2,    "normal" },
249         EXIF_TEXT_LIST_END
250 };
251
252 static ExifTextList CanonSet1Quality[] = {
253         { 2,    "normal" },
254         { 3,    "fine" },
255         { 4,    "raw" },
256         { 5,    "superfine" },
257         EXIF_TEXT_LIST_END
258 };
259
260 static ExifTextList CanonSet1FlashMode[] = {
261         { 0,    "flash not fired" },
262         { 1,    "auto" },
263         { 2,    "on" },
264         { 3,    "red-eye reduction" },
265         { 4,    "slow sync" },
266         { 5,    "auto + red-eye reduction" },
267         { 6,    "on + red-eye reduction" },
268         { 16,   "external flash" },
269         EXIF_TEXT_LIST_END
270 };
271
272 static ExifTextList CanonSet1DriveMode[] = {
273         { 0,    "single or timer" },
274         { 1,    "continuous" },
275         EXIF_TEXT_LIST_END
276 };
277
278 static ExifTextList CanonSet1FocusMode[] = {
279         { 0,    "one-shot AF" },
280         { 1,    "AI servo AF" },
281         { 2,    "AI focus AF" },
282         { 3,    "manual" },
283         { 4,    "single" },
284         { 5,    "continuous" },
285         { 6,    "manual" },
286         EXIF_TEXT_LIST_END
287 };
288
289 static ExifTextList CanonSet1ImageSize[] = {
290         { 0,    "large" },
291         { 1,    "medium" },
292         { 2,    "small" },
293         /* where (or) does Medium 1/2 fit in here ? */
294         EXIF_TEXT_LIST_END
295 };
296
297 static ExifTextList CanonSet1ShootingMode[] = {
298         { 0,    "auto" },
299         { 1,    "manual" },
300         { 2,    "landscape" },
301         { 3,    "fast shutter" },
302         { 4,    "slow shutter" },
303         { 5,    "night" },
304         { 6,    "black and white" },
305         { 7,    "sepia" },
306         { 8,    "portrait" },
307         { 9,    "sports" },
308         { 10,   "macro" },
309         { 11,   "pan focus" },
310         EXIF_TEXT_LIST_END
311 };
312
313 /* Don't think this is interpreted correctly/completely, A60 at 2.5x Digital sets value of 3 */
314 static ExifTextList CanonSet1DigitalZoom[] = {
315         { 0,    "none" },
316         { 1,    "2x" },
317         { 2,    "4x" },
318         { 3,    "other" },
319         EXIF_TEXT_LIST_END
320 };
321
322 static ExifTextList CanonSet1ConSatSharp[] = {
323         { 0,    "normal" },
324         { 1,    "high" },
325         { 65535,"low" },
326         EXIF_TEXT_LIST_END
327 };
328
329 static ExifTextList CanonSet1ISOSpeed[] = {
330 /*      { 0,    "not set/see EXIF tag" }, */
331         { 15,   "auto" },
332         { 16,   "50" },
333         { 17,   "100" },
334         { 18,   "200" },
335         { 19,   "400" },
336         EXIF_TEXT_LIST_END
337 };
338
339 static ExifTextList CanonSet1MeteringMode[] = {
340         { 0,    "default" },
341         { 1,    "spot" },
342         { 3,    "evaluative" },
343         { 4,    "partial" },
344         { 5,    "center-weighted" },
345         EXIF_TEXT_LIST_END
346 };
347
348 static ExifTextList CanonSet1FocusType[] = {
349         { 0,    "manual" },
350         { 1,    "auto" },
351         { 2,    "auto" },
352         { 3,    "macro" },
353         { 7,    "infinity" },
354         { 8,    "locked" },
355         EXIF_TEXT_LIST_END
356 };
357
358 static ExifTextList CanonSet1AutoFocusPoint[] = {
359         { 0x2005,       "manual AF point selection" },
360         { 0x3000,       "manual focus" },
361         { 0x3001,       "auto" },
362         { 0x3002,       "right" },
363         { 0x3003,       "center" },
364         { 0x3004,       "left" },
365         { 0x4001,       "auto AF point selection" },
366         EXIF_TEXT_LIST_END
367 };
368
369 static ExifTextList CanonSet1ExposureMode[] = {
370         { 0,    "auto" },
371         { 1,    "program" },
372         { 2,    "Tv priority" },
373         { 3,    "Av priority" },
374         { 4,    "manual" },
375         { 5,    "A-DEP" },
376         EXIF_TEXT_LIST_END
377 };
378
379 static ExifTextList CanonSet1FlashFired[] = {
380         { 0,    "no" },
381         { 1,    "yes" },
382         EXIF_TEXT_LIST_END
383 };
384
385 static ExifTextList CanonSet1FocusCont[] = {
386         { 0,    "no (single)" },
387         { 1,    "yes" },
388         EXIF_TEXT_LIST_END
389 };
390
391 static ExifMarker CanonSet1[] = {
392 /* 0 is length of array in bytes (2 x array size) */
393 { 1,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MacroMode",   "Macro mode",           CanonSet1MacroMode },
394 { 2,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SelfTimer",   "Self timer (10ths of second)", nullptr },
395 { 3,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Quality",     "Quality",              CanonSet1Quality },
396 { 4,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashMode",   "Flash mode",           CanonSet1FlashMode },
397 { 5,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DriveMode",   "Drive mode",           CanonSet1DriveMode },
398 { 7,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusMode",   "Focus mode",           CanonSet1FocusMode },
399 { 10,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ImageSize",   "Image size",           CanonSet1ImageSize },
400 { 11,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ShootingMode","Shooting mode",        CanonSet1ShootingMode },
401  { 11,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureProgram",       "ExposureProgram",      CanonSet1ShootingMode },
402 { 12,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.DigitalZoom", "Digital zoom",         CanonSet1DigitalZoom },
403 { 13,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Contrast",    "Contrast",             CanonSet1ConSatSharp },
404 { 14,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Saturation",  "Saturation",           CanonSet1ConSatSharp },
405 { 15,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.Sharpness",   "Sharpness",            CanonSet1ConSatSharp },
406 { 16,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ISOSpeed",    "ISO speed",            CanonSet1ISOSpeed },
407  { 16,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ISOSpeedRatings",       "ISO speed",            CanonSet1ISOSpeed },
408 { 17,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.MeteringMode","Metering mode",        CanonSet1MeteringMode },
409 { 18,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocusType",   "Focus type",           CanonSet1FocusType },
410 { 19,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.AutoFocus",   "AutoFocus point",      CanonSet1AutoFocusPoint },
411 { 20,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ExposureMode","Exposure mode",        CanonSet1ExposureMode },
412  { 20,  EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureMode",          "Exposure mode",        CanonSet1ExposureMode },
413 { 23,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthLong","Long focal length", nullptr },
414 { 24,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthShort","Short focal length", nullptr },
415 { 25,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FocalLengthUnits","Focal units per mm", nullptr },
416 { 28,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashFired",  "Flash fired",          CanonSet1FlashFired },
417 { 29,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashDetails","Flash details",        nullptr },
418 { 32,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.ContinuousFocus","Continuous focus",  CanonSet1FocusCont },
419 EXIF_MARKER_LIST_END
420 };
421
422 static ExifTextList CanonSet2WhiteBalance[] = {
423         { 0,    "auto" },
424         { 1,    "sunny" },
425         { 2,    "cloudy" },
426         { 3,    "tungsten" },
427         { 4,    "fluorescent" },
428         { 5,    "flash" },
429         { 6,    "custom" },
430         { 7,    "black and white" },
431         { 8,    "shade" },
432         { 9,    "manual" },
433         { 14,   "daylight fluorescent" },
434         { 17,   "underwater" },
435         EXIF_TEXT_LIST_END
436 };
437
438 static ExifTextList CanonSet2FlashBias[] = {
439         { 0x0000,       "0" },
440         { 0x000c,       "0.33" },
441         { 0x0010,       "0.5" },
442         { 0x0014,       "0.67" },
443         { 0x0020,       "1" },
444         { 0x002c,       "1.33" },
445         { 0x0030,       "1.5" },
446         { 0x0034,       "1.67" },
447         { 0x0040,       "2" },
448         { 0xffc0,       "-2" },
449         { 0xffcc,       "-1.67" },
450         { 0xffd0,       "-1.5" },
451         { 0xffd4,       "-1.33" },
452         { 0xffe0,       "-1" },
453         { 0xffec,       "-0.67" },
454         { 0xfff0,       "-0.5" },
455         { 0xfff4,       "-0.33" },
456         EXIF_TEXT_LIST_END
457 };
458
459 static ExifMarker CanonSet2[] = {
460 /* 0 is length of array in bytes (2 x array size) */
461 { 7,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.WhiteBalance","White balance",        CanonSet2WhiteBalance },
462  { 7,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "LightSource",           "White balance",        CanonSet2WhiteBalance },
463 { 9,    EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SequenceNumber","Sequence number",    nullptr },
464 { 15,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.FlashBias",   "Flash bias",           CanonSet2FlashBias },
465 /* distance needs more than just this (metric) value */
466 { 19,   EXIF_FORMAT_SHORT_UNSIGNED, 1, "MkN.Canon.SubjectDistance",     "Subject Distance", nullptr },
467 EXIF_MARKER_LIST_END
468 };
469
470
471 static ExifMarker CanonExifMarkersList[] = {
472         { 1,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings1",          nullptr, nullptr },
473         { 4,    EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.Settings2",          nullptr, nullptr },
474         { 6,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.ImageType",          "Image type", nullptr },
475         { 7,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.FirmwareVersion",    "Firmware version", nullptr },
476         { 8,    EXIF_FORMAT_LONG_UNSIGNED, 1,   "MkN.Canon.ImageNumber",        "Image number", nullptr },
477         { 9,    EXIF_FORMAT_STRING, -1,         "MkN.Canon.OwnerName",          "Owner name", nullptr },
478         { 12,   EXIF_FORMAT_LONG_UNSIGNED, -1,  "MkN.Canon.SerialNumber",       "Camera serial number", nullptr },
479         { 15,   EXIF_FORMAT_SHORT_UNSIGNED, -1, "MkN.Canon.CustomFunctions",    nullptr, nullptr },
480         EXIF_MARKER_LIST_END
481 };
482
483 static void canon_mknote_parse_settings(ExifData *exif,
484                                         guint16 *data, guint32 len, ExifByteOrder bo,
485                                         ExifMarker *list)
486 {
487         gint i;
488
489         i = 0;
490         while (list[i].tag != 0)
491                 {
492                 if (list[i].tag < len)
493                         {
494                         ExifItem *item;
495
496                         item = exif_item_new(EXIF_FORMAT_SHORT_UNSIGNED, list[i].tag, 1, &list[i]);
497                         exif_item_copy_data(item, &data[list[i].tag], 2, EXIF_FORMAT_SHORT_UNSIGNED, bo);
498                         exif->items = g_list_prepend(exif->items, item);
499                         }
500
501                 i++;
502                 }
503 }
504
505
506 gboolean format_canon_makernote(ExifData *exif, guchar *tiff, guint offset,
507                                 guint size, ExifByteOrder bo)
508 {
509         ExifItem *item;
510
511         if (exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, CanonExifMarkersList) != 0)
512                 {
513                 return FALSE;
514                 }
515
516         item = exif_get_item(exif, "MkN.Canon.Settings1");
517         if (item)
518                 {
519                 canon_mknote_parse_settings(exif, static_cast<guint16*>(item->data), item->data_len, bo, CanonSet1);
520                 }
521
522         item = exif_get_item(exif, "MkN.Canon.Settings2");
523         if (item)
524                 {
525                 canon_mknote_parse_settings(exif, static_cast<guint16*>(item->data), item->data_len, bo, CanonSet2);
526                 }
527
528         return TRUE;
529 }
530
531 #else
532 using dummy_variable = int;
533 #endif
534 /* not HAVE_EXIV2 */
535 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */