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