view src/name/blackcap/exifwasher/exiv2/native.cpp @ 22:cd2ca4727b7f

Builds under Windows.
author davidb
date Thu, 16 Apr 2020 11:10:39 -0700
parents a59d84674fb0
children
line wrap: on
line source

#include <jni.h>
#include <string.h>
#include <exiv2/exiv2.hpp>
#include <exception>
#include <iostream>
#include <iomanip>
#include <cassert>

/* Functions for class name_blackcap_exifwasher_exiv2_Image */

#ifndef _Included_name_blackcap_exifwasher_exiv2_Image
#define _Included_name_blackcap_exifwasher_exiv2_Image
#ifdef __cplusplus
extern "C" {
#endif

/*
 * Utility function to get pointer field.
 */
Exiv2::Image *getPointer(JNIEnv *jEnv, jobject jThis) {
    return reinterpret_cast<Exiv2::Image *>
        (jEnv->GetLongField(jThis,
            jEnv->GetFieldID(jEnv->GetObjectClass(jThis), "pointer", "J")));
}

/*
 * Class:     name_blackcap_exifwasher_exiv2_Image
 * Method:    _ctor
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1ctor
  (JNIEnv *jEnv, jobject jThis, jstring path) {
      const char *cPath = jEnv->GetStringUTFChars(path, NULL);
      jlong ret = 0;
      try {
          ret = reinterpret_cast<jlong> (Exiv2::ImageFactory::open(cPath).release());
      } catch (std::exception& e) {
          jEnv->ExceptionClear();
          jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception");
          jEnv->ThrowNew(ex, e.what());
      }
      jEnv->ReleaseStringUTFChars(path, cPath);
      return ret;
  }

/*
 * Class:     name_blackcap_exifwasher_exiv2_Image
 * Method:    _writeMetadata
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1writeMetadata
  (JNIEnv *jEnv, jobject jThis) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      if (jEnv->ExceptionCheck()) return;
      try {
          image->writeMetadata();
      } catch (std::exception& e) {
          jEnv->ExceptionClear();
          jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception");
          jEnv->ThrowNew(ex, e.what());
      }
  }

/*
 * Class:     name_blackcap_exifwasher_exiv2_Image
 * Method:    _getMetadata
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1getMetadata
  (JNIEnv *jEnv, jobject jThis) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      if (jEnv->ExceptionCheck()) return 0;
      try {
          image->readMetadata();
      } catch (std::exception& e) {
          jEnv->ExceptionClear();
          jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception");
          jEnv->ThrowNew(ex, e.what());
          return 0;
      }
      return reinterpret_cast<jlong>(image);
  }

/*
 * Class:     name_blackcap_exifwasher_exiv2_Image
 * Method:    _dtor
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_Image__1dtor
  (JNIEnv *jEnv, jobject jThis) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      if (jEnv->ExceptionCheck()) return;
      delete image;
  }

#ifdef __cplusplus
}
#endif
#endif
/* Header for class name_blackcap_exifwasher_exiv2_ExifData */

/*
 * Utility function to parse out a type prefix from a key name.
 */
char *getType(const char *key) {
    const char *dot = strchr(key, '.');
    if (dot == NULL)
        throw std::invalid_argument(std::string("invalid key: ") + std::string(key));
    int length = dot - key;
    char *ret = (char *) malloc(length + 1);
    memcpy(ret, key, length);
    ret[length] = '\0';
    return ret;
}

/*
 * Utility function to delete a (key, value) pair.
 */
template<class D, class K>
void deleteValue(D &data, const char *key) {
    typename D::iterator found = data.findKey(K(std::string(key)));
    data.erase(found);
}

/*
 * Utility function to retrieve a value, given a key.
 */
template<class D, class K>
jobject getValue(JNIEnv *jEnv, D &data, const char *key) {
    typename D::iterator found = data.findKey(K(std::string(key)));
    if (found == data.end()) {
        return NULL;
    }
    jclass klass = jEnv->FindClass("name/blackcap/exifwasher/exiv2/ExifData$Value");
    if (jEnv->ExceptionCheck()) return NULL;
    jstring type = jEnv->NewStringUTF(found->typeName());
    jstring value = jEnv->NewStringUTF(found->toString().c_str());
    jmethodID method = jEnv->GetMethodID(klass, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
    if (jEnv->ExceptionCheck()) return NULL;
    return jEnv->NewObject(klass, method, type, value);
}

/*
 * Utility function to read keys, given a target to put them and a collection
 * of data.
 */
template<class D>
jsize getKeys(JNIEnv *jEnv, jobjectArray target, jsize start, D &data) {
    typename D::const_iterator end = data.end();
    jsize j = start;
    for (typename D::const_iterator i = data.begin(); i != end; ++i) {
        jEnv->SetObjectArrayElement(target, j++, jEnv->NewStringUTF(i->key().c_str()));
        if (jEnv->ExceptionCheck()) break;
    }
    return j;
}

#ifndef _Included_name_blackcap_exifwasher_exiv2_ExifData
#define _Included_name_blackcap_exifwasher_exiv2_ExifData
#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     name_blackcap_exifwasher_exiv2_ExifData
 * Method:    _erase
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1erase
  (JNIEnv *jEnv, jobject jThis, jstring key) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      if (jEnv->ExceptionCheck()) return;
      const char *cKey = jEnv->GetStringUTFChars(key, NULL);
      char *type = NULL;
      try {
          type = getType(cKey);
          if (!strcmp(type, "Exif")) {
              deleteValue<Exiv2::ExifData, Exiv2::ExifKey>(image->exifData(), cKey);
          } else if (!strcmp(type, "Xmp")) {
              deleteValue<Exiv2::XmpData, Exiv2::XmpKey>(image->xmpData(), cKey);
          } else if (!strcmp(type, "Iptc")) {
              deleteValue<Exiv2::IptcData, Exiv2::IptcKey>(image->iptcData(), cKey);
          } else {
              throw std::invalid_argument(std::string("invalid key: ") + std::string(cKey));
          }
      } catch (std::exception& e) {
          jEnv->ExceptionClear();
          jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception");
          jEnv->ThrowNew(ex, e.what());
      }
      if (type != NULL) free(type);
      jEnv->ReleaseStringUTFChars(key, cKey);
  }

/*
 * Class:     name_blackcap_exifwasher_exiv2_ExifData
 * Method:    _value
 * Signature: (Ljava/lang/String;)Lname/blackcap/exifwasher/exiv2/ExifData/Value;
 */
JNIEXPORT jobject JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1value
  (JNIEnv *jEnv, jobject jThis, jstring key) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      if (jEnv->ExceptionCheck()) return NULL;
      const char *cKey = jEnv->GetStringUTFChars(key, NULL);
      char *type = NULL;
      jobject ret = NULL;
      try {
          type = getType(cKey);
          if (!strcmp(type, "Exif")) {
              ret = getValue<Exiv2::ExifData, Exiv2::ExifKey>(jEnv, image->exifData(), cKey);
          } else if (!strcmp(type, "Xmp")) {
              ret = getValue<Exiv2::XmpData, Exiv2::XmpKey>(jEnv, image->xmpData(), cKey);
          } else if (!strcmp(type, "Iptc")) {
              ret = getValue<Exiv2::IptcData, Exiv2::IptcKey>(jEnv, image->iptcData(), cKey);
          } else {
              throw std::invalid_argument(std::string("invalid key: ") + std::string(cKey));
          }
      } catch (std::exception& e) {
          jEnv->ExceptionClear();
          jclass ex = jEnv->FindClass("name/blackcap/exifwasher/exiv2/Exiv2Exception");
          jEnv->ThrowNew(ex, e.what());
      }
      if (type != NULL) free(type);
      jEnv->ReleaseStringUTFChars(key, cKey);
      return ret;
  }

/*
 * Class:     name_blackcap_exifwasher_exiv2_ExifData
 * Method:    _keys
 * Signature: ()[Ljava/lang/String;
 */
JNIEXPORT jobjectArray JNICALL Java_name_blackcap_exifwasher_exiv2_ExifData__1keys
  (JNIEnv *jEnv, jobject jThis) {
      Exiv2::Image *image = getPointer(jEnv, jThis);
      Exiv2::ExifData eData = image->exifData();
      Exiv2::XmpData xData = image->xmpData();
      Exiv2::IptcData iData = image->iptcData();
      if (jEnv->ExceptionCheck()) return NULL;
      jclass klass = jEnv->FindClass("java/lang/String");
      if (jEnv->ExceptionCheck()) return NULL;
      jobjectArray ret = jEnv->NewObjectArray(eData.count() + iData.count() + xData.count(), klass, NULL);
      if (jEnv->ExceptionCheck()) return NULL;
      jsize start = getKeys(jEnv, ret, 0, eData);
      if (jEnv->ExceptionCheck()) return NULL;
      start = getKeys(jEnv, ret, start, xData);
      if (jEnv->ExceptionCheck()) return NULL;
      start = getKeys(jEnv, ret, start, iData);
      if (jEnv->ExceptionCheck()) return NULL;
      return ret;
  }

#ifdef __cplusplus
}
#endif
#endif