134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Parsing of GPS info from exif header.
334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
4434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen// Matthias Wandel,  Dec 1999 - Dec 2002
534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include "jhead.h"
734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <string.h>
934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <utils/Log.h>
1034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_LAT_REF    1
1334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_LAT        2
1434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_LONG_REF   3
1534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_LONG       4
1634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_ALT_REF    5
1734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define TAG_GPS_ALT        6
18a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen#define TAG_GPS_TIMESTAMP  7
19434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen#define TAG_GPS_PROCESSING_METHOD 27
20a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen#define TAG_GPS_DATESTAMP  29
2134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
2234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic TagTable_t GpsTags[]= {
2334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x00, "GPSVersionID", FMT_BYTE, 4},
2434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x01, "GPSLatitudeRef", FMT_STRING, 2},
2534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x02, "GPSLatitude", FMT_URATIONAL, 3},
2634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x03, "GPSLongitudeRef", FMT_STRING, 2},
2734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x04, "GPSLongitude", FMT_URATIONAL, 3},
2834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x05, "GPSAltitudeRef", FMT_BYTE, 1},
291ed8197f0cefb2541f630830993e109c59ba822cWu-cheng Li    { 0x06, "GPSAltitude", FMT_URATIONAL, 1},
3034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x07, "GPSTimeStamp", FMT_SRATIONAL, 3},
3134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x08, "GPSSatellites", FMT_STRING, -1},
3234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x09, "GPSStatus", FMT_STRING, 2},
3334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0A, "GPSMeasureMode", FMT_STRING, 2},
3434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0B, "GPSDOP", FMT_SRATIONAL, 1},
3534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0C, "GPSSpeedRef", FMT_STRING, 2},
3634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0D, "GPSSpeed", FMT_SRATIONAL, 1},
3734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0E, "GPSTrackRef", FMT_STRING, 2},
3834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x0F, "GPSTrack", FMT_SRATIONAL, 1},
3934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x10, "GPSImgDirectionRef", FMT_STRING, -1},
4034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x11, "GPSImgDirection", FMT_SRATIONAL, 1},
4134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x12, "GPSMapDatum", FMT_STRING, -1},
4234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x13, "GPSDestLatitudeRef", FMT_STRING, 2},
4334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x14, "GPSDestLatitude", FMT_SRATIONAL, 3},
4434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x15, "GPSDestLongitudeRef", FMT_STRING, 2},
4534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x16, "GPSDestLongitude", FMT_SRATIONAL, 3},
4634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x17, "GPSDestBearingRef", FMT_STRING, 1},
4734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x18, "GPSDestBearing", FMT_SRATIONAL, 1},
4834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x19, "GPSDestDistanceRef", FMT_STRING, 2},
4934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x1A, "GPSDestDistance", FMT_SRATIONAL, 1},
50bd90094d709a579d8d74c326269e492627be9daaTyler Luu    { 0x1B, "GPSProcessingMethod", FMT_UNDEFINED, -1},
5134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x1C, "GPSAreaInformation", FMT_STRING, -1},
5234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x1D, "GPSDateStamp", FMT_STRING, 11},
5334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    { 0x1E, "GPSDifferential", FMT_SSHORT, 1},
5434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project};
5534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define MAX_GPS_TAG  (sizeof(GpsTags) / sizeof(TagTable_t))
57434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen#define EXIF_ASCII_PREFIX_LEN (sizeof(ExifAsciiPrefix))
5834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Define the line below to turn on poor man's debugging output
6034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#undef SUPERDEBUG
6134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
637a314dab81f01bac02d617ffca9dbf7b6cc00700Steve Block#define printf ALOGE
6434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
6534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint IsGpsTag(const char* tag) {
6834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return strstr(tag, "GPS") == tag;
6934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
7034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
7134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectTagTable_t* GpsTagToTagTableEntry(unsigned short tag)
7234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
7334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned int i;
7434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < MAX_GPS_TAG; i++) {
7534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (GpsTags[i].Tag == tag) {
7634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("found tag %d", tag);
7734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int format = GpsTags[i].Format;
7834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (format == 0) {
7934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("tag %s format not defined", GpsTags[i].Desc);
8034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return NULL;
8134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
8234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return &GpsTags[i];
8334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
8434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
8534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("tag %d NOT FOUND", tag);
8634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return NULL;
8734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
8834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint GpsTagToFormatType(unsigned short tag)
9034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
9134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned int i;
9234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < MAX_GPS_TAG; i++) {
9334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (GpsTags[i].Tag == tag) {
9434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("found tag %d", tag);
9534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            int format = GpsTags[i].Format;
9634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (format == 0) {
9734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("tag %s format not defined", GpsTags[i].Desc);
9834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                return -1;
9934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
10034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return format;
10134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
10234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
10334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("tag %d NOT FOUND", tag);
10434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return -1;
10534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
10634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectint GpsTagNameToValue(const char* tagName)
10834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
10934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned int i;
11034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < MAX_GPS_TAG; i++) {
11134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (strcmp(GpsTags[i].Desc, tagName) == 0) {
11234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            printf("found GPS tag %s val %d", GpsTags[i].Desc, GpsTags[i].Tag);
11334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return GpsTags[i].Tag;
11434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
11534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
11634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("GPS tag %s NOT FOUND", tagName);
11734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return -1;
11834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
11934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
12034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
12134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
12234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Process GPS info directory
12334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//--------------------------------------------------------------------------
12434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid ProcessGpsInfo(unsigned char * DirStart, int ByteCountUnused, unsigned char * OffsetBase, unsigned ExifLength)
12534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
12634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int de;
12734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unsigned a;
12834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int NumDirEntries;
12934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
13034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    NumDirEntries = Get16u(DirStart);
13134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
13234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
13334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ShowTags){
13434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        printf("(dir has %d entries)\n",NumDirEntries);
13534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
13634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
13734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.GpsInfoPresent = TRUE;
13834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    strcpy(ImageInfo.GpsLat, "? ?");
13934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    strcpy(ImageInfo.GpsLong, "? ?");
14034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.GpsAlt[0] = 0;
14134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
14234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (de=0;de<NumDirEntries;de++){
14334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned Tag, Format, Components;
14434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * ValuePtr;
14534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int ComponentSize;
14634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned ByteCount;
14734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unsigned char * DirEntry;
14834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        DirEntry = DIR_ENTRY_ADDR(DirStart, de);
14934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
15034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (DirEntry+12 > OffsetBase+ExifLength){
15134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("GPS info directory goes past end of exif",0,0);
15234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return;
15334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
15434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
15534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Tag = Get16u(DirEntry);
15634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Format = Get16u(DirEntry+2);
15734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Components = Get32u(DirEntry+4);
15834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
15934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if ((Format-1) >= NUM_FORMATS) {
16034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // (-1) catches illegal zero case as unsigned underflows to positive large.
16134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
16234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            continue;
16334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
16434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
16534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ComponentSize = BytesPerFormat[Format];
16634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ByteCount = Components * ComponentSize;
16734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
16834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
16934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("GPS tag %x format %s #components %d componentsize %d bytecount %d", Tag, formatStr(Format), Components, ComponentSize,
17034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ByteCount);
17134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
17234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
17334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ByteCount > 4){
17434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            unsigned OffsetVal;
17534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            OffsetVal = Get32u(DirEntry+8);
17634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // If its bigger than 4 bytes, the dir entry contains an offset.
17734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (OffsetVal+ByteCount > ExifLength){
17834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Bogus pointer offset and / or bytecount value
17934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
18034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                continue;
18134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
18234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ValuePtr = OffsetBase+OffsetVal;
18334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }else{
18434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // 4 bytes or less and value is in the dir entry itself
18534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ValuePtr = DirEntry+8;
18634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
18734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
18834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        switch(Tag){
18934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            char FmtString[21];
1902bfc190bd3be7e1b91fe3d7ca49412ebf0f5ceeeWang Kun            char TempString[MAX_BUF_SIZE];
19134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            double Values[3];
19234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
19334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_LAT_REF:
19434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLat[0] = ValuePtr[0];
19534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLatRef[0] = ValuePtr[0];
19634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLatRef[1] = '\0';
19734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
19834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
19934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_LONG_REF:
20034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLong[0] = ValuePtr[0];
20134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLongRef[0] = ValuePtr[0];
20234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsLongRef[1] = '\0';
20334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
20434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
20534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_LAT:
20634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_LONG:
20734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Format != FMT_URATIONAL){
20834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    ErrNonfatal("Inappropriate format (%d) for GPS coordinates!", Format, 0);
20934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
21034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                strcpy(FmtString, "%0.0fd %0.0fm %0.0fs");
21134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                for (a=0;a<3;a++){
21234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    int den, digits;
21334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
21434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    den = Get32s(ValuePtr+4+a*ComponentSize);
21534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    digits = 0;
216d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    while (den > 1 && digits <= 6){
21734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        den = den / 10;
21834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        digits += 1;
21934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
220d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    if (digits > 6) digits = 6;
22134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    FmtString[1+a*7] = (char)('2'+digits+(digits ? 1 : 0));
22234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    FmtString[3+a*7] = (char)('0'+digits);
22334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
22434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format);
22534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
226d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
22734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                sprintf(TempString, FmtString, Values[0], Values[1], Values[2]);
22834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
22934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Tag == TAG_GPS_LAT){
23034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    strncpy(ImageInfo.GpsLat+2, TempString, 29);
23134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
23234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    strncpy(ImageInfo.GpsLong+2, TempString, 29);
23334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
23434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
23534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                sprintf(TempString, "%d/%d,%d/%d,%d/%d",
23634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Get32s(ValuePtr), Get32s(4+(char*)ValuePtr),
23734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Get32s(8+(char*)ValuePtr), Get32s(12+(char*)ValuePtr),
23834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    Get32s(16+(char*)ValuePtr), Get32s(20+(char*)ValuePtr));
23934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                if (Tag == TAG_GPS_LAT){
2402bfc190bd3be7e1b91fe3d7ca49412ebf0f5ceeeWang Kun                    strncpy(ImageInfo.GpsLatRaw, TempString, MAX_BUF_SIZE);
24134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }else{
2422bfc190bd3be7e1b91fe3d7ca49412ebf0f5ceeeWang Kun                    strncpy(ImageInfo.GpsLongRaw, TempString, MAX_BUF_SIZE);
24334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                }
24434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
24534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
24634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_ALT_REF:
24734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                ImageInfo.GpsAlt[0] = (char)(ValuePtr[0] ? '-' : ' ');
2481ed8197f0cefb2541f630830993e109c59ba822cWu-cheng Li                ImageInfo.GpsAltRef = (char)ValuePtr[0];
24934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
25034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
25134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            case TAG_GPS_ALT:
252d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                sprintf(ImageInfo.GpsAlt + 1, "%.2fm",
253d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang                    ConvertAnyFormat(ValuePtr, Format));
2541ed8197f0cefb2541f630830993e109c59ba822cWu-cheng Li                ImageInfo.GpsAltRaw.num = Get32u(ValuePtr);
2551ed8197f0cefb2541f630830993e109c59ba822cWu-cheng Li                ImageInfo.GpsAltRaw.denom = Get32u(4+(char *)ValuePtr);
25634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                break;
257a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen
258a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            case TAG_GPS_TIMESTAMP:
259a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                snprintf(ImageInfo.GpsTimeStamp,
260a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                    sizeof(ImageInfo.GpsTimeStamp), "%d:%d:%d",
261a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                    (int) ConvertAnyFormat(ValuePtr, Format),
262a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                    (int) ConvertAnyFormat(ValuePtr + 8, Format),
263a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                    (int) ConvertAnyFormat(ValuePtr + 16, Format)
264a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                );
265a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                break;
266a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen
267a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            case TAG_GPS_DATESTAMP:
268a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                strncpy(ImageInfo.GpsDateStamp, (char*)ValuePtr, sizeof(ImageInfo.GpsDateStamp));
269a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen                break;
270434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen
271434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen            case TAG_GPS_PROCESSING_METHOD:
2728d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen                if (ByteCount > EXIF_ASCII_PREFIX_LEN &&
273434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                    memcmp(ValuePtr, ExifAsciiPrefix, EXIF_ASCII_PREFIX_LEN) == 0) {
274434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                    int length =
275434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                        ByteCount < GPS_PROCESSING_METHOD_LEN + EXIF_ASCII_PREFIX_LEN ?
276434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                        ByteCount - EXIF_ASCII_PREFIX_LEN : GPS_PROCESSING_METHOD_LEN;
277434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                    memcpy(ImageInfo.GpsProcessingMethod,
278434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                        (char*)(ValuePtr + EXIF_ASCII_PREFIX_LEN), length);
279434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                    ImageInfo.GpsProcessingMethod[length] = 0;
280434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                } else {
281d282614624d8e5e6f049bff9af237a76f3b14e31Steve Block                    ALOGW("Unsupported encoding for GPSProcessingMethod");
282434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                }
283434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen                break;
28434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
28534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
28634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ShowTags){
28734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // Show tag value.
28834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (Tag < MAX_GPS_TAG){
28934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("        %s =", GpsTags[Tag].Desc);
29034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }else{
29134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                // Show unknown tag
29234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                printf("        Illegal GPS tag %04x=", Tag);
29334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
294d6a02c32e6fa83fad5794b0e19b1d28563e5a99bChih-Chung Chang
29534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            switch(Format){
29634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                case FMT_UNDEFINED:
29734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Undefined is typically an ascii string.
29834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
29934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                case FMT_STRING:
30034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // String arrays printed without function call (different from int arrays)
30134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    {
30234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        printf("\"");
30334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        for (a=0;a<ByteCount;a++){
30434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                            int ZeroSkipped = 0;
30534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                            if (ValuePtr[a] >= 32){
30634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                if (ZeroSkipped){
30734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    printf("?");
30834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    ZeroSkipped = 0;
30934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                }
31034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                putchar(ValuePtr[a]);
31134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                            }else{
31234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                if (ValuePtr[a] == 0){
31334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    ZeroSkipped = 1;
31434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                }
31534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                            }
31634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        }
31734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        printf("\"\n");
31834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
31934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    break;
32034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
32134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                default:
32234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    // Handle arrays of numbers later (will there ever be?)
32334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    for (a=0;;){
32434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        PrintFormatNumber(ValuePtr+a*ComponentSize, Format, ByteCount);
32534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        if (++a >= Components) break;
32634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                        printf(", ");
32734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    }
32834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                    printf("\n");
32934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
33034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
33134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
33234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
33334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
334434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen
335