~ubuntu-branches/ubuntu/precise/spatialite/precise

« back to all changes in this revision

Viewing changes to libspatialite/src/gaiaexif/gaia_exif.c

  • Committer: Package Import Robot
  • Author(s): David Paleino, Francesco Paolo Lovergine, David Paleino
  • Date: 2011-11-21 12:10:43 UTC
  • mfrom: (4.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20111121121043-0g14o2uf0r343a82
Tags: 3.0.0~beta20110817-3
[ Francesco Paolo Lovergine ]
* Fixed linking order for sqlite3 in debian patch 00-systemlibs.patch.
  (closes: #638929)

[ David Paleino ]
* Conditionally disable full EPSG initialization (for srs_init.c)
  on powerpc, and document what projections are available on that
  architecture (Closes: #649302)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
 gaia_exif.c -- Gaia EXIF support
 
4
  
 
5
 version 3.0, 2011 July 20
 
6
 
 
7
 Author: Sandro Furieri a.furieri@lqt.it
 
8
 
 
9
 ------------------------------------------------------------------------------
 
10
 
 
11
 Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
12
 
 
13
 The contents of this file are subject to the Mozilla Public License Version
 
14
 1.1 (the "License"); you may not use this file except in compliance with
 
15
 the License. You may obtain a copy of the License at
 
16
 http://www.mozilla.org/MPL/
 
17
 
 
18
Software distributed under the License is distributed on an "AS IS" basis,
 
19
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
20
for the specific language governing rights and limitations under the
 
21
License.
 
22
 
 
23
The Original Code is the SpatiaLite library
 
24
 
 
25
The Initial Developer of the Original Code is Alessandro Furieri
 
26
 
 
27
Portions created by the Initial Developer are Copyright (C) 2008
 
28
the Initial Developer. All Rights Reserved.
 
29
 
 
30
Contributor(s):
 
31
 
 
32
Alternatively, the contents of this file may be used under the terms of
 
33
either the GNU General Public License Version 2 or later (the "GPL"), or
 
34
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
35
in which case the provisions of the GPL or the LGPL are applicable instead
 
36
of those above. If you wish to allow use of your version of this file only
 
37
under the terms of either the GPL or the LGPL, and not to allow others to
 
38
use your version of this file under the terms of the MPL, indicate your
 
39
decision by deleting the provisions above and replace them with the notice
 
40
and other provisions required by the GPL or the LGPL. If you do not delete
 
41
the provisions above, a recipient may use your version of this file under
 
42
the terms of any one of the MPL, the GPL or the LGPL.
 
43
 
 
44
*/
 
45
 
 
46
#include <sys/types.h>
 
47
#include <stdlib.h>
 
48
#include <stdio.h>
 
49
#include <memory.h>
 
50
#include <math.h>
 
51
#include <float.h>
 
52
#include <string.h>
 
53
 
 
54
#ifdef SPL_AMALGAMATION /* spatialite-amalgamation */
 
55
#include <spatialite/sqlite3ext.h>
 
56
#else
 
57
#include <sqlite3ext.h>
 
58
#endif
 
59
 
 
60
#include <spatialite/gaiageo.h>
 
61
#include <spatialite/gaiaexif.h>
 
62
#include <spatialite.h>
 
63
 
 
64
#ifdef _WIN32
 
65
#define strcasecmp      _stricmp
 
66
#endif /* not WIN32 */
 
67
 
 
68
static void
 
69
exifTagName (char gps, unsigned short tag_id, char *str, int len)
 
70
{
 
71
/* returns the canonical name corresponding to an EXIF TAG ID */
 
72
    int l;
 
73
    char *name = "UNKNOWN";
 
74
    if (gps)
 
75
      {
 
76
          switch (tag_id)
 
77
            {
 
78
            case 0x00:
 
79
                name = "GPSVersionID";
 
80
                break;
 
81
            case 0x01:
 
82
                name = "GPSLatitudeRef";
 
83
                break;
 
84
            case 0x02:
 
85
                name = "GPSLatitude";
 
86
                break;
 
87
            case 0x03:
 
88
                name = "GPSLongitudeRef";
 
89
                break;
 
90
            case 0x04:
 
91
                name = "GPSLongitude";
 
92
                break;
 
93
            case 0x05:
 
94
                name = "GPSAltitudeRef";
 
95
                break;
 
96
            case 0x06:
 
97
                name = "GPSAltitude";
 
98
                break;
 
99
            case 0x07:
 
100
                name = "GPSTimeStamp";
 
101
                break;
 
102
            case 0x08:
 
103
                name = "GPSSatellites";
 
104
                break;
 
105
            case 0x09:
 
106
                name = "GPSStatus";
 
107
                break;
 
108
            case 0x0A:
 
109
                name = "GPSMeasureMode";
 
110
                break;
 
111
            case 0x0B:
 
112
                name = "GPSDOP";
 
113
                break;
 
114
            case 0x0C:
 
115
                name = "GPSSpeedRef";
 
116
                break;
 
117
            case 0x0D:
 
118
                name = "GPSSpeed";
 
119
                break;
 
120
            case 0x0E:
 
121
                name = "GPSTrackRef";
 
122
                break;
 
123
            case 0x0F:
 
124
                name = "GPSTrack";
 
125
                break;
 
126
            case 0x10:
 
127
                name = "GPSImgDirectionRef";
 
128
                break;
 
129
            case 0x11:
 
130
                name = "GPSImgDirection";
 
131
                break;
 
132
            case 0x12:
 
133
                name = "GPSMapDatum";
 
134
                break;
 
135
            case 0x13:
 
136
                name = "GPSDestLatitudeRef";
 
137
                break;
 
138
            case 0x14:
 
139
                name = "GPSDestLatitude";
 
140
                break;
 
141
            case 0x15:
 
142
                name = "GPSDestLongitudeRef";
 
143
                break;
 
144
            case 0x16:
 
145
                name = "GPSDestLongitude";
 
146
                break;
 
147
            case 0x17:
 
148
                name = "GPSDestBearingRef";
 
149
                break;
 
150
            case 0x18:
 
151
                name = "GPSDestBearing";
 
152
                break;
 
153
            case 0x19:
 
154
                name = "GPSDestDistanceRef";
 
155
                break;
 
156
            case 0x1A:
 
157
                name = "GPSDestDistance";
 
158
                break;
 
159
            case 0x1B:
 
160
                name = "GPSProcessingMethod";
 
161
                break;
 
162
            case 0x1C:
 
163
                name = "GPSAreaInformation";
 
164
                break;
 
165
            case 0x1D:
 
166
                name = "GPSDateStamp";
 
167
                break;
 
168
            case 0x1E:
 
169
                name = "GPSDifferential";
 
170
                break;
 
171
            };
 
172
      }
 
173
    else
 
174
      {
 
175
          switch (tag_id)
 
176
            {
 
177
            case 0x000B:
 
178
                name = "ACDComment";
 
179
                break;
 
180
            case 0x00FE:
 
181
                name = "NewSubFile";
 
182
                break;
 
183
            case 0x00FF:
 
184
                name = "SubFile";
 
185
                break;
 
186
            case 0x0100:
 
187
                name = "ImageWidth";
 
188
                break;
 
189
            case 0x0101:
 
190
                name = "ImageLength";
 
191
                break;
 
192
            case 0x0102:
 
193
                name = "BitsPerSample";
 
194
                break;
 
195
            case 0x0103:
 
196
                name = "Compression";
 
197
                break;
 
198
            case 0x0106:
 
199
                name = "PhotometricInterpretation";
 
200
                break;
 
201
            case 0x010A:
 
202
                name = "FillOrder";
 
203
                break;
 
204
            case 0x010D:
 
205
                name = "DocumentName";
 
206
                break;
 
207
            case 0x010E:
 
208
                name = "ImageDescription";
 
209
                break;
 
210
            case 0x010F:
 
211
                name = "Make";
 
212
                break;
 
213
            case 0x0110:
 
214
                name = "Model";
 
215
                break;
 
216
            case 0x0111:
 
217
                name = "StripOffsets";
 
218
                break;
 
219
            case 0x0112:
 
220
                name = "Orientation";
 
221
                break;
 
222
            case 0x0115:
 
223
                name = "SamplesPerPixel";
 
224
                break;
 
225
            case 0x0116:
 
226
                name = "RowsPerStrip";
 
227
                break;
 
228
            case 0x0117:
 
229
                name = "StripByteCounts";
 
230
                break;
 
231
            case 0x0118:
 
232
                name = "MinSampleValue";
 
233
                break;
 
234
            case 0x0119:
 
235
                name = "MaxSampleValue";
 
236
                break;
 
237
            case 0x011A:
 
238
                name = "XResolution";
 
239
                break;
 
240
            case 0x011B:
 
241
                name = "YResolution";
 
242
                break;
 
243
            case 0x011C:
 
244
                name = "PlanarConfiguration";
 
245
                break;
 
246
            case 0x011D:
 
247
                name = "PageName";
 
248
                break;
 
249
            case 0x011E:
 
250
                name = "XPosition";
 
251
                break;
 
252
            case 0x011F:
 
253
                name = "YPosition";
 
254
                break;
 
255
            case 0x0120:
 
256
                name = "FreeOffsets";
 
257
                break;
 
258
            case 0x0121:
 
259
                name = "FreeByteCounts";
 
260
                break;
 
261
            case 0x0122:
 
262
                name = "GrayResponseUnit";
 
263
                break;
 
264
            case 0x0123:
 
265
                name = "GrayResponseCurve";
 
266
                break;
 
267
            case 0x0124:
 
268
                name = "T4Options";
 
269
                break;
 
270
            case 0x0125:
 
271
                name = "T6Options";
 
272
                break;
 
273
            case 0x0128:
 
274
                name = "ResolutionUnit";
 
275
                break;
 
276
            case 0x0129:
 
277
                name = "PageNumber";
 
278
                break;
 
279
            case 0x012D:
 
280
                name = "TransferFunction";
 
281
                break;
 
282
            case 0x0131:
 
283
                name = "Software";
 
284
                break;
 
285
            case 0x0132:
 
286
                name = "DateTime";
 
287
                break;
 
288
            case 0x013B:
 
289
                name = "Artist";
 
290
                break;
 
291
            case 0x013C:
 
292
                name = "HostComputer";
 
293
                break;
 
294
            case 0x013D:
 
295
                name = "Predictor";
 
296
                break;
 
297
            case 0x013E:
 
298
                name = "WhitePoint";
 
299
                break;
 
300
            case 0x013F:
 
301
                name = "PrimaryChromaticities";
 
302
                break;
 
303
            case 0x0140:
 
304
                name = "ColorMap";
 
305
                break;
 
306
            case 0x0141:
 
307
                name = "HalfToneHints";
 
308
                break;
 
309
            case 0x0142:
 
310
                name = "TileWidth";
 
311
                break;
 
312
            case 0x0143:
 
313
                name = "TileLength";
 
314
                break;
 
315
            case 0x0144:
 
316
                name = "TileOffsets";
 
317
                break;
 
318
            case 0x0145:
 
319
                name = "TileByteCounts";
 
320
                break;
 
321
            case 0x014A:
 
322
                name = "SubIFD";
 
323
                break;
 
324
            case 0x014C:
 
325
                name = "InkSet";
 
326
                break;
 
327
            case 0x014D:
 
328
                name = "InkNames";
 
329
                break;
 
330
            case 0x014E:
 
331
                name = "NumberOfInks";
 
332
                break;
 
333
            case 0x0150:
 
334
                name = "DotRange";
 
335
                break;
 
336
            case 0x0151:
 
337
                name = "TargetPrinter";
 
338
                break;
 
339
            case 0x0152:
 
340
                name = "ExtraSample";
 
341
                break;
 
342
            case 0x0153:
 
343
                name = "SampleFormat";
 
344
                break;
 
345
            case 0x0154:
 
346
                name = "SMinSampleValue";
 
347
                break;
 
348
            case 0x0155:
 
349
                name = "SMaxSampleValue";
 
350
                break;
 
351
            case 0x0156:
 
352
                name = "TransferRange";
 
353
                break;
 
354
            case 0x0157:
 
355
                name = "ClipPath";
 
356
                break;
 
357
            case 0x0158:
 
358
                name = "XClipPathUnits";
 
359
                break;
 
360
            case 0x0159:
 
361
                name = "YClipPathUnits";
 
362
                break;
 
363
            case 0x015A:
 
364
                name = "Indexed";
 
365
                break;
 
366
            case 0x015B:
 
367
                name = "JPEGTables";
 
368
                break;
 
369
            case 0x015F:
 
370
                name = "OPIProxy";
 
371
                break;
 
372
            case 0x0200:
 
373
                name = "JPEGProc";
 
374
                break;
 
375
            case 0x0201:
 
376
                name = "JPEGInterchangeFormat";
 
377
                break;
 
378
            case 0x0202:
 
379
                name = "JPEGInterchangeFormatLength";
 
380
                break;
 
381
            case 0x0203:
 
382
                name = "JPEGRestartInterval";
 
383
                break;
 
384
            case 0x0205:
 
385
                name = "JPEGLosslessPredictors";
 
386
                break;
 
387
            case 0x0206:
 
388
                name = "JPEGPointTransforms";
 
389
                break;
 
390
            case 0x0207:
 
391
                name = "JPEGQTables";
 
392
                break;
 
393
            case 0x0208:
 
394
                name = "JPEGDCTables";
 
395
                break;
 
396
            case 0x0209:
 
397
                name = "JPEGACTables";
 
398
                break;
 
399
            case 0x0211:
 
400
                name = "YCbCrCoefficients";
 
401
                break;
 
402
            case 0x0212:
 
403
                name = "YCbCrSubSampling";
 
404
                break;
 
405
            case 0x0213:
 
406
                name = "YCbCrPositioning";
 
407
                break;
 
408
            case 0x0214:
 
409
                name = "ReferenceBlackWhite";
 
410
                break;
 
411
            case 0x02BC:
 
412
                name = "ExtensibleMetadataPlatform";
 
413
                break;
 
414
            case 0x0301:
 
415
                name = "Gamma";
 
416
                break;
 
417
            case 0x0302:
 
418
                name = "ICCProfileDescriptor";
 
419
                break;
 
420
            case 0x0303:
 
421
                name = "SRGBRenderingIntent";
 
422
                break;
 
423
            case 0x0320:
 
424
                name = "ImageTitle";
 
425
                break;
 
426
            case 0x5001:
 
427
                name = "ResolutionXUnit";
 
428
                break;
 
429
            case 0x5002:
 
430
                name = "ResolutionYUnit";
 
431
                break;
 
432
            case 0x5003:
 
433
                name = "ResolutionXLengthUnit";
 
434
                break;
 
435
            case 0x5004:
 
436
                name = "ResolutionYLengthUnit";
 
437
                break;
 
438
            case 0x5005:
 
439
                name = "PrintFlags";
 
440
                break;
 
441
            case 0x5006:
 
442
                name = "PrintFlagsVersion";
 
443
                break;
 
444
            case 0x5007:
 
445
                name = "PrintFlagsCrop";
 
446
                break;
 
447
            case 0x5008:
 
448
                name = "PrintFlagsBleedWidth";
 
449
                break;
 
450
            case 0x5009:
 
451
                name = "PrintFlagsBleedWidthScale";
 
452
                break;
 
453
            case 0x500A:
 
454
                name = "HalftoneLPI";
 
455
                break;
 
456
            case 0x500B:
 
457
                name = "HalftoneLPIUnit";
 
458
                break;
 
459
            case 0x500C:
 
460
                name = "HalftoneDegree";
 
461
                break;
 
462
            case 0x500D:
 
463
                name = "HalftoneShape";
 
464
                break;
 
465
            case 0x500E:
 
466
                name = "HalftoneMisc";
 
467
                break;
 
468
            case 0x500F:
 
469
                name = "HalftoneScreen";
 
470
                break;
 
471
            case 0x5010:
 
472
                name = "JPEGQuality";
 
473
                break;
 
474
            case 0x5011:
 
475
                name = "GridSize";
 
476
                break;
 
477
            case 0x5012:
 
478
                name = "ThumbnailFormat";
 
479
                break;
 
480
            case 0x5013:
 
481
                name = "ThumbnailWidth";
 
482
                break;
 
483
            case 0x5014:
 
484
                name = "ThumbnailHeight";
 
485
                break;
 
486
            case 0x5015:
 
487
                name = "ThumbnailColorDepth";
 
488
                break;
 
489
            case 0x5016:
 
490
                name = "ThumbnailPlanes";
 
491
                break;
 
492
            case 0x5017:
 
493
                name = "ThumbnailRawBytes";
 
494
                break;
 
495
            case 0x5018:
 
496
                name = "ThumbnailSize";
 
497
                break;
 
498
            case 0x5019:
 
499
                name = "ThumbnailCompressedSize";
 
500
                break;
 
501
            case 0x501A:
 
502
                name = "ColorTransferFunction";
 
503
                break;
 
504
            case 0x501B:
 
505
                name = "ThumbnailData";
 
506
                break;
 
507
            case 0x5020:
 
508
                name = "ThumbnailImageWidth";
 
509
                break;
 
510
            case 0x5021:
 
511
                name = "ThumbnailImageHeight";
 
512
                break;
 
513
            case 0x5022:
 
514
                name = "ThumbnailBitsPerSample";
 
515
                break;
 
516
            case 0x5023:
 
517
                name = "ThumbnailCompression";
 
518
                break;
 
519
            case 0x5024:
 
520
                name = "ThumbnailPhotometricInterp";
 
521
                break;
 
522
            case 0x5025:
 
523
                name = "ThumbnailImageDescription";
 
524
                break;
 
525
            case 0x5026:
 
526
                name = "ThumbnailEquipMake";
 
527
                break;
 
528
            case 0x5027:
 
529
                name = "ThumbnailEquipModel";
 
530
                break;
 
531
            case 0x5028:
 
532
                name = "ThumbnailStripOffsets";
 
533
                break;
 
534
            case 0x5029:
 
535
                name = "ThumbnailOrientation";
 
536
                break;
 
537
            case 0x502A:
 
538
                name = "ThumbnailSamplesPerPixel";
 
539
                break;
 
540
            case 0x502B:
 
541
                name = "ThumbnailRowsPerStrip";
 
542
                break;
 
543
            case 0x502C:
 
544
                name = "ThumbnailStripBytesCount";
 
545
                break;
 
546
            case 0x502D:
 
547
                name = "ThumbnailResolutionX";
 
548
                break;
 
549
            case 0x502E:
 
550
                name = "ThumbnailResolutionY";
 
551
                break;
 
552
            case 0x502F:
 
553
                name = "ThumbnailPlanarConfig";
 
554
                break;
 
555
            case 0x5030:
 
556
                name = "ThumbnailResolutionUnit";
 
557
                break;
 
558
            case 0x5031:
 
559
                name = "ThumbnailTransferFunction";
 
560
                break;
 
561
            case 0x5032:
 
562
                name = "ThumbnailSoftwareUsed";
 
563
                break;
 
564
            case 0x5033:
 
565
                name = "ThumbnailDateTime";
 
566
                break;
 
567
            case 0x5034:
 
568
                name = "ThumbnailArtist";
 
569
                break;
 
570
            case 0x5035:
 
571
                name = "ThumbnailWhitePoint";
 
572
                break;
 
573
            case 0x5036:
 
574
                name = "ThumbnailPrimaryChromaticities";
 
575
                break;
 
576
            case 0x5037:
 
577
                name = "ThumbnailYCbCrCoefficients";
 
578
                break;
 
579
            case 0x5038:
 
580
                name = "ThumbnailYCbCrSubsampling";
 
581
                break;
 
582
            case 0x5039:
 
583
                name = "ThumbnailYCbCrPositioning";
 
584
                break;
 
585
            case 0x503A:
 
586
                name = "ThumbnailRefBlackWhite";
 
587
                break;
 
588
            case 0x503B:
 
589
                name = "ThumbnailCopyRight";
 
590
                break;
 
591
            case 0x5090:
 
592
                name = "LuminanceTable";
 
593
                break;
 
594
            case 0x5091:
 
595
                name = "ChrominanceTable";
 
596
                break;
 
597
            case 0x5100:
 
598
                name = "FrameDelay";
 
599
                break;
 
600
            case 0x5101:
 
601
                name = "LoopCount";
 
602
                break;
 
603
            case 0x5110:
 
604
                name = "PixelUnit";
 
605
                break;
 
606
            case 0x5111:
 
607
                name = "PixelPerUnitX";
 
608
                break;
 
609
            case 0x5112:
 
610
                name = "PixelPerUnitY";
 
611
                break;
 
612
            case 0x5113:
 
613
                name = "PaletteHistogram";
 
614
                break;
 
615
            case 0x1000:
 
616
                name = "RelatedImageFileFormat";
 
617
                break;
 
618
            case 0x800D:
 
619
                name = "ImageID";
 
620
                break;
 
621
            case 0x80E3:
 
622
                name = "Matteing";
 
623
                break;
 
624
            case 0x80E4:
 
625
                name = "DataType";
 
626
                break;
 
627
            case 0x80E5:
 
628
                name = "ImageDepth";
 
629
                break;
 
630
            case 0x80E6:
 
631
                name = "TileDepth";
 
632
                break;
 
633
            case 0x828D:
 
634
                name = "CFARepeatPatternDim";
 
635
                break;
 
636
            case 0x828E:
 
637
                name = "CFAPattern";
 
638
                break;
 
639
            case 0x828F:
 
640
                name = "BatteryLevel";
 
641
                break;
 
642
            case 0x8298:
 
643
                name = "Copyright";
 
644
                break;
 
645
            case 0x829A:
 
646
                name = "ExposureTime";
 
647
                break;
 
648
            case 0x829D:
 
649
                name = "FNumber";
 
650
                break;
 
651
            case 0x83BB:
 
652
                name = "IPTC/NAA";
 
653
                break;
 
654
            case 0x84E3:
 
655
                name = "IT8RasterPadding";
 
656
                break;
 
657
            case 0x84E5:
 
658
                name = "IT8ColorTable";
 
659
                break;
 
660
            case 0x8649:
 
661
                name = "ImageResourceInformation";
 
662
                break;
 
663
            case 0x8769:
 
664
                name = "Exif IFD Pointer";
 
665
                break;
 
666
            case 0x8773:
 
667
                name = "ICC_Profile";
 
668
                break;
 
669
            case 0x8822:
 
670
                name = "ExposureProgram";
 
671
                break;
 
672
            case 0x8824:
 
673
                name = "SpectralSensitivity";
 
674
                break;
 
675
            case 0x8825:
 
676
                name = "GPSInfo IFD Pointer";
 
677
                break;
 
678
            case 0x8827:
 
679
                name = "ISOSpeedRatings";
 
680
                break;
 
681
            case 0x8828:
 
682
                name = "OECF";
 
683
                break;
 
684
            case 0x9000:
 
685
                name = "ExifVersion";
 
686
                break;
 
687
            case 0x9003:
 
688
                name = "DateTimeOriginal";
 
689
                break;
 
690
            case 0x9004:
 
691
                name = "DateTimeDigitized";
 
692
                break;
 
693
            case 0x9101:
 
694
                name = "ComponentsConfiguration";
 
695
                break;
 
696
            case 0x9102:
 
697
                name = "CompressedBitsPerPixel";
 
698
                break;
 
699
            case 0x9201:
 
700
                name = "ShutterSpeedValue";
 
701
                break;
 
702
            case 0x9202:
 
703
                name = "ApertureValue";
 
704
                break;
 
705
            case 0x9203:
 
706
                name = "BrightnessValue";
 
707
                break;
 
708
            case 0x9204:
 
709
                name = "ExposureBiasValue";
 
710
                break;
 
711
            case 0x9205:
 
712
                name = "MaxApertureValue";
 
713
                break;
 
714
            case 0x9206:
 
715
                name = "SubjectDistance";
 
716
                break;
 
717
            case 0x9207:
 
718
                name = "MeteringMode";
 
719
                break;
 
720
            case 0x9208:
 
721
                name = "LightSource";
 
722
                break;
 
723
            case 0x9209:
 
724
                name = "Flash";
 
725
                break;
 
726
            case 0x920A:
 
727
                name = "FocalLength";
 
728
                break;
 
729
            case 0x920B:
 
730
            case 0xA20B:
 
731
                name = "FlashEnergy";
 
732
                break;
 
733
            case 0x920C:
 
734
            case 0xA20C:
 
735
                name = "SpatialFrequencyResponse";
 
736
                break;
 
737
            case 0x920D:
 
738
                name = "Noise";
 
739
                break;
 
740
            case 0x920E:
 
741
            case 0xA20E:
 
742
                name = "FocalPlaneXResolution";
 
743
                break;
 
744
            case 0x920F:
 
745
            case 0XA20F:
 
746
                name = "FocalPlaneYResolution";
 
747
                break;
 
748
            case 0x9210:
 
749
            case 0xA210:
 
750
                name = "FocalPlaneResolutionUnit";
 
751
                break;
 
752
            case 0x9211:
 
753
                name = "ImageNumber";
 
754
                break;
 
755
            case 0x9212:
 
756
                name = "SecurityClassification";
 
757
                break;
 
758
            case 0x9213:
 
759
                name = "ImageHistory";
 
760
                break;
 
761
            case 0x9214:
 
762
            case 0xA214:
 
763
                name = "SubjectLocation";
 
764
                break;
 
765
            case 0x9215:
 
766
            case 0xA215:
 
767
                name = "ExposureIndex";
 
768
                break;
 
769
            case 0x9216:
 
770
                name = "TIFF/EPStandardID";
 
771
                break;
 
772
            case 0x9217:
 
773
            case 0xA217:
 
774
                name = "SensingMethod";
 
775
                break;
 
776
            case 0x923F:
 
777
                name = "StoNits";
 
778
                break;
 
779
            case 0x927C:
 
780
                name = "MakerNote";
 
781
                break;
 
782
            case 0x9286:
 
783
                name = "UserComment";
 
784
                break;
 
785
            case 0x9290:
 
786
                name = "SubSecTime";
 
787
                break;
 
788
            case 0x9291:
 
789
                name = "SubSecTimeOriginal";
 
790
                break;
 
791
            case 0x9292:
 
792
                name = "SubSecTimeDigitized";
 
793
                break;
 
794
            case 0xA000:
 
795
                name = "FlashpixVersion";
 
796
                break;
 
797
            case 0xA001:
 
798
                name = "ColorSpace";
 
799
                break;
 
800
            case 0xA002:
 
801
                name = "ExifImageWidth";
 
802
                break;
 
803
            case 0xA003:
 
804
                name = "ExifImageLength";
 
805
                break;
 
806
            case 0xA004:
 
807
                name = "RelatedSoundFile";
 
808
                break;
 
809
            case 0xA005:
 
810
                name = "Interoperability IFD Pointer";
 
811
                break;
 
812
            case 0xA20D:
 
813
                name = "Noise";
 
814
                break;
 
815
            case 0xA211:
 
816
                name = "ImageNumber";
 
817
                break;
 
818
            case 0xA212:
 
819
                name = "SecurityClassification";
 
820
                break;
 
821
            case 0xA213:
 
822
                name = "ImageHistory";
 
823
                break;
 
824
            case 0xA216:
 
825
                name = "TIFF/EPStandardID";
 
826
                break;
 
827
            case 0xA300:
 
828
                name = "FileSource";
 
829
                break;
 
830
            case 0xA301:
 
831
                name = "SceneType";
 
832
                break;
 
833
            case 0xA302:
 
834
                name = "CFAPattern";
 
835
                break;
 
836
            case 0xA401:
 
837
                name = "CustomRendered";
 
838
                break;
 
839
            case 0xA402:
 
840
                name = "ExposureMode";
 
841
                break;
 
842
            case 0xA403:
 
843
                name = "WhiteBalance";
 
844
                break;
 
845
            case 0xA404:
 
846
                name = "DigitalZoomRatio";
 
847
                break;
 
848
            case 0xA405:
 
849
                name = "FocalLengthIn35mmFilm";
 
850
                break;
 
851
            case 0xA406:
 
852
                name = "SceneCaptureType";
 
853
                break;
 
854
            case 0xA407:
 
855
                name = "GainControl";
 
856
                break;
 
857
            case 0xA408:
 
858
                name = "Contrast";
 
859
                break;
 
860
            case 0xA409:
 
861
                name = "Saturation";
 
862
                break;
 
863
            case 0xA40A:
 
864
                name = "Sharpness";
 
865
                break;
 
866
            case 0xA40B:
 
867
                name = "DeviceSettingDescription";
 
868
                break;
 
869
            case 0xA40C:
 
870
                name = "SubjectDistanceRange";
 
871
                break;
 
872
            case 0xA420:
 
873
                name = "ImageUniqueID";
 
874
                break;
 
875
            };
 
876
      }
 
877
    l = strlen (name);
 
878
    if (len > l)
 
879
        strcpy (str, name);
 
880
    else
 
881
      {
 
882
          memset (str, '\0', len);
 
883
          memcpy (str, name, len - 1);
 
884
      }
 
885
}
 
886
 
 
887
static unsigned short
 
888
exifImportU16 (const unsigned char *p, int little_endian,
 
889
               int little_endian_arch)
 
890
{
 
891
/* fetches an unsigned 16bit int from BLOB respecting declared endiannes */
 
892
    union cvt
 
893
    {
 
894
        unsigned char byte[2];
 
895
        unsigned short short_value;
 
896
    } convert;
 
897
    if (little_endian_arch)
 
898
      {
 
899
          /* Litte-Endian architecture [e.g. x86] */
 
900
          if (!little_endian)
 
901
            {
 
902
                /* Big Endian data */
 
903
                convert.byte[0] = *(p + 1);
 
904
                convert.byte[1] = *(p + 0);
 
905
            }
 
906
          else
 
907
            {
 
908
                /* Little Endian data */
 
909
                convert.byte[0] = *(p + 0);
 
910
                convert.byte[1] = *(p + 1);
 
911
            }
 
912
      }
 
913
    else
 
914
      {
 
915
          /* Big Endian architecture [e.g. PPC] */
 
916
          if (!little_endian)
 
917
            {
 
918
                /* Big Endian data */
 
919
                convert.byte[0] = *(p + 0);
 
920
                convert.byte[1] = *(p + 1);
 
921
            }
 
922
          else
 
923
            {
 
924
                /* Little Endian data */
 
925
                convert.byte[0] = *(p + 1);
 
926
                convert.byte[1] = *(p + 0);
 
927
            }
 
928
      }
 
929
    return convert.short_value;
 
930
}
 
931
 
 
932
static unsigned int
 
933
exifImportU32 (const unsigned char *p, int little_endian,
 
934
               int little_endian_arch)
 
935
{
 
936
/* fetches an unsigned 32bit int from BLOB respecting declared endiannes */
 
937
    union cvt
 
938
    {
 
939
        unsigned char byte[4];
 
940
        unsigned int int_value;
 
941
    } convert;
 
942
    if (little_endian_arch)
 
943
      {
 
944
          /* Litte-Endian architecture [e.g. x86] */
 
945
          if (!little_endian)
 
946
            {
 
947
                /* Big Endian data */
 
948
                convert.byte[0] = *(p + 3);
 
949
                convert.byte[1] = *(p + 2);
 
950
                convert.byte[2] = *(p + 1);
 
951
                convert.byte[3] = *(p + 0);
 
952
            }
 
953
          else
 
954
            {
 
955
                /* Little Endian data */
 
956
                convert.byte[0] = *(p + 0);
 
957
                convert.byte[1] = *(p + 1);
 
958
                convert.byte[2] = *(p + 2);
 
959
                convert.byte[3] = *(p + 3);
 
960
            }
 
961
      }
 
962
    else
 
963
      {
 
964
          /* Big Endian architecture [e.g. PPC] */
 
965
          if (!little_endian)
 
966
            {
 
967
                /* Big Endian data */
 
968
                convert.byte[0] = *(p + 0);
 
969
                convert.byte[1] = *(p + 1);
 
970
                convert.byte[2] = *(p + 2);
 
971
                convert.byte[3] = *(p + 3);
 
972
            }
 
973
          else
 
974
            {
 
975
                /* Little Endian data */
 
976
                convert.byte[0] = *(p + 3);
 
977
                convert.byte[1] = *(p + 2);
 
978
                convert.byte[2] = *(p + 1);
 
979
                convert.byte[3] = *(p + 0);
 
980
            }
 
981
      }
 
982
    return convert.int_value;
 
983
}
 
984
 
 
985
static float
 
986
exifImportFloat32 (const unsigned char *p, int little_endian,
 
987
                   int little_endian_arch)
 
988
{
 
989
/* fetches a 32bit FLOAT from BLOB respecting declared endiannes */
 
990
    union cvt
 
991
    {
 
992
        unsigned char byte[4];
 
993
        float float_value;
 
994
    } convert;
 
995
    if (little_endian_arch)
 
996
      {
 
997
          /* Litte-Endian architecture [e.g. x86] */
 
998
          if (!little_endian)
 
999
            {
 
1000
                /* Big Endian data */
 
1001
                convert.byte[0] = *(p + 3);
 
1002
                convert.byte[1] = *(p + 2);
 
1003
                convert.byte[2] = *(p + 1);
 
1004
                convert.byte[3] = *(p + 0);
 
1005
            }
 
1006
          else
 
1007
            {
 
1008
                /* Little Endian data */
 
1009
                convert.byte[0] = *(p + 0);
 
1010
                convert.byte[1] = *(p + 1);
 
1011
                convert.byte[2] = *(p + 2);
 
1012
                convert.byte[3] = *(p + 3);
 
1013
            }
 
1014
      }
 
1015
    else
 
1016
      {
 
1017
          /* Big Endian architecture [e.g. PPC] */
 
1018
          if (!little_endian)
 
1019
            {
 
1020
                /* Big Endian data */
 
1021
                convert.byte[0] = *(p + 0);
 
1022
                convert.byte[1] = *(p + 1);
 
1023
                convert.byte[2] = *(p + 2);
 
1024
                convert.byte[3] = *(p + 3);
 
1025
            }
 
1026
          else
 
1027
            {
 
1028
                /* Little Endian data */
 
1029
                convert.byte[0] = *(p + 3);
 
1030
                convert.byte[1] = *(p + 2);
 
1031
                convert.byte[2] = *(p + 1);
 
1032
                convert.byte[3] = *(p + 0);
 
1033
            }
 
1034
      }
 
1035
    return convert.float_value;
 
1036
}
 
1037
 
 
1038
static void
 
1039
exifSetTagValue (gaiaExifTagPtr tag, const unsigned char *blob, int endian_mode,
 
1040
                 int endian_arch, int app1_offset)
 
1041
{
 
1042
/* setting the TAG value */
 
1043
    int i;
 
1044
    int sz = 0;
 
1045
    unsigned int offset;
 
1046
    const unsigned char *ptr;
 
1047
    unsigned short short_value;
 
1048
    unsigned int int_value;
 
1049
    short sign_short_value;
 
1050
    int sign_int_value;
 
1051
    float float_value;
 
1052
    double double_value;
 
1053
    if (tag->Type == 1 || tag->Type == 2 || tag->Type == 6 || tag->Type == 7)
 
1054
        sz = tag->Count;
 
1055
    if (tag->Type == 3 || tag->Type == 8)
 
1056
        sz = tag->Count * 2;
 
1057
    if (tag->Type == 4 || tag->Type == 9 || tag->Type == 11)
 
1058
        sz = tag->Count * 4;
 
1059
    if (tag->Type == 5 || tag->Type == 10 || tag->Type == 12)
 
1060
        sz = tag->Count * 8;
 
1061
    if (sz <= 4)
 
1062
      {
 
1063
          /* TAG values is stored within the offset */
 
1064
          ptr = tag->TagOffset;
 
1065
      }
 
1066
    else
 
1067
      {
 
1068
          /* jumping to offset */
 
1069
          offset = exifImportU32 (tag->TagOffset, endian_mode, endian_arch);
 
1070
          offset += app1_offset + 10;
 
1071
          ptr = blob + offset;
 
1072
      }
 
1073
    if (tag->Type == 1 || tag->Type == 6 || tag->Type == 7)
 
1074
      {
 
1075
          /* BYTE type */
 
1076
          tag->ByteValue = malloc (tag->Count);
 
1077
          memcpy (tag->ByteValue, ptr, tag->Count);
 
1078
      }
 
1079
    if (tag->Type == 2)
 
1080
      {
 
1081
          /* STRING type */
 
1082
          tag->StringValue = malloc (tag->Count);
 
1083
          memcpy (tag->StringValue, ptr, tag->Count);
 
1084
      }
 
1085
    if (tag->Type == 3)
 
1086
      {
 
1087
          /* SHORT type */
 
1088
          tag->ShortValues = malloc (tag->Count * sizeof (unsigned short));
 
1089
          for (i = 0; i < tag->Count; i++)
 
1090
            {
 
1091
                short_value =
 
1092
                    exifImportU16 (ptr + (i * 2), endian_mode, endian_arch);
 
1093
                *(tag->ShortValues + i) = short_value;
 
1094
            }
 
1095
      }
 
1096
    if (tag->Type == 4)
 
1097
      {
 
1098
          /* LONG type */
 
1099
          tag->LongValues = malloc (tag->Count * sizeof (unsigned int));
 
1100
          for (i = 0; i < tag->Count; i++)
 
1101
            {
 
1102
                int_value =
 
1103
                    exifImportU32 (ptr + (i * 4), endian_mode, endian_arch);
 
1104
                *(tag->LongValues + i) = int_value;
 
1105
            }
 
1106
      }
 
1107
    if (tag->Type == 5)
 
1108
      {
 
1109
          /* RATIONAL type */
 
1110
          tag->LongRationals1 = malloc (tag->Count * sizeof (unsigned int));
 
1111
          tag->LongRationals2 = malloc (tag->Count * sizeof (unsigned int));
 
1112
          for (i = 0; i < tag->Count; i++)
 
1113
            {
 
1114
                int_value =
 
1115
                    exifImportU32 (ptr + (i * 8), endian_mode, endian_arch);
 
1116
                *(tag->LongRationals1 + i) = int_value;
 
1117
                int_value =
 
1118
                    exifImportU32 (ptr + (i * 8) + 4, endian_mode, endian_arch);
 
1119
                *(tag->LongRationals2 + i) = int_value;
 
1120
            }
 
1121
      }
 
1122
    if (tag->Type == 8)
 
1123
      {
 
1124
          /* SSHORT type */
 
1125
          tag->SignedShortValues = malloc (tag->Count * sizeof (short));
 
1126
          for (i = 0; i < tag->Count; i++)
 
1127
            {
 
1128
                sign_short_value =
 
1129
                    gaiaImport16 (ptr + (i * 2), endian_mode, endian_arch);
 
1130
                *(tag->SignedShortValues + i) = sign_short_value;
 
1131
            }
 
1132
      }
 
1133
    if (tag->Type == 9)
 
1134
      {
 
1135
          /* SIGNED LONG type */
 
1136
          tag->SignedLongValues = malloc (tag->Count * sizeof (int));
 
1137
          for (i = 0; i < tag->Count; i++)
 
1138
            {
 
1139
                sign_int_value =
 
1140
                    gaiaImport32 (ptr + (i * 4), endian_mode, endian_arch);
 
1141
                *(tag->SignedLongValues + i) = sign_int_value;
 
1142
            }
 
1143
      }
 
1144
    if (tag->Type == 10)
 
1145
      {
 
1146
          /* SIGNED RATIONAL type */
 
1147
          tag->SignedLongRationals1 = malloc (tag->Count * sizeof (int));
 
1148
          tag->SignedLongRationals2 = malloc (tag->Count * sizeof (int));
 
1149
          for (i = 0; i < tag->Count; i++)
 
1150
            {
 
1151
                sign_int_value =
 
1152
                    gaiaImport32 (ptr + (i * 8), endian_mode, endian_arch);
 
1153
                *(tag->SignedLongRationals1 + i) = sign_int_value;
 
1154
                sign_int_value =
 
1155
                    gaiaImport32 (ptr + (i * 8) + 4, endian_mode, endian_arch);
 
1156
                *(tag->SignedLongRationals2 + i) = sign_int_value;
 
1157
            }
 
1158
      }
 
1159
    if (tag->Type == 11)
 
1160
      {
 
1161
          /* FLOAT type */
 
1162
          tag->FloatValues = malloc (tag->Count * sizeof (float));
 
1163
          for (i = 0; i < tag->Count; i++)
 
1164
            {
 
1165
                float_value =
 
1166
                    exifImportFloat32 (ptr + (i * 4), endian_mode, endian_arch);
 
1167
                *(tag->FloatValues + i) = float_value;
 
1168
            }
 
1169
      }
 
1170
    if (tag->Type == 12)
 
1171
      {
 
1172
          /* DOUBLE type */
 
1173
          tag->DoubleValues = malloc (tag->Count * sizeof (double));
 
1174
          for (i = 0; i < tag->Count; i++)
 
1175
            {
 
1176
                double_value =
 
1177
                    gaiaImport64 (ptr + (i * 8), endian_mode, endian_arch);
 
1178
                *(tag->DoubleValues + i) = double_value;
 
1179
            }
 
1180
      }
 
1181
}
 
1182
 
 
1183
static void
 
1184
exifParseTag (const unsigned char *blob, unsigned int offset, int endian_mode,
 
1185
              int endian_arch, gaiaExifTagListPtr list, int gps,
 
1186
              int app1_offset)
 
1187
{
 
1188
/* parsing some TAG and inserting into the list */
 
1189
    unsigned short tag_id;
 
1190
    unsigned short type;
 
1191
    unsigned int count;
 
1192
    gaiaExifTagPtr tag;
 
1193
    tag_id = exifImportU16 (blob + offset, endian_mode, endian_arch);
 
1194
    type = exifImportU16 (blob + offset + 2, endian_mode, endian_arch);
 
1195
    count = exifImportU32 (blob + offset + 4, endian_mode, endian_arch);
 
1196
    tag = malloc (sizeof (gaiaExifTag));
 
1197
    tag->Gps = (char) gps;
 
1198
    tag->TagId = tag_id;
 
1199
    tag->Type = type;
 
1200
    tag->Count = (unsigned short) count;
 
1201
    memcpy (tag->TagOffset, blob + offset + 8, 4);
 
1202
    tag->ByteValue = NULL;
 
1203
    tag->StringValue = NULL;
 
1204
    tag->ShortValues = NULL;
 
1205
    tag->LongValues = NULL;
 
1206
    tag->LongRationals1 = NULL;
 
1207
    tag->LongRationals2 = NULL;
 
1208
    tag->SignedShortValues = NULL;
 
1209
    tag->SignedLongValues = NULL;
 
1210
    tag->SignedLongRationals1 = NULL;
 
1211
    tag->SignedLongRationals2 = NULL;
 
1212
    tag->FloatValues = NULL;
 
1213
    tag->DoubleValues = NULL;
 
1214
    exifSetTagValue (tag, blob, endian_mode, endian_arch, app1_offset);
 
1215
    tag->Next = NULL;
 
1216
    if (!(list->First))
 
1217
        list->First = tag;
 
1218
    if (list->Last)
 
1219
        (list->Last)->Next = tag;
 
1220
    list->Last = tag;
 
1221
    (list->NumTags)++;
 
1222
}
 
1223
 
 
1224
static void
 
1225
exifExpandIFD (gaiaExifTagListPtr list, const unsigned char *blob,
 
1226
               int endian_mode, int endian_arch, int app1_offset)
 
1227
{
 
1228
/* trying to expand the EXIF-IFD */
 
1229
    unsigned int offset;
 
1230
    unsigned short items;
 
1231
    unsigned short i;
 
1232
    gaiaExifTagPtr tag;
 
1233
    if (!list)
 
1234
        return;
 
1235
    tag = list->First;
 
1236
    while (tag)
 
1237
      {
 
1238
          if (tag->TagId == 34665)
 
1239
            {
 
1240
                /* ok, this one is an IFD pointer */
 
1241
                offset =
 
1242
                    exifImportU32 (tag->TagOffset, endian_mode, endian_arch);
 
1243
                offset += app1_offset + 10;
 
1244
                items = exifImportU16 (blob + offset, endian_mode, endian_arch);
 
1245
                offset += 2;
 
1246
                for (i = 0; i < items; i++)
 
1247
                  {
 
1248
                      /* fetching the TAGs */
 
1249
                      exifParseTag (blob, offset, endian_mode, endian_arch,
 
1250
                                    list, 0, app1_offset);
 
1251
                      offset += 12;
 
1252
                  }
 
1253
            }
 
1254
          tag = tag->Next;
 
1255
      }
 
1256
}
 
1257
 
 
1258
static void
 
1259
exifExpandGPS (gaiaExifTagListPtr list, const unsigned char *blob,
 
1260
               int endian_mode, int endian_arch, int app1_offset)
 
1261
{
 
1262
/* trying to expand the EXIF-GPS */
 
1263
    unsigned int offset;
 
1264
    unsigned short items;
 
1265
    unsigned short i;
 
1266
    gaiaExifTagPtr tag;
 
1267
    if (!list)
 
1268
        return;
 
1269
    tag = list->First;
 
1270
    while (tag)
 
1271
      {
 
1272
          if (tag->TagId == 34853)
 
1273
            {
 
1274
                /* ok, this one is a GPSinfo-IFD pointer */
 
1275
                offset =
 
1276
                    exifImportU32 (tag->TagOffset, endian_mode, endian_arch);
 
1277
                offset += app1_offset + 10;
 
1278
                items = exifImportU16 (blob + offset, endian_mode, endian_arch);
 
1279
                offset += 2;
 
1280
                for (i = 0; i < items; i++)
 
1281
                  {
 
1282
                      /* fetching the TAGs */
 
1283
                      exifParseTag (blob, offset, endian_mode, endian_arch,
 
1284
                                    list, 1, app1_offset);
 
1285
                      offset += 12;
 
1286
                  }
 
1287
            }
 
1288
          tag = tag->Next;
 
1289
      }
 
1290
}
 
1291
 
 
1292
GAIAEXIF_DECLARE gaiaExifTagListPtr
 
1293
gaiaGetExifTags (const unsigned char *blob, int size)
 
1294
{
 
1295
/* trying to parse a BLOB as an EXIF photo */
 
1296
    gaiaExifTagListPtr list;
 
1297
    int endian_arch = gaiaEndianArch ();
 
1298
    int endian_mode;
 
1299
    unsigned short app1_size;
 
1300
    unsigned int offset;
 
1301
    unsigned short items;
 
1302
    unsigned short i;
 
1303
    int x;
 
1304
    int app1_offset;
 
1305
    int app1_marker = 0;
 
1306
    gaiaExifTagPtr pT;
 
1307
    if (!blob)
 
1308
        goto error;
 
1309
    if (size < 14)
 
1310
        goto error;
 
1311
/* cecking for SOI [Start Of Image] */
 
1312
    if (*(blob + 0) == 0xff && *(blob + 1) == 0xd8)
 
1313
        ;
 
1314
    else
 
1315
        goto error;
 
1316
    app1_offset = 2;
 
1317
    for (x = 2; x < size; x++)
 
1318
      {
 
1319
          /* retrieving the APP1 Marker */
 
1320
          if (*(blob + x) == 0xff)
 
1321
              app1_marker = 1;
 
1322
          if (*(blob + x) == 0xe1)
 
1323
            {
 
1324
                if (app1_marker)
 
1325
                  {
 
1326
                      app1_offset = x - 1;
 
1327
                      break;
 
1328
                  }
 
1329
                else
 
1330
                    app1_marker = 0;
 
1331
            }
 
1332
      }
 
1333
/* checking for APP1 Marker */
 
1334
    if (*(blob + app1_offset) == 0xff && *(blob + app1_offset + 1) == 0xe1)
 
1335
        ;
 
1336
    else
 
1337
        goto error;
 
1338
/* checking for EXIF identifier */
 
1339
    if (memcmp (blob + app1_offset + 4, "Exif", 4) == 0)
 
1340
        ;
 
1341
    else
 
1342
        goto error;
 
1343
/* checking for Pad */
 
1344
    if (*(blob + app1_offset + 8) == 0x00 && *(blob + app1_offset + 9) == 0x00)
 
1345
        ;
 
1346
    else
 
1347
        goto error;
 
1348
    if (memcmp (blob + app1_offset + 10, "II", 2) == 0)
 
1349
        endian_mode = GAIA_LITTLE_ENDIAN;
 
1350
    else if (memcmp (blob + app1_offset + 10, "MM", 2) == 0)
 
1351
        endian_mode = GAIA_BIG_ENDIAN;
 
1352
    else
 
1353
        goto error;
 
1354
/* OK: this BLOB seems to contain a valid EXIF */
 
1355
    app1_size =
 
1356
        exifImportU16 (blob + app1_offset + 2, endian_mode, endian_arch);
 
1357
    if ((app1_size + app1_offset + 4) > size)
 
1358
        goto error;
 
1359
/* checking for marker */
 
1360
    if (endian_mode == GAIA_BIG_ENDIAN)
 
1361
      {
 
1362
          if (*(blob + app1_offset + 12) == 0x00
 
1363
              && *(blob + app1_offset + 13) == 0x2a)
 
1364
              ;
 
1365
          else
 
1366
              goto error;
 
1367
      }
 
1368
    else
 
1369
      {
 
1370
          if (*(blob + app1_offset + 12) == 0x2a
 
1371
              && *(blob + app1_offset + 13) == 0x00)
 
1372
              ;
 
1373
          else
 
1374
              goto error;
 
1375
      }
 
1376
/* allocating an EXIF TAG LIST */
 
1377
    list = malloc (sizeof (gaiaExifTagList));
 
1378
    list->First = NULL;
 
1379
    list->Last = NULL;
 
1380
    list->NumTags = 0;
 
1381
    list->TagsArray = NULL;
 
1382
    offset = exifImportU32 (blob + app1_offset + 14, endian_mode, endian_arch);
 
1383
    offset += app1_offset + 10;
 
1384
/* jump to offset */
 
1385
    items = exifImportU16 (blob + offset, endian_mode, endian_arch);
 
1386
    offset += 2;
 
1387
    for (i = 0; i < items; i++)
 
1388
      {
 
1389
/* fetching the EXIF TAGs */
 
1390
          exifParseTag (blob, offset, endian_mode, endian_arch, list, 0,
 
1391
                        app1_offset);
 
1392
          offset += 12;
 
1393
      }
 
1394
/* expanding the IFD and GPS tags */
 
1395
    exifExpandIFD (list, blob, endian_mode, endian_arch, app1_offset);
 
1396
    exifExpandGPS (list, blob, endian_mode, endian_arch, app1_offset);
 
1397
    if (list->NumTags)
 
1398
      {
 
1399
          /* organizing the EXIF TAGS as an Array */
 
1400
          list->TagsArray = malloc (sizeof (gaiaExifTagPtr) * list->NumTags);
 
1401
          pT = list->First;
 
1402
          i = 0;
 
1403
          while (pT)
 
1404
            {
 
1405
                *(list->TagsArray + i++) = pT;
 
1406
                pT = pT->Next;
 
1407
            }
 
1408
      }
 
1409
    return list;
 
1410
  error:
 
1411
    return NULL;
 
1412
}
 
1413
 
 
1414
GAIAEXIF_DECLARE void
 
1415
gaiaExifTagsFree (gaiaExifTagListPtr p)
 
1416
{
 
1417
/* memory cleanup; freeing the EXIF TAG list */
 
1418
    gaiaExifTagPtr pT;
 
1419
    gaiaExifTagPtr pTn;
 
1420
    if (!p)
 
1421
        return;
 
1422
    pT = p->First;
 
1423
    while (pT)
 
1424
      {
 
1425
          pTn = pT->Next;
 
1426
          if (pT->ByteValue)
 
1427
              free (pT->ByteValue);
 
1428
          if (pT->StringValue)
 
1429
              free (pT->StringValue);
 
1430
          if (pT->ShortValues)
 
1431
              free (pT->ShortValues);
 
1432
          if (pT->LongValues)
 
1433
              free (pT->LongValues);
 
1434
          if (pT->LongRationals1)
 
1435
              free (pT->LongRationals1);
 
1436
          if (pT->LongRationals2)
 
1437
              free (pT->LongRationals2);
 
1438
          if (pT->SignedShortValues)
 
1439
              free (pT->SignedShortValues);
 
1440
          if (pT->SignedLongValues)
 
1441
              free (pT->SignedLongValues);
 
1442
          if (pT->SignedLongRationals1)
 
1443
              free (pT->SignedLongRationals1);
 
1444
          if (pT->SignedLongRationals2)
 
1445
              free (pT->SignedLongRationals2);
 
1446
          if (pT->FloatValues)
 
1447
              free (pT->FloatValues);
 
1448
          if (pT->DoubleValues)
 
1449
              free (pT->DoubleValues);
 
1450
          free (pT);
 
1451
          pT = pTn;
 
1452
      }
 
1453
    if (p->TagsArray)
 
1454
        free (p->TagsArray);
 
1455
    free (p);
 
1456
}
 
1457
 
 
1458
GAIAEXIF_DECLARE int
 
1459
gaiaGetExifTagsCount (gaiaExifTagListPtr tag_list)
 
1460
{
 
1461
/* returns the # TAGSs into this list */
 
1462
    return tag_list->NumTags;
 
1463
}
 
1464
 
 
1465
GAIAEXIF_DECLARE gaiaExifTagPtr
 
1466
gaiaGetExifTagByPos (gaiaExifTagListPtr tag_list, const int pos)
 
1467
{
 
1468
/* returns the Nth TAG from this list */
 
1469
    if (pos >= 0 && pos < tag_list->NumTags)
 
1470
        return *(tag_list->TagsArray + pos);
 
1471
    return NULL;
 
1472
}
 
1473
 
 
1474
GAIAEXIF_DECLARE gaiaExifTagPtr
 
1475
gaiaGetExifTagById (const gaiaExifTagListPtr tag_list,
 
1476
                    const unsigned short tag_id)
 
1477
{
 
1478
/* returns a not-GPS TAG identified by its ID */
 
1479
    gaiaExifTagPtr pT = tag_list->First;
 
1480
    while (pT)
 
1481
      {
 
1482
          if (!(pT->Gps) && pT->TagId == tag_id)
 
1483
              return pT;
 
1484
          pT = pT->Next;
 
1485
      }
 
1486
    return NULL;
 
1487
}
 
1488
 
 
1489
GAIAEXIF_DECLARE gaiaExifTagPtr
 
1490
gaiaGetExifGpsTagById (const gaiaExifTagListPtr tag_list,
 
1491
                       const unsigned short tag_id)
 
1492
{
 
1493
/* returns a GPS TAG identified by its ID */
 
1494
    gaiaExifTagPtr pT = tag_list->First;
 
1495
    while (pT)
 
1496
      {
 
1497
          if (pT->Gps && pT->TagId == tag_id)
 
1498
              return pT;
 
1499
          pT = pT->Next;
 
1500
      }
 
1501
    return NULL;
 
1502
}
 
1503
 
 
1504
GAIAEXIF_DECLARE gaiaExifTagPtr
 
1505
gaiaGetExifTagByName (const gaiaExifTagListPtr tag_list, const char *tag_name)
 
1506
{
 
1507
/* returns a TAG identified by its Name */
 
1508
    char name[128];
 
1509
    gaiaExifTagPtr pT = tag_list->First;
 
1510
    while (pT)
 
1511
      {
 
1512
          exifTagName (pT->Gps, pT->TagId, name, 128);
 
1513
          if (strcasecmp (name, tag_name) == 0)
 
1514
              return pT;
 
1515
          pT = pT->Next;
 
1516
      }
 
1517
    return NULL;
 
1518
}
 
1519
 
 
1520
GAIAEXIF_DECLARE unsigned short
 
1521
gaiaExifTagGetId (const gaiaExifTagPtr tag)
 
1522
{
 
1523
/* returns the TAG ID */
 
1524
    return tag->TagId;
 
1525
}
 
1526
 
 
1527
GAIAEXIF_DECLARE int
 
1528
gaiaIsExifGpsTag (const gaiaExifTagPtr tag)
 
1529
{
 
1530
/* checks if this one is a GPS tag */
 
1531
    return tag->Gps;
 
1532
}
 
1533
 
 
1534
GAIAEXIF_DECLARE void
 
1535
gaiaExifTagGetName (const gaiaExifTagPtr tag, char *str, int len)
 
1536
{
 
1537
/* returns the TAG symbolic Name */
 
1538
    exifTagName (tag->Gps, tag->TagId, str, len);
 
1539
}
 
1540
 
 
1541
GAIAEXIF_DECLARE unsigned short
 
1542
gaiaExifTagGetValueType (const gaiaExifTagPtr tag)
 
1543
{
 
1544
/* returns the TAG value Type */
 
1545
    return tag->Type;
 
1546
}
 
1547
 
 
1548
GAIAEXIF_DECLARE unsigned short
 
1549
gaiaExifTagGetNumValues (const gaiaExifTagPtr tag)
 
1550
{
 
1551
/* returns the # TAG Values */
 
1552
    return tag->Count;
 
1553
}
 
1554
 
 
1555
GAIAEXIF_DECLARE unsigned char
 
1556
gaiaExifTagGetByteValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1557
{
 
1558
/* returns the Nth Byte value */
 
1559
    if (ind >= 0
 
1560
        && ind <
 
1561
        tag->Count && (tag->Type == 1 || tag->Type == 6 || tag->Type == 7))
 
1562
      {
 
1563
          *ok = 1;
 
1564
          return *(tag->ByteValue + ind);
 
1565
      }
 
1566
    *ok = 0;
 
1567
    return 0;
 
1568
}
 
1569
 
 
1570
GAIAEXIF_DECLARE void
 
1571
gaiaExifTagGetStringValue (const gaiaExifTagPtr tag, char *str, int len,
 
1572
                           int *ok)
 
1573
{
 
1574
/* returns the String value */
 
1575
    int l;
 
1576
    if (tag->Type == 2)
 
1577
      {
 
1578
          *ok = 1;
 
1579
          l = strlen (tag->StringValue);
 
1580
          if (len > l)
 
1581
              strcpy (str, tag->StringValue);
 
1582
          else
 
1583
            {
 
1584
                memset (str, '\0', len);
 
1585
                memcpy (str, tag->StringValue, len - 1);
 
1586
            }
 
1587
          return;
 
1588
      }
 
1589
    *ok = 0;
 
1590
}
 
1591
 
 
1592
GAIAEXIF_DECLARE unsigned short
 
1593
gaiaExifTagGetShortValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1594
{
 
1595
/* returns the Nth Short value */
 
1596
    if (ind >= 0 && ind < tag->Count && tag->Type == 3)
 
1597
      {
 
1598
          *ok = 1;
 
1599
          return *(tag->ShortValues + ind);
 
1600
      }
 
1601
    *ok = 0;
 
1602
    return 0;
 
1603
}
 
1604
 
 
1605
GAIAEXIF_DECLARE unsigned int
 
1606
gaiaExifTagGetLongValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1607
{
 
1608
/* returns the Nth Long value */
 
1609
    if (ind >= 0 && ind < tag->Count && tag->Type == 4)
 
1610
      {
 
1611
          *ok = 1;
 
1612
          return *(tag->LongValues + ind);
 
1613
      }
 
1614
    *ok = 0;
 
1615
    return 0;
 
1616
}
 
1617
 
 
1618
GAIAEXIF_DECLARE unsigned int
 
1619
gaiaExifTagGetRational1Value (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1620
{
 
1621
/* returns the Nth Rational (1) value */
 
1622
    if (ind >= 0 && ind < tag->Count && tag->Type == 5)
 
1623
      {
 
1624
          *ok = 1;
 
1625
          return *(tag->LongRationals1 + ind);
 
1626
      }
 
1627
    *ok = 0;
 
1628
    return 0;
 
1629
}
 
1630
 
 
1631
GAIAEXIF_DECLARE unsigned int
 
1632
gaiaExifTagGetRational2Value (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1633
{
 
1634
/* returns the Nth Rational (2) value */
 
1635
    if (ind >= 0 && ind < tag->Count && tag->Type == 5)
 
1636
      {
 
1637
          *ok = 1;
 
1638
          return *(tag->LongRationals2 + ind);
 
1639
      }
 
1640
    *ok = 0;
 
1641
    return 0;
 
1642
}
 
1643
 
 
1644
GAIAEXIF_DECLARE double
 
1645
gaiaExifTagGetRationalValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1646
{
 
1647
/* returns the Nth Rational  value as Double */
 
1648
    double x;
 
1649
    if (ind >= 0
 
1650
        && ind < tag->Count && tag->Type == 5 && *(tag->LongRationals2 + ind))
 
1651
      {
 
1652
          *ok = 1;
 
1653
          x = (double) (*(tag->LongRationals1 + ind)) /
 
1654
              (double) (*(tag->LongRationals2 + ind));
 
1655
          return x;
 
1656
      }
 
1657
    *ok = 0;
 
1658
    return 0;
 
1659
}
 
1660
 
 
1661
GAIAEXIF_DECLARE short
 
1662
gaiaExifTagGetSignedShortValue (const gaiaExifTagPtr tag, const int ind,
 
1663
                                int *ok)
 
1664
{
 
1665
/* returns the Nth Signed Short value */
 
1666
    if (ind >= 0 && ind < tag->Count && tag->Type == 8)
 
1667
      {
 
1668
          *ok = 1;
 
1669
          return *(tag->SignedShortValues + ind);
 
1670
      }
 
1671
    *ok = 0;
 
1672
    return 0;
 
1673
}
 
1674
 
 
1675
GAIAEXIF_DECLARE int
 
1676
gaiaExifTagGetSignedLongValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1677
{
 
1678
/* returns the Nth Signed Long value */
 
1679
    if (ind >= 0 && ind < tag->Count && tag->Type == 9)
 
1680
      {
 
1681
          *ok = 1;
 
1682
          return *(tag->SignedLongValues + ind);
 
1683
      }
 
1684
    *ok = 0;
 
1685
    return 0;
 
1686
}
 
1687
 
 
1688
GAIAEXIF_DECLARE int
 
1689
gaiaExifTagGetSignedRational1Value (const gaiaExifTagPtr tag, const int ind,
 
1690
                                    int *ok)
 
1691
{
 
1692
/* returns the Nth Signed Rational (1) value */
 
1693
    if (ind >= 0 && ind < tag->Count && tag->Type == 10)
 
1694
      {
 
1695
          *ok = 1;
 
1696
          return *(tag->SignedLongRationals1 + ind);
 
1697
      }
 
1698
    *ok = 0;
 
1699
    return 0;
 
1700
}
 
1701
 
 
1702
GAIAEXIF_DECLARE int
 
1703
gaiaExifTagGetSignedRational2Value (const gaiaExifTagPtr tag, const int ind,
 
1704
                                    int *ok)
 
1705
{
 
1706
/* returns the Nth Signed Rational (2) value */
 
1707
    if (ind >= 0 && ind < tag->Count && tag->Type == 10)
 
1708
      {
 
1709
          *ok = 1;
 
1710
          return *(tag->SignedLongRationals2 + ind);
 
1711
      }
 
1712
    *ok = 0;
 
1713
    return 0;
 
1714
}
 
1715
 
 
1716
GAIAEXIF_DECLARE double
 
1717
gaiaExifTagGetSignedRationalValue (const gaiaExifTagPtr tag, const int ind,
 
1718
                                   int *ok)
 
1719
{
 
1720
/* returns the Nth Signed Rational  value as Double */
 
1721
    double x;
 
1722
    if (ind >= 0
 
1723
        && ind <
 
1724
        tag->Count && tag->Type == 10 && *(tag->SignedLongRationals2 + ind))
 
1725
      {
 
1726
          *ok = 1;
 
1727
          x = (double) (*(tag->SignedLongRationals1 + ind)) /
 
1728
              (double) (*(tag->SignedLongRationals2 + ind));
 
1729
          return x;
 
1730
      }
 
1731
    *ok = 0;
 
1732
    return 0;
 
1733
}
 
1734
 
 
1735
GAIAEXIF_DECLARE float
 
1736
gaiaExifTagGetFloatValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1737
{
 
1738
/* returns the Nth Float value */
 
1739
    if (ind >= 0 && ind < tag->Count && tag->Type == 11)
 
1740
      {
 
1741
          *ok = 1;
 
1742
          return *(tag->FloatValues + ind);
 
1743
      }
 
1744
    *ok = 0;
 
1745
    return 0;
 
1746
}
 
1747
 
 
1748
GAIAEXIF_DECLARE double
 
1749
gaiaExifTagGetDoubleValue (const gaiaExifTagPtr tag, const int ind, int *ok)
 
1750
{
 
1751
/* returns the Nth Double value */
 
1752
    if (ind >= 0 && ind < tag->Count && tag->Type == 12)
 
1753
      {
 
1754
          *ok = 1;
 
1755
          return *(tag->DoubleValues + ind);
 
1756
      }
 
1757
    *ok = 0;
 
1758
    return 0;
 
1759
}
 
1760
 
 
1761
GAIAEXIF_DECLARE void
 
1762
gaiaExifTagGetHumanReadable (const gaiaExifTagPtr tag, char *str, int len,
 
1763
                             int *ok)
 
1764
{
 
1765
/* returns the Human Readable value */
 
1766
    char *human = "";
 
1767
    char dummy[1024];
 
1768
    int l;
 
1769
    int xok;
 
1770
    double dblval;
 
1771
    switch (tag->TagId)
 
1772
      {
 
1773
      case 0x0128:              /* ResolutionUnit */
 
1774
          if (tag->Type == 3 && tag->Count == 1)
 
1775
            {
 
1776
                switch (*(tag->ShortValues + 0))
 
1777
                  {
 
1778
                  case 2:
 
1779
                      human = "Inches";
 
1780
                      break;
 
1781
                  case 3:
 
1782
                      human = "Centimeters";
 
1783
                      break;
 
1784
                  };
 
1785
            }
 
1786
          break;
 
1787
      case 0x8822:              /* ExposureProgram */
 
1788
          if (tag->Type == 3 && tag->Count == 1)
 
1789
            {
 
1790
                switch (*(tag->ShortValues + 0))
 
1791
                  {
 
1792
                  case 0:
 
1793
                      human = "Not defined";
 
1794
                      break;
 
1795
                  case 1:
 
1796
                      human = "Manual";
 
1797
                      break;
 
1798
                  case 2:
 
1799
                      human = "Normal program";
 
1800
                      break;
 
1801
                  case 3:
 
1802
                      human = "Aperture priority";
 
1803
                      break;
 
1804
                  case 4:
 
1805
                      human = "Shutter priority";
 
1806
                      break;
 
1807
                  case 5:
 
1808
                      human = "Creative program (biased toward depth of field)";
 
1809
                      break;
 
1810
                  case 6:
 
1811
                      human =
 
1812
                          "Action program (biased toward fast shutter speed)";
 
1813
                      break;
 
1814
                  case 7:
 
1815
                      human =
 
1816
                          "Portrait mode (for closeup photos with the background out of focus)";
 
1817
                      break;
 
1818
                  case 8:
 
1819
                      human =
 
1820
                          "Landscape mode (for landscape photos with the background in focus)";
 
1821
                      break;
 
1822
                  };
 
1823
            }
 
1824
          break;
 
1825
      case 0xA402:              /* ExposureMode */
 
1826
          if (tag->Type == 3 && tag->Count == 1)
 
1827
            {
 
1828
                switch (*(tag->ShortValues + 0))
 
1829
                  {
 
1830
                  case 0:
 
1831
                      human = "Auto exposure";
 
1832
                      break;
 
1833
                  case 1:
 
1834
                      human = "Manual exposure";
 
1835
                      break;
 
1836
                  case 2:
 
1837
                      human = "Auto bracket";
 
1838
                      break;
 
1839
                  };
 
1840
            }
 
1841
          break;
 
1842
      case 0x0112:              /* Orientation */
 
1843
          if (tag->Type == 3 && tag->Count == 1)
 
1844
            {
 
1845
                switch (*(tag->ShortValues + 0))
 
1846
                  {
 
1847
                  case 1:
 
1848
                      human = "Normal";
 
1849
                      break;
 
1850
                  case 2:
 
1851
                      human = "Mirrored";
 
1852
                      break;
 
1853
                  case 3:
 
1854
                      human = "Upsidedown";
 
1855
                      break;
 
1856
                  case 4:
 
1857
                      human = "Upsidedown Mirrored";
 
1858
                      break;
 
1859
                  case 5:
 
1860
                      human = "90 deg Clockwise Mirrored";
 
1861
                      break;
 
1862
                  case 6:
 
1863
                      human = "90 deg Counterclocwise";
 
1864
                      break;
 
1865
                  case 7:
 
1866
                      human = "90 deg Counterclocwise Mirrored";
 
1867
                      break;
 
1868
                  case 8:
 
1869
                      human = "90 deg Mirrored";
 
1870
                      break;
 
1871
                  };
 
1872
            }
 
1873
          break;
 
1874
      case 0x9207:              /* MeteringMode */
 
1875
          if (tag->Type == 3 && tag->Count == 1)
 
1876
            {
 
1877
                switch (*(tag->ShortValues + 0))
 
1878
                  {
 
1879
                  case 1:
 
1880
                      human = "Average";
 
1881
                      break;
 
1882
                  case 2:
 
1883
                      human = "Center Weighted Average";
 
1884
                      break;
 
1885
                  case 3:
 
1886
                      human = "Spot";
 
1887
                      break;
 
1888
                  case 4:
 
1889
                      human = "MultiSpot";
 
1890
                      break;
 
1891
                  case 5:
 
1892
                      human = "MultiSegment";
 
1893
                      break;
 
1894
                  case 6:
 
1895
                      human = "Partial";
 
1896
                      break;
 
1897
                  case 255:
 
1898
                      human = "Other";
 
1899
                      break;
 
1900
                  };
 
1901
            }
 
1902
          break;
 
1903
      case 0xA403:              /* WhiteBalance */
 
1904
          if (tag->Type == 3 && tag->Count == 1)
 
1905
            {
 
1906
                switch (*(tag->ShortValues + 0))
 
1907
                  {
 
1908
                  case 0:
 
1909
                      human = "Auto";
 
1910
                      break;
 
1911
                  case 1:
 
1912
                      human = "Sunny";
 
1913
                      break;
 
1914
                  case 2:
 
1915
                      human = "Cloudy";
 
1916
                      break;
 
1917
                  case 3:
 
1918
                      human = "Tungsten";
 
1919
                      break;
 
1920
                  case 4:
 
1921
                      human = "Fluorescent";
 
1922
                      break;
 
1923
                  case 5:
 
1924
                      human = "Flash";
 
1925
                      break;
 
1926
                  case 6:
 
1927
                      human = "Custom";
 
1928
                      break;
 
1929
                  case 129:
 
1930
                      human = "Manual";
 
1931
                      break;
 
1932
                  };
 
1933
            }
 
1934
          break;
 
1935
      case 0x9209:              /* Flash */
 
1936
          if (tag->Type == 3 && tag->Count == 1)
 
1937
            {
 
1938
                switch (*(tag->ShortValues + 0))
 
1939
                  {
 
1940
                  case 0:
 
1941
                  case 16:
 
1942
                  case 24:
 
1943
                  case 32:
 
1944
                      human = "No Flash";
 
1945
                      break;
 
1946
                  case 1:
 
1947
                      human = "Flash";
 
1948
                      break;
 
1949
                  case 5:
 
1950
                      human = "Flash, strobe return light not detected";
 
1951
                      break;
 
1952
                  case 7:
 
1953
                      human = "Flash, strobe return light detected";
 
1954
                      break;
 
1955
                  case 9:
 
1956
                      human = "Compulsory Flash";
 
1957
                      break;
 
1958
                  case 13:
 
1959
                      human = "Compulsory Flash, Return light not detected";
 
1960
                      break;
 
1961
                  case 15:
 
1962
                      human = "Compulsory Flash, Return light detected";
 
1963
                      break;
 
1964
                  case 25:
 
1965
                      human = "Flash, Auto-Mode";
 
1966
                      break;
 
1967
                  case 29:
 
1968
                      human = "Flash, Auto-Mode, Return light not detected";
 
1969
                      break;
 
1970
                  case 31:
 
1971
                      human = "Flash, Auto-Mode, Return light detected";
 
1972
                      break;
 
1973
                  case 65:
 
1974
                      human = "Red Eye";
 
1975
                      break;
 
1976
                  case 69:
 
1977
                      human = "Red Eye, Return light not detected";
 
1978
                      break;
 
1979
                  case 71:
 
1980
                      human = "Red Eye, Return light detected";
 
1981
                      break;
 
1982
                  case 73:
 
1983
                      human = "Red Eye, Compulsory Flash";
 
1984
                      break;
 
1985
                  case 77:
 
1986
                      human =
 
1987
                          "Red Eye, Compulsory Flash, Return light not detected";
 
1988
                      break;
 
1989
                  case 79:
 
1990
                      human =
 
1991
                          "Red Eye, Compulsory Flash, Return light detected";
 
1992
                      break;
 
1993
                  case 89:
 
1994
                      human = "Red Eye, Auto-Mode";
 
1995
                      break;
 
1996
                  case 93:
 
1997
                      human = "Red Eye, Auto-Mode, Return light not detected";
 
1998
                      break;
 
1999
                  case 95:
 
2000
                      human = "Red Eye, Auto-Mode, Return light detected";
 
2001
                      break;
 
2002
                  };
 
2003
            }
 
2004
          break;
 
2005
      case 0xA217:              /* SensingMethod */
 
2006
          if (tag->Type == 3 && tag->Count == 1)
 
2007
            {
 
2008
                switch (*(tag->ShortValues + 0))
 
2009
                  {
 
2010
                  case 1:
 
2011
                      human = "Not defined";
 
2012
                      break;
 
2013
                  case 2:
 
2014
                      human = "One Chip Color Area Sensor";
 
2015
                      break;
 
2016
                  case 3:
 
2017
                      human = "Two Chip Color Area Sensor";
 
2018
                      break;
 
2019
                  case 4:
 
2020
                      human = "Three Chip Color Area Sensor";
 
2021
                      break;
 
2022
                  case 5:
 
2023
                      human = "Color Sequential Area Sensor";
 
2024
                      break;
 
2025
                  case 7:
 
2026
                      human = "Trilinear Sensor";
 
2027
                      break;
 
2028
                  case 8:
 
2029
                      human = "Color Sequential Linear Sensor";
 
2030
                      break;
 
2031
                  };
 
2032
            }
 
2033
          break;
 
2034
      case 0xA406:              /* SceneCaptureType */
 
2035
          if (tag->Type == 3 && tag->Count == 1)
 
2036
            {
 
2037
                switch (*(tag->ShortValues + 0))
 
2038
                  {
 
2039
                  case 0:
 
2040
                      human = "Standard";
 
2041
                      break;
 
2042
                  case 1:
 
2043
                      human = "Landscape";
 
2044
                      break;
 
2045
                  case 2:
 
2046
                      human = "Portrait";
 
2047
                      break;
 
2048
                  case 3:
 
2049
                      human = "Night scene";
 
2050
                      break;
 
2051
                  };
 
2052
            }
 
2053
          break;
 
2054
      case 0xA407:              /* GainControl */
 
2055
          if (tag->Type == 3 && tag->Count == 1)
 
2056
            {
 
2057
                switch (*(tag->ShortValues + 0))
 
2058
                  {
 
2059
                  case 0:
 
2060
                      human = "None";
 
2061
                      break;
 
2062
                  case 1:
 
2063
                      human = "Low gain up";
 
2064
                      break;
 
2065
                  case 2:
 
2066
                      human = "High gain up";
 
2067
                      break;
 
2068
                  case 3:
 
2069
                      human = "Low gain down";
 
2070
                      break;
 
2071
                  case 4:
 
2072
                      human = "High gain down";
 
2073
                      break;
 
2074
                  };
 
2075
            }
 
2076
          break;
 
2077
      case 0xA408:              /* Contrast */
 
2078
          if (tag->Type == 3 && tag->Count == 1)
 
2079
            {
 
2080
                switch (*(tag->ShortValues + 0))
 
2081
                  {
 
2082
                  case 0:
 
2083
                      human = "Normal";
 
2084
                      break;
 
2085
                  case 1:
 
2086
                      human = "Soft";
 
2087
                      break;
 
2088
                  case 2:
 
2089
                      human = "Hard";
 
2090
                      break;
 
2091
                  };
 
2092
            }
 
2093
          break;
 
2094
      case 0xA409:              /* Saturation */
 
2095
          if (tag->Type == 3 && tag->Count == 1)
 
2096
            {
 
2097
                switch (*(tag->ShortValues + 0))
 
2098
                  {
 
2099
                  case 0:
 
2100
                      human = "Normal";
 
2101
                      break;
 
2102
                  case 1:
 
2103
                      human = "Low saturation";
 
2104
                      break;
 
2105
                  case 2:
 
2106
                      human = "High saturation";
 
2107
                      break;
 
2108
                  };
 
2109
            }
 
2110
          break;
 
2111
      case 0xA40A:              /* Sharpness */
 
2112
          if (tag->Type == 3 && tag->Count == 1)
 
2113
            {
 
2114
                switch (*(tag->ShortValues + 0))
 
2115
                  {
 
2116
                  case 0:
 
2117
                      human = "Normal";
 
2118
                      break;
 
2119
                  case 1:
 
2120
                      human = "Soft";
 
2121
                      break;
 
2122
                  case 2:
 
2123
                      human = "Hard";
 
2124
                      break;
 
2125
                  };
 
2126
            }
 
2127
          break;
 
2128
      case 0xA40C:              /* SubjectDistanceRange */
 
2129
          if (tag->Type == 3 && tag->Count == 1)
 
2130
            {
 
2131
                switch (*(tag->ShortValues + 0))
 
2132
                  {
 
2133
                  case 0:
 
2134
                      human = "Unknown";
 
2135
                      break;
 
2136
                  case 1:
 
2137
                      human = "Macro";
 
2138
                      break;
 
2139
                  case 2:
 
2140
                      human = "Close view";
 
2141
                      break;
 
2142
                  case 3:
 
2143
                      human = "Distant view";
 
2144
                      break;
 
2145
                  };
 
2146
            }
 
2147
          break;
 
2148
      case 0x9208:              /* LightSource */
 
2149
          if (tag->Type == 3 && tag->Count == 1)
 
2150
            {
 
2151
                switch (*(tag->ShortValues + 0))
 
2152
                  {
 
2153
                  case 0:
 
2154
                      human = "Unknown";
 
2155
                      break;
 
2156
                  case 1:
 
2157
                      human = "Daylight";
 
2158
                      break;
 
2159
                  case 2:
 
2160
                      human = "Fluorescent";
 
2161
                      break;
 
2162
                  case 3:
 
2163
                      human = "Tungsten (incandescent light)";
 
2164
                      break;
 
2165
                  case 4:
 
2166
                      human = "Flash";
 
2167
                      break;
 
2168
                  case 9:
 
2169
                      human = "Fine weather";
 
2170
                      break;
 
2171
                  case 10:
 
2172
                      human = "Cloudy weather";
 
2173
                      break;
 
2174
                  case 11:
 
2175
                      human = "Shade";
 
2176
                  case 12:
 
2177
                      human = "Daylight fluorescent (D 5700 � 7100K)";
 
2178
                      break;
 
2179
                  case 13:
 
2180
                      human = "Day white fluorescent (N 4600 � 5400K)";
 
2181
                      break;
 
2182
                  case 14:
 
2183
                      human = "Cool white fluorescent (W 3900 � 4500K)";
 
2184
                  case 15:
 
2185
                      human = "White fluorescent (WW 3200 � 3700K)";
 
2186
                      break;
 
2187
                  case 17:
 
2188
                      human = "Standard light A";
 
2189
                      break;
 
2190
                  case 18:
 
2191
                      human = "Standard light B";
 
2192
                      break;
 
2193
                  case 19:
 
2194
                      human = "Standard light C";
 
2195
                      break;
 
2196
                  case 20:
 
2197
                      human = "D55";
 
2198
                      break;
 
2199
                  case 21:
 
2200
                      human = "D65";
 
2201
                      break;
 
2202
                  case 22:
 
2203
                      human = "D75";
 
2204
                      break;
 
2205
                  case 23:
 
2206
                      human = "D50";
 
2207
                      break;
 
2208
                  case 24:
 
2209
                      human = "ISO studio tungsten";
 
2210
                      break;
 
2211
                  case 255:
 
2212
                      human = "other light source";
 
2213
                      break;
 
2214
                  };
 
2215
            }
 
2216
          break;
 
2217
      case 0xA001:              /* ColorSpace */
 
2218
          if (tag->Type == 3 && tag->Count == 1)
 
2219
            {
 
2220
                switch (*(tag->ShortValues + 0))
 
2221
                  {
 
2222
                  case 1:
 
2223
                      human = "sRGB";
 
2224
                      break;
 
2225
                  case 0xffff:
 
2226
                      human = "Uncalibrated";
 
2227
                      break;
 
2228
                  };
 
2229
            }
 
2230
          break;
 
2231
      case 0x8827:              /* ISOSpeedRatings */
 
2232
          if (tag->Type == 3 && tag->Count == 1)
 
2233
            {
 
2234
                sprintf (dummy, "%u ISO", *(tag->ShortValues + 0));
 
2235
                human = dummy;
 
2236
            }
 
2237
          break;
 
2238
      case 0xA002:              /* ExifImageWidth */
 
2239
      case 0xA003:              /* ExifImageLength */
 
2240
          if (tag->Type == 3 && tag->Count == 1)
 
2241
            {
 
2242
                sprintf (dummy, "%u pixels", *(tag->ShortValues + 0));
 
2243
                human = dummy;
 
2244
            }
 
2245
          else if (tag->Type == 4 && tag->Count == 1)
 
2246
            {
 
2247
                sprintf (dummy, "%u pixels", *(tag->LongValues + 0));
 
2248
                human = dummy;
 
2249
            }
 
2250
          break;
 
2251
      case 0x829A:              /* ExposureTime */
 
2252
          if (tag->Type == 5 && tag->Count == 1)
 
2253
            {
 
2254
                dblval = gaiaExifTagGetRationalValue (tag, 0, &xok);
 
2255
                if (xok)
 
2256
                  {
 
2257
                      if (dblval < 1.0)
 
2258
                        {
 
2259
                            dblval = 1.0 / dblval;
 
2260
                            sprintf (dummy, "1/%1.0f sec", dblval);
 
2261
                            human = dummy;
 
2262
                        }
 
2263
                      else
 
2264
                        {
 
2265
                            sprintf (dummy, "%1.0f sec", dblval);
 
2266
                            human = dummy;
 
2267
                        }
 
2268
                  }
 
2269
            }
 
2270
          break;
 
2271
      case 0x9201:              /* ShutterSpeedValue */
 
2272
          if (tag->Type == 10 && tag->Count == 1)
 
2273
            {
 
2274
                dblval = gaiaExifTagGetSignedRationalValue (tag, 0, &xok);
 
2275
                if (xok)
 
2276
                  {
 
2277
                      dblval = exp (dblval * log (2));
 
2278
                      if (dblval > 1.0)
 
2279
                          dblval = floor (dblval);
 
2280
                      if (dblval < 1.0)
 
2281
                        {
 
2282
                            dblval = math_round (1.0 / dblval);
 
2283
                            sprintf (dummy, "%1.0f sec", dblval);
 
2284
                            human = dummy;
 
2285
                        }
 
2286
                      else
 
2287
                        {
 
2288
                            sprintf (dummy, "1/%1.0f sec", dblval);
 
2289
                            human = dummy;
 
2290
                        }
 
2291
                  }
 
2292
            }
 
2293
          break;
 
2294
      case 0x829D:              /* FNumber */
 
2295
          if (tag->Type == 5 && tag->Count == 1)
 
2296
            {
 
2297
                dblval = gaiaExifTagGetRationalValue (tag, 0, &xok);
 
2298
                if (xok)
 
2299
                  {
 
2300
                      sprintf (dummy, "F %1.1f", dblval);
 
2301
                      human = dummy;
 
2302
                  }
 
2303
            }
 
2304
          break;
 
2305
      case 0x9202:              /* ApertureValue */
 
2306
      case 0x9205:              /* MaxApertureValue */
 
2307
          if (tag->Type == 5 && tag->Count == 1)
 
2308
            {
 
2309
                dblval = gaiaExifTagGetRationalValue (tag, 0, &xok);
 
2310
                if (xok)
 
2311
                  {
 
2312
                      dblval = exp ((dblval * log (2)) / 2.0);
 
2313
                      sprintf (dummy, "F %1.1f", dblval);
 
2314
                      human = dummy;
 
2315
                  }
 
2316
            }
 
2317
          break;
 
2318
      case 0x920A:              /* FocalLength */
 
2319
          if (tag->Type == 5 && tag->Count == 1)
 
2320
            {
 
2321
                dblval = gaiaExifTagGetRationalValue (tag, 0, &xok);
 
2322
                if (xok)
 
2323
                  {
 
2324
                      sprintf (dummy, "%1.1f mm", dblval);
 
2325
                      human = dummy;
 
2326
                  }
 
2327
            }
 
2328
          break;
 
2329
      case 0xA405:              /* FocalLengthIn35mmFilm */
 
2330
          if (tag->Type == 3 && tag->Count == 1)
 
2331
            {
 
2332
                sprintf (dummy, "%u mm", *(tag->ShortValues + 0));
 
2333
                human = dummy;
 
2334
            }
 
2335
          break;
 
2336
      case 0x9204:              /* ExposureBiasValue */
 
2337
          if (tag->Type == 10 && tag->Count == 1)
 
2338
            {
 
2339
                dblval = gaiaExifTagGetSignedRationalValue (tag, 0, &xok);
 
2340
                if (xok)
 
2341
                  {
 
2342
                      sprintf (dummy, "%1.2f EV", dblval);
 
2343
                      human = dummy;
 
2344
                  }
 
2345
            }
 
2346
          break;
 
2347
      };
 
2348
    l = strlen (human);
 
2349
    if (l > 0)
 
2350
      {
 
2351
          if (len > l)
 
2352
              strcpy (str, human);
 
2353
          else
 
2354
            {
 
2355
                memset (str, '\0', len);
 
2356
                memcpy (str, human, len - 1);
 
2357
            }
 
2358
          *ok = 1;
 
2359
          return;
 
2360
      }
 
2361
    *ok = 0;
 
2362
}
 
2363
 
 
2364
GAIAEXIF_DECLARE int
 
2365
gaiaGuessBlobType (const unsigned char *blob, int size)
 
2366
{
 
2367
/* returns the BLOB content type */
 
2368
    int jpeg = 0;
 
2369
    int exif = 0;
 
2370
    int exif_gps = 0;
 
2371
    int geom = 1;
 
2372
    gaiaExifTagListPtr exif_list;
 
2373
    gaiaExifTagPtr pT;
 
2374
    unsigned char jpeg1_signature[2];
 
2375
    unsigned char jpeg2_signature[2];
 
2376
    unsigned char jpeg3_signature[4];
 
2377
    unsigned char jfif_signature[4];
 
2378
    unsigned char exif_signature[4];
 
2379
    unsigned char png_signature[8];
 
2380
    unsigned char zip_signature[4];
 
2381
    unsigned char tiff_signature_little[4];
 
2382
    unsigned char tiff_signature_big[4];
 
2383
    jpeg1_signature[0] = 0xff;
 
2384
    jpeg1_signature[1] = 0xd8;
 
2385
    jpeg2_signature[0] = 0xff;
 
2386
    jpeg2_signature[1] = 0xd9;
 
2387
    jpeg3_signature[0] = 0xff;
 
2388
    jpeg3_signature[1] = 0xd8;
 
2389
    jpeg3_signature[2] = 0xff;
 
2390
    jpeg3_signature[3] = 0xe0;
 
2391
    jfif_signature[0] = 0x4a;
 
2392
    jfif_signature[1] = 0x46;
 
2393
    jfif_signature[2] = 0x49;
 
2394
    jfif_signature[3] = 0x46;
 
2395
    exif_signature[0] = 0x45;
 
2396
    exif_signature[1] = 0x78;
 
2397
    exif_signature[2] = 0x69;
 
2398
    exif_signature[3] = 0x66;
 
2399
    png_signature[0] = 0x89;
 
2400
    png_signature[1] = 0x50;
 
2401
    png_signature[2] = 0x4e;
 
2402
    png_signature[3] = 0x47;
 
2403
    png_signature[4] = 0x0d;
 
2404
    png_signature[5] = 0x0a;
 
2405
    png_signature[6] = 0x1a;
 
2406
    png_signature[7] = 0x0a;
 
2407
    zip_signature[0] = 0x50;
 
2408
    zip_signature[1] = 0x4b;
 
2409
    zip_signature[2] = 0x03;
 
2410
    zip_signature[3] = 0x04;
 
2411
    tiff_signature_little[0] = 'I';
 
2412
    tiff_signature_little[1] = 'I';
 
2413
    tiff_signature_little[2] = 0x2a;
 
2414
    tiff_signature_little[3] = 0x00;
 
2415
    tiff_signature_big[0] = 'M';
 
2416
    tiff_signature_big[1] = 'M';
 
2417
    tiff_signature_big[2] = 0x00;
 
2418
    tiff_signature_big[3] = 0x2a;
 
2419
    if (size < 1 || !blob)
 
2420
        return GAIA_HEX_BLOB;
 
2421
    if (size > 4)
 
2422
      {
 
2423
          if (memcmp (blob, tiff_signature_big, 4) == 0)
 
2424
              return GAIA_TIFF_BLOB;
 
2425
          if (memcmp (blob, tiff_signature_little, 4) == 0)
 
2426
              return GAIA_TIFF_BLOB;
 
2427
      }
 
2428
    if (size > 5)
 
2429
      {
 
2430
          if (strncmp ((char *) blob, "%PDF-", 5) == 0)
 
2431
              return GAIA_PDF_BLOB;
 
2432
      }
 
2433
    if (size > 4)
 
2434
      {
 
2435
          if (memcmp (blob, zip_signature, 4) == 0)
 
2436
              return GAIA_ZIP_BLOB;
 
2437
      }
 
2438
    if (size > 6)
 
2439
      {
 
2440
          if (strncmp ((char *) blob, "GIF87a", 6) == 0
 
2441
              || strncmp ((char *) blob, "GIF89a", 6) == 0)
 
2442
              return GAIA_GIF_BLOB;
 
2443
      }
 
2444
    if (size > 8)
 
2445
      {
 
2446
          if (memcmp (blob, png_signature, 8) == 0)
 
2447
              return GAIA_PNG_BLOB;
 
2448
      }
 
2449
    if (size > 4)
 
2450
      {
 
2451
          if (memcmp (blob, jpeg1_signature, 2) == 0
 
2452
              && memcmp (blob + size - 2, jpeg2_signature, 2) == 0)
 
2453
              jpeg = 1;         /* this one is the standard JPEG signature */
 
2454
          if (memcmp (blob, jpeg3_signature, 4) == 0)
 
2455
              jpeg = 1;         /* another common JPEG signature */
 
2456
      }
 
2457
    if (size > 10)
 
2458
      {
 
2459
          if (memcmp (blob + 6, jfif_signature, 4) == 0)
 
2460
              jpeg = 1;         /* standard JFIF signature */
 
2461
          if (memcmp (blob + 6, exif_signature, 4) == 0)
 
2462
              jpeg = 1;         /* standard EXIF signature */
 
2463
      }
 
2464
    if (jpeg)
 
2465
      {
 
2466
          exif_list = gaiaGetExifTags (blob, size);
 
2467
          if (exif_list)
 
2468
            {
 
2469
                exif = 1;
 
2470
                pT = exif_list->First;
 
2471
                while (pT)
 
2472
                  {
 
2473
                      if (pT->Gps)
 
2474
                        {
 
2475
                            exif_gps = 1;
 
2476
                            break;
 
2477
                        }
 
2478
                      pT = pT->Next;
 
2479
                  }
 
2480
                gaiaExifTagsFree (exif_list);
 
2481
            }
 
2482
      }
 
2483
    if (jpeg && exif && exif_gps)
 
2484
        return GAIA_EXIF_GPS_BLOB;
 
2485
    if (jpeg && exif)
 
2486
        return GAIA_EXIF_BLOB;
 
2487
    if (jpeg)
 
2488
        return GAIA_JPEG_BLOB;
 
2489
/* testing for GEOMETRY */
 
2490
    if (size < 45)
 
2491
        geom = 0;
 
2492
    else
 
2493
      {
 
2494
          if (*(blob + 0) != GAIA_MARK_START)
 
2495
              geom = 0;
 
2496
          if (*(blob + (size - 1)) != GAIA_MARK_END)
 
2497
              geom = 0;
 
2498
          if (*(blob + 38) != GAIA_MARK_MBR)
 
2499
              geom = 0;
 
2500
          if (*(blob + 1) == 0 || *(blob + 1) == 1)
 
2501
              ;
 
2502
          else
 
2503
              geom = 0;
 
2504
      }
 
2505
    if (geom)
 
2506
        return GAIA_GEOMETRY_BLOB;
 
2507
    return GAIA_HEX_BLOB;
 
2508
}
 
2509
 
 
2510
GAIAEXIF_DECLARE int
 
2511
gaiaGetGpsCoords (const unsigned char *blob, int size, double *longitude,
 
2512
                  double *latitude)
 
2513
{
 
2514
/* returns the ExifGps coords, if they exists */
 
2515
    gaiaExifTagListPtr exif_list;
 
2516
    gaiaExifTagPtr pT;
 
2517
    char lat_ref = '\0';
 
2518
    char long_ref = '\0';
 
2519
    double lat_degs = -DBL_MAX;
 
2520
    double lat_mins = -DBL_MAX;
 
2521
    double lat_secs = -DBL_MAX;
 
2522
    double long_degs = -DBL_MAX;
 
2523
    double long_mins = -DBL_MAX;
 
2524
    double long_secs = -DBL_MAX;
 
2525
    double dblval;
 
2526
    double sign;
 
2527
    int ok;
 
2528
    if (size < 1 || !blob)
 
2529
        return 0;
 
2530
    exif_list = gaiaGetExifTags (blob, size);
 
2531
    if (exif_list)
 
2532
      {
 
2533
          pT = exif_list->First;
 
2534
          while (pT)
 
2535
            {
 
2536
                if (pT->Gps && pT->TagId == 0x01)
 
2537
                  {
 
2538
                      /* ok, this one is the GPSLatitudeRef tag */
 
2539
                      if (pT->Type == 2)
 
2540
                          lat_ref = *(pT->StringValue);
 
2541
                  }
 
2542
                if (pT->Gps && pT->TagId == 0x03)
 
2543
                  {
 
2544
                      /* ok, this one is the GPSLongitudeRef tag */
 
2545
                      if (pT->Type == 2)
 
2546
                          long_ref = *(pT->StringValue);
 
2547
                  }
 
2548
                if (pT->Gps && pT->TagId == 0x02)
 
2549
                  {
 
2550
                      /* ok, this one is the GPSLatitude tag */
 
2551
                      if (pT->Type == 5 && pT->Count == 3)
 
2552
                        {
 
2553
                            dblval = gaiaExifTagGetRationalValue (pT, 0, &ok);
 
2554
                            if (ok)
 
2555
                                lat_degs = dblval;
 
2556
                            dblval = gaiaExifTagGetRationalValue (pT, 1, &ok);
 
2557
                            if (ok)
 
2558
                                lat_mins = dblval;
 
2559
                            dblval = gaiaExifTagGetRationalValue (pT, 2, &ok);
 
2560
                            if (ok)
 
2561
                                lat_secs = dblval;
 
2562
                        }
 
2563
                  }
 
2564
                if (pT->Gps && pT->TagId == 0x04)
 
2565
                  {
 
2566
                      /* ok, this one is the GPSLongitude tag */
 
2567
                      if (pT->Type == 5 && pT->Count == 3)
 
2568
                        {
 
2569
                            dblval = gaiaExifTagGetRationalValue (pT, 0, &ok);
 
2570
                            if (ok)
 
2571
                                long_degs = dblval;
 
2572
                            dblval = gaiaExifTagGetRationalValue (pT, 1, &ok);
 
2573
                            if (ok)
 
2574
                                long_mins = dblval;
 
2575
                            dblval = gaiaExifTagGetRationalValue (pT, 2, &ok);
 
2576
                            if (ok)
 
2577
                                long_secs = dblval;
 
2578
                        }
 
2579
                  }
 
2580
                pT = pT->Next;
 
2581
            }
 
2582
          gaiaExifTagsFree (exif_list);
 
2583
          if ((lat_ref == 'N' || lat_ref == 'S' || long_ref == 'E'
 
2584
               || long_ref == 'W') && lat_degs != -DBL_MAX
 
2585
              && lat_mins != -DBL_MAX && lat_secs != -DBL_MAX
 
2586
              && long_degs != -DBL_MAX && long_mins != -DBL_MAX
 
2587
              && long_secs != -DBL_MAX)
 
2588
            {
 
2589
                if (lat_ref == 'S')
 
2590
                    sign = -1.0;
 
2591
                else
 
2592
                    sign = 1.0;
 
2593
                lat_degs = math_round (lat_degs * 1000000.0);
 
2594
                lat_mins = math_round (lat_mins * 1000000.0);
 
2595
                lat_secs = math_round (lat_secs * 1000000.0);
 
2596
                dblval =
 
2597
                    math_round (lat_degs + (lat_mins / 60.0) +
 
2598
                                (lat_secs / 3600.0)) * (sign / 1000000.0);
 
2599
                *latitude = dblval;
 
2600
                if (long_ref == 'W')
 
2601
                    sign = -1.0;
 
2602
                else
 
2603
                    sign = 1.0;
 
2604
                long_degs = math_round (long_degs * 1000000.0);
 
2605
                long_mins = math_round (long_mins * 1000000.0);
 
2606
                long_secs = math_round (long_secs * 1000000.0);
 
2607
                dblval =
 
2608
                    math_round (long_degs + (long_mins / 60.0) +
 
2609
                                (long_secs / 3600.0)) * (sign / 1000000.0);
 
2610
                *longitude = dblval;
 
2611
                return 1;
 
2612
            }
 
2613
      }
 
2614
    return 0;
 
2615
}
 
2616
 
 
2617
GAIAEXIF_DECLARE int
 
2618
gaiaGetGpsLatLong (const unsigned char *blob, int size, char *latlong,
 
2619
                   int ll_size)
 
2620
{
 
2621
/* returns the ExifGps Latitude and Longitude, if they exists */
 
2622
    gaiaExifTagListPtr exif_list;
 
2623
    gaiaExifTagPtr pT;
 
2624
    char lat_ref = '\0';
 
2625
    char long_ref = '\0';
 
2626
    double lat_degs = -DBL_MAX;
 
2627
    double lat_mins = -DBL_MAX;
 
2628
    double lat_secs = -DBL_MAX;
 
2629
    double long_degs = -DBL_MAX;
 
2630
    double long_mins = -DBL_MAX;
 
2631
    double long_secs = -DBL_MAX;
 
2632
    double dblval;
 
2633
    int ok;
 
2634
    char ll[1024];
 
2635
    int len;
 
2636
    *latlong = '\0';
 
2637
    if (size < 1 || !blob)
 
2638
        return 0;
 
2639
    exif_list = gaiaGetExifTags (blob, size);
 
2640
    if (exif_list)
 
2641
      {
 
2642
          pT = exif_list->First;
 
2643
          while (pT)
 
2644
            {
 
2645
                if (pT->Gps && pT->TagId == 0x01)
 
2646
                  {
 
2647
                      /* ok, this one is the GPSLatitudeRef tag */
 
2648
                      if (pT->Type == 2)
 
2649
                          lat_ref = *(pT->StringValue);
 
2650
                  }
 
2651
                if (pT->Gps && pT->TagId == 0x03)
 
2652
                  {
 
2653
                      /* ok, this one is the GPSLongitudeRef tag */
 
2654
                      if (pT->Type == 2)
 
2655
                          long_ref = *(pT->StringValue);
 
2656
                  }
 
2657
                if (pT->Gps && pT->TagId == 0x02)
 
2658
                  {
 
2659
                      /* ok, this one is the GPSLatitude tag */
 
2660
                      if (pT->Type == 5 && pT->Count == 3)
 
2661
                        {
 
2662
                            dblval = gaiaExifTagGetRationalValue (pT, 0, &ok);
 
2663
                            if (ok)
 
2664
                                lat_degs = dblval;
 
2665
                            dblval = gaiaExifTagGetRationalValue (pT, 1, &ok);
 
2666
                            if (ok)
 
2667
                                lat_mins = dblval;
 
2668
                            dblval = gaiaExifTagGetRationalValue (pT, 2, &ok);
 
2669
                            if (ok)
 
2670
                                lat_secs = dblval;
 
2671
                        }
 
2672
                  }
 
2673
                if (pT->Gps && pT->TagId == 0x04)
 
2674
                  {
 
2675
                      /* ok, this one is the GPSLongitude tag */
 
2676
                      if (pT->Type == 5 && pT->Count == 3)
 
2677
                        {
 
2678
                            dblval = gaiaExifTagGetRationalValue (pT, 0, &ok);
 
2679
                            if (ok)
 
2680
                                long_degs = dblval;
 
2681
                            dblval = gaiaExifTagGetRationalValue (pT, 1, &ok);
 
2682
                            if (ok)
 
2683
                                long_mins = dblval;
 
2684
                            dblval = gaiaExifTagGetRationalValue (pT, 2, &ok);
 
2685
                            if (ok)
 
2686
                                long_secs = dblval;
 
2687
                        }
 
2688
                  }
 
2689
                pT = pT->Next;
 
2690
            }
 
2691
          gaiaExifTagsFree (exif_list);
 
2692
          if ((lat_ref == 'N' || lat_ref == 'S' || long_ref == 'E'
 
2693
               || long_ref == 'W') && lat_degs != -DBL_MAX
 
2694
              && lat_mins != -DBL_MAX && lat_secs != -DBL_MAX
 
2695
              && long_degs != -DBL_MAX && long_mins != -DBL_MAX
 
2696
              && long_secs != -DBL_MAX)
 
2697
            {
 
2698
                sprintf (ll,
 
2699
                         "%c %1.2f %1.2f %1.2f / %c %1.2f %1.2f %1.2f",
 
2700
                         lat_ref, lat_degs, lat_mins, lat_secs, long_ref,
 
2701
                         long_degs, long_mins, long_secs);
 
2702
                len = strlen (ll);
 
2703
                if (len < ll_size)
 
2704
                    strcpy (latlong, ll);
 
2705
                else
 
2706
                  {
 
2707
                      memcpy (latlong, ll, ll_size - 1);
 
2708
                      latlong[ll_size] = '\0';
 
2709
                  }
 
2710
                return 1;
 
2711
            }
 
2712
      }
 
2713
    return 0;
 
2714
}