main.c revision 8d61723fea0a5cdcd08e34325123fbd3e0bd41ae
134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project/*
234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectCopyright (c) 2008, The Android Open Source Project
434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectAll rights reserved.
534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectRedistribution and use in source and binary forms, with or without
734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectmodification, are permitted provided that the following conditions
834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectare met:
934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Redistributions of source code must retain the above copyright
1034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project   notice, this list of conditions and the following disclaimer.
1134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Redistributions in binary form must reproduce the above copyright
1234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project   notice, this list of conditions and the following disclaimer in
13db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync   the documentation and/or other materials provided with the
1434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project   distribution.
1534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Neither the name of Google, Inc. nor the names of its contributors
1634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project   may be used to endorse or promote products derived from this
1734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project   software without specific prior written permission.
1834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
1934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo syncOF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectAND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectOF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectSUCH DAMAGE.
3134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project*/
3334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <nativehelper/JNIHelp.h>
3534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <nativehelper/jni.h>
3634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
3734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <assert.h>
3834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <dlfcn.h>
3934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <stdio.h>
4034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <string.h>
4134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <sys/stat.h>
4234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include <utils/Log.h>
4334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
4434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#include "jhead.h"
4534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
4634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifndef NELEM
4734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
4834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
4934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Define the line below to turn on poor man's debugging output
5134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#undef SUPERDEBUG
5234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Various tests
5434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#undef REALLOCTEST
5534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#undef OUTOFMEMORYTEST1
5634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
5734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void addExifAttibute(JNIEnv *env, jmethodID putMethod, jobject hashMap, char* key, char* value) {
5834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jstring jkey = (*env)->NewStringUTF(env, key);
5934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jstring jvalue = (*env)->NewStringUTF(env, value);
6034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jobject jobject_of_entryset = (*env)->CallObjectMethod(env, hashMap, putMethod, jkey, jvalue);
6234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*env)->ReleaseStringUTFChars(env, jkey, key);
6434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*env)->ReleaseStringUTFChars(env, jvalue, value);
6534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
6634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectextern void ResetJpgfile();
6834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
6934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int loadExifInfo(const char* FileName, int readJPG) {
7034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
7134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("loadExifInfo");
7234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
7334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int Modified = FALSE;
7434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ReadMode_t ReadMode = READ_METADATA;
7534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (readJPG) {
7634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Must add READ_IMAGE else we can't write the JPG back out.
7734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ReadMode |= READ_IMAGE;
7834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
7934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
8134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("ResetJpgfile");
8234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
8334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ResetJpgfile();
8434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
8534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Start with an empty image information structure.
8634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    memset(&ImageInfo, 0, sizeof(ImageInfo));
8734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.FlashUsed = -1;
8834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.MeteringMode = -1;
8934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.Whitebalance = -1;
90db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
9134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Store file date/time.
9234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    {
9334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        struct stat st;
9434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (stat(FileName, &st) >= 0) {
9534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ImageInfo.FileDateTime = st.st_mtime;
9634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ImageInfo.FileSize = st.st_size;
9734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
9834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
9934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    strncpy(ImageInfo.FileName, FileName, PATH_MAX);
10134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
10234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("ReadJpegFile");
10334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
10434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return ReadJpegFile(FileName, ReadMode);
10534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
10634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
10734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void saveJPGFile(const char* filename) {
10834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char backupName[400];
10934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    struct stat buf;
11034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
11134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
11234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("Modified: %s\n", filename);
11334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
11434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
11534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    strncpy(backupName, filename, 395);
11634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    strcat(backupName, ".t");
11734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
11834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Remove any .old file name that may pre-exist
11934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
12034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("removing backup %s", backupName);
12134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
12234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    unlink(backupName);
12334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
12434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Rename the old file.
12534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
12634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("rename %s to %s", filename, backupName);
12734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
12834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    rename(filename, backupName);
12934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
13034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Write the new file.
13134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
13234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("WriteJpegFile %s", filename);
13334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
13434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (WriteJpegFile(filename)) {
135db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
13634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Copy the access rights from original file
13734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
13834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("stating old file %s", backupName);
13934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
14034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (stat(backupName, &buf) == 0){
14134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // set Unix access rights and time to new file
14234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            struct utimbuf mtime;
14334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            chmod(filename, buf.st_mode);
144db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
14534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            mtime.actime = buf.st_mtime;
14634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            mtime.modtime = buf.st_mtime;
147db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
14834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            utime(filename, &mtime);
14934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
150db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
15134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Now that we are done, remove original file.
15234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
15334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("unlinking old file %s", backupName);
15434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
15534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        unlink(backupName);
15634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
15734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("returning from saveJPGFile");
15834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
15934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    } else {
16034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
16134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("WriteJpegFile failed, restoring from backup file");
16234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
16334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // move back the backup file
16434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        rename(backupName, filename);
16534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
16634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
16734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
16834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectvoid copyThumbnailData(uchar* thumbnailData, int thumbnailLen) {
16934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
17034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** copyThumbnailData\n");
17134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
17234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Section_t* ExifSection = FindSection(M_EXIF);
17334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ExifSection == NULL) {
17434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
17534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
17634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int NewExifSize = ImageInfo.ThumbnailOffset+8+thumbnailLen;
17734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifSection->Data = (uchar *)realloc(ExifSection->Data, NewExifSize);
17834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ExifSection->Data == NULL) {
17934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return;
18034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
18134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    uchar* ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
18234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
18334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    memcpy(ThumbnailPointer, thumbnailData, thumbnailLen);
18434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
18534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ImageInfo.ThumbnailSize = thumbnailLen;
18634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
18734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    Put32u(ExifSection->Data+ImageInfo.ThumbnailSizeOffset+8, thumbnailLen);
18834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
18934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifSection->Data[0] = (uchar)(NewExifSize >> 8);
19034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifSection->Data[1] = (uchar)NewExifSize;
19134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifSection->Size = NewExifSize;
19234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
19334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
19434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void saveAttributes(JNIEnv *env, jobject jobj, jstring jfilename, jstring jattributes)
19534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
19634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
19734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** saveAttributes\n");
19834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
19934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // format of attributes string passed from java:
20034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
20134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // example input: "4 ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
20234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ExifElement_t* exifElementTable = NULL;
20334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* filename = NULL;
20434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    uchar* thumbnailData = NULL;
20534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int attrCnt = 0;
20634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* attributes = (*env)->GetStringUTFChars(env, jattributes, NULL);
20734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (attributes == NULL) {
20834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        goto exit;
20934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
21034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
21134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("attributes %s\n", attributes);
21234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
21334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
21434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Get the number of attributes - it's the first number in the string.
21534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    attrCnt = atoi(attributes);
21634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char* attrPtr = strchr(attributes, ' ') + 1;
21734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
21834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("attribute count %d attrPtr %s\n", attrCnt, attrPtr);
21934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
22034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
22134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Load all the hash exif elements into a more c-like structure
22234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    exifElementTable = malloc(sizeof(ExifElement_t) * attrCnt);
22334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (exifElementTable == NULL) {
22434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        goto exit;
22534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
22634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef OUTOFMEMORYTEST1
22734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    goto exit;
22834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
22934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
23034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int i;
23134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char tag[100];
23234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int gpsTagCount = 0;
23334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int exifTagCount = 0;
23434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
23534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (i = 0; i < attrCnt; i++) {
23634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // get an element from the attribute string and add it to the c structure
23734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // first, extract the attribute name
23834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        char* tagEnd = strchr(attrPtr, '=');
23934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (tagEnd == 0) {
24034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
24134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            LOGE("saveAttributes: couldn't find end of tag");
24234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
24334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto exit;
24434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
24534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (tagEnd - attrPtr > 99) {
24634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
24734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            LOGE("saveAttributes: attribute tag way too long");
24834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
24934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto exit;
25034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
25134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        memcpy(tag, attrPtr, tagEnd - attrPtr);
25234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        tag[tagEnd - attrPtr] = 0;
25334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
25434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (IsGpsTag(tag)) {
25534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            exifElementTable[i].GpsTag = TRUE;
25634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            exifElementTable[i].Tag = GpsTagNameToValue(tag);
25734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ++gpsTagCount;
25834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        } else {
25934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            exifElementTable[i].GpsTag = FALSE;
26034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            exifElementTable[i].Tag = TagNameToValue(tag);
26134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            ++exifTagCount;
26234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
26334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        attrPtr = tagEnd + 1;
26434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
26534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // next get the length of the attribute value
26634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        int valueLen = atoi(attrPtr);
26734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        attrPtr = strchr(attrPtr, ' ') + 1;
26834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (attrPtr == 0) {
26934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
27034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            LOGE("saveAttributes: couldn't find end of value len");
27134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
27234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto exit;
27334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
27434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        exifElementTable[i].Value = malloc(valueLen + 1);
27534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (exifElementTable[i].Value == NULL) {
27634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto exit;
27734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
27834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        memcpy(exifElementTable[i].Value, attrPtr, valueLen);
27934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        exifElementTable[i].Value[valueLen] = 0;
28034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        exifElementTable[i].DataLength = valueLen;
28134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
28234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        attrPtr += valueLen;
28334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
28434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
28534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("tag %s id %d value %s data length=%d isGps=%d", tag, exifElementTable[i].Tag,
28634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            exifElementTable[i].Value, exifElementTable[i].DataLength, exifElementTable[i].GpsTag);
28734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
28834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
28934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
29034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
29134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
29234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("Call loadAttributes() with filename is %s. Loading exif info\n", filename);
29334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
29434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    loadExifInfo(filename, TRUE);
29534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
29634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
29734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    DumpExifMap = TRUE;
29834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ShowTags = TRUE;
29934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ShowImageInfo(TRUE);
30034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("create exif 2");
30134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
30234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
30334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // If the jpg file has a thumbnail, preserve it.
30434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int thumbnailLength = ImageInfo.ThumbnailSize;
30534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ThumbnailOffset) {
30634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Section_t* ExifSection = FindSection(M_EXIF);
30734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ExifSection) {
30834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            uchar* thumbnailPointer = ExifSection->Data + ImageInfo.ThumbnailOffset + 8;
30934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            thumbnailData = (uchar*)malloc(ImageInfo.ThumbnailSize);
31034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            // if the malloc fails, we just won't copy the thumbnail
31134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (thumbnailData) {
31234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                memcpy(thumbnailData, thumbnailPointer, thumbnailLength);
31334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            }
31434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
31534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
31634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
31734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    create_EXIF(exifElementTable, exifTagCount, gpsTagCount);
31834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
31934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (thumbnailData) {
32034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        copyThumbnailData(thumbnailData, thumbnailLength);
32134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
32234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
32334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectexit:
32434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
32534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("cleaning up now in saveAttributes");
32634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
32734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // try to clean up resources
32834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (attributes) {
32934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->ReleaseStringUTFChars(env, jattributes, attributes);
33034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
33134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (filename) {
33234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->ReleaseStringUTFChars(env, jfilename, filename);
33334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
33434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (exifElementTable) {
33534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // free the table
33634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        for (i = 0; i < attrCnt; i++) {
33734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            free(exifElementTable[i].Value);
33834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
33934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        free(exifElementTable);
34034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
34134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (thumbnailData) {
34234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        free(thumbnailData);
34334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
34434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
34534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("returning from saveAttributes");
34634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
34734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
34834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// Temporarily saving these commented out lines because they represent a lot of figuring out
34934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// patterns for JNI.
35034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get link to Method "entrySet"
35134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID entrySetMethod = (*env)->GetMethodID(env, jclass_of_hashmap, "entrySet", "()Ljava/util/Set;");
35234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
35334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Invoke the "entrySet" method on the HashMap object
35434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jobject jobject_of_entryset = (*env)->CallObjectMethod(env, hashMap, entrySetMethod);
35534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
35634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get the Set Class
35734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jclass jclass_of_set = (*env)->FindClass(env, "java/util/Set");
35834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
35934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    if (jclass_of_set == 0) {
36034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//        printf("java/util/Set lookup failed\n");
36134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//        return;
36234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    }
36334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
36434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get link to Method "iterator"
36534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID iteratorMethod = (*env)->GetMethodID(env, jclass_of_set, "iterator", "()Ljava/util/Iterator;");
36634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
36734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Invoke the "iterator" method on the jobject_of_entryset variable of type Set
36834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jobject jobject_of_iterator = (*env)->CallObjectMethod(env, jobject_of_entryset, iteratorMethod);
36934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
37034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get the "Iterator" class
37134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jclass jclass_of_iterator = (*env)->FindClass(env, "java/util/Iterator");
37234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
37334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get link to Method "hasNext"
37434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID hasNextMethod = (*env)->GetMethodID(env, jclass_of_iterator, "hasNext", "()Z");
37534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
37634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Invoke - Get the value hasNextMethod
37734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jboolean bHasNext = (*env)->CallBooleanMethod(env, jobject_of_iterator, hasNextMethod);
37834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
37934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    // Get link to Method "hasNext"
38034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID nextMethod = (*env)->GetMethodID(env, jclass_of_iterator, "next", "()Ljava/util/Map/Entry;");
38134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
38234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jclass jclass_of_mapentry = (*env)->FindClass(env, "java/util/Map/Entry");
38334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
38434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID getKeyMethod = (*env)->GetMethodID(env, jclass_of_mapentry, "getKey", "()Ljava/lang/Object");
38534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//
38634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project//    jmethodID getValueMethod = (*env)->GetMethodID(env, jclass_of_mapentry, "getValue", "()Ljava/lang/Object");
38734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
38834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
38934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic jboolean appendThumbnail(JNIEnv *env, jobject jobj, jstring jfilename, jstring jthumbnailfilename)
39034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
39134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
39234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** appendThumbnail\n");
39334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
39434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
39534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
39634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (filename == NULL) {
39734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return JNI_FALSE;
39834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
39934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* thumbnailfilename = (*env)->GetStringUTFChars(env, jthumbnailfilename, NULL);
40034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (thumbnailfilename == NULL) {
40134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return JNI_FALSE;
40234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
40334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project #ifdef SUPERDEBUG
40434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project     LOGE("*******before actual call to ReplaceThumbnail\n");
40534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project     ShowImageInfo(TRUE);
40634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project #endif
40734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ReplaceThumbnail(thumbnailfilename);
40834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project #ifdef SUPERDEBUG
40934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project     ShowImageInfo(TRUE);
41034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project #endif
41134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*env)->ReleaseStringUTFChars(env, jfilename, filename);
41234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*env)->ReleaseStringUTFChars(env, jthumbnailfilename, thumbnailfilename);
413db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo sync
41434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    DiscardData();
41534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return JNI_TRUE;
41634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
41734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
41834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic void commitChanges(JNIEnv *env, jobject jobj, jstring jfilename)
41934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
42034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
42134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** commitChanges\n");
42234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
42334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
42434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (filename) {
42534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        saveJPGFile(filename);
4266a3cf8f158c6f0f7e069f8aeb0825a3fefeabd02Chih-Chung Chang        DiscardData();
42734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->ReleaseStringUTFChars(env, jfilename, filename);
42834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
42934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
43034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
43134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic jbyteArray getThumbnail(JNIEnv *env, jobject jobj, jstring jfilename)
43234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
43334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
43434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** getThumbnail\n");
43534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
43634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
43734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
43834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (filename) {
43934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        loadExifInfo(filename, FALSE);
44034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        Section_t* ExifSection = FindSection(M_EXIF);
44134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ExifSection == NULL ||  ImageInfo.ThumbnailSize == 0) {
44234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
44334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("no exif section or size == 0, so no thumbnail\n");
44434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
44534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto noThumbnail;
44634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
44734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        uchar* thumbnailPointer = ExifSection->Data + ImageInfo.ThumbnailOffset + 8;
44834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
44934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        jbyteArray byteArray = (*env)->NewByteArray(env, ImageInfo.ThumbnailSize);
45034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (byteArray == NULL) {
45134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
45234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("couldn't allocate thumbnail memory, so no thumbnail\n");
45334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
45434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            goto noThumbnail;
45534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
45634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->SetByteArrayRegion(env, byteArray, 0, ImageInfo.ThumbnailSize, thumbnailPointer);
45734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
45834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("thumbnail size %d\n", ImageInfo.ThumbnailSize);
45934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
46034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->ReleaseStringUTFChars(env, jfilename, filename);
46134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return byteArray;
46234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
46334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source ProjectnoThumbnail:
46434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (filename) {
46534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        (*env)->ReleaseStringUTFChars(env, jfilename, filename);
46634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
46734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    DiscardData();
46834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return NULL;
46934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
47034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
47134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int attributeCount;      // keep track of how many attributes we've added
47234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
47334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// returns new buffer length
47434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int addKeyValueString(char** buf, int bufLen, const char* key, const char* value) {
47534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // Appends to buf like this: "ImageLength=4 1024"
47634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
47734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char valueLen[15];
47834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    snprintf(valueLen, 15, "=%d ", (int)strlen(value));
47934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
48034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // check to see if buf has enough room to append
48134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int len = strlen(key) + strlen(valueLen) + strlen(value);
48234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int newLen = strlen(*buf) + len;
48334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (newLen >= bufLen) {
48434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef REALLOCTEST
48534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = newLen + 5;
48634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        LOGE("reallocing to %d", bufLen);
48734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#else
48834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = newLen + 500;
48934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
49034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        *buf = realloc(*buf, bufLen);
49134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (*buf == NULL) {
49234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            return 0;
49334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
49434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
49534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // append the new attribute and value
49634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    snprintf(*buf + strlen(*buf), bufLen, "%s%s%s", key, valueLen, value);
49734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
49834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("buf %s", *buf);
49934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
50034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ++attributeCount;
50134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return bufLen;
50234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
50334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
50434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// returns new buffer length
50534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int addKeyValueInt(char** buf, int bufLen, const char* key, int value) {
50634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char valueStr[20];
50734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    snprintf(valueStr, 20, "%d", value);
50834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
50934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return addKeyValueString(buf, bufLen, key, valueStr);
51034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
51134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
51234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project// returns new buffer length
51334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int addKeyValueDouble(char** buf, int bufLen, const char* key, double value, const char* format) {
51434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char valueStr[30];
51534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    snprintf(valueStr, 30, format, value);
51634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
51734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return addKeyValueString(buf, bufLen, key, valueStr);
51834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
51934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
520574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li// Returns new buffer length. Rational value will be appended as "numerator/denominator".
521574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Listatic int addKeyValueRational(char** buf, int bufLen, const char* key, rat_t value) {
522574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li    char valueStr[25];
523574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li    snprintf(valueStr, sizeof(valueStr), "%u/%u", value.num, value.denom);
524574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li    return addKeyValueString(buf, bufLen, key, valueStr);
525574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li}
526574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li
52734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic jstring getAttributes(JNIEnv *env, jobject jobj, jstring jfilename)
52834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
52934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
53034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("******************************** getAttributes\n");
53134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
53234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    const char* filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
53334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    loadExifInfo(filename, FALSE);
53434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
53534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    ShowImageInfo(TRUE);
53634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
53734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    (*env)->ReleaseStringUTFChars(env, jfilename, filename);
53834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
53934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    attributeCount = 0;
54034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef REALLOCTEST
54134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int bufLen = 5;
54234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#else
54334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int bufLen = 1000;
54434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
54534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char* buf = malloc(bufLen);
54634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (buf == NULL) {
54734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return NULL;
54834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
54934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    *buf = 0;   // start the string out at zero length
55034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
55134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // save a fake "hasThumbnail" tag to pass to the java ExifInterface
55234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueString(&buf, bufLen, "hasThumbnail",
55334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE || ImageInfo.ThumbnailSize == 0 ?
55434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            "false" : "true");
55534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
55634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
55734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.CameraMake[0]) {
55834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueString(&buf, bufLen, "Make", ImageInfo.CameraMake);
55934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
56034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
56134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.CameraModel[0]) {
56234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueString(&buf, bufLen, "Model", ImageInfo.CameraModel);
56334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
56434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
56534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.DateTime[0]) {
56634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueString(&buf, bufLen, "DateTime", ImageInfo.DateTime);
56734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
56834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
56934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "ImageWidth", ImageInfo.Width);
57034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
57134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
57234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "ImageLength", ImageInfo.Height);
57334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
57434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
57534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "Orientation", ImageInfo.Orientation);
57634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
57734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
57834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "Flash", ImageInfo.FlashUsed);
57934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
58034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
581574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li    if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0) {
582574d52d26f44b600cdab3d3361eaa5f6dd9d7a4dWu-cheng Li        bufLen = addKeyValueRational(&buf, bufLen, "FocalLength", ImageInfo.FocalLength);
58334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
58434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
58534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
58634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.DigitalZoomRatio > 1.0){
58734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // Digital zoom used.  Shame on you!
58834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueDouble(&buf, bufLen, "DigitalZoomRatio", ImageInfo.DigitalZoomRatio, "%1.3f");
58934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
59034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
59134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
59234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureTime){
59334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        const char* format;
59434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.ExposureTime < 0.010){
59534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            format = "%6.4f";
59634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        } else {
59734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            format = "%5.3f";
59834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
59934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
60034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueDouble(&buf, bufLen, "ExposureTime", (double)ImageInfo.ExposureTime, format);
60134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
60234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
60334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
60434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ApertureFNumber){
60534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueDouble(&buf, bufLen, "FNumber", (double)ImageInfo.ApertureFNumber, "%3.1f");
60634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
60734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
60834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
60934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Distance){
61034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueDouble(&buf, bufLen, "SubjectDistance", (double)ImageInfo.Distance, "%4.2f");
61134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
61234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
61334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
61434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ISOequivalent){
61534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueInt(&buf, bufLen, "ISOSpeedRatings", ImageInfo.ISOequivalent);
61634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
61734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
61834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
61934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureBias){
62034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // If exposure bias was specified, but set to zero, presumably its no bias at all,
62134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        // so only show it if its nonzero.
62234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueDouble(&buf, bufLen, "ExposureBiasValue", (double)ImageInfo.ExposureBias, "%4.2f");
62334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
62434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
62534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
62634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "WhiteBalance", ImageInfo.Whitebalance);
62734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
62834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
62934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    bufLen = addKeyValueInt(&buf, bufLen, "LightSource", ImageInfo.LightSource);
63034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (bufLen == 0) return NULL;
63134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
63234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
63334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.MeteringMode) {
63434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueInt(&buf, bufLen, "MeteringMode", ImageInfo.MeteringMode);
63534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
63634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
63734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
63834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureProgram) {
63934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueInt(&buf, bufLen, "ExposureProgram", ImageInfo.ExposureProgram);
64034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
64134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
64234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
64334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.ExposureMode) {
64434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueInt(&buf, bufLen, "ExposureMode", ImageInfo.ExposureMode);
64534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
64634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
64734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
64834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.GpsInfoPresent) {
6498d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        if (ImageInfo.GpsLatRaw[0]) {
6508d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSLatitude", ImageInfo.GpsLatRaw);
6518d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            if (bufLen == 0) return NULL;
6528d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        }
6538d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        if (ImageInfo.GpsLatRef[0]) {
6548d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSLatitudeRef", ImageInfo.GpsLatRef);
6558d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            if (bufLen == 0) return NULL;
6568d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        }
6578d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        if (ImageInfo.GpsLongRaw[0]) {
6588d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSLongitude", ImageInfo.GpsLongRaw);
6598d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            if (bufLen == 0) return NULL;
6608d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        }
6618d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        if (ImageInfo.GpsLongRef[0]) {
6628d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSLongitudeRef", ImageInfo.GpsLongRef);
6638d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen            if (bufLen == 0) return NULL;
6648d61723fea0a5cdcd08e34325123fbd3e0bd41aeRay Chen        }
66534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (ImageInfo.GpsAlt[0]) {
66634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            bufLen = addKeyValueString(&buf, bufLen, "GPSAltitude", ImageInfo.GpsAlt);
66734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            if (bufLen == 0) return NULL;
66834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        }
669a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen        if (ImageInfo.GpsDateStamp[0]) {
670a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSDateStamp", ImageInfo.GpsDateStamp);
671a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            if (bufLen == 0) return NULL;
672a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen        }
673a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen        if (ImageInfo.GpsTimeStamp[0]) {
674a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSTimeStamp", ImageInfo.GpsTimeStamp);
675a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen            if (bufLen == 0) return NULL;
676a39920ca4b96a456511fa32ba90c77f119a274c3Ray Chen        }
677434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen        if (ImageInfo.GpsProcessingMethod[0]) {
678434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen            bufLen = addKeyValueString(&buf, bufLen, "GPSProcessingMethod", ImageInfo.GpsProcessingMethod);
679434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen            if (bufLen == 0) return NULL;
680434623a0e87c8e145dbb46917b4ab9777475d9ebRay Chen        }
68134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
68234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
68334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (ImageInfo.Comments[0]) {
68434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        bufLen = addKeyValueString(&buf, bufLen, "UserComment", ImageInfo.Comments);
68534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (bufLen == 0) return NULL;
68634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
68734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
68834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    // put the attribute count at the beginnnig of the string
68934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int finalBufLen = strlen(buf) + 20;
69034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    char* finalResult = malloc(finalBufLen);
69134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (finalResult == NULL) {
69234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        free(buf);
69334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return NULL;
69434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
69534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    snprintf(finalResult, finalBufLen, "%d %s", attributeCount, buf);
69634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    int k;
69734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    for (k = 0; k < finalBufLen; k++)
69834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        if (finalResult[k] > 127)
69934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            finalResult[k] = '?';
70034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    free(buf);
70134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
70234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#ifdef SUPERDEBUG
70334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    LOGE("*********Returning result \"%s\"", finalResult);
70434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project#endif
70534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jstring result = ((*env)->NewStringUTF(env, finalResult));
70634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    free(finalResult);
70734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    DiscardData();
70834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return result;
70934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
71034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
711db940f2a0ed054ea4d3f39e823220ecf1b15f64crepo syncstatic const char *classPathName = "android/media/ExifInterface";
71234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
71334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic JNINativeMethod methods[] = {
71434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project  {"saveAttributesNative", "(Ljava/lang/String;Ljava/lang/String;)V", (void*)saveAttributes },
71534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project  {"getAttributesNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getAttributes },
71634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project  {"appendThumbnailNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)appendThumbnail },
71734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project  {"commitChangesNative", "(Ljava/lang/String;)V", (void*)commitChanges },
71834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project  {"getThumbnailNative", "(Ljava/lang/String;)[B", (void*)getThumbnail },
71934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project};
72034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
72134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project/*
72234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Register several native methods for one class.
72334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project */
72434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int registerNativeMethods(JNIEnv* env, const char* className,
72534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    JNINativeMethod* gMethods, int numMethods)
72634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
72734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jclass clazz;
72834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
72934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    clazz = (*env)->FindClass(env, className);
73034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (clazz == NULL) {
73134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        fprintf(stderr,
73234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project            "Native registration unable to find class '%s'\n", className);
73334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return JNI_FALSE;
73434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
73534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
73634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        fprintf(stderr, "RegisterNatives failed for '%s'\n", className);
73734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        return JNI_FALSE;
73834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
73934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
74034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return JNI_TRUE;
74134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
74234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
74334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project/*
74434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Register native methods for all classes we know about.
74534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project */
74634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectstatic int registerNatives(JNIEnv* env)
74734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
74834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return jniRegisterNativeMethods(env, classPathName,
74934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project                                    methods, NELEM(methods));
75034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
75134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
75234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project/*
75334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Set some test stuff up.
75434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project *
75534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project * Returns the JNI version on success, -1 on failure.
75634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project */
75734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project__attribute__ ((visibility("default"))) jint JNI_OnLoad(JavaVM* vm, void* reserved)
75834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project{
75934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    JNIEnv* env = NULL;
76034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    jint result = -1;
76134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
76234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
76334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        fprintf(stderr, "ERROR: GetEnv failed\n");
76434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        goto bail;
76534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
76634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    assert(env != NULL);
76734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
76834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    printf("In mgmain JNI_OnLoad\n");
76934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
77034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    if (registerNatives(env) < 0) {
77134a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        fprintf(stderr, "ERROR: Exif native registration failed\n");
77234a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project        goto bail;
77334a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    }
77434a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
77534a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    /* success -- return valid version number */
77634a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    result = JNI_VERSION_1_4;
77734a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project
77834a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Projectbail:
77934a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project    return result;
78034a2564d3268a5ca1472c5076675782fbaf724d6The Android Open Source Project}
781