summaryrefslogtreecommitdiffstats
path: root/java/zbarjni.c
diff options
context:
space:
mode:
Diffstat (limited to 'java/zbarjni.c')
-rw-r--r--java/zbarjni.c618
1 files changed, 618 insertions, 0 deletions
diff --git a/java/zbarjni.c b/java/zbarjni.c
new file mode 100644
index 0000000..3506a32
--- /dev/null
+++ b/java/zbarjni.c
@@ -0,0 +1,618 @@
+/*------------------------------------------------------------------------
+ * Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+#include <assert.h>
+#include <inttypes.h>
+#include <jni.h>
+#include <zbar.h>
+
+static jfieldID SymbolSet_peer;
+static jfieldID Symbol_peer;
+static jfieldID Image_peer, Image_data;
+static jfieldID ImageScanner_peer;
+
+static struct {
+ int SymbolSet_create, SymbolSet_destroy;
+ int Symbol_create, Symbol_destroy;
+ int Image_create, Image_destroy;
+ int ImageScanner_create, ImageScanner_destroy;
+} stats;
+
+#define PEER_CAST(l) ((void *)(uintptr_t)(l))
+
+#define GET_PEER(c, o) PEER_CAST((*env)->GetLongField(env, (o), c##_peer))
+
+static inline void throw_exc(JNIEnv *env, const char *name, const char *msg)
+{
+ jclass cls = (*env)->FindClass(env, name);
+
+ if (cls)
+ (*env)->ThrowNew(env, cls, msg);
+ (*env)->DeleteLocalRef(env, cls);
+}
+
+static inline uint32_t format_to_fourcc(JNIEnv *env, jstring format)
+{
+ if (!format)
+ goto invalid;
+
+ int n = (*env)->GetStringLength(env, format);
+ if (0 >= n || n > 4)
+ goto invalid;
+
+ char fmtstr[8];
+ (*env)->GetStringUTFRegion(env, format, 0, n, fmtstr);
+
+ uint32_t fourcc = 0;
+ int i;
+ for (i = 0; i < n; i++) {
+ if (fmtstr[i] < ' ' || 'Z' < fmtstr[i] ||
+ ('9' < fmtstr[i] && fmtstr[i] < 'A') ||
+ (' ' < fmtstr[i] && fmtstr[i] < '0'))
+ goto invalid;
+ fourcc |= ((uint32_t)fmtstr[i]) << (8 * i);
+ }
+ return (fourcc);
+
+invalid:
+ throw_exc(env, "java/lang/IllegalArgumentException",
+ "invalid format fourcc");
+ return (0);
+}
+
+static JavaVM *jvm = NULL;
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *_jvm, void *reserved)
+{
+ jvm = _jvm;
+ return (JNI_VERSION_1_2);
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *_jvm, void *reserved)
+{
+ assert(stats.SymbolSet_create == stats.SymbolSet_destroy);
+ assert(stats.Symbol_create == stats.Symbol_destroy);
+ assert(stats.Image_create == stats.Image_destroy);
+ assert(stats.ImageScanner_create == stats.ImageScanner_destroy);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_SymbolSet_init(JNIEnv *env,
+ jclass cls)
+{
+ SymbolSet_peer = (*env)->GetFieldID(env, cls, "peer", "J");
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_SymbolSet_destroy(JNIEnv *env,
+ jobject obj,
+ jlong peer)
+{
+ zbar_symbol_set_ref(PEER_CAST(peer), -1);
+ stats.SymbolSet_destroy++;
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_SymbolSet_size(JNIEnv *env,
+ jobject obj)
+{
+ zbar_symbol_set_t *zsyms = GET_PEER(SymbolSet, obj);
+ if (!zsyms)
+ return (0);
+ return (zbar_symbol_set_get_size(zsyms));
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_SymbolSet_firstSymbol(
+ JNIEnv *env, jobject obj, jlong peer)
+{
+ if (!peer)
+ return (0);
+ const zbar_symbol_t *zsym = zbar_symbol_set_first_symbol(PEER_CAST(peer));
+ if (zsym) {
+ zbar_symbol_ref(zsym, 1);
+ stats.Symbol_create++;
+ }
+ return ((intptr_t)zsym);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Symbol_init(JNIEnv *env,
+ jclass cls)
+{
+ Symbol_peer = (*env)->GetFieldID(env, cls, "peer", "J");
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Symbol_destroy(JNIEnv *env,
+ jobject obj,
+ jlong peer)
+{
+ zbar_symbol_ref(PEER_CAST(peer), -1);
+ stats.Symbol_destroy++;
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getType(JNIEnv *env,
+ jobject obj,
+ jlong peer)
+{
+ return (zbar_symbol_get_type(PEER_CAST(peer)));
+}
+
+JNIEXPORT jint JNICALL
+Java_net_sourceforge_zbar_Symbol_getConfigMask(JNIEnv *env, jobject obj)
+{
+ return (zbar_symbol_get_configs(GET_PEER(Symbol, obj)));
+}
+
+JNIEXPORT jint JNICALL
+Java_net_sourceforge_zbar_Symbol_getModifierMask(JNIEnv *env, jobject obj)
+{
+ return (zbar_symbol_get_modifiers(GET_PEER(Symbol, obj)));
+}
+
+JNIEXPORT jstring JNICALL Java_net_sourceforge_zbar_Symbol_getData(JNIEnv *env,
+ jobject obj)
+{
+ const char *data = zbar_symbol_get_data(GET_PEER(Symbol, obj));
+
+ return ((*env)->NewStringUTF(env, data));
+}
+
+JNIEXPORT jstring JNICALL
+Java_net_sourceforge_zbar_Symbol_getDataBytes(JNIEnv *env, jobject obj)
+{
+ const zbar_symbol_t *zsym = GET_PEER(Symbol, obj);
+ const void *data = zbar_symbol_get_data(zsym);
+ unsigned long datalen = zbar_symbol_get_data_length(zsym);
+
+ if (!data || !datalen)
+ return (NULL);
+
+ jbyteArray bytes = (*env)->NewByteArray(env, datalen);
+ if (!bytes)
+ return (NULL);
+
+ (*env)->SetByteArrayRegion(env, bytes, 0, datalen, data);
+ return (bytes);
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getQuality(JNIEnv *env,
+ jobject obj)
+{
+ return (zbar_symbol_get_quality(GET_PEER(Symbol, obj)));
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getCount(JNIEnv *env,
+ jobject obj)
+{
+ return (zbar_symbol_get_count(GET_PEER(Symbol, obj)));
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getLocationSize(
+ JNIEnv *env, jobject obj, jlong peer)
+{
+ return (zbar_symbol_get_loc_size(PEER_CAST(peer)));
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getLocationX(
+ JNIEnv *env, jobject obj, jlong peer, jint idx)
+{
+ return (zbar_symbol_get_loc_x(PEER_CAST(peer), idx));
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Symbol_getLocationY(
+ JNIEnv *env, jobject obj, jlong peer, jint idx)
+{
+ return (zbar_symbol_get_loc_y(PEER_CAST(peer), idx));
+}
+
+JNIEXPORT jint JNICALL
+Java_net_sourceforge_zbar_Symbol_getOrientation(JNIEnv *env, jobject obj)
+{
+ return (zbar_symbol_get_orientation(GET_PEER(Symbol, obj)));
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_Symbol_getComponents(
+ JNIEnv *env, jobject obj, jlong peer)
+{
+ const zbar_symbol_set_t *zsyms;
+
+ zsyms = zbar_symbol_get_components(PEER_CAST(peer));
+ if (zsyms) {
+ zbar_symbol_set_ref(zsyms, 1);
+ stats.SymbolSet_create++;
+ }
+ return ((intptr_t)zsyms);
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_Symbol_next(JNIEnv *env,
+ jobject obj)
+{
+ const zbar_symbol_t *zsym = zbar_symbol_next(GET_PEER(Symbol, obj));
+ if (zsym) {
+ zbar_symbol_ref(zsym, 1);
+ stats.Symbol_create++;
+ }
+ return ((intptr_t)zsym);
+}
+
+static void Image_cleanupByteArray(zbar_image_t *zimg)
+{
+ jobject data = zbar_image_get_userdata(zimg);
+ assert(data);
+
+ JNIEnv *env = NULL;
+ if ((*jvm)->AttachCurrentThread(jvm, (void *)&env, NULL))
+ return;
+ assert(env);
+ if (env && data) {
+ void *raw = (void *)zbar_image_get_data(zimg);
+ assert(raw);
+ /* const image data is unchanged - abort copy back */
+ (*env)->ReleaseByteArrayElements(env, data, raw, JNI_ABORT);
+ (*env)->DeleteGlobalRef(env, data);
+ zbar_image_set_userdata(zimg, NULL);
+ }
+}
+
+static void Image_cleanupIntArray(zbar_image_t *zimg)
+{
+ jobject data = zbar_image_get_userdata(zimg);
+ assert(data);
+
+ JNIEnv *env = NULL;
+ if ((*jvm)->AttachCurrentThread(jvm, (void *)&env, NULL))
+ return;
+ assert(env);
+ if (env && data) {
+ void *raw = (void *)zbar_image_get_data(zimg);
+ assert(raw);
+ /* const image data is unchanged - abort copy back */
+ (*env)->ReleaseIntArrayElements(env, data, raw, JNI_ABORT);
+ (*env)->DeleteGlobalRef(env, data);
+ zbar_image_set_userdata(zimg, NULL);
+ }
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_init(JNIEnv *env,
+ jclass cls)
+{
+ Image_peer = (*env)->GetFieldID(env, cls, "peer", "J");
+ Image_data = (*env)->GetFieldID(env, cls, "data", "Ljava/lang/Object;");
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_Image_create(JNIEnv *env,
+ jobject obj)
+{
+ zbar_image_t *zimg = zbar_image_create();
+ if (!zimg) {
+ throw_exc(env, "java/lang/OutOfMemoryError", NULL);
+ return (0);
+ }
+ stats.Image_create++;
+ return ((intptr_t)zimg);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_destroy(JNIEnv *env,
+ jobject obj,
+ jlong peer)
+{
+ zbar_image_ref(PEER_CAST(peer), -1);
+ stats.Image_destroy++;
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_Image_convert(JNIEnv *env,
+ jobject obj,
+ jlong peer,
+ jstring format)
+{
+ uint32_t fourcc = format_to_fourcc(env, format);
+ if (!fourcc)
+ return (0);
+ zbar_image_t *zimg = zbar_image_convert(PEER_CAST(peer), fourcc);
+ if (!zimg)
+ throw_exc(env, "java/lang/UnsupportedOperationException",
+ "unsupported image format");
+ else
+ stats.Image_create++;
+ return ((intptr_t)zimg);
+}
+
+JNIEXPORT jstring JNICALL Java_net_sourceforge_zbar_Image_getFormat(JNIEnv *env,
+ jobject obj)
+{
+ uint32_t fourcc = zbar_image_get_format(GET_PEER(Image, obj));
+
+ if (!fourcc)
+ return (NULL);
+
+ char fmtstr[5] = { fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24, 0 };
+ return ((*env)->NewStringUTF(env, fmtstr));
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setFormat(JNIEnv *env,
+ jobject obj,
+ jstring format)
+{
+ uint32_t fourcc = format_to_fourcc(env, format);
+
+ if (!fourcc)
+ return;
+ zbar_image_set_format(GET_PEER(Image, obj), fourcc);
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Image_getSequence(JNIEnv *env,
+ jobject obj)
+{
+ return (zbar_image_get_sequence(GET_PEER(Image, obj)));
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setSequence(JNIEnv *env,
+ jobject obj,
+ jint seq)
+{
+ zbar_image_set_sequence(GET_PEER(Image, obj), seq);
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Image_getWidth(JNIEnv *env,
+ jobject obj)
+{
+ return (zbar_image_get_width(GET_PEER(Image, obj)));
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_Image_getHeight(JNIEnv *env,
+ jobject obj)
+{
+ return (zbar_image_get_height(GET_PEER(Image, obj)));
+}
+
+JNIEXPORT jobject JNICALL Java_net_sourceforge_zbar_Image_getSize(JNIEnv *env,
+ jobject obj)
+{
+ jintArray size = (*env)->NewIntArray(env, 2);
+ if (!size)
+ return (NULL);
+
+ unsigned dims[2];
+ zbar_image_get_size(GET_PEER(Image, obj), dims, dims + 1);
+ jint jdims[2] = { dims[0], dims[1] };
+ (*env)->SetIntArrayRegion(env, size, 0, 2, jdims);
+ return (size);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setSize__II(JNIEnv *env,
+ jobject obj,
+ jint width,
+ jint height)
+{
+ if (width < 0)
+ width = 0;
+ if (height < 0)
+ height = 0;
+ zbar_image_set_size(GET_PEER(Image, obj), width, height);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setSize___3I(
+ JNIEnv *env, jobject obj, jintArray size)
+{
+ if ((*env)->GetArrayLength(env, size) != 2)
+ throw_exc(env, "java/lang/IllegalArgumentException",
+ "size must be an array of two ints");
+ jint dims[2];
+ (*env)->GetIntArrayRegion(env, size, 0, 2, dims);
+ if (dims[0] < 0)
+ dims[0] = 0;
+ if (dims[1] < 0)
+ dims[1] = 0;
+ zbar_image_set_size(GET_PEER(Image, obj), dims[0], dims[1]);
+}
+
+JNIEXPORT jobject JNICALL Java_net_sourceforge_zbar_Image_getCrop(JNIEnv *env,
+ jobject obj)
+{
+ jintArray crop = (*env)->NewIntArray(env, 4);
+ if (!crop)
+ return (NULL);
+
+ unsigned dims[4];
+ zbar_image_get_crop(GET_PEER(Image, obj), dims, dims + 1, dims + 2,
+ dims + 3);
+ jint jdims[4] = { dims[0], dims[1], dims[2], dims[3] };
+ (*env)->SetIntArrayRegion(env, crop, 0, 4, jdims);
+ return (crop);
+}
+
+#define VALIDATE_CROP(u, m) \
+ if ((u) < 0) { \
+ (m) += (u); \
+ (u) = 0; \
+ }
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setCrop__IIII(
+ JNIEnv *env, jobject obj, jint x, jint y, jint w, jint h)
+{
+ VALIDATE_CROP(x, w);
+ VALIDATE_CROP(y, h);
+ zbar_image_set_crop(GET_PEER(Image, obj), x, y, w, h);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setCrop___3I(
+ JNIEnv *env, jobject obj, jintArray crop)
+{
+ if ((*env)->GetArrayLength(env, crop) != 4)
+ throw_exc(env, "java/lang/IllegalArgumentException",
+ "crop must be an array of four ints");
+ jint dims[4];
+ (*env)->GetIntArrayRegion(env, crop, 0, 4, dims);
+ VALIDATE_CROP(dims[0], dims[2]);
+ VALIDATE_CROP(dims[1], dims[3]);
+ zbar_image_set_crop(GET_PEER(Image, obj), dims[0], dims[1], dims[2],
+ dims[3]);
+}
+#undef VALIDATE_CROP
+
+JNIEXPORT jobject JNICALL Java_net_sourceforge_zbar_Image_getData(JNIEnv *env,
+ jobject obj)
+{
+ jobject data = (*env)->GetObjectField(env, obj, Image_data);
+ if (data)
+ return (data);
+
+ zbar_image_t *zimg = GET_PEER(Image, obj);
+ data = zbar_image_get_userdata(zimg);
+ if (data)
+ return (data);
+
+ unsigned long rawlen = zbar_image_get_data_length(zimg);
+ const void *raw = zbar_image_get_data(zimg);
+ if (!rawlen || !raw)
+ return (NULL);
+
+ data = (*env)->NewByteArray(env, rawlen);
+ if (!data)
+ return (NULL);
+
+ (*env)->SetByteArrayRegion(env, data, 0, rawlen, raw);
+ (*env)->SetObjectField(env, obj, Image_data, data);
+ return (data);
+}
+
+static inline void Image_setData(JNIEnv *env, jobject obj, jbyteArray data,
+ void *raw, unsigned long rawlen,
+ zbar_image_cleanup_handler_t *cleanup)
+{
+ if (!data)
+ cleanup = NULL;
+ (*env)->SetObjectField(env, obj, Image_data, data);
+ zbar_image_t *zimg = GET_PEER(Image, obj);
+ zbar_image_set_data(zimg, raw, rawlen, cleanup);
+ zbar_image_set_userdata(zimg, (*env)->NewGlobalRef(env, data));
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setData___3B(
+ JNIEnv *env, jobject obj, jbyteArray data)
+{
+ jbyte *raw = NULL;
+ unsigned long rawlen = 0;
+ if (data) {
+ raw = (*env)->GetByteArrayElements(env, data, NULL);
+ if (!raw)
+ return;
+ rawlen = (*env)->GetArrayLength(env, data);
+ }
+ Image_setData(env, obj, data, raw, rawlen, Image_cleanupByteArray);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_Image_setData___3I(
+ JNIEnv *env, jobject obj, jintArray data)
+{
+ jint *raw = NULL;
+ unsigned long rawlen = 0;
+ if (data) {
+ raw = (*env)->GetIntArrayElements(env, data, NULL);
+ if (!raw)
+ return;
+ rawlen = (*env)->GetArrayLength(env, data) * sizeof(*raw);
+ }
+ Image_setData(env, obj, data, raw, rawlen, Image_cleanupIntArray);
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_Image_getSymbols(JNIEnv *env,
+ jobject obj,
+ jlong peer)
+{
+ const zbar_symbol_set_t *zsyms = zbar_image_get_symbols(PEER_CAST(peer));
+ if (zsyms) {
+ zbar_symbol_set_ref(zsyms, 1);
+ stats.SymbolSet_create++;
+ }
+ return ((intptr_t)zsyms);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_ImageScanner_init(JNIEnv *env,
+ jclass cls)
+{
+ ImageScanner_peer = (*env)->GetFieldID(env, cls, "peer", "J");
+}
+
+JNIEXPORT jlong JNICALL
+Java_net_sourceforge_zbar_ImageScanner_create(JNIEnv *env, jobject obj)
+{
+ zbar_image_scanner_t *zscn = zbar_image_scanner_create();
+ if (!zscn) {
+ throw_exc(env, "java/lang/OutOfMemoryError", NULL);
+ return (0);
+ }
+ stats.ImageScanner_create++;
+ return ((intptr_t)zscn);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_ImageScanner_destroy(
+ JNIEnv *env, jobject obj, jlong peer)
+{
+ zbar_image_scanner_destroy(PEER_CAST(peer));
+ stats.ImageScanner_destroy++;
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_ImageScanner_setConfig(
+ JNIEnv *env, jobject obj, jint symbology, jint config, jint value)
+{
+ zbar_image_scanner_set_config(GET_PEER(ImageScanner, obj), symbology,
+ config, value);
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_ImageScanner_parseConfig(
+ JNIEnv *env, jobject obj, jstring cfg)
+{
+ const char *cfgstr = (*env)->GetStringUTFChars(env, cfg, NULL);
+ if (!cfgstr)
+ return;
+ if (zbar_image_scanner_parse_config(GET_PEER(ImageScanner, obj), cfgstr))
+ throw_exc(env, "java/lang/IllegalArgumentException",
+ "unknown configuration");
+}
+
+JNIEXPORT void JNICALL Java_net_sourceforge_zbar_ImageScanner_enableCache(
+ JNIEnv *env, jobject obj, jboolean enable)
+{
+ zbar_image_scanner_enable_cache(GET_PEER(ImageScanner, obj), enable);
+}
+
+JNIEXPORT jlong JNICALL Java_net_sourceforge_zbar_ImageScanner_getResults(
+ JNIEnv *env, jobject obj, jlong peer)
+{
+ const zbar_symbol_set_t *zsyms =
+ zbar_image_scanner_get_results(PEER_CAST(peer));
+ if (zsyms) {
+ zbar_symbol_set_ref(zsyms, 1);
+ stats.SymbolSet_create++;
+ }
+ return ((intptr_t)zsyms);
+}
+
+JNIEXPORT jint JNICALL Java_net_sourceforge_zbar_ImageScanner_scanImage(
+ JNIEnv *env, jobject obj, jobject image)
+{
+ zbar_image_scanner_t *zscn = GET_PEER(ImageScanner, obj);
+ zbar_image_t *zimg = GET_PEER(Image, image);
+
+ int n = zbar_scan_image(zscn, zimg);
+ if (n < 0)
+ throw_exc(env, "java/lang/UnsupportedOperationException",
+ "unsupported image format");
+ return (n);
+}