File Coverage

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