most numeric parameters to the XS implementation now throw an exception if supplied...
[imager.git] / imexif.c
1 #include "imager.h"
2 #include "imexif.h"
3 #include <stdlib.h>
4 #include <float.h>
5 #include <string.h>
6 #include <stdio.h>
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   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, 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<data_base> for C<data_size> 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 im_decode_exif(i_img *im, unsigned char *data, size_t length) {
290   imtiff tiff;
291   unsigned long exif_ifd_offset = 0;
292   unsigned long gps_ifd_offset = 0;
293
294   if (!tiff_init(&tiff, data, length)) {
295     mm_log((2, "Exif header found, but no valid TIFF header\n"));
296     return 1;
297   }
298   if (!tiff_load_ifd(&tiff, tiff.first_ifd_offset)) {
299     mm_log((2, "Exif header found, but could not load IFD 0\n"));
300     tiff_final(&tiff);
301     return 1;
302   }
303
304   save_ifd0_tags(im, &tiff, &exif_ifd_offset, &gps_ifd_offset);
305
306   if (exif_ifd_offset) {
307     if (tiff_load_ifd(&tiff, exif_ifd_offset)) {
308       save_exif_ifd_tags(im, &tiff);
309     }
310     else {
311       mm_log((2, "Could not load Exif IFD\n"));
312     }
313   }
314
315   if (gps_ifd_offset) {
316     if (tiff_load_ifd(&tiff, gps_ifd_offset)) {
317       save_gps_ifd_tags(im, &tiff);
318     }
319     else {
320       mm_log((2, "Could not load GPS IFD\n"));
321     }
322   }
323
324   tiff_final(&tiff);
325
326   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 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   for (tag_index = 0, entry = tiff->ifd; 
399        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
400     switch (entry->tag) {
401     case tag_exif_ifd:
402       if (tiff_get_tag_int(tiff, tag_index, &work))
403         *exif_ifd_offset = work;
404       break;
405
406     case tag_gps_ifd:
407       if (tiff_get_tag_int(tiff, tag_index, &work))
408         *gps_ifd_offset = work;
409       break;
410     }
411   }
412
413   copy_string_tags(im, tiff, ifd0_string_tags, ifd0_string_tag_count);
414   copy_int_tags(im, tiff, ifd0_int_tags, ifd0_int_tag_count);
415   copy_rat_tags(im, tiff, ifd0_rat_tags, ARRAY_COUNT(ifd0_rat_tags));
416   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 }
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 Ð 7100K)" },
541     { 13, "Day white fluorescent (N 4600 Ð 5400K)" },
542     { 14, "Cool white fluorescent (W 3900 Ð 4500K)" },
543     { 15, "White fluorescent (WW 3200 Ð 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 save_exif_ifd_tags(i_img *im, imtiff *tiff) {
681   int i, tag_index;
682   ifd_entry *entry;
683   char *user_comment;
684   unsigned long maker_note_offset = 0;
685   size_t maker_note_size = 0;
686
687   for (tag_index = 0, entry = tiff->ifd; 
688        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
689     switch (entry->tag) {
690     case tag_user_comment:
691       /* I don't want to trash the source, so work on a copy */
692       user_comment = mymalloc(entry->size);
693       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       for (i = 0; i < entry->size && i < 8; ++i) {
697         if (user_comment[i] == '\0')
698           user_comment[i] = ' ';
699       }
700       /* find the actual end of the string */
701       while (i < entry->size && user_comment[i])
702         ++i;
703       i_tags_set(&im->tags, "exif_user_comment", user_comment, i);
704       myfree(user_comment);
705       break;
706
707     case tag_maker_note:
708       maker_note_offset = entry->offset;
709       maker_note_size = entry->size;
710       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       break;
721     }
722   }
723
724   copy_string_tags(im, tiff, exif_ifd_string_tags, exif_ifd_string_tag_count);
725   copy_int_tags(im, tiff, exif_ifd_int_tags, exif_ifd_int_tag_count);
726   copy_rat_tags(im, tiff, exif_ifd_rat_tags, exif_ifd_rat_tag_count);
727   copy_name_tags(im, tiff, exif_ifd_values, ARRAY_COUNT(exif_ifd_values));
728   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   if (maker_note_offset) {
732     process_maker_note(im, tiff, maker_note_offset, maker_note_size);
733   }
734 }
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 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   copy_string_tags(im, tiff, gps_ifd_string_tags, 
794          ARRAY_COUNT(gps_ifd_string_tags));
795   copy_int_tags(im, tiff, gps_ifd_int_tags, ARRAY_COUNT(gps_ifd_int_tags));
796   copy_rat_tags(im, tiff, gps_ifd_rat_tags, ARRAY_COUNT(gps_ifd_rat_tags));
797   copy_name_tags(im, tiff, gps_ifd_values, ARRAY_COUNT(gps_ifd_values));
798   copy_num_array_tags(im, tiff, gps_num_arrays, ARRAY_COUNT(gps_num_arrays));
799 }
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 process_maker_note(i_img *im, imtiff *tiff, unsigned long offset, size_t size) {
814   /* this will be added in a future release */
815 }
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 tiff_init(imtiff *tiff, unsigned char *data, size_t length) {
844   int version;
845
846   tiff->base = data;
847   tiff->size = length;
848   if (length < 8) /* well... would have to be much bigger to be useful */
849     return 0;
850   if (data[0] == 'M' && data[1] == 'M')
851     tiff->type = tt_motorola;
852   else if (data[0] == 'I' && data[1] == 'I') 
853     tiff->type = tt_intel;
854   else
855     return 0; /* invalid header */
856
857   version = tiff_get16(tiff, 2);
858   if (version != 42)
859     return 0;
860
861   tiff->first_ifd_offset = tiff_get32(tiff, 4);
862   if (tiff->first_ifd_offset > length || tiff->first_ifd_offset < 8)
863     return 0;
864
865   tiff->ifd_size = 0;
866   tiff->ifd = NULL;
867   tiff->next_ifd = 0;
868
869   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 tiff_final(imtiff *tiff) {
884   tiff_clear_ifd(tiff);
885 }
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 tiff_load_ifd(imtiff *tiff, unsigned long offset) {
906   unsigned count;
907   int ifd_size;
908   ifd_entry *entries = NULL;
909   int i;
910   unsigned long base;
911
912   tiff_clear_ifd(tiff);
913
914   /* rough check count + 1 entry + next offset */
915   if (offset + (2+12+4) > tiff->size) {
916     mm_log((2, "offset %lu beyond end off Exif block", offset));
917     return 0;
918   }
919
920   count = tiff_get16(tiff, offset);
921   
922   /* check we can fit the whole thing */
923   ifd_size = 2 + count * 12 + 4; /* count + count entries + next offset */
924   if (offset + ifd_size > tiff->size) {
925     mm_log((2, "offset %lu beyond end off Exif block", offset));
926     return 0;
927   }
928
929   entries = mymalloc(count * sizeof(ifd_entry));
930   memset(entries, 0, count * sizeof(ifd_entry));
931   base = offset + 2;
932   for (i = 0; i < count; ++i) {
933     ifd_entry *entry = entries + i;
934     entry->tag = tiff_get16(tiff, base);
935     entry->type = tiff_get16(tiff, base+2);
936     entry->count = tiff_get32(tiff, base+4);
937     if (entry->type >= 1 && entry->type <= ift_last) {
938       entry->item_size = type_sizes[entry->type];
939       entry->size = entry->item_size * entry->count;
940       if (entry->size / entry->item_size != entry->count) {
941         myfree(entries);
942         mm_log((1, "Integer overflow calculating tag data size processing EXIF block\n"));
943         return 0;
944       }
945       else if (entry->size <= 4) {
946         entry->offset = base + 8;
947       }
948       else {
949         entry->offset = tiff_get32(tiff, base+8);
950         if (entry->offset + entry->size > tiff->size) {
951           mm_log((2, "Invalid data offset processing IFD\n"));
952           myfree(entries);
953           return 0;
954         }
955       }
956     }
957     else {
958       entry->size = 0;
959       entry->offset = 0;
960     }
961     base += 12;
962   }
963
964   tiff->ifd_size = count;
965   tiff->ifd = entries;
966   tiff->next_ifd = tiff_get32(tiff, base);
967
968   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 tiff_clear_ifd(imtiff *tiff) {
986   if (tiff->ifd_size && tiff->ifd) {
987     myfree(tiff->ifd);
988     tiff->ifd_size = 0;
989     tiff->ifd = NULL;
990   }
991 }
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 tiff_get_tag_double_array(imtiff *tiff, int index, double *result, 
1011                           int array_index) {
1012   ifd_entry *entry;
1013   unsigned long offset;
1014   if (index < 0 || index >= tiff->ifd_size) {
1015     mm_log((3, "tiff_get_tag_double_array() tag index out of range"));
1016     return 0;
1017   }
1018   
1019   entry = tiff->ifd + index;
1020   if (array_index < 0 || array_index >= entry->count) {
1021     mm_log((3, "tiff_get_tag_double_array() array index out of range"));
1022     return 0;
1023   }
1024
1025   offset = entry->offset + array_index * entry->item_size;
1026
1027   switch (entry->type) {
1028   case ift_short:
1029     *result = tiff_get16(tiff, offset);
1030     return 1;
1031    
1032   case ift_long:
1033     *result = tiff_get32(tiff, offset);
1034     return 1;
1035
1036   case ift_rational:
1037     *result = tiff_get_rat(tiff, offset);
1038     return 1;
1039
1040   case ift_sshort:
1041     *result = tiff_get16s(tiff, offset);
1042     return 1;
1043
1044   case ift_slong:
1045     *result = tiff_get32s(tiff, offset);
1046     return 1;
1047
1048   case ift_srational:
1049     *result = tiff_get_rats(tiff, offset);
1050     return 1;
1051
1052   case ift_byte:
1053     *result = *(tiff->base + offset);
1054     return 1;
1055   }
1056
1057   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 tiff_get_tag_double(imtiff *tiff, int index, double *result) {
1078   ifd_entry *entry;
1079   if (index < 0 || index >= tiff->ifd_size) {
1080     mm_log((3, "tiff_get_tag_double() index out of range"));
1081     return 0;
1082   }
1083   
1084   entry = tiff->ifd + index;
1085   if (entry->count != 1) {
1086     mm_log((3, "tiff_get_tag_double() called on tag with multiple values"));
1087     return 0;
1088   }
1089
1090   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 tiff_get_tag_int_array(imtiff *tiff, int index, int *result, int array_index) {
1109   ifd_entry *entry;
1110   unsigned long offset;
1111   if (index < 0 || index >= tiff->ifd_size) {
1112     mm_log((3, "tiff_get_tag_int_array() tag index out of range"));
1113     return 0;
1114   }
1115   
1116   entry = tiff->ifd + index;
1117   if (array_index < 0 || array_index >= entry->count) {
1118     mm_log((3, "tiff_get_tag_int_array() array index out of range"));
1119     return 0;
1120   }
1121
1122   offset = entry->offset + array_index * entry->item_size;
1123
1124   switch (entry->type) {
1125   case ift_short:
1126     *result = tiff_get16(tiff, offset);
1127     return 1;
1128    
1129   case ift_long:
1130     *result = tiff_get32(tiff, offset);
1131     return 1;
1132
1133   case ift_sshort:
1134     *result = tiff_get16s(tiff, offset);
1135     return 1;
1136
1137   case ift_slong:
1138     *result = tiff_get32s(tiff, offset);
1139     return 1;
1140
1141   case ift_byte:
1142     *result = *(tiff->base + offset);
1143     return 1;
1144   }
1145
1146   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 tiff_get_tag_int(imtiff *tiff, int index, int *result) {
1167   ifd_entry *entry;
1168   if (index < 0 || index >= tiff->ifd_size) {
1169     mm_log((3, "tiff_get_tag_int() index out of range"));
1170     return 0;
1171   }
1172
1173   entry = tiff->ifd + index;
1174   if (entry->count != 1) {
1175     mm_log((3, "tiff_get_tag_int() called on tag with multiple values"));
1176     return 0;
1177   }
1178
1179   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 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   for (tag_index = 0, entry = tiff->ifd; 
1206        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1207     for (i = 0; i < map_count; ++i) {
1208       int value;
1209       if (map[i].tag == entry->tag
1210           && tiff_get_tag_int(tiff, tag_index, &value)) {
1211         i_tags_setn(&im->tags, map[i].name, value);
1212         break;
1213       }
1214     }
1215   }
1216 }
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 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   for (tag_index = 0, entry = tiff->ifd; 
1232        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1233     for (i = 0; i < map_count; ++i) {
1234       double value;
1235       if (map[i].tag == entry->tag
1236           && tiff_get_tag_double(tiff, tag_index, &value)) {
1237         i_tags_set_float2(&im->tags, map[i].name, 0, value, 6);
1238         break;
1239       }
1240     }
1241   }
1242 }
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 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   for (tag_index = 0, entry = tiff->ifd; 
1258        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1259     for (i = 0; i < map_count; ++i) {
1260       if (map[i].tag == entry->tag) {
1261         int len = entry->type == ift_ascii ? entry->size - 1 : entry->size;
1262         i_tags_set(&im->tags, map[i].name,
1263                    (char const *)(tiff->base + entry->offset), len);
1264         break;
1265       }
1266     }
1267   }
1268 }
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 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   for (tag_index = 0, entry = tiff->ifd; 
1288        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1289     for (i = 0; i < map_count; ++i) {
1290       if (map[i].tag == entry->tag && entry->count <= MAX_ARRAY_VALUES) {
1291         if (entry->type == ift_rational || entry->type == ift_srational) {
1292           double value;
1293           char workstr[MAX_ARRAY_STRING];
1294           size_t len = 0, item_len;
1295           *workstr = '\0';
1296           for (j = 0; j < entry->count; ++j) {
1297             if (!tiff_get_tag_double_array(tiff, tag_index, &value, j)) {
1298               mm_log((3, "unexpected failure from tiff_get_tag_double_array(..., %d, ..., %d)\n", tag_index, j));
1299               return;
1300             }
1301             if (len >= sizeof(workstr) - 1) {
1302               mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1303               return;
1304             }
1305             if (j) {
1306               strcat(workstr, " ");
1307               ++len;
1308             }
1309 #ifdef IMAGER_SNPRINTF
1310             item_len = snprintf(workstr + len, sizeof(workstr)-len, "%.6g", value);
1311 #else
1312             item_len = sprintf(workstr + len, "%.6g", value);
1313 #endif
1314             len += item_len;
1315           }
1316           i_tags_set(&im->tags, map[i].name, workstr, -1);
1317         }
1318         else if (entry->type == ift_short || entry->type == ift_long
1319                  || entry->type == ift_sshort || entry->type == ift_slong
1320                  || entry->type == ift_byte) {
1321           int value;
1322           char workstr[MAX_ARRAY_STRING];
1323           size_t len = 0, item_len;
1324           *workstr = '\0';
1325           for (j = 0; j < entry->count; ++j) {
1326             if (!tiff_get_tag_int_array(tiff, tag_index, &value, j)) {
1327               mm_log((3, "unexpected failure from tiff_get_tag_int_array(..., %d, ..., %d)\n", tag_index, j));
1328               return;
1329             }
1330             if (len >= sizeof(workstr) - 1) {
1331               mm_log((3, "Buffer would overflow reading tag %#x\n", entry->tag));
1332               return;
1333             }
1334             if (j) {
1335               strcat(workstr, " ");
1336               ++len;
1337             }
1338 #ifdef IMAGER_SNPRINTF
1339             item_len = snprintf(workstr + len, sizeof(workstr) - len, "%d", value);
1340 #else
1341             item_len = sprintf(workstr + len, "%d", value);
1342 #endif
1343             len += item_len;
1344           }
1345           i_tags_set(&im->tags, map[i].name, workstr, -1);
1346         }
1347         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 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   for (tag_index = 0, entry = tiff->ifd; 
1370        tag_index < tiff->ifd_size; ++tag_index, ++entry) {
1371     for (i = 0; i < map_count; ++i) {
1372       int value;
1373       if (map[i].tag == entry->tag
1374           && tiff_get_tag_int(tiff, tag_index, &value)) {
1375         tag_map const *found = NULL;
1376         for (j = 0; j < map[i].map_count; ++j) {
1377           if (value == map[i].map[j].tag) {
1378             found = map[i].map + j;
1379             break;
1380           }
1381         }
1382         if (found) {
1383           i_tags_set(&im->tags, map[i].name, found->name, -1);
1384         }
1385         break;
1386       }
1387     }
1388   }
1389 }
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 tiff_get16(imtiff *tiff, unsigned long offset) {
1415   if (offset + 2 > tiff->size) {
1416     mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1417             (unsigned long)tiff->size));
1418     return 0;
1419   }
1420
1421   if (tiff->type == tt_intel) 
1422     return tiff->base[offset] + 0x100 * tiff->base[offset+1];
1423   else
1424     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 tiff_get32(imtiff *tiff, unsigned long offset) {
1437   if (offset + 4 > tiff->size) {
1438     mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1439             (unsigned long)tiff->size));
1440     return 0;
1441   }
1442
1443   if (tiff->type == tt_intel) 
1444     return tiff->base[offset] + 0x100 * tiff->base[offset+1] 
1445       + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1446   else
1447     return tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1448       + 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 tiff_get16s(imtiff *tiff, unsigned long offset) {
1487   int result;
1488
1489   if (offset + 2 > tiff->size) {
1490     mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1491             (unsigned long)tiff->size));
1492     return 0;
1493   }
1494
1495   if (tiff->type == tt_intel) 
1496     result = tiff->base[offset] + 0x100 * tiff->base[offset+1];
1497   else
1498     result = tiff->base[offset+1] + 0x100 * tiff->base[offset];
1499
1500   if (result > 0x7FFF)
1501     result -= 0x10000;
1502
1503   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 tiff_get32s(imtiff *tiff, unsigned long offset) {
1516   unsigned work;
1517
1518   if (offset + 4 > tiff->size) {
1519     mm_log((3, "attempt to get16 at %lu in %lu image", offset,
1520             (unsigned long)tiff->size));
1521     return 0;
1522   }
1523
1524   if (tiff->type == tt_intel) 
1525     work = tiff->base[offset] + 0x100 * tiff->base[offset+1] 
1526       + 0x10000 * tiff->base[offset+2] + 0x1000000 * tiff->base[offset+3];
1527   else
1528     work = tiff->base[offset+3] + 0x100 * tiff->base[offset+2]
1529       + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
1530
1531   /* not really needed on 32-bit int machines */
1532   if (work > 0x7FFFFFFFUL)
1533     return work - 0x80000000UL;
1534   else
1535     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 tiff_get_rat(imtiff *tiff, unsigned long offset) {
1548   unsigned long numer, denom;
1549   if (offset + 8 > tiff->size) {
1550     mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1551             (unsigned long)tiff->size));
1552     return 0;
1553   }
1554
1555   numer = tiff_get32(tiff, offset);
1556   denom = tiff_get32(tiff, offset+4);
1557
1558   if (denom == 0) {
1559     return -DBL_MAX;
1560   }
1561
1562   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 tiff_get_rats(imtiff *tiff, unsigned long offset) {
1575   long numer, denom;
1576   if (offset + 8 > tiff->size) {
1577     mm_log((3, "attempt to get_rat at %lu in %lu image", offset,
1578             (unsigned long)tiff->size));
1579     return 0;
1580   }
1581
1582   numer = tiff_get32s(tiff, offset);
1583   denom = tiff_get32s(tiff, offset+4);
1584
1585   if (denom == 0) {
1586     return -DBL_MAX;
1587   }
1588
1589   return (double)numer / denom;
1590 }
1591
1592 /*
1593 =back
1594
1595 =head1 SEE ALSO
1596
1597 L<Imager>, jpeg.c
1598
1599 http://www.exif.org/
1600
1601 =head1 AUTHOR
1602
1603 Tony Cook <tonyc@cpan.org>
1604
1605 =head1 REVISION
1606
1607 $Revision$
1608
1609 =cut
1610 */