File Coverage

imexif.c
Criterion Covered Total %
statement 0 370 0.0
branch 0 188 0.0
condition n/a
subroutine n/a
pod n/a
total 0 558 0.0


line stmt bran cond sub pod time code
1             #include "imager.h"
2             #include "imexif.h"
3             #include
4             #include
5             #include
6             #include
7              
8             /*
9             =head1 NAME
10              
11             imexif.c - EXIF support for Imager
12              
13             =head1 SYNOPSIS
14              
15             if (im_decode_exif(im, app1data, app1datasize)) {
16             // exif block seen
17             }
18              
19             =head1 DESCRIPTION
20              
21             This code provides a basic EXIF data decoder. It is intended to be
22             called from the JPEG reader code when an APP1 data block is found, and
23             will set tags in the supplied image.
24              
25             =cut
26             */
27              
28             typedef enum tiff_type_tag {
29             tt_intel = 'I',
30             tt_motorola = 'M'
31             } tiff_type;
32              
33             typedef enum {
34             ift_byte = 1,
35             ift_ascii = 2,
36             ift_short = 3,
37             ift_long = 4,
38             ift_rational = 5,
39             ift_sbyte = 6,
40             ift_undefined = 7,
41             ift_sshort = 8,
42             ift_slong = 9,
43             ift_srational = 10,
44             ift_float = 11,
45             ift_double = 12,
46             ift_last = 12 /* keep the same as the highest type code */
47             } ifd_entry_type;
48              
49             static unsigned
50             type_sizes[] =
51             {
52             0, /* not used */
53             1, /* byte */
54             1, /* ascii */
55             2, /* short */
56             4, /* long */
57             8, /* rational */
58             1, /* sbyte */
59             1, /* undefined */
60             2, /* sshort */
61             4, /* slong */
62             8, /* srational */
63             4, /* float */
64             8, /* double */
65             };
66              
67             typedef struct {
68             int tag;
69             int type;
70             unsigned count;
71             unsigned item_size;
72             size_t size;
73             size_t offset;
74             } ifd_entry;
75              
76             typedef struct {
77             int tag;
78             char const *name;
79             } tag_map;
80              
81             typedef struct {
82             int tag;
83             char const *name;
84             tag_map const *map;
85             unsigned map_count;
86             } tag_value_map;
87              
88             #define PASTE(left, right) PASTE_(left, right)
89             #define PASTE_(left, right) left##right
90             #define QUOTE(value) #value
91              
92             #define VALUE_MAP_ENTRY(name) \
93             { \
94             PASTE(tag_, name), \
95             "exif_" QUOTE(name) "_name", \
96             PASTE(name, _values), \
97             ARRAY_COUNT(PASTE(name, _values)) \
98             }
99              
100             /* we don't process every tag */
101             #define tag_make 271
102             #define tag_model 272
103             #define tag_orientation 274
104             #define tag_x_resolution 282
105             #define tag_y_resolution 283
106             #define tag_resolution_unit 296
107             #define tag_copyright 33432
108             #define tag_software 305
109             #define tag_artist 315
110             #define tag_date_time 306
111             #define tag_image_description 270
112              
113             #define tag_exif_ifd 34665
114             #define tag_gps_ifd 34853
115              
116             #define resunit_none 1
117             #define resunit_inch 2
118             #define resunit_centimeter 3
119              
120             /* tags from the EXIF ifd */
121             #define tag_exif_version 0x9000
122             #define tag_flashpix_version 0xA000
123             #define tag_color_space 0xA001
124             #define tag_component_configuration 0x9101
125             #define tag_component_bits_per_pixel 0x9102
126             #define tag_pixel_x_dimension 0xA002
127             #define tag_pixel_y_dimension 0xA003
128             #define tag_maker_note 0x927C
129             #define tag_user_comment 0x9286
130             #define tag_related_sound_file 0xA004
131             #define tag_date_time_original 0x9003
132             #define tag_date_time_digitized 0x9004
133             #define tag_sub_sec_time 0x9290
134             #define tag_sub_sec_time_original 0x9291
135             #define tag_sub_sec_time_digitized 0x9292
136             #define tag_image_unique_id 0xA420
137             #define tag_exposure_time 0x829a
138             #define tag_f_number 0x829D
139             #define tag_exposure_program 0x8822
140             #define tag_spectral_sensitivity 0x8824
141             #define tag_iso_speed_ratings 0x8827
142             #define tag_oecf 0x8828
143             #define tag_shutter_speed 0x9201
144             #define tag_aperture 0x9202
145             #define tag_brightness 0x9203
146             #define tag_exposure_bias 0x9204
147             #define tag_max_aperture 0x9205
148             #define tag_subject_distance 0x9206
149             #define tag_metering_mode 0x9207
150             #define tag_light_source 0x9208
151             #define tag_flash 0x9209
152             #define tag_focal_length 0x920a
153             #define tag_subject_area 0x9214
154             #define tag_flash_energy 0xA20B
155             #define tag_spatial_frequency_response 0xA20C
156             #define tag_focal_plane_x_resolution 0xA20e
157             #define tag_focal_plane_y_resolution 0xA20F
158             #define tag_focal_plane_resolution_unit 0xA210
159             #define tag_subject_location 0xA214
160             #define tag_exposure_index 0xA215
161             #define tag_sensing_method 0xA217
162             #define tag_file_source 0xA300
163             #define tag_scene_type 0xA301
164             #define tag_cfa_pattern 0xA302
165             #define tag_custom_rendered 0xA401
166             #define tag_exposure_mode 0xA402
167             #define tag_white_balance 0xA403
168             #define tag_digital_zoom_ratio 0xA404
169             #define tag_focal_length_in_35mm_film 0xA405
170             #define tag_scene_capture_type 0xA406
171             #define tag_gain_control 0xA407
172             #define tag_contrast 0xA408
173             #define tag_saturation 0xA409
174             #define tag_sharpness 0xA40A
175             #define tag_device_setting_description 0xA40B
176             #define tag_subject_distance_range 0xA40C
177              
178             /* GPS tags */
179             #define tag_gps_version_id 0
180             #define tag_gps_latitude_ref 1
181             #define tag_gps_latitude 2
182             #define tag_gps_longitude_ref 3
183             #define tag_gps_longitude 4
184             #define tag_gps_altitude_ref 5
185             #define tag_gps_altitude 6
186             #define tag_gps_time_stamp 7
187             #define tag_gps_satellites 8
188             #define tag_gps_status 9
189             #define tag_gps_measure_mode 10
190             #define tag_gps_dop 11
191             #define tag_gps_speed_ref 12
192             #define tag_gps_speed 13
193             #define tag_gps_track_ref 14
194             #define tag_gps_track 15
195             #define tag_gps_img_direction_ref 16
196             #define tag_gps_img_direction 17
197             #define tag_gps_map_datum 18
198             #define tag_gps_dest_latitude_ref 19
199             #define tag_gps_dest_latitude 20
200             #define tag_gps_dest_longitude_ref 21
201             #define tag_gps_dest_longitude 22
202             #define tag_gps_dest_bearing_ref 23
203             #define tag_gps_dest_bearing 24
204             #define tag_gps_dest_distance_ref 25
205             #define tag_gps_dest_distance 26
206             #define tag_gps_processing_method 27
207             #define tag_gps_area_information 28
208             #define tag_gps_date_stamp 29
209             #define tag_gps_differential 30
210              
211             /* don't use this on pointers */
212             #define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
213              
214             /* in memory tiff structure */
215             typedef struct {
216             /* the data we use as a tiff */
217             const unsigned char *base;
218             size_t size;
219              
220             /* intel or motorola byte order */
221             tiff_type type;
222              
223             /* initial ifd offset */
224             unsigned long first_ifd_offset;
225            
226             /* size (in entries) and data */
227             unsigned ifd_size;
228             ifd_entry *ifd;
229             unsigned long next_ifd;
230             } imtiff;
231              
232             static int tiff_init(imtiff *tiff, const unsigned char *base, size_t length);
233             static int tiff_load_ifd(imtiff *tiff, unsigned long offset);
234             static void tiff_final(imtiff *tiff);
235             static void tiff_clear_ifd(imtiff *tiff);
236             #if 0 /* currently unused, but that may change */
237             static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset,
238             size_t count);
239             #endif
240             static int tiff_get_tag_double(imtiff *, unsigned index, double *result);
241             static int tiff_get_tag_int(imtiff *, unsigned index, int *result);
242             static unsigned tiff_get16(imtiff *, unsigned long offset);
243             static unsigned tiff_get32(imtiff *, unsigned long offset);
244             static int tiff_get16s(imtiff *, unsigned long offset);
245             static int tiff_get32s(imtiff *, unsigned long offset);
246             static double tiff_get_rat(imtiff *, unsigned long offset);
247             static double tiff_get_rats(imtiff *, unsigned long offset);
248             static void save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset, unsigned long *gps_ifd_offset);
249             static void save_exif_ifd_tags(i_img *im, imtiff *tiff);
250             static void save_gps_ifd_tags(i_img *im, imtiff *tiff);
251             static void
252             copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count);
253             static void
254             copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count);
255             static void
256             copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count);
257             static void
258             copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count);
259             static void
260             copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, unsigned map_count);
261             static void process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size);
262              
263             /*
264             =head1 PUBLIC FUNCTIONS
265              
266             These functions are available to other parts of Imager. They aren't
267             intended to be called from outside of Imager.
268              
269             =over
270              
271             =item im_decode_exif
272              
273             im_decode_exif(im, data_base, data_size);
274              
275             The data from C for C bytes will be scanned for
276             EXIF data.
277              
278             Any data found will be used to set tags in the supplied image.
279              
280             The intent is that invalid EXIF data will simply fail to set tags, and
281             write to the log. In no case should this code exit when supplied
282             invalid data.
283              
284             Returns true if the EXIF block was valid, this is mostly used for
285             testing, you don't need to test this in a typical file reader unless
286             you have a strict mode.
287              
288             This is a limited version of "validity", eg. IFDs are meant to be
289             sorted, which this doesn't check.
290              
291             =cut
292             */
293              
294             int
295 0           im_decode_exif(i_img *im, const unsigned char *data, size_t length) {
296             imtiff tiff;
297 0           unsigned long exif_ifd_offset = 0;
298 0           unsigned long gps_ifd_offset = 0;
299 0           int ok = 1;
300              
301 0           mm_log((2, "Exif: start parsing\n"));
302              
303 0 0         if (!tiff_init(&tiff, data, length)) {
304 0           mm_log((2, "Exif: no valid TIFF header\n"));
305 0           return 0;
306             }
307 0 0         if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) {
308 0           mm_log((2, "Exif header found, but could not load IFD 0\n"));
309 0           tiff_final(&tiff);
310 0           return 0;
311             }
312              
313 0           save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset);
314              
315 0 0         if (exif_ifd_offset) {
316 0 0         if (tiff_load_ifd(&tiff, exif_ifd_offset)) {
317 0           save_exif_ifd_tags(im, &tiff);
318             }
319             else {
320 0           mm_log((2, "Could not load Exif IFD\n"));
321 0           ok = 0;
322             }
323             }
324              
325 0 0         if (gps_ifd_offset) {
326 0 0         if (tiff_load_ifd(&tiff, gps_ifd_offset)) {
327 0           save_gps_ifd_tags(im, &tiff);
328             }
329             else {
330 0           mm_log((2, "Could not load GPS IFD\n"));
331 0           ok = 0;
332             }
333             }
334              
335 0           tiff_final(&tiff);
336              
337 0           mm_log((2, "Exif: done parsing\n"));
338              
339 0           return ok;
340             }
341              
342             /*
343              
344             =back
345              
346             =head1 INTERNAL FUNCTIONS
347              
348             =head2 EXIF Processing
349              
350             =over
351              
352             =item save_ifd0_tags
353              
354             save_ifd0_tags(im, tiff, &exif_ifd_offset, &gps_ifd_offset)
355              
356             Scans the currently loaded IFD for tags expected in IFD0 and sets them
357             in the image.
358              
359             Sets *exif_ifd_offset to the offset of the EXIF IFD if found.
360              
361             =cut
362              
363             */
364              
365             static tag_map ifd0_string_tags[] =
366             {
367             { tag_make, "exif_make" },
368             { tag_model, "exif_model" },
369             { tag_copyright, "exif_copyright" },
370             { tag_software, "exif_software" },
371             { tag_artist, "exif_artist" },
372             { tag_date_time, "exif_date_time" },
373             { tag_image_description, "exif_image_description" },
374             };
375              
376             static const unsigned
377             ifd0_string_tag_count = ARRAY_COUNT(ifd0_string_tags);
378              
379             static tag_map ifd0_int_tags[] =
380             {
381             { tag_orientation, "exif_orientation", },
382             { tag_resolution_unit, "exif_resolution_unit" },
383             };
384              
385             static const unsigned
386             ifd0_int_tag_count = ARRAY_COUNT(ifd0_int_tags);
387              
388             static tag_map ifd0_rat_tags[] =
389             {
390             { tag_x_resolution, "exif_x_resolution" },
391             { tag_y_resolution, "exif_y_resolution" },
392             };
393              
394             static tag_map resolution_unit_values[] =
395             {
396             { 1, "none" },
397             { 2, "inches" },
398             { 3, "centimeters" },
399             };
400              
401             static tag_value_map ifd0_values[] =
402             {
403             VALUE_MAP_ENTRY(resolution_unit),
404             };
405              
406             static void
407 0           save_ifd0_tags(i_img *im, imtiff *tiff, unsigned long *exif_ifd_offset,
408             unsigned long *gps_ifd_offset) {
409             unsigned tag_index;
410             int work;
411             ifd_entry *entry;
412              
413 0           for (tag_index = 0, entry = tiff->ifd;
414 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
415 0           switch (entry->tag) {
416 0           case tag_exif_ifd:
417 0 0         if (tiff_get_tag_int(tiff, tag_index, &work))
418 0           *exif_ifd_offset = work;
419 0           break;
420              
421 0           case tag_gps_ifd:
422 0 0         if (tiff_get_tag_int(tiff, tag_index, &work))
423 0           *gps_ifd_offset = work;
424 0           break;
425             }
426             }
427              
428 0           copy_string_tags(im, tiff, ifd0_string_tags, ifd0_string_tag_count);
429 0           copy_int_tags(im, tiff, ifd0_int_tags, ifd0_int_tag_count);
430 0           copy_rat_tags(im, tiff, ifd0_rat_tags, ARRAY_COUNT(ifd0_rat_tags));
431 0           copy_name_tags(im, tiff, ifd0_values, ARRAY_COUNT(ifd0_values));
432             /* copy_num_array_tags(im, tiff, ifd0_num_arrays, ARRAY_COUNT(ifd0_num_arrays)); */
433 0           }
434              
435             /*
436             =item save_exif_ifd_tags
437              
438             save_exif_ifd_tags(im, tiff)
439              
440             Scans the currently loaded IFD for the tags expected in the EXIF IFD
441             and sets them as tags in the image.
442              
443             =cut
444              
445             */
446              
447             static tag_map exif_ifd_string_tags[] =
448             {
449             { tag_exif_version, "exif_version", },
450             { tag_flashpix_version, "exif_flashpix_version", },
451             { tag_related_sound_file, "exif_related_sound_file", },
452             { tag_date_time_original, "exif_date_time_original", },
453             { tag_date_time_digitized, "exif_date_time_digitized", },
454             { tag_sub_sec_time, "exif_sub_sec_time" },
455             { tag_sub_sec_time_original, "exif_sub_sec_time_original" },
456             { tag_sub_sec_time_digitized, "exif_sub_sec_time_digitized" },
457             { tag_image_unique_id, "exif_image_unique_id" },
458             { tag_spectral_sensitivity, "exif_spectral_sensitivity" },
459             };
460              
461             static const int exif_ifd_string_tag_count = ARRAY_COUNT(exif_ifd_string_tags);
462              
463             static tag_map exif_ifd_int_tags[] =
464             {
465             { tag_color_space, "exif_color_space" },
466             { tag_exposure_program, "exif_exposure_program" },
467             { tag_metering_mode, "exif_metering_mode" },
468             { tag_light_source, "exif_light_source" },
469             { tag_flash, "exif_flash" },
470             { tag_focal_plane_resolution_unit, "exif_focal_plane_resolution_unit" },
471             { tag_subject_location, "exif_subject_location" },
472             { tag_sensing_method, "exif_sensing_method" },
473             { tag_custom_rendered, "exif_custom_rendered" },
474             { tag_exposure_mode, "exif_exposure_mode" },
475             { tag_white_balance, "exif_white_balance" },
476             { tag_focal_length_in_35mm_film, "exif_focal_length_in_35mm_film" },
477             { tag_scene_capture_type, "exif_scene_capture_type" },
478             { tag_contrast, "exif_contrast" },
479             { tag_saturation, "exif_saturation" },
480             { tag_sharpness, "exif_sharpness" },
481             { tag_subject_distance_range, "exif_subject_distance_range" },
482             };
483              
484              
485             static const int exif_ifd_int_tag_count = ARRAY_COUNT(exif_ifd_int_tags);
486              
487             static tag_map exif_ifd_rat_tags[] =
488             {
489             { tag_exposure_time, "exif_exposure_time" },
490             { tag_f_number, "exif_f_number" },
491             { tag_shutter_speed, "exif_shutter_speed" },
492             { tag_aperture, "exif_aperture" },
493             { tag_brightness, "exif_brightness" },
494             { tag_exposure_bias, "exif_exposure_bias" },
495             { tag_max_aperture, "exif_max_aperture" },
496             { tag_subject_distance, "exif_subject_distance" },
497             { tag_focal_length, "exif_focal_length" },
498             { tag_flash_energy, "exif_flash_energy" },
499             { tag_focal_plane_x_resolution, "exif_focal_plane_x_resolution" },
500             { tag_focal_plane_y_resolution, "exif_focal_plane_y_resolution" },
501             { tag_exposure_index, "exif_exposure_index" },
502             { tag_digital_zoom_ratio, "exif_digital_zoom_ratio" },
503             { tag_gain_control, "exif_gain_control" },
504             };
505              
506             static const int exif_ifd_rat_tag_count = ARRAY_COUNT(exif_ifd_rat_tags);
507              
508             static tag_map exposure_mode_values[] =
509             {
510             { 0, "Auto exposure" },
511             { 1, "Manual exposure" },
512             { 2, "Auto bracket" },
513             };
514             static tag_map color_space_values[] =
515             {
516             { 1, "sRGB" },
517             { 0xFFFF, "Uncalibrated" },
518             };
519              
520             static tag_map exposure_program_values[] =
521             {
522             { 0, "Not defined" },
523             { 1, "Manual" },
524             { 2, "Normal program" },
525             { 3, "Aperture priority" },
526             { 4, "Shutter priority" },
527             { 5, "Creative program" },
528             { 6, "Action program" },
529             { 7, "Portrait mode" },
530             { 8, "Landscape mode" },
531             };
532              
533             static tag_map metering_mode_values[] =
534             {
535             { 0, "unknown" },
536             { 1, "Average" },
537             { 2, "CenterWeightedAverage" },
538             { 3, "Spot" },
539             { 4, "MultiSpot" },
540             { 5, "Pattern" },
541             { 6, "Partial" },
542             { 255, "other" },
543             };
544              
545             static tag_map light_source_values[] =
546             {
547             { 0, "unknown" },
548             { 1, "Daylight" },
549             { 2, "Fluorescent" },
550             { 3, "Tungsten (incandescent light)" },
551             { 4, "Flash" },
552             { 9, "Fine weather" },
553             { 10, "Cloudy weather" },
554             { 11, "Shade" },
555             { 12, "Daylight fluorescent (D 5700 \xD0 7100K)" },
556             { 13, "Day white fluorescent (N 4600 \xD0 5400K)" },
557             { 14, "Cool white fluorescent (W 3900 \xD0 4500K)" },
558             { 15, "White fluorescent (WW 3200 \xD0 3700K)" },
559             { 17, "Standard light A" },
560             { 18, "Standard light B" },
561             { 19, "Standard light C" },
562             { 20, "D55" },
563             { 21, "D65" },
564             { 22, "D75" },
565             { 23, "D50" },
566             { 24, "ISO studio tungsten" },
567             { 255, "other light source" },
568             };
569              
570             static tag_map flash_values[] =
571             {
572             { 0x0000, "Flash did not fire." },
573             { 0x0001, "Flash fired." },
574             { 0x0005, "Strobe return light not detected." },
575             { 0x0007, "Strobe return light detected." },
576             { 0x0009, "Flash fired, compulsory flash mode" },
577             { 0x000D, "Flash fired, compulsory flash mode, return light not detected" },
578             { 0x000F, "Flash fired, compulsory flash mode, return light detected" },
579             { 0x0010, "Flash did not fire, compulsory flash mode" },
580             { 0x0018, "Flash did not fire, auto mode" },
581             { 0x0019, "Flash fired, auto mode" },
582             { 0x001D, "Flash fired, auto mode, return light not detected" },
583             { 0x001F, "Flash fired, auto mode, return light detected" },
584             { 0x0020, "No flash function" },
585             { 0x0041, "Flash fired, red-eye reduction mode" },
586             { 0x0045, "Flash fired, red-eye reduction mode, return light not detected" },
587             { 0x0047, "Flash fired, red-eye reduction mode, return light detected" },
588             { 0x0049, "Flash fired, compulsory flash mode, red-eye reduction mode" },
589             { 0x004D, "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected" },
590             { 0x004F, "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected" },
591             { 0x0059, "Flash fired, auto mode, red-eye reduction mode" },
592             { 0x005D, "Flash fired, auto mode, return light not detected, red-eye reduction mode" },
593             { 0x005F, "Flash fired, auto mode, return light detected, red-eye reduction mode" },
594             };
595              
596             static tag_map sensing_method_values[] =
597             {
598             { 1, "Not defined" },
599             { 2, "One-chip color area sensor" },
600             { 3, "Two-chip color area sensor" },
601             { 4, "Three-chip color area sensor" },
602             { 5, "Color sequential area sensor" },
603             { 7, "Trilinear sensor" },
604             { 8, "Color sequential linear sensor" },
605             };
606              
607             static tag_map custom_rendered_values[] =
608             {
609             { 0, "Normal process" },
610             { 1, "Custom process" },
611             };
612              
613             static tag_map white_balance_values[] =
614             {
615             { 0, "Auto white balance" },
616             { 1, "Manual white balance" },
617             };
618              
619             static tag_map scene_capture_type_values[] =
620             {
621             { 0, "Standard" },
622             { 1, "Landscape" },
623             { 2, "Portrait" },
624             { 3, "Night scene" },
625             };
626              
627             static tag_map gain_control_values[] =
628             {
629             { 0, "None" },
630             { 1, "Low gain up" },
631             { 2, "High gain up" },
632             { 3, "Low gain down" },
633             { 4, "High gain down" },
634             };
635              
636             static tag_map contrast_values[] =
637             {
638             { 0, "Normal" },
639             { 1, "Soft" },
640             { 2, "Hard" },
641             };
642              
643             static tag_map saturation_values[] =
644             {
645             { 0, "Normal" },
646             { 1, "Low saturation" },
647             { 2, "High saturation" },
648             };
649              
650             static tag_map sharpness_values[] =
651             {
652             { 0, "Normal" },
653             { 1, "Soft" },
654             { 2, "Hard" },
655             };
656              
657             static tag_map subject_distance_range_values[] =
658             {
659             { 0, "unknown" },
660             { 1, "Macro" },
661             { 2, "Close view" },
662             { 3, "Distant view" },
663             };
664              
665             #define focal_plane_resolution_unit_values resolution_unit_values
666              
667             static tag_value_map exif_ifd_values[] =
668             {
669             VALUE_MAP_ENTRY(exposure_mode),
670             VALUE_MAP_ENTRY(color_space),
671             VALUE_MAP_ENTRY(exposure_program),
672             VALUE_MAP_ENTRY(metering_mode),
673             VALUE_MAP_ENTRY(light_source),
674             VALUE_MAP_ENTRY(flash),
675             VALUE_MAP_ENTRY(sensing_method),
676             VALUE_MAP_ENTRY(custom_rendered),
677             VALUE_MAP_ENTRY(white_balance),
678             VALUE_MAP_ENTRY(scene_capture_type),
679             VALUE_MAP_ENTRY(gain_control),
680             VALUE_MAP_ENTRY(contrast),
681             VALUE_MAP_ENTRY(saturation),
682             VALUE_MAP_ENTRY(sharpness),
683             VALUE_MAP_ENTRY(subject_distance_range),
684             VALUE_MAP_ENTRY(focal_plane_resolution_unit),
685             };
686              
687             static tag_map exif_num_arrays[] =
688             {
689             { tag_iso_speed_ratings, "exif_iso_speed_ratings" },
690             { tag_subject_area, "exif_subject_area" },
691             { tag_subject_location, "exif_subject_location" },
692             };
693              
694             static void
695 0           save_exif_ifd_tags(i_img *im, imtiff *tiff) {
696             unsigned i, tag_index;
697             ifd_entry *entry;
698             char *user_comment;
699 0           unsigned long maker_note_offset = 0;
700 0           size_t maker_note_size = 0;
701              
702 0           for (tag_index = 0, entry = tiff->ifd;
703 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
704 0           switch (entry->tag) {
705 0           case tag_user_comment:
706             /* I don't want to trash the source, so work on a copy */
707 0           user_comment = mymalloc(entry->size);
708 0           memcpy(user_comment, tiff->base + entry->offset, entry->size);
709             /* the first 8 bytes indicate the encoding, make them into spaces
710             for better presentation */
711 0 0         for (i = 0; i < entry->size && i < 8; ++i) {
    0          
712 0 0         if (user_comment[i] == '\0')
713 0           user_comment[i] = ' ';
714             }
715             /* find the actual end of the string */
716 0 0         while (i < entry->size && user_comment[i])
    0          
717 0           ++i;
718 0           i_tags_set(&im->tags, "exif_user_comment", user_comment, i);
719 0           myfree(user_comment);
720 0           break;
721              
722 0           case tag_maker_note:
723 0           maker_note_offset = entry->offset;
724 0           maker_note_size = entry->size;
725 0           break;
726              
727             /* the following aren't processed yet */
728 0           case tag_oecf:
729             case tag_spatial_frequency_response:
730             case tag_file_source:
731             case tag_scene_type:
732             case tag_cfa_pattern:
733             case tag_device_setting_description:
734             case tag_subject_area:
735 0           break;
736             }
737             }
738              
739 0           copy_string_tags(im, tiff, exif_ifd_string_tags, exif_ifd_string_tag_count);
740 0           copy_int_tags(im, tiff, exif_ifd_int_tags, exif_ifd_int_tag_count);
741 0           copy_rat_tags(im, tiff, exif_ifd_rat_tags, exif_ifd_rat_tag_count);
742 0           copy_name_tags(im, tiff, exif_ifd_values, ARRAY_COUNT(exif_ifd_values));
743 0           copy_num_array_tags(im, tiff, exif_num_arrays, ARRAY_COUNT(exif_num_arrays));
744              
745             /* This trashes the IFD - make sure it's done last */
746 0 0         if (maker_note_offset) {
747 0           process_maker_note(im, tiff, maker_note_offset, maker_note_size);
748             }
749 0           }
750              
751             static tag_map gps_ifd_string_tags[] =
752             {
753             { tag_gps_version_id, "exif_gps_version_id" },
754             { tag_gps_latitude_ref, "exif_gps_latitude_ref" },
755             { tag_gps_longitude_ref, "exif_gps_longitude_ref" },
756             { tag_gps_altitude_ref, "exif_gps_altitude_ref" },
757             { tag_gps_satellites, "exif_gps_satellites" },
758             { tag_gps_status, "exif_gps_status" },
759             { tag_gps_measure_mode, "exif_gps_measure_mode" },
760             { tag_gps_speed_ref, "exif_gps_speed_ref" },
761             { tag_gps_track_ref, "exif_gps_track_ref" },
762             };
763              
764             static tag_map gps_ifd_int_tags[] =
765             {
766             { tag_gps_differential, "exif_gps_differential" },
767             };
768              
769             static tag_map gps_ifd_rat_tags[] =
770             {
771             { tag_gps_altitude, "exif_gps_altitude" },
772             { tag_gps_time_stamp, "exif_gps_time_stamp" },
773             { tag_gps_dop, "exif_gps_dop" },
774             { tag_gps_speed, "exif_gps_speed" },
775             { tag_gps_track, "exif_track" }
776             };
777              
778             static tag_map gps_differential_values [] =
779             {
780             { 0, "without differential correction" },
781             { 1, "Differential correction applied" },
782             };
783              
784             static tag_value_map gps_ifd_values[] =
785             {
786             VALUE_MAP_ENTRY(gps_differential),
787             };
788              
789             static tag_map gps_num_arrays[] =
790             {
791             { tag_gps_latitude, "exif_gps_latitude" },
792             { tag_gps_longitude, "exif_gps_longitude" },
793             };
794              
795             static void
796 0           save_gps_ifd_tags(i_img *im, imtiff *tiff) {
797             /* int i, tag_index;
798             int work;
799             ifd_entry *entry; */
800              
801             /* for (tag_index = 0, entry = tiff->ifd;
802             tag_index < tiff->ifd_size; ++tag_index, ++entry) {
803             switch (entry->tag) {
804             break;
805             }
806             }*/
807              
808 0           copy_string_tags(im, tiff, gps_ifd_string_tags,
809             ARRAY_COUNT(gps_ifd_string_tags));
810 0           copy_int_tags(im, tiff, gps_ifd_int_tags, ARRAY_COUNT(gps_ifd_int_tags));
811 0           copy_rat_tags(im, tiff, gps_ifd_rat_tags, ARRAY_COUNT(gps_ifd_rat_tags));
812 0           copy_name_tags(im, tiff, gps_ifd_values, ARRAY_COUNT(gps_ifd_values));
813 0           copy_num_array_tags(im, tiff, gps_num_arrays, ARRAY_COUNT(gps_num_arrays));
814 0           }
815              
816             /*
817             =item process_maker_note
818              
819             This is a stub for processing the maker note tag.
820              
821             Maker notes aren't covered by EXIF itself and in general aren't
822             documented by the manufacturers.
823              
824             =cut
825             */
826              
827             static void
828 0           process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size) {
829             /* this will be added in a future release */
830             (void)im;
831             (void)tiff;
832             (void)offset;
833             (void)size;
834 0           }
835              
836             /*
837             =back
838              
839             =head2 High level TIFF functions
840              
841             To avoid relying upon tifflib when we're not processing an image we
842             have some simple in-memory TIFF file management.
843              
844             =over
845              
846             =item tiff_init
847              
848             imtiff tiff;
849             if (tiff_init(tiff, data_base, data_size)) {
850             // success
851             }
852              
853             Initialize the tiff data structure.
854              
855             Scans for the byte order and version markers, and stores the offset to
856             the first IFD (IFD0 in EXIF) in first_ifd_offset.
857              
858             =cut
859             */
860              
861             static int
862 0           tiff_init(imtiff *tiff, const unsigned char *data, size_t length) {
863             int version;
864              
865 0           tiff->base = data;
866 0           tiff->size = length;
867 0 0         if (length < 8) /* well... would have to be much bigger to be useful */
868 0           return 0;
869 0 0         if (data[0] == 'M' && data[1] == 'M')
    0          
870 0           tiff->type = tt_motorola;
871 0 0         else if (data[0] == 'I' && data[1] == 'I')
    0          
872 0           tiff->type = tt_intel;
873             else
874 0           return 0; /* invalid header */
875              
876 0           version = tiff_get16(tiff, 2);
877 0 0         if (version != 42)
878 0           return 0;
879              
880 0           tiff->first_ifd_offset = tiff_get32(tiff, 4);
881 0 0         if (tiff->first_ifd_offset > length || tiff->first_ifd_offset < 8)
    0          
882 0           return 0;
883              
884 0           tiff->ifd_size = 0;
885 0           tiff->ifd = NULL;
886 0           tiff->next_ifd = 0;
887              
888 0           return 1;
889             }
890              
891             /*
892             =item tiff_final
893              
894             tiff_final(&tiff)
895              
896             Clean up the tiff structure initialized by tiff_init()
897              
898             =cut
899             */
900              
901             static void
902 0           tiff_final(imtiff *tiff) {
903 0           tiff_clear_ifd(tiff);
904 0           }
905              
906             /*
907             =item tiff_load_ifd
908              
909             if (tiff_load_ifd(tiff, offset)) {
910             // process the ifd
911             }
912              
913             Loads the IFD from the given offset into the tiff objects ifd.
914              
915             This can fail if the IFD extends beyond end of file, or if any data
916             offsets combined with their sizes, extends beyond end of file.
917              
918             Returns true on success.
919              
920             =cut
921             */
922              
923             static int
924 0           tiff_load_ifd(imtiff *tiff, unsigned long offset) {
925             unsigned count;
926             unsigned ifd_size;
927             unsigned long ifd_end;
928 0           ifd_entry *entries = NULL;
929             unsigned i;
930             unsigned long base;
931              
932 0           tiff_clear_ifd(tiff);
933              
934             /* rough check count + 1 entry + next offset */
935 0 0         if (offset + (2+12+4) > tiff->size) {
936 0           mm_log((2, "Exif: IFD start offset %lu beyond end of Exif block", offset));
937 0           return 0;
938             }
939              
940 0           count = tiff_get16(tiff, offset);
941            
942             /* check we can fit the whole thing */
943 0           ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */
944 0           ifd_end = offset + ifd_size;
945 0 0         if (ifd_end > tiff->size) {
946 0           mm_log((2, "Exif: IFD end offset %lu beyond end of Exif block", ifd_end));
947 0           return 0;
948             }
949              
950 0           entries = mymalloc(count * sizeof(ifd_entry));
951 0           memset(entries, 0, count * sizeof(ifd_entry));
952 0           base = offset + 2;
953 0 0         for (i = 0; i < count; ++i) {
954 0           ifd_entry *entry = entries + i;
955 0           entry->tag = tiff_get16(tiff, base);
956 0           entry->type = tiff_get16(tiff, base+2);
957 0           entry->count = tiff_get32(tiff, base+4);
958 0 0         if (entry->type >= 1 && entry->type <= ift_last) {
    0          
959 0           entry->item_size = type_sizes[entry->type];
960 0           entry->size = entry->item_size * entry->count;
961 0 0         if (entry->size / entry->item_size != entry->count) {
962 0           myfree(entries);
963 0           mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n"));
964 0           return 0;
965             }
966 0 0         else if (entry->size <= 4) {
967 0           entry->offset = base + 8;
968             }
969             else {
970 0           entry->offset = tiff_get32(tiff, base+8);
971 0 0         if (entry->offset + entry->size > tiff->size) {
972 0           mm_log((2, "Invalid data offset processing IFD\n"));
973 0           myfree(entries);
974 0           return 0;
975             }
976             }
977             }
978             else {
979 0           entry->size = 0;
980 0           entry->offset = 0;
981             }
982 0           base += 12;
983             }
984              
985 0           tiff->ifd_size = count;
986 0           tiff->ifd = entries;
987 0           tiff->next_ifd = tiff_get32(tiff, base);
988              
989 0           return 1;
990             }
991              
992             /*
993             =item tiff_clear_ifd
994              
995             tiff_clear_ifd(tiff)
996              
997             Releases any memory associated with the stored IFD and resets the IFD
998             pointers.
999              
1000             This is called by tiff_load_ifd() and tiff_final().
1001              
1002             =cut
1003             */
1004              
1005             static void
1006 0           tiff_clear_ifd(imtiff *tiff) {
1007 0 0         if (tiff->ifd_size && tiff->ifd) {
    0          
1008 0           myfree(tiff->ifd);
1009 0           tiff->ifd_size = 0;
1010 0           tiff->ifd = NULL;
1011             }
1012 0           }
1013              
1014             /*
1015             =item tiff_get_tag_double
1016              
1017             double value;
1018             if (tiff_get_tag(tiff, index, &value)) {
1019             // process value
1020             }
1021              
1022             Attempts to retrieve a double value from the given index in the
1023             current IFD.
1024              
1025             The value must have a count of 1.
1026              
1027             =cut
1028             */
1029              
1030             static int
1031 0           tiff_get_tag_double_array(imtiff *tiff, unsigned index, double *result,
1032             unsigned array_index) {
1033             ifd_entry *entry;
1034             unsigned long offset;
1035 0 0         if (index >= tiff->ifd_size) {
1036 0           mm_log((3, "tiff_get_tag_double_array() tag index %u out of range", index));
1037 0           return 0;
1038             }
1039            
1040 0           entry = tiff->ifd + index;
1041 0 0         if (array_index >= entry->count) {
1042 0           mm_log((3, "tiff_get_tag_double_array() array index %u out of range", array_index));
1043 0           return 0;
1044             }
1045              
1046 0           offset = entry->offset + array_index * entry->item_size;
1047              
1048 0           switch (entry->type) {
1049 0           case ift_short:
1050 0           *result = tiff_get16(tiff, offset);
1051 0           return 1;
1052            
1053 0           case ift_long:
1054 0           *result = tiff_get32(tiff, offset);
1055 0           return 1;
1056              
1057 0           case ift_rational:
1058 0           *result = tiff_get_rat(tiff, offset);
1059 0           return 1;
1060              
1061 0           case ift_sshort:
1062 0           *result = tiff_get16s(tiff, offset);
1063 0           return 1;
1064              
1065 0           case ift_slong:
1066 0           *result = tiff_get32s(tiff, offset);
1067 0           return 1;
1068              
1069 0           case ift_srational:
1070 0           *result = tiff_get_rats(tiff, offset);
1071 0           return 1;
1072              
1073 0           case ift_byte:
1074 0           *result = *(tiff->base + offset);
1075 0           return 1;
1076             }
1077              
1078 0           return 0;
1079             }
1080              
1081             /*
1082             =item tiff_get_tag_double
1083              
1084             double value;
1085             if (tiff_get_tag(tiff, index, &value)) {
1086             // process value
1087             }
1088              
1089             Attempts to retrieve a double value from the given index in the
1090             current IFD.
1091              
1092             The value must have a count of 1.
1093              
1094             =cut
1095             */
1096              
1097             static int
1098 0           tiff_get_tag_double(imtiff *tiff, unsigned index, double *result) {
1099             ifd_entry *entry;
1100 0 0         if (index >= tiff->ifd_size) {
1101 0           mm_log((3, "tiff_get_tag_double() index %u out of range", index));
1102 0           return 0;
1103             }
1104            
1105 0           entry = tiff->ifd + index;
1106 0 0         if (entry->count != 1) {
1107 0           mm_log((3, "tiff_get_tag_double() called on tag with multiple values"));
1108 0           return 0;
1109             }
1110              
1111 0           return tiff_get_tag_double_array(tiff, index, result, 0);
1112             }
1113              
1114             /*
1115             =item tiff_get_tag_int_array
1116              
1117             int value;
1118             if (tiff_get_tag_int_array(tiff, index, &value, array_index)) {
1119             // process value
1120             }
1121              
1122             Attempts to retrieve an integer value from the given index in the
1123             current IFD.
1124              
1125             =cut
1126             */
1127              
1128             static int
1129 0           tiff_get_tag_int_array(imtiff *tiff, unsigned index, int *result, unsigned array_index) {
1130             ifd_entry *entry;
1131             unsigned long offset;
1132 0 0         if (index >= tiff->ifd_size) {
1133 0           mm_log((3, "tiff_get_tag_int_array() tag index %u out of range", index));
1134 0           return 0;
1135             }
1136            
1137 0           entry = tiff->ifd + index;
1138 0 0         if (array_index >= entry->count) {
1139 0           mm_log((3, "tiff_get_tag_int_array() array index %u out of range", array_index));
1140 0           return 0;
1141             }
1142              
1143 0           offset = entry->offset + array_index * entry->item_size;
1144              
1145 0           switch (entry->type) {
1146 0           case ift_short:
1147 0           *result = tiff_get16(tiff, offset);
1148 0           return 1;
1149            
1150 0           case ift_long:
1151 0           *result = tiff_get32(tiff, offset);
1152 0           return 1;
1153              
1154 0           case ift_sshort:
1155 0           *result = tiff_get16s(tiff, offset);
1156 0           return 1;
1157              
1158 0           case ift_slong:
1159 0           *result = tiff_get32s(tiff, offset);
1160 0           return 1;
1161              
1162 0           case ift_byte:
1163 0           *result = *(tiff->base + offset);
1164 0           return 1;
1165             }
1166              
1167 0           return 0;
1168             }
1169              
1170             /*
1171             =item tiff_get_tag_int
1172              
1173             int value;
1174             if (tiff_get_tag_int(tiff, index, &value)) {
1175             // process value
1176             }
1177              
1178             Attempts to retrieve an integer value from the given index in the
1179             current IFD.
1180              
1181             The value must have a count of 1.
1182              
1183             =cut
1184             */
1185              
1186             static int
1187 0           tiff_get_tag_int(imtiff *tiff, unsigned index, int *result) {
1188             ifd_entry *entry;
1189 0 0         if (index >= tiff->ifd_size) {
1190 0           mm_log((3, "tiff_get_tag_int() index %u out of range", index));
1191 0           return 0;
1192             }
1193              
1194 0           entry = tiff->ifd + index;
1195 0 0         if (entry->count != 1) {
1196 0           mm_log((3, "tiff_get_tag_int() called on tag with multiple values"));
1197 0           return 0;
1198             }
1199              
1200 0           return tiff_get_tag_int_array(tiff, index, result, 0);
1201             }
1202              
1203             /*
1204             =back
1205              
1206             =head2 Table-based tag setters
1207              
1208             This set of functions checks for matches between the current IFD and
1209             tags supplied in an array, when there's a match it sets the
1210             appropriate tag in the image.
1211              
1212             =over
1213              
1214             =item copy_int_tags
1215              
1216             Scans the IFD for integer tags and sets them in the image,
1217              
1218             =cut
1219             */
1220              
1221             static void
1222 0           copy_int_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count) {
1223             unsigned i, tag_index;
1224             ifd_entry *entry;
1225              
1226 0           for (tag_index = 0, entry = tiff->ifd;
1227 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1228 0 0         for (i = 0; i < map_count; ++i) {
1229             int value;
1230 0 0         if (map[i].tag == entry->tag
1231 0 0         && tiff_get_tag_int(tiff, tag_index, &value)) {
1232 0           i_tags_setn(&im->tags, map[i].name, value);
1233 0           break;
1234             }
1235             }
1236             }
1237 0           }
1238              
1239             /*
1240             =item copy_rat_tags
1241              
1242             Scans the IFD for rational tags and sets them in the image.
1243              
1244             =cut
1245             */
1246              
1247             static void
1248 0           copy_rat_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count) {
1249             unsigned i, tag_index;
1250             ifd_entry *entry;
1251              
1252 0           for (tag_index = 0, entry = tiff->ifd;
1253 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1254 0 0         for (i = 0; i < map_count; ++i) {
1255             double value;
1256 0 0         if (map[i].tag == entry->tag
1257 0 0         && tiff_get_tag_double(tiff, tag_index, &value)) {
1258 0           i_tags_set_float2(&im->tags, map[i].name, 0, value, 6);
1259 0           break;
1260             }
1261             }
1262             }
1263 0           }
1264              
1265             /*
1266             =item copy_string_tags
1267              
1268             Scans the IFD for string tags and sets them in the image.
1269              
1270             =cut
1271             */
1272              
1273             static void
1274 0           copy_string_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count) {
1275             unsigned i, tag_index;
1276             ifd_entry *entry;
1277              
1278 0           for (tag_index = 0, entry = tiff->ifd;
1279 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1280 0 0         for (i = 0; i < map_count; ++i) {
1281 0 0         if (map[i].tag == entry->tag) {
1282 0 0         int len = entry->type == ift_ascii ? entry->size - 1 : entry->size;
1283 0           i_tags_set(&im->tags, map[i].name,
1284 0           (char const *)(tiff->base + entry->offset), len);
1285 0           break;
1286             }
1287             }
1288             }
1289 0           }
1290              
1291             /*
1292             =item copy_num_array_tags
1293              
1294             Scans the IFD for arrays of numbers and sets them in the image.
1295              
1296             =cut
1297             */
1298              
1299             /* a more general solution would be better in some ways, but we don't need it */
1300             #define MAX_ARRAY_VALUES 10
1301             #define MAX_ARRAY_STRING (MAX_ARRAY_VALUES * 20)
1302              
1303             static void
1304 0           copy_num_array_tags(i_img *im, imtiff *tiff, tag_map *map, unsigned map_count) {
1305             unsigned i, j, tag_index;
1306             ifd_entry *entry;
1307              
1308 0           for (tag_index = 0, entry = tiff->ifd;
1309 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1310 0 0         for (i = 0; i < map_count; ++i) {
1311 0 0         if (map[i].tag == entry->tag) {
1312 0 0         if (entry->count <= MAX_ARRAY_VALUES) {
1313 0 0         if (entry->type == ift_rational || entry->type == ift_srational) {
    0          
1314             double value;
1315             char workstr[MAX_ARRAY_STRING];
1316 0           size_t len = 0, item_len;
1317 0           *workstr = '\0';
1318 0 0         for (j = 0; j < entry->count; ++j) {
1319 0 0         if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) {
1320 0           mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j));
1321 0           return;
1322             }
1323 0 0         if (len >= sizeof(workstr) - 1) {
1324 0           mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1325 0           return;
1326             }
1327 0 0         if (j) {
1328 0           strcat(workstr, " ");
1329 0           ++len;
1330             }
1331             #ifdef IMAGER_SNPRINTF
1332 0           item_len = snprintf(workstr + len, sizeof(workstr)-len, "%.6g", value);
1333             #else
1334             item_len = sprintf(workstr + len, "%.6g", value);
1335             #endif
1336 0           len += item_len;
1337             }
1338 0           i_tags_set(&im->tags, map[i].name, workstr, -1);
1339             }
1340 0 0         else if (entry->type == ift_short || entry->type == ift_long
    0          
1341 0 0         || entry->type == ift_sshort || entry->type == ift_slong
    0          
1342 0 0         || entry->type == ift_byte) {
1343             int value;
1344             char workstr[MAX_ARRAY_STRING];
1345 0           size_t len = 0, item_len;
1346 0           *workstr = '\0';
1347 0 0         for (j = 0; j < entry->count; ++j) {
1348 0 0         if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) {
1349 0           mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j));
1350 0           return;
1351             }
1352 0 0         if (len >= sizeof(workstr) - 1) {
1353 0           mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1354 0           return;
1355             }
1356 0 0         if (j) {
1357 0           strcat(workstr, " ");
1358 0           ++len;
1359             }
1360             #ifdef IMAGER_SNPRINTF
1361 0           item_len = snprintf(workstr + len, sizeof(workstr) - len, "%d", value);
1362             #else
1363             item_len = sprintf(workstr + len, "%d", value);
1364             #endif
1365 0           len += item_len;
1366             }
1367 0           i_tags_set(&im->tags, map[i].name, workstr, -1);
1368             }
1369 0           break;
1370             }
1371             else {
1372 0           mm_log((2, "Exif: array for %s has too many entries %u, skipping\n",
1373             map[i].name, entry->count));
1374             }
1375             }
1376             }
1377             }
1378             }
1379              
1380             /*
1381             =item copy_name_tags
1382              
1383             This function maps integer values to descriptions for those values.
1384              
1385             In general we handle the integer value through copy_int_tags() and
1386             then the same tage with a "_name" suffix here.
1387              
1388             =cut
1389             */
1390              
1391             static void
1392 0           copy_name_tags(i_img *im, imtiff *tiff, tag_value_map *map, unsigned map_count) {
1393             unsigned i, j, tag_index;
1394             ifd_entry *entry;
1395              
1396 0           for (tag_index = 0, entry = tiff->ifd;
1397 0 0         tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1398 0 0         for (i = 0; i < map_count; ++i) {
1399             int value;
1400 0 0         if (map[i].tag == entry->tag
1401 0 0         && tiff_get_tag_int(tiff, tag_index, &value)) {
1402 0           tag_map const *found = NULL;
1403 0 0         for (j = 0; j < map[i].map_count; ++j) {
1404 0 0         if (value == map[i].map[j].tag) {
1405 0           found = map[i].map + j;
1406 0           break;
1407             }
1408             }
1409 0 0         if (found) {
1410 0           i_tags_set(&im->tags, map[i].name, found->name, -1);
1411             }
1412 0           break;
1413             }
1414             }
1415             }
1416 0           }
1417              
1418              
1419             /*
1420             =back
1421              
1422             =head2 Low level data access functions
1423              
1424             These functions use the byte order in the tiff object to extract
1425             various types of data from the tiff data.
1426              
1427             These functions will abort if called with an out of range offset.
1428              
1429             The intent is that any offset checks should have been done by the caller.
1430              
1431             =over
1432              
1433             =item tiff_get16
1434              
1435             Retrieve a 16 bit unsigned integer from offset.
1436              
1437             =cut
1438             */
1439              
1440             static unsigned
1441 0           tiff_get16(imtiff *tiff, unsigned long offset) {
1442 0 0         if (offset + 2 > tiff->size) {
1443 0           mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1444             (unsigned long)tiff->size));
1445 0           return 0;
1446             }
1447              
1448 0 0         if (tiff->type == tt_intel)
1449 0           return tiff->base[offset] + 0x100 * tiff->base[offset+1];
1450             else
1451 0           return tiff->base[offset+1] + 0x100 * tiff->base[offset];
1452             }
1453              
1454             /*
1455             =item tiff_get32
1456              
1457             Retrieve a 32-bit unsigned integer from offset.
1458              
1459             =cut
1460             */
1461              
1462             static unsigned
1463 0           tiff_get32(imtiff *tiff, unsigned long offset) {
1464 0 0         if (offset + 4 > tiff->size) {
1465 0           mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1466             (unsigned long)tiff->size));
1467 0           return 0;
1468             }
1469              
1470 0 0         if (tiff->type == tt_intel)
1471 0           return tiff->base[offset] + 0x100 * tiff->base[offset+1]
1472 0           + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1473             else
1474 0           return tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1475 0           + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1476             }
1477              
1478             #if 0 /* currently unused, but that may change */
1479              
1480             /*
1481             =item tiff_get_bytes
1482              
1483             Retrieve a byte string from offset.
1484              
1485             This isn't used much, you can usually deal with the data in-situ.
1486             This is intended for use when you need to modify the data in some way.
1487              
1488             =cut
1489             */
1490              
1491             static int
1492             tiff_get_bytes(imtiff *tiff, unsigned char *data, size_t offset,
1493             size_t size) {
1494             if (offset + size > tiff->size)
1495             return 0;
1496              
1497             memcpy(data, tiff->base+offset, size);
1498              
1499             return 1;
1500             }
1501              
1502             #endif
1503              
1504             /*
1505             =item tiff_get16s
1506              
1507             Retrieve a 16-bit signed integer from offset.
1508              
1509             =cut
1510             */
1511              
1512             static int
1513 0           tiff_get16s(imtiff *tiff, unsigned long offset) {
1514             int result;
1515              
1516 0 0         if (offset + 2 > tiff->size) {
1517 0           mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1518             (unsigned long)tiff->size));
1519 0           return 0;
1520             }
1521              
1522 0 0         if (tiff->type == tt_intel)
1523 0           result = tiff->base[offset] + 0x100 * tiff->base[offset+1];
1524             else
1525 0           result = tiff->base[offset+1] + 0x100 * tiff->base[offset];
1526              
1527 0 0         if (result > 0x7FFF)
1528 0           result -= 0x10000;
1529              
1530 0           return result;
1531             }
1532              
1533             /*
1534             =item tiff_get32s
1535              
1536             Retrieve a 32-bit signed integer from offset.
1537              
1538             =cut
1539             */
1540              
1541             static int
1542 0           tiff_get32s(imtiff *tiff, unsigned long offset) {
1543             unsigned work;
1544              
1545 0 0         if (offset + 4 > tiff->size) {
1546 0           mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1547             (unsigned long)tiff->size));
1548 0           return 0;
1549             }
1550              
1551 0 0         if (tiff->type == tt_intel)
1552 0           work = tiff->base[offset] + 0x100 * tiff->base[offset+1]
1553 0           + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1554             else
1555 0           work = tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1556 0           + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1557              
1558             /* not really needed on 32-bit int machines */
1559 0 0         if (work > 0x7FFFFFFFUL)
1560 0           return work - 0x80000000UL;
1561             else
1562 0           return work;
1563             }
1564              
1565             /*
1566             =item tiff_get_rat
1567              
1568             Retrieve an unsigned rational from offset.
1569              
1570             =cut
1571             */
1572              
1573             static double
1574 0           tiff_get_rat(imtiff *tiff, unsigned long offset) {
1575             unsigned long numer, denom;
1576 0 0         if (offset + 8 > tiff->size) {
1577 0           mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1578             (unsigned long)tiff->size));
1579 0           return 0;
1580             }
1581              
1582 0           numer = tiff_get32(tiff, offset);
1583 0           denom = tiff_get32(tiff, offset+4);
1584              
1585 0 0         if (denom == 0) {
1586 0           return -DBL_MAX;
1587             }
1588              
1589 0           return (double)numer / denom;
1590             }
1591              
1592             /*
1593             =item tiff_get_rats
1594              
1595             Retrieve an signed rational from offset.
1596              
1597             =cut
1598             */
1599              
1600             static double
1601 0           tiff_get_rats(imtiff *tiff, unsigned long offset) {
1602             long numer, denom;
1603 0 0         if (offset + 8 > tiff->size) {
1604 0           mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1605             (unsigned long)tiff->size));
1606 0           return 0;
1607             }
1608              
1609 0           numer = tiff_get32s(tiff, offset);
1610 0           denom = tiff_get32s(tiff, offset+4);
1611              
1612 0 0         if (denom == 0) {
1613 0           return -DBL_MAX;
1614             }
1615              
1616 0           return (double)numer / denom;
1617             }
1618              
1619             /*
1620             =back
1621              
1622             =head1 SEE ALSO
1623              
1624             L, jpeg.c
1625              
1626             http://www.exif.org/
1627              
1628             =head1 AUTHOR
1629              
1630             Tony Cook
1631              
1632             =cut
1633             */