mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-08 03:24:13 +00:00
JNI interface returns byte[] instead of String
This allows the output fields of any command to contain nul characters, which paves the way for extracting a manifest or other binary data directly instead of having to write it into a temporary file.
This commit is contained in:
parent
4450116472
commit
5185c944c9
@ -83,20 +83,25 @@ static int outv_growbuf(size_t needed)
|
||||
|
||||
static int outv_end_field()
|
||||
{
|
||||
outv_growbuf(1);
|
||||
*outv_current++ = '\0';
|
||||
jstring str = (jstring)(*jni_env)->NewStringUTF(jni_env, outv_buffer);
|
||||
size_t length = outv_current - outv_buffer;
|
||||
outv_current = outv_buffer;
|
||||
if (str == NULL) {
|
||||
jbyteArray arr = (*jni_env)->NewByteArray(jni_env, length);
|
||||
if (arr == NULL) {
|
||||
jni_exception = 1;
|
||||
return WHY("Exception thrown from NewStringUTF()");
|
||||
return WHY("Exception thrown from NewByteArray()");
|
||||
}
|
||||
(*jni_env)->CallBooleanMethod(jni_env, outv_list, listAddMethodId, str);
|
||||
(*jni_env)->SetByteArrayRegion(jni_env, arr, 0, length, (jbyte*)outv_buffer);
|
||||
DEBUGF("SetByteArrayRegion(%s)", alloca_toprint(-1, outv_buffer, length));
|
||||
if ((*jni_env)->ExceptionOccurred(jni_env)) {
|
||||
jni_exception = 1;
|
||||
return WHY("Exception thrown from SetByteArrayRegion()");
|
||||
}
|
||||
(*jni_env)->CallBooleanMethod(jni_env, outv_list, listAddMethodId, arr);
|
||||
if ((*jni_env)->ExceptionOccurred(jni_env)) {
|
||||
jni_exception = 1;
|
||||
return WHY("Exception thrown from CallBooleanMethod()");
|
||||
}
|
||||
(*jni_env)->DeleteLocalRef(jni_env, str);
|
||||
(*jni_env)->DeleteLocalRef(jni_env, arr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -215,6 +220,32 @@ int cli_putchar(char c)
|
||||
return putchar(c);
|
||||
}
|
||||
|
||||
/* Write a buffer of data to output. If in a JNI call, then this appends the data to the
|
||||
current output field, including any embedded nul characters. Returns a non-negative integer on
|
||||
success, EOF on error.
|
||||
*/
|
||||
int cli_write(const unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef HAVE_JNI_H
|
||||
if (jni_env) {
|
||||
size_t avail = outv_limit - outv_current;
|
||||
if (avail < len) {
|
||||
memcpy(outv_current, buf, avail);
|
||||
outv_current = outv_limit;
|
||||
if (outv_growbuf(len) == -1)
|
||||
return EOF;
|
||||
len -= avail;
|
||||
buf += avail;
|
||||
}
|
||||
memcpy(outv_current, buf, len);
|
||||
outv_current += len;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return fwrite(buf, len, 1, stdout);
|
||||
}
|
||||
|
||||
/* Write a null-terminated string to output. If in a JNI call, then this appends the string to the
|
||||
current output field. The terminating null is not included. Returns a non-negative integer on
|
||||
success, EOF on error.
|
||||
@ -222,21 +253,8 @@ int cli_putchar(char c)
|
||||
int cli_puts(const char *str)
|
||||
{
|
||||
#ifdef HAVE_JNI_H
|
||||
if (jni_env) {
|
||||
size_t len = strlen(str);
|
||||
size_t avail = outv_limit - outv_current;
|
||||
if (avail < len) {
|
||||
strncpy(outv_current, str, avail);
|
||||
outv_current = outv_limit;
|
||||
if (outv_growbuf(len) == -1)
|
||||
return EOF;
|
||||
len -= avail;
|
||||
str += avail;
|
||||
}
|
||||
strncpy(outv_current, str, len);
|
||||
outv_current += len;
|
||||
return 0;
|
||||
}
|
||||
if (jni_env)
|
||||
return cli_write((const unsigned char *) str, strlen(str));
|
||||
else
|
||||
#endif
|
||||
return fputs(str, stdout);
|
||||
@ -307,11 +325,21 @@ void cli_flush()
|
||||
int app_echo(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||
{
|
||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
int i = 1;
|
||||
int escapes = 0;
|
||||
if (i < argc && strcmp(argv[i], "-e") == 0) {
|
||||
escapes = 1;
|
||||
++i;
|
||||
}
|
||||
for (; i < argc; ++i) {
|
||||
if (debug & DEBUG_VERBOSE)
|
||||
DEBUGF("echo:argv[%d]=%s", i, argv[i]);
|
||||
cli_puts(argv[i]);
|
||||
DEBUGF("echo:argv[%d]=\"%s\"", i, argv[i]);
|
||||
if (escapes) {
|
||||
unsigned char buf[strlen(argv[i])];
|
||||
size_t len = str_fromprint(buf, argv[i]);
|
||||
cli_write(buf, len);
|
||||
} else
|
||||
cli_puts(argv[i]);
|
||||
cli_delim(NULL);
|
||||
}
|
||||
return 0;
|
||||
|
@ -26,18 +26,18 @@ import java.util.LinkedList;
|
||||
class ServalD
|
||||
{
|
||||
int status;
|
||||
List<String> outv;
|
||||
List<byte[]> outv;
|
||||
|
||||
public ServalD()
|
||||
{
|
||||
System.loadLibrary("servald");
|
||||
}
|
||||
|
||||
public native int rawCommand(List<String> outv, String... args);
|
||||
public native int rawCommand(List<byte[]> outv, String... args);
|
||||
|
||||
public void command(String... args)
|
||||
{
|
||||
this.outv = new LinkedList<String>();
|
||||
this.outv = new LinkedList<byte[]>();
|
||||
this.status = this.rawCommand(this.outv, args);
|
||||
}
|
||||
|
||||
@ -45,8 +45,8 @@ class ServalD
|
||||
{
|
||||
ServalD servald = new ServalD();
|
||||
servald.command(args);
|
||||
for (String s: servald.outv) {
|
||||
System.out.println(s);
|
||||
for (byte[] a: servald.outv) {
|
||||
System.out.println(new String(a));
|
||||
}
|
||||
System.exit(servald.status);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ class ServalDTests
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
Class cls = new Object() { }.getClass().getEnclosingClass();
|
||||
Class<?> cls = new Object() { }.getClass().getEnclosingClass();
|
||||
Method m = cls.getMethod(args[0], String[].class);
|
||||
m.invoke(null, (Object) Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
@ -29,9 +29,9 @@ class ServalDTests
|
||||
for (int i = 0; i != repeat; ++i) {
|
||||
servald.command(Arrays.copyOfRange(args, 1, args.length));
|
||||
System.out.print(servald.status);
|
||||
for (String s: servald.outv) {
|
||||
for (byte[] a: servald.outv) {
|
||||
System.out.print(":");
|
||||
System.out.print(s);
|
||||
System.out.print(new String(a));
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
|
11
tests/jni
11
tests/jni
@ -24,6 +24,7 @@ source "${0%/*}/../testconfig.sh"
|
||||
|
||||
setup() {
|
||||
setup_servald
|
||||
executeOk_servald config set debug.verbose 1
|
||||
assert_echo_works
|
||||
compile_java_classes
|
||||
setup_servald_so
|
||||
@ -32,21 +33,21 @@ setup() {
|
||||
compile_java_classes() {
|
||||
assert --message='Java compiler was detected by ./configure' [ "$JAVAC" ]
|
||||
mkdir classes
|
||||
assert $JAVAC -d classes "$servald_source_root"/java/org/servalproject/servald/*.java
|
||||
assert $JAVAC -Xlint:unchecked -d classes "$servald_source_root"/java/org/servalproject/servald/*.java
|
||||
assert [ -r classes/org/servalproject/servald/ServalD.class ]
|
||||
assert [ -r classes/org/servalproject/servald/ServalDTests.class ]
|
||||
}
|
||||
|
||||
# Make sure that the normal echo command-line works, without JNI.
|
||||
assert_echo_works() {
|
||||
executeOk $servald echo 'Hello,' 'world!'
|
||||
assertStdoutIs -e 'Hello,\nworld!\n'
|
||||
executeOk $servald echo -e 'Hello,\ttab' 'world\0!'
|
||||
assertStdoutIs -e 'Hello,\ttab\nworld\0!\n'
|
||||
}
|
||||
|
||||
doc_Echo="Serval JNI echo Hello world"
|
||||
test_Echo() {
|
||||
executeOk java -classpath "$PWD/classes" org.servalproject.servald.ServalD echo 'Hello,' 'world!'
|
||||
assertStdoutIs -e 'Hello,\nworld!\n'
|
||||
executeOk java -classpath "$PWD/classes" org.servalproject.servald.ServalD echo -e 'Hello,\ttab' 'world\0!'
|
||||
assertStdoutIs -e 'Hello,\ttab\nworld\0!\n'
|
||||
}
|
||||
|
||||
doc_Delim="Serval non-JNI output delimiter environment variable"
|
||||
|
Loading…
x
Reference in New Issue
Block a user