// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.
#include <stdlib.h>
#include "Library.h"
#include "klip_version.h"
#include "net_avadeaux_klipspringer_codec_Library.h" // generated by javac -h
static jobject errClass, ioexClass, ecodexClass, fnotfClass, pictargetClass, bigEnd, littleEnd, platformEnd;
static jmethodID ecodexMid, orderMid, clearMid, positionMid, limitMid, pictureMid;
static jint support = 0; // actual value is set when init is called
void init_error(const char *message, ...) {
va_list ap;
va_start(ap, message);
vfprintf(stderr, message, ap);
fprintf(stderr, "\n");
exit(1);
}
static jmethodID initMethodID(JNIEnv *env, jclass jClass, const char *name, const char *signature) {
jmethodID mid = (*env)->GetMethodID(env, jClass, name, signature);
if (mid == NULL) { init_error("Method not found: %s(%s)", name, signature); }
return mid;
}
static jobject initGlobalObject(JNIEnv *env, jobject local) {
jobject global = (*env)->NewGlobalRef(env, local);
if (global == NULL) { init_error("Failed to get global reference"); }
return global;
}
jobject platform_order() { return platformEnd; }
jobject wrapByteBuffer(JNIEnv *env, void *p, jlong capacity, jboolean bigend) {
jobject bb = (*env)->NewDirectByteBuffer(env, p, capacity);
if (bb == NULL) {
raiseError(env, "Failed to wrap array as byte buffer");
return NULL;
}
(*env)->CallObjectMethod(env, bb, orderMid, bigend ? bigEnd : littleEnd);
if ((*env)->ExceptionCheck(env)) { return NULL; }
return bb;
}
bool byteBufferClear(JNIEnv *env, jobject bb) {
(*env)->CallObjectMethod(env, bb, clearMid);
return !(*env)->ExceptionCheck(env);
}
bool byteBufferPosition(JNIEnv *env, jobject bb, jint pos) {
(*env)->CallObjectMethod(env, bb, positionMid, pos);
return !(*env)->ExceptionCheck(env);
}
bool byteBufferLimit(JNIEnv *env, jobject bb, jint lim) {
(*env)->CallObjectMethod(env, bb, limitMid, lim);
return !(*env)->ExceptionCheck(env);
}
// Throws if not already thrown.
const char *raiseException(JNIEnv *env, const jclass exClass, const char *message) {
if (!(*env)->ExceptionCheck(env)) {
(*env)->ThrowNew(env, exClass, message);
}
return message;
}
const char *raiseError(JNIEnv *env, const char *message) { return raiseException(env, errClass, message); }
const char *raiseIOException(JNIEnv *env, const char *message) { return raiseException(env, ioexClass, message); }
const char *raiseFileNotFound(JNIEnv *env, const char *message) { return raiseException(env, fnotfClass, message); }
const char *raiseErrorCodeException(JNIEnv *env, jint code, const char *message) {
jstring m = (*env)->NewStringUTF(env, message);
if (m == NULL) { return raiseError(env, "Failed to create message string"); }
jobject ex = (*env)->NewObject(env, ecodexClass, ecodexMid, code, m);
if (ex == NULL) { return raiseError(env, "Construction of error code exception failed"); }
(*env)->Throw(env, ex);
return message;
}
bool accepts_picture(JNIEnv *env, jobject pictarget) {
return (*env)->IsInstanceOf(env, pictarget, pictargetClass);
}
bool picture(JNIEnv *env, jobject pictarget, const char *mime_type, const char *type, const char *desc, void *data, jlong data_length) {
jstring jmime = (*env)->NewStringUTF(env, mime_type);
if (jmime == NULL) { raiseError(env, "Cannot create MIME string"); return false; }
jstring jtype = (*env)->NewStringUTF(env, type);
if (jtype == NULL) { raiseError(env, "Cannot create type string"); return false; }
jstring jdesc = (*env)->NewStringUTF(env, desc);
if (jdesc == NULL) { raiseError(env, "Cannot create description string"); return false; }
jobject bb = wrapByteBuffer(env, data, data_length, platform_bigend());
if (bb == NULL) { return false; }
(*env)->CallObjectMethod(env, pictarget, pictureMid, jmime, jtype, jdesc, bb);
return !(*env)->ExceptionCheck(env);
}
// -------------------------------------------------------------------------------------------------
// Native Library methods
#define METHOD(name) JNICALL Java_net_avadeaux_klipspringer_codec_Library_ ## name
JNIEXPORT void
METHOD(init) (JNIEnv *env,
jclass jthisClass, // JniUtil class, because static method
jint jflacbit, // mask bit for FLAC support
jint jlamebit, // mask bit for LAME support
jint jalsabit, // mask bit for ALSA support
jint jvorbisbit, // mask bit for Vorbis support
jint jopusbit, // mask bit for Opus support
jclass jbbClass, // ByteBuffer class
jclass jerrClass, // Error class
jclass jioexClass, // IOException class
jclass jecodexClass, // CodeIOException class
jclass jfnotfClass, // FileNotFoundException class
jclass jpictargetClass, // AudioDecoder.PictureTarget class
jobject jbigEnd, // ByteOrder.BIG_ENDIAN
jobject jlittleEnd) // ByteOrder.LITTLE_ENDIAN
{
support = 0;
# ifndef FLAC_UNSUPPORTED
support |= jflacbit;
# endif
# ifndef LAME_UNSUPPORTED
support |= jlamebit;
# endif
# ifndef ALSA_UNSUPPORTED
support |= jalsabit;
# endif
# ifndef VORBIS_UNSUPPORTED
support |= jvorbisbit;
# endif
# ifndef OPUS_UNSUPPORTED
support |= jopusbit;
# endif
errClass = initGlobalObject(env, jerrClass);
ioexClass = initGlobalObject(env, jioexClass);
ecodexClass = initGlobalObject(env, jecodexClass);
fnotfClass = initGlobalObject(env, jfnotfClass);
pictargetClass = initGlobalObject(env, jpictargetClass);
bigEnd = initGlobalObject(env, jbigEnd);
littleEnd = initGlobalObject(env, jlittleEnd);
platformEnd = platform_bigend() ? bigEnd : littleEnd;
ecodexMid = initMethodID(env, ecodexClass, "<init>", "(ILjava/lang/String;)V");
orderMid = initMethodID(env, jbbClass, "order", "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
clearMid = initMethodID(env, jbbClass, "clear", "()Ljava/nio/ByteBuffer;");
positionMid = initMethodID(env, jbbClass, "position", "(I)Ljava/nio/ByteBuffer;");
limitMid = initMethodID(env, jbbClass, "limit", "(I)Ljava/nio/ByteBuffer;");
pictureMid = initMethodID(env, pictargetClass, "picture", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/nio/ByteBuffer;)V");
}
JNIEXPORT jint
METHOD(support) (JNIEnv *env,
jclass jthisClass)
{
return support;
}
JNIEXPORT jstring
METHOD(version) (JNIEnv *env,
jclass jthisClass)
{
return (*env)->NewStringUTF(env, KLIP_VERSION);
}
Version: v4.3.2.2 (2026-05-16T17:03:34+02:00)
Raw file
Source code overview
Klipspringer home