diff --git a/Makefile b/Makefile index 09aa037b487ff0c210810246275a77a76c882fdd..37d808572ffc98178f918aae1b68cf639091ed3e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # and kick off a recursive make # Also, "make src/all" turns into "make -C src all" -SUBDIRS = src examples jni +SUBDIRS = src examples src/bindings/jni include config.mk TOPLEVEL=. diff --git a/SConstruct b/SConstruct index c7e3ba5371c8e5419086e2373511bc5478ae0828..3120df44a885b706cc57534e9a0f548bcd1a0562 100644 --- a/SConstruct +++ b/SConstruct @@ -14,7 +14,7 @@ if platform.system() == 'Windows': vars = Variables(None, ARGUMENTS) vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate)) vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept)) -vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['cpp', 'dotnet', 'perl', 'php', 'python', 'ruby'])) +vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['cpp', 'dotnet', 'jni', 'perl', 'php', 'python', 'ruby'])) vars.Add('python', 'Python interpreter', 'python') tools = ['default', 'scanreplace'] diff --git a/src/bindings/jni/ConfigureJNI.py b/src/bindings/jni/ConfigureJNI.py new file mode 100644 index 0000000000000000000000000000000000000000..573bd682192e88618cba6c9b847128a98d6e08db --- /dev/null +++ b/src/bindings/jni/ConfigureJNI.py @@ -0,0 +1,99 @@ +#!python + +from __future__ import absolute_import, division, print_function + +import os +import sys + +def walkDirs(path): + """helper function to get a list of all subdirectories""" + def addDirs(pathlist, dirname, names): + """internal function to pass to os.walk""" + print("in addDirs") + for n in names: + f = os.path.join(dirname, n) + if os.path.isdir(f): + pathlist.append(f) + pathlist = [path] + os.walk(path, addDirs, pathlist) + print(pathlist) + return pathlist + +def ConfigureJNI(env): + """Configure the given environment for compiling Java Native Interface + c or c++ language files.""" + + print( "Configuring JNI includes") + + if not env.get('JAVAC'): + print( "The Java compiler must be installed and in the current path.") + return 0 + + # first look for a shell variable called JAVA_HOME + java_base = os.environ.get('JAVA_HOME') + if not java_base: + if sys.platform == 'darwin': + # Apple's OS X has its own special java base directory + java_base = '/System/Library/Frameworks/JavaVM.framework' + else: + # Search for the java compiler + print ("JAVA_HOME environment variable is not set. Searching for java... ") + jcdir = os.path.dirname(env.WhereIs('javac')) + if not jcdir: + print( "not found.") + return 0 + # assuming the compiler found is in some directory like + # /usr/jdkX.X/bin/javac, java's home directory is /usr/jdkX.X + java_base = os.path.join(jcdir, "..") + print( "found.") + + if sys.platform == 'cygwin': + # Cygwin and Sun Java have different ideas of how path names + # are defined. Use cygpath to convert the windows path to + # a cygwin path. i.e. C:\jdkX.X to /cygdrive/c/jdkX.X + java_base = os.popen("cygpath -up '"+java_base+"'").read().replace( \ + '\n', '') + + if sys.platform == 'darwin': + # Apple does not use Sun's naming convention + java_headers = [os.path.join(java_base, 'Headers')] + java_libs = [os.path.join(java_base, 'Libraries')] + else: + # windows and linux + java_headers = [os.path.join(java_base, 'include')] + java_libs = [os.path.join(java_base, 'lib')] + # Sun's windows and linux JDKs keep system-specific header + # files in a sub-directory of include + if java_base == '/usr' or java_base == '/usr/local': + # too many possible subdirectories. Just use defaults + java_headers.append(os.path.join(java_headers[0], 'win32')) + java_headers.append(os.path.join(java_headers[0], 'linux')) + java_headers.append(os.path.join(java_headers[0], 'solaris')) + else: + # add all subdirs of 'include'. The system specific headers + # should be in there somewhere + java_headers = walkDirs(java_headers[0]) + + if not any(os.path.exists(os.path.join(path, 'jni.h')) + for path in java_headers): + print("Can't find jni.h in %s" % java_headers) + return 0 + + # add Java's include and lib directory to the environment + java_headers.append(os.path.join(java_headers[0], 'linux')) + env.Append(CPPPATH = java_headers) + env.Append(LIBPATH = java_libs) + + # add any special platform-specific compilation or linking flags + if sys.platform == 'darwin': + env.Append(SHLINKFLAGS = '-dynamiclib -framework JavaVM') + env['SHLIBSUFFIX'] = '.jnilib' + elif sys.platform == 'cygwin': + env.Append(CCFLAGS = '-mno-cygwin') + env.Append(SHLINKFLAGS = '-mno-cygwin -Wl,--kill-at') + + # Add extra potentially useful environment variables + env['JAVA_HOME'] = java_base + env['JNI_CPPPATH'] = java_headers + env['JNI_LIBPATH'] = java_libs + return 1 \ No newline at end of file diff --git a/jni/Example.java b/src/bindings/jni/Example.java similarity index 75% rename from jni/Example.java rename to src/bindings/jni/Example.java index 4e6d76825aa64ddeb9e916ea0596e457ff2751f0..52f89e27b42b1ee0f28658a5eba9df3a08674749 100644 --- a/jni/Example.java +++ b/src/bindings/jni/Example.java @@ -84,6 +84,20 @@ public static void main(String args[]) Parser i3parsers[] = {Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()}; handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()), i3, i3.length)); + out("permutation"); + byte ch3[] = {(byte) 'a', (byte) 'b', (byte) 'c'}; + handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'a'), Hammer.ch((byte)'b'), Hammer.ch((byte)'c')), ch3, ch3.length)); + handle(Hammer.parse(Hammer.permutation(Hammer.ch((byte)'b'), Hammer.ch((byte)'a'), Hammer.ch((byte)'c')), ch3, ch3.length)); + + out("skip"); + byte ch6[] = {(byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'}; + handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.skip((int)32), Hammer.ch((byte)'f')), ch6, ch6.length)); + + out("seek"); + final int SEEK_SET = 0; /* Seek from beginning of file. */ + //final int SEEK_CUR = 1; /* Seek from current position. */ + //final int SEEK_END = 2; /* Seek from end of file. */ + handle(Hammer.parse(Hammer.sequence(Hammer.ch((byte)'a'), Hammer.seek((int)40, (int)SEEK_SET), Hammer.ch((byte)'f')), ch6, ch6.length)); } diff --git a/jni/Makefile b/src/bindings/jni/Makefile similarity index 87% rename from jni/Makefile rename to src/bindings/jni/Makefile index 85be973388223c6b9332c0d72a54f8a283e2c899..ea257872242da2e27c70eef26825137d4247d154 100644 --- a/jni/Makefile +++ b/src/bindings/jni/Makefile @@ -5,17 +5,18 @@ CSOURCES := com_upstandinghackers_hammer_Hammer.c com_upstandinghackers_hammer_P # ls *.h *.o *.so com/upstandinghackers/hammer/*.class | grep -v jhammer.h | tr '\n' ' '; replace single $ with $$ OUTPUTS := com/upstandinghackers/hammer/Action.class com/upstandinghackers/hammer/Hammer.class com_upstandinghackers_hammer_Hammer.h com_upstandinghackers_hammer_Hammer.o com/upstandinghackers/hammer/Hammer\$TokenType.class com_upstandinghackers_hammer_Hammer_TokenType.h com/upstandinghackers/hammer/ParsedToken.class com_upstandinghackers_hammer_ParsedToken.h com_upstandinghackers_hammer_ParsedToken.o com/upstandinghackers/hammer/Parser.class com/upstandinghackers/hammer/ParseResult.class com_upstandinghackers_hammer_ParseResult.h com_upstandinghackers_hammer_ParseResult.o com_upstandinghackers_hammer_Parser.h com_upstandinghackers_hammer_Parser.o com/upstandinghackers/hammer/Predicate.class libjhammer.so -TOPLEVEL := ../ +TOPLEVEL := ../../../ JC=javac JH=javah CP=com/upstandinghackers/hammer PACKAGE=com.upstandinghackers.hammer -include ../common.mk +include ../../../common.mk -JNI_INCLUDE := /usr/lib/jvm/java-6-openjdk/include/ -CFLAGS += -fPIC -I. -I $(TOPLEVEL)/src/ -I jni -I $(JNI_INCLUDE) +JNI_INCLUDE := /usr/lib/jvm/java-8-oracle/include/ +JNI_INCLUDE_LINUX := /usr/lib/jvm/java-8-oracle/include/linux +CFLAGS += -fPIC -I. -I $(TOPLEVEL)/src/ -I jni -I $(JNI_INCLUDE) -I $(JNI_INCLUDE_LINUX) %.java: $(call ifsilent,| $(HUSH)) $(call hush, "Compiling Java source $@") $(JC) $(CP)/$@ @@ -23,7 +24,7 @@ CFLAGS += -fPIC -I. -I $(TOPLEVEL)/src/ -I jni -I $(JNI_INCLUDE) all: javacc prepare compile link link: compile - $(call hush, "Generating libjhammer.so") $(CC) -shared $(CFLAGS) -o libjhammer.so *.o ../src/*.o ../src/backends/*.o ../src/parsers/*.o + $(call hush, "Generating libjhammer.so") $(CC) -shared $(CFLAGS) -o libjhammer.so *.o ../../../src/*.o ../../../src/backends/*.o ../../../src/parsers/*.o $(CSOURCES): prepare $(call hush, "Compiling $@") $(CC) -c $(CFLAGS) $@ diff --git a/jni/NOTES b/src/bindings/jni/NOTES similarity index 100% rename from jni/NOTES rename to src/bindings/jni/NOTES diff --git a/src/bindings/jni/SConscript b/src/bindings/jni/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..81582868ff07bff5d46d162a9d8ed2936dd52e28 --- /dev/null +++ b/src/bindings/jni/SConscript @@ -0,0 +1,42 @@ +# -*- python -*- + +from __future__ import absolute_import, division, print_function + +import os, os.path +import sys +Import('env libhammer_shared testruns targets') +from src.bindings.jni.ConfigureJNI import ConfigureJNI + +javaenv = env.Clone() + +if not ConfigureJNI(javaenv): + print("Java Native Interface is required... Exiting") + Exit(0) + + +javaenv.Append(CPPPATH=[".", "../.."], + LIBS=['hammer'], + LIBPATH=["../.."]) + +# compile java classes +jni_classes = javaenv.Java(".", "#src/bindings/jni/com") + +print(jni_classes) +jni_headers = javaenv.JavaH(".", jni_classes) +print(jni_headers) +Default(jni_classes) +Default(jni_headers) + +#print(javaenv.Dump()) + +shlib_env = env.Clone(CPPPATH=javaenv['JNI_CPPPATH'] + ['../..'], + LIBS=['hammer'], + LIBPATH=["../.."]) +csources = ['com_upstandinghackers_hammer_Hammer.c', + 'com_upstandinghackers_hammer_ParsedToken.c', + 'com_upstandinghackers_hammer_Parser.c', + 'com_upstandinghackers_hammer_ParseResult.c'] + +libjhammer_shared = shlib_env.SharedLibrary('libjhammer', csources) +Default(libjhammer_shared) + diff --git a/jni/com/upstandinghackers/hammer/Action.java b/src/bindings/jni/com/upstandinghackers/hammer/Action.java similarity index 100% rename from jni/com/upstandinghackers/hammer/Action.java rename to src/bindings/jni/com/upstandinghackers/hammer/Action.java diff --git a/jni/com/upstandinghackers/hammer/Hammer.java b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java similarity index 85% rename from jni/com/upstandinghackers/hammer/Hammer.java rename to src/bindings/jni/com/upstandinghackers/hammer/Hammer.java index 3e06a91eca4b15eebbfe28c99547829a3c2d6068..2b77a564af480140a21b8d2aa992c49d6bf2bcf4 100644 --- a/jni/com/upstandinghackers/hammer/Hammer.java +++ b/src/bindings/jni/com/upstandinghackers/hammer/Hammer.java @@ -53,10 +53,12 @@ public class Hammer public static native Parser middle(Parser p, Parser x, Parser q); // public static native Parser action(Parser p, Action a); public static native Parser in(byte[] charset, int length); + public static native Parser notIn(byte[] charset, int length); public static native Parser endP(); public static native Parser nothingP(); public static native Parser sequence(Parser... parsers); public static native Parser choice(Parser... parsers); + public static native Parser permutation(Parser... parsers); public static native Parser butNot(Parser p1, Parser p2); public static native Parser difference(Parser p1, Parser p2); public static native Parser xor(Parser p1, Parser p2); @@ -73,4 +75,11 @@ public class Hammer public static native Parser and(Parser p); public static native Parser not(Parser p); public static native Parser indirect(); +// public static native Parser bindIndirect(Parser indirect, Parser inner); + public static native Parser withEndianess(byte endianess, Parser p); +// public static native Parser bind(Parser p, HContinuation k, void *env); + public static native Parser skip(int n); + public static native Parser seek(int n, int whence); + public static native Parser tell(); + } diff --git a/jni/com/upstandinghackers/hammer/ParseResult.java b/src/bindings/jni/com/upstandinghackers/hammer/ParseResult.java similarity index 100% rename from jni/com/upstandinghackers/hammer/ParseResult.java rename to src/bindings/jni/com/upstandinghackers/hammer/ParseResult.java diff --git a/jni/com/upstandinghackers/hammer/ParsedToken.java b/src/bindings/jni/com/upstandinghackers/hammer/ParsedToken.java similarity index 100% rename from jni/com/upstandinghackers/hammer/ParsedToken.java rename to src/bindings/jni/com/upstandinghackers/hammer/ParsedToken.java diff --git a/jni/com/upstandinghackers/hammer/Parser.java b/src/bindings/jni/com/upstandinghackers/hammer/Parser.java similarity index 100% rename from jni/com/upstandinghackers/hammer/Parser.java rename to src/bindings/jni/com/upstandinghackers/hammer/Parser.java diff --git a/jni/com/upstandinghackers/hammer/Predicate.java b/src/bindings/jni/com/upstandinghackers/hammer/Predicate.java similarity index 100% rename from jni/com/upstandinghackers/hammer/Predicate.java rename to src/bindings/jni/com/upstandinghackers/hammer/Predicate.java diff --git a/jni/com_upstandinghackers_hammer_Hammer.c b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c similarity index 83% rename from jni/com_upstandinghackers_hammer_Hammer.c rename to src/bindings/jni/com_upstandinghackers_hammer_Hammer.c index f83414bc8bd9c443a338e16300f4eb3bd3637d37..7087792789092167c4c3a1adcfa4487bbaf01a5e 100644 --- a/jni/com_upstandinghackers_hammer_Hammer.c +++ b/src/bindings/jni/com_upstandinghackers_hammer_Hammer.c @@ -157,6 +157,13 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in } +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_notIn + (JNIEnv *env, jclass class, jbyteArray charset, jint length) +{ + RETURNWRAP(env, h_not_in((uint8_t*) ((*env)->GetByteArrayElements(env, charset, NULL)), (size_t)length)); +} + + JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_endP (JNIEnv *env, jclass class) { @@ -227,6 +234,34 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_choice } +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_permutation + (JNIEnv *env, jclass class, jobjectArray permutation) +{ + jsize length; + void **parsers; + int i; + jobject current; + const HParser *result; + + length = (*env)->GetArrayLength(env, permutation); + parsers = malloc(sizeof(HParser *)*(length+1)); + if(NULL==parsers) + { + return NULL; + } + + for(i=0; i<length; i++) + { + current = (*env)->GetObjectArrayElement(env, permutation, (jsize)i); + parsers[i] = UNWRAP(env, current); + } + parsers[length] = NULL; + + result = h_permutation__a(parsers); + RETURNWRAP(env, result); +} + + JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_butNot (JNIEnv *env, jclass class, jobject p, jobject q) { @@ -332,4 +367,29 @@ JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_indirect } +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_with_endianness + (JNIEnv *env, jclass class, jbyte endianess, jobject p) +{ + RETURNWRAP(env, h_with_endianness((char) endianess, UNWRAP(env, p))); +} + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_skip + (JNIEnv *env, jclass class, jint n) +{ + RETURNWRAP(env, h_skip((size_t) n)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_seek + (JNIEnv *env, jclass class, jint offset, jint whence) +{ + RETURNWRAP(env, h_seek((ssize_t) offset, (int) whence)); +} + + +JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_tell + (JNIEnv *env, jclass class) +{ + RETURNWRAP(env, h_tell()); +} diff --git a/jni/com_upstandinghackers_hammer_ParseResult.c b/src/bindings/jni/com_upstandinghackers_hammer_ParseResult.c similarity index 100% rename from jni/com_upstandinghackers_hammer_ParseResult.c rename to src/bindings/jni/com_upstandinghackers_hammer_ParseResult.c diff --git a/jni/com_upstandinghackers_hammer_ParsedToken.c b/src/bindings/jni/com_upstandinghackers_hammer_ParsedToken.c similarity index 100% rename from jni/com_upstandinghackers_hammer_ParsedToken.c rename to src/bindings/jni/com_upstandinghackers_hammer_ParsedToken.c diff --git a/jni/com_upstandinghackers_hammer_Parser.c b/src/bindings/jni/com_upstandinghackers_hammer_Parser.c similarity index 100% rename from jni/com_upstandinghackers_hammer_Parser.c rename to src/bindings/jni/com_upstandinghackers_hammer_Parser.c diff --git a/jni/jhammer.h b/src/bindings/jni/jhammer.h similarity index 100% rename from jni/jhammer.h rename to src/bindings/jni/jhammer.h