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