JNI ready for testing. -fPIC enabled for objects in src and jni.

This commit is contained in:
aegis 2013-05-10 12:05:20 +02:00
parent 1529c0641e
commit 106b8bb6a7
25 changed files with 954 additions and 145 deletions

View file

@ -3,7 +3,7 @@
# and kick off a recursive make
# Also, "make src/all" turns into "make -C src all"
SUBDIRS = src examples
SUBDIRS = src examples jni
include config.mk

View file

@ -8,7 +8,7 @@ include $(TOPLEVEL)/config.mk
TEST_CFLAGS = $(shell pkg-config --cflags glib-2.0) -DINCLUDE_TESTS
TEST_LDFLAGS = $(shell pkg-config --libs glib-2.0)
CFLAGS := -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes
CFLAGS := -std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes -g
LDFLAGS :=
CC ?= gcc

View file

@ -1,38 +1,18 @@
import com.upstandinghackers.hammer.*;
import java.util.Arrays;
/**
* Example JHammer usage
*/
public class Example
{
private HParser initParser()
{
HParser digit = Hammer.chRange(0x30, 0x39);
HParser alpha = Hammer.choice({Hammer.chRange(0x41, 0x5a), Hammer.chRange(0x61, 0x7a)});
HParser plus = Hammer.ch('+');
HParser slash = Hammer.ch('/');
HParser equals = Hammer.ch('=');
HParser bsfdig = Hammer.choice({alpha, digit, plus, slash});
byte[] AEIMQUYcgkosw048 = "AEIMQUYcgkosw048".getBytes();
HParser bsfdig_4bit = Hammer.in(AEIMQUYcgkosw048, AEIMQUYcgkosw048.length);
byte[] AQgw = "AQgw".getBytes();
HParser bsfdig_2bit = Hammer.in(AQgw, AQgw.length);
HParser base64_3 = Hammer.repeatN(bsfdig, 4);
HParser base64_2 = Hammer.sequence({bsfdig, bsfdig, bsfdig_4bit, equals});
HParser base64_1 = Hammer.sequence({bsfdig, bsfdig_2bit, equals, equals});
HParser base64 = Hammer.sequence({ Hammer.many(base64_3),
Hammer.optional(Hammer.choice({base64_2, base64_1}))
});
return Hammer.sequence({Hammer.whitespace(base64), Hammer.whitespace(Hammer.endP()}});
static {
System.loadLibrary("jhammer");
}
public static void main(String args[])
private static void handle(ParseResult result)
{
byte[] input = "RXMgaXN0IFNwYXJnZWx6ZWl0IQo=".getBytes();
int length = input.length;
HParsedResult result = Hammer.parse(initParser(), input, length);
if(result == null)
{
System.out.println("FAIL");
@ -40,10 +20,73 @@ public static void main(String args[])
else
{
System.out.println("PASS");
//TODO: Pretty print
handleToken(result.getAst());
}
}
private static void handleToken(ParsedToken p)
{
if(p==null)
{
System.out.println("Empty AST");
return;
}
switch(p.getTokenType())
{
case NONE: out("NONE token type"); break;
case BYTES: out("BYTES token type, value: " + Arrays.toString(p.getBytesValue())); break;
case SINT: out("SINT token type, value: " + p.getSIntValue()); break;
case UINT: out("UINT token type, value: " + p.getUIntValue()); break;
case SEQUENCE: out("SEQUENCE token type"); for(ParsedToken tok : p.getSeqValue()) {handleToken(tok);} break;
case ERR: out("ERR token type"); break;
case USER: out("USER token type"); break;
}
}
private static void out(String msg)
{
System.out.println(">> " + msg);
}
public static void main(String args[])
{
out("chRange");
handle(Hammer.parse(Hammer.chRange((byte)0x30, (byte)0x39), "1".getBytes(), 1));
handle(Hammer.parse(Hammer.chRange((byte)0x30, (byte)0x39), "a".getBytes(), 1));
out("ch");
handle(Hammer.parse(Hammer.ch((byte)0x31), "1".getBytes(), 1));
handle(Hammer.parse(Hammer.ch((byte)0x31), "0".getBytes(), 1));
out("token");
handle(Hammer.parse(Hammer.token("herp".getBytes(), 4), "herp".getBytes(), 4));
handle(Hammer.parse(Hammer.token("herp".getBytes(), 4), "derp".getBytes(), 4));
out("intRange");
byte inbytes[] = {0x31, 0x31, 0x31, 0x31};
handle(Hammer.parse(Hammer.intRange(Hammer.uInt8(), 0L, 0x32), inbytes, inbytes.length));
handle(Hammer.parse(Hammer.intRange(Hammer.uInt8(), 0L, 0x30), inbytes, inbytes.length));
out("bits");
handle(Hammer.parse(Hammer.bits(7, false), inbytes, inbytes.length));
out("int64");
byte ints[] = {(byte)0x8F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
handle(Hammer.parse(Hammer.int64(), ints, ints.length));
handle(Hammer.parse(Hammer.int64(), inbytes, inbytes.length));
out("choice");
Parser two32s[] = {Hammer.intRange(Hammer.uInt32(), 0x00, 0x01), Hammer.int32()};
handle(Hammer.parse(Hammer.choice(two32s), ints, ints.length));
out("sequence");
byte i3[] = {(byte)'i', (byte)3, (byte)0xFF};
Parser i3parsers[] = {Hammer.ch((byte)'i'), Hammer.uInt8(), Hammer.int8()};
handle(Hammer.parse(Hammer.sequence(i3parsers), i3, i3.length));
}
}

42
jni/Makefile Normal file
View file

@ -0,0 +1,42 @@
JSOURCES := Action.java Hammer.java ParsedToken.java ParseResult.java Parser.java Predicate.java
JSOURCES_NATIVE := Hammer ParsedToken Parser ParseResult
CSOURCES := com_upstandinghackers_hammer_Hammer.c com_upstandinghackers_hammer_ParsedToken.c com_upstandinghackers_hammer_Parser.c com_upstandinghackers_hammer_ParseResult.c
# 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 := ../
JC=javac
JH=javah
CP=com/upstandinghackers/hammer
PACKAGE=com.upstandinghackers.hammer
include ../common.mk
JNI_INCLUDE := /usr/lib/jvm/java-6-openjdk/include/
CFLAGS += -fPIC -I. -I $(TOPLEVEL)/src/ -I jni -I $(JNI_INCLUDE)
%.java: $(call ifsilent,| $(HUSH))
$(call hush, "Compiling Java source $@") $(JC) $(CP)/$@
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
$(CSOURCES): prepare
$(call hush, "Compiling $@") $(CC) -c $(CFLAGS) $@
compile: prepare $(CSOURCES)
prepare: javacc $(JSOURCES_NATIVE)
$(JSOURCES_NATIVE): javacc
$(call hush, "Generating JNI headers for $@") $(JH) $(PACKAGE).$@
javacc: $(JSOURCES)
#TODO make this not-as-hardcoded
#clean:
# rm $(CP)/*.class && rm com_upstandinghackers_*.h && rm com_upstandinghackers_*.o && rm libjhammer.so

View file

@ -1,12 +1,26 @@
Compilation:
javac com/upstandinghackers/hammer/*.java
USING THE JNI BINDINGS:
1. import com.upstandinghackers.hammer.*;
2. Add a static initializer block that loads the correct library, like this: static { System.loadLibrary("jhammer"); }
3. Code stuff. Just look at Example.java for a few handy snippets (for walking the resulting syntax tree [AST] etc)
4. Compile your java sources like always
5. Add the folder containing libhammer.so/dll/whatever to Java's library path to run it, for example: java -Djava.library.path=. <CLASS>
Conversion to JNI headers:
find -name "*.class" | sed -e 's/.class$//' | tr '/' '.' | cut -c 3- | xargs javah
Not working:
enums aren't converted at all, no idea why
UNIMPLEMENTED:
User-defined types, predicates and actions are unimplemented.
Memory leaks because there is no reliable garbage collection.
TODO:
Implement the entire JNI side
Testing
TYPE MAPPING:
Hammer Java JNI
uint8_t byte jbyte jbyte/byte is signed
char byte jbyte jchar would be 16 bit wide
size_t int jint signed as well; jsize == jint, actually
int64_t long jlong
uint64_t long jlong signed!
bool boolean jboolean JNI_TRUE / JNI_FALSE
float float jfloat
double double jdouble
void void void

View file

@ -0,0 +1,8 @@
package com.upstandinghackers.hammer;
import java.util.List;
public interface Action
{
public List<ParsedToken> execute(ParseResult p);
}

View file

@ -1,8 +0,0 @@
package com.upstandinghackers.hammer;
import java.util.List;
public interface HAction
{
public List<HParsedToken> execute(HParseResult p);
}

View file

@ -1,9 +0,0 @@
package com.upstandinghackers.hammer;
import java.util.List;
public class HParseResult
{
public native List<HParsedToken> getAst();
public native long getBitLength();
}

View file

@ -1,28 +0,0 @@
package com.upstandinghackers.hammer;
import java.util.List;
public class HParsedToken
{
public native Hammer.HTokenType getTokenType();
public native int getIndex();
public native byte getBitOffset();
public native byte[] getBytesValue();
public native long getSIntValue();
public native long getUIntValue();
public native double getDoubleValue();
public native float getFloatValue();
public native List<HParsedToken> getSeqValue();
public native Object getUserValue();
native void setTokenType(Hammer.HTokenType type);
native void setIndex(int index);
native void setBitOffset(byte offset);
native void setBytesValue(byte[] value);
native void setSIntValue(long value);
native void setUIntValue(long value);
native void setDoubleValue(double value);
native void setFloatValue(float value);
native void setSeqValue(List<HParsedToken> value);
native void setUserValue(Object value);
}

View file

@ -1,6 +0,0 @@
package com.upstandinghackers.hammer;
public class HParser
{
public native void bindIndirect(HParser inner);
}

View file

@ -1,6 +0,0 @@
package com.upstandinghackers.hammer;
public interface HPredicate
{
public boolean apply(HParseResult p);
}

View file

@ -1,4 +1,5 @@
package com.upstandinghackers.hammer;
import java.util.HashMap;
public class Hammer
{
@ -7,59 +8,69 @@ public class Hammer
public final static byte BYTE_LITTLE_ENDIAN = 0x0;
public final static byte BIT_LITTLE_ENDIAN = 0x0;
public enum HTokenType
static final HashMap<Integer, TokenType> tokenTypeMap = new HashMap<Integer, TokenType>();
public enum TokenType
{
TT_NONE(1),
TT_BYTES(2),
TT_SINT(4),
TT_UINT(8),
TT_SEQUENCE(16),
TT_ERR(32),
TT_USER(64),
NONE(1),
BYTES(2),
SINT(4),
UINT(8),
SEQUENCE(16),
ERR(32),
USER(64);
private int value;
public int getValue() { return this.value; }
private HTokenType(int value) { this.value = value; }
private TokenType(int value) { this.value = value; }
}
public static native HParseResult parse(HParser parser, byte[] input, int length);
public static native HParser token(byte[] str, int length);
public static native HParser ch(byte c);
public static native HParser chRange(byte from, byte to);
public static native HParser intRange(HParser p, int lower, int upper);
public static native HParser bits(int len, boolean sign);
public static native HParser int64();
public static native HParser int32();
public static native HParser int16();
public static native HParser int8();
public static native HParser uInt64();
public static native HParser uInt32();
public static native HParser uInt16();
public static native HParser uInt8();
public static native HParser whitespace(HParser p);
public static native HParser left(HParser p, HParser q);
public static native HParser right(HParser p, HParser q);
public static native HParser middle(HParser p, HParser x, HParser q);
public static native HParser action(HParser p, HAction a);
public static native HParser in(byte[] charset, int length);
public static native HParser endP();
public static native HParser nothingP();
public static native HParser sequence(HParser[] parsers);
public static native HParser choice(HParser[] parsers);
public static native HParser butNot(HParser p1, HParser p2);
public static native HParser difference(HParser p1, HParser p2);
public static native HParser xor(HParser p1, HParser p2);
public static native HParser many(HParser p);
public static native HParser many1(HParser p);
public static native HParser repeatN(HParser p, int n);
public static native HParser optional(HParser p);
public static native HParser ignore(HParser p);
public static native HParser sepBy(HParser p, HParser sep);
public static native HParser sepBy1(HParser p, HParser sep);
public static native HParser epsilonP();
public static native HParser lengthValue(HParser length, HParser value);
public static native HParser attrBool(HParser p, HPredicate pred);
public static native HParser and(HParser p);
public static native HParser not(HParser p);
public static native HParser indirect();
static
{
for(TokenType tt : TokenType.values())
{
Hammer.tokenTypeMap.put(new Integer(tt.getValue()), tt);
}
}
public static native ParseResult parse(Parser parser, byte[] input, int length);
public static native Parser token(byte[] str, int length);
public static native Parser ch(byte c);
public static native Parser chRange(byte from, byte to);
public static native Parser intRange(Parser p, long lower, long upper);
public static native Parser bits(int len, boolean sign);
public static native Parser int64();
public static native Parser int32();
public static native Parser int16();
public static native Parser int8();
public static native Parser uInt64();
public static native Parser uInt32();
public static native Parser uInt16();
public static native Parser uInt8();
public static native Parser whitespace(Parser p);
public static native Parser left(Parser p, Parser q);
public static native Parser right(Parser p, Parser q);
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 endP();
public static native Parser nothingP();
public static native Parser sequence(Parser[] parsers);
public static native Parser choice(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);
public static native Parser many(Parser p);
public static native Parser many1(Parser p);
public static native Parser repeatN(Parser p, int n);
public static native Parser optional(Parser p);
public static native Parser ignore(Parser p);
public static native Parser sepBy(Parser p, Parser sep);
public static native Parser sepBy1(Parser p, Parser sep);
public static native Parser epsilonP();
public static native Parser lengthValue(Parser length, Parser value);
// public static native Parser attrBool(Parser p, Predicate pred);
public static native Parser and(Parser p);
public static native Parser not(Parser p);
public static native Parser indirect();
}

View file

@ -0,0 +1,15 @@
package com.upstandinghackers.hammer;
import java.util.List;
public class ParseResult
{
public native ParsedToken getAst();
public native long getBitLength();
public native void free();
public long getInner() {return this.inner;}
private long inner;
ParseResult(long inner) {this.inner=inner;}
}

View file

@ -0,0 +1,40 @@
package com.upstandinghackers.hammer;
public class ParsedToken
{
public Hammer.TokenType getTokenType()
{
int tt = this.getTokenTypeInternal();
if(0==tt)
return null;
return Hammer.tokenTypeMap.get(new Integer(tt));
}
private native int getTokenTypeInternal();
public native int getIndex();
public native byte getBitOffset();
public native byte[] getBytesValue();
public native long getSIntValue();
public native long getUIntValue();
public native double getDoubleValue();
public native float getFloatValue();
public native ParsedToken[] getSeqValue();
// public native Object getUserValue();
native void setTokenType(Hammer.TokenType type);
native void setIndex(int index);
native void setBitOffset(byte offset);
native void setBytesValue(byte[] value);
native void setSIntValue(long value);
native void setUIntValue(long value);
native void setDoubleValue(double value);
native void setFloatValue(float value);
native void setSeqValue(ParsedToken value[]);
// native void setUserValue(Object value);
// public native void free();
public long getInner() {return this.inner;}
private long inner;
ParsedToken(long inner) {this.inner=inner;}
}

View file

@ -0,0 +1,11 @@
package com.upstandinghackers.hammer;
public class Parser
{
public native void bindIndirect(Parser inner);
public native void free();
public long getInner() {return this.inner;}
private long inner;
Parser(long inner) {this.inner=inner;}
}

View file

@ -0,0 +1,6 @@
package com.upstandinghackers.hammer;
public interface Predicate
{
public boolean apply(ParseResult p);
}

View file

@ -0,0 +1,335 @@
#include "jhammer.h"
#include "com_upstandinghackers_hammer_Hammer.h"
#include <stdlib.h>
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_parse
(JNIEnv *env, jclass class, jobject obj, jbyteArray input_, jint length_)
{
HParser *parser;
uint8_t* input;
size_t length;
HParseResult *result;
jclass resultClass;
jobject retVal;
parser = UNWRAP(env, obj);
input = (uint8_t *) ((*env)->GetByteArrayElements(env, input_, NULL));
length = (size_t) length_;
result = h_parse(parser, input, length);
if(result==NULL)
return NULL;
FIND_CLASS(resultClass, env, "com/upstandinghackers/hammer/ParseResult");
NEW_INSTANCE(retVal, env, resultClass, result);
return retVal;
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_token
(JNIEnv *env, jclass class, jbyteArray str, jint len)
{
RETURNWRAP(env, h_token((uint8_t *) ((*env)->GetByteArrayElements(env, str, NULL)), (size_t) len));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_ch
(JNIEnv *env, jclass class, jbyte c)
{
RETURNWRAP(env, h_ch((uint8_t) c));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_chRange
(JNIEnv *env, jclass class, jbyte lower, jbyte upper)
{
RETURNWRAP(env, h_ch_range((uint8_t) lower, (uint8_t) upper));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_intRange
(JNIEnv *env, jclass class, jobject obj, jlong lower, jlong upper)
{
HParser *parser;
parser = UNWRAP(env, obj);
RETURNWRAP(env, h_int_range(parser, (int64_t) lower, (int64_t) upper));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_bits
(JNIEnv *env, jclass class, jint len, jboolean sign)
{
RETURNWRAP(env, h_bits((size_t) len, (bool)(sign & JNI_TRUE)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int64
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_int64());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int32
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_int32());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int16
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_int16());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_int8
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_int8());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt64
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_uint64());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt32
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_uint32());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt16
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_uint16());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_uInt8
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_uint8());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_whitespace
(JNIEnv *env, jclass class, jobject parser)
{
RETURNWRAP(env, h_whitespace(UNWRAP(env, parser)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_left
(JNIEnv *env, jclass class, jobject p, jobject q)
{
RETURNWRAP(env, h_left(UNWRAP(env, p), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_right
(JNIEnv *env, jclass class, jobject p, jobject q)
{
RETURNWRAP(env, h_right(UNWRAP(env, p), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_middle
(JNIEnv *env, jclass class, jobject p, jobject x, jobject q)
{
RETURNWRAP(env, h_middle(UNWRAP(env, p), UNWRAP(env, x), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_in
(JNIEnv *env, jclass class, jbyteArray charset, jint length)
{
RETURNWRAP(env, h_in((uint8_t *) ((*env)->GetByteArrayElements(env, charset, NULL)), (size_t)length));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_endP
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_end_p());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_nothingP
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_nothing_p());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sequence
(JNIEnv *env, jclass class, jobjectArray sequence)
{
jsize length;
void **parsers;
int i;
jobject current;
const HParser *result;
length = (*env)->GetArrayLength(env, sequence);
parsers = malloc(sizeof(void *)*(length+1));
if(NULL==parsers)
{
return NULL;
}
for(i=0; i<length; i++)
{
current = (*env)->GetObjectArrayElement(env, sequence, (jsize)i);
parsers[i] = UNWRAP(env, current);
}
parsers[length] = NULL;
result = h_sequence__a(parsers);
RETURNWRAP(env, result);
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_choice
(JNIEnv *env, jclass class, jobjectArray choices)
{
jsize length;
void **parsers;
int i;
jobject current;
const HParser *result;
length = (*env)->GetArrayLength(env, choices);
parsers = malloc(sizeof(HParser *)*(length+1));
if(NULL==parsers)
{
return NULL;
}
for(i=0; i<length; i++)
{
current = (*env)->GetObjectArrayElement(env, choices, (jsize)i);
parsers[i] = UNWRAP(env, current);
}
parsers[length] = NULL;
result = h_choice__a(parsers);
RETURNWRAP(env, result);
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_butNot
(JNIEnv *env, jclass class, jobject p, jobject q)
{
RETURNWRAP(env, h_butnot(UNWRAP(env, p), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_difference
(JNIEnv *env, jclass class, jobject p, jobject q)
{
RETURNWRAP(env, h_difference(UNWRAP(env, p), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_xor
(JNIEnv *env, jclass class, jobject p, jobject q)
{
RETURNWRAP(env, h_xor(UNWRAP(env, p), UNWRAP(env, q)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_many
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_many(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_many1
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_many1(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_repeatN
(JNIEnv *env, jclass class, jobject p, jint n)
{
RETURNWRAP(env, h_repeat_n(UNWRAP(env, p), (size_t)n));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_optional
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_optional(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_ignore
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_ignore(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sepBy
(JNIEnv *env, jclass class, jobject p, jobject sep)
{
RETURNWRAP(env, h_sepBy(UNWRAP(env, p), UNWRAP(env, sep)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_sepBy1
(JNIEnv *env, jclass class, jobject p, jobject sep)
{
RETURNWRAP(env, h_sepBy1(UNWRAP(env, p), UNWRAP(env, sep)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_epsilonP
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_epsilon_p());
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_lengthValue
(JNIEnv *env, jclass class, jobject length, jobject value)
{
RETURNWRAP(env, h_length_value(UNWRAP(env, length), UNWRAP(env, value)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_and
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_and(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_not
(JNIEnv *env, jclass class, jobject p)
{
RETURNWRAP(env, h_not(UNWRAP(env, p)));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_Hammer_indirect
(JNIEnv *env, jclass class)
{
RETURNWRAP(env, h_indirect());
}

View file

@ -0,0 +1,45 @@
#include "jhammer.h"
#include "com_upstandinghackers_hammer_ParseResult.h"
HParseResult *unwrap_parse_result(JNIEnv *env, jobject obj)
{
jclass parseResultClass;
jfieldID parseResultInner;
FIND_CLASS(parseResultClass, env, "com/upstandinghackers/hammer/ParseResult");
parseResultInner = (*env)->GetFieldID(env, parseResultClass, "inner", "J");
return (HParseResult *)((*env)->GetLongField(env, obj, parseResultInner));
}
JNIEXPORT jobject JNICALL Java_com_upstandinghackers_hammer_ParseResult_getAst
(JNIEnv *env, jobject this)
{
HParseResult *inner;
jclass parsedTokenClass;
jobject retVal;
if(this == NULL)
return NULL; // parse unsuccessful
inner = unwrap_parse_result(env, this);
if(inner->ast == NULL)
return NULL; // parse successful, but empty
FIND_CLASS(parsedTokenClass, env, "com/upstandinghackers/hammer/ParsedToken");
NEW_INSTANCE(retVal, env, parsedTokenClass, inner->ast);
return retVal;
}
JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParseResult_getBitLength
(JNIEnv *env, jobject this)
{
HParseResult *inner = unwrap_parse_result(env, this);
return (jlong) (inner->bit_length);
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParseResult_free
(JNIEnv *env, jobject this)
{
//XXX: NOT IMPLEMENTED
}

View file

@ -0,0 +1,195 @@
#include "jhammer.h"
#include "com_upstandinghackers_hammer_ParsedToken.h"
#define HPT_UNWRAP(env, this) HParsedToken *inner = unwrap_parsed_token(env, this); assert(inner!=NULL)
HParsedToken *unwrap_parsed_token(JNIEnv *env, jobject obj)
{
jclass parsedTokenClass;
jfieldID parsedTokenInner;
FIND_CLASS(parsedTokenClass, env, "com/upstandinghackers/hammer/ParsedToken");
parsedTokenInner = (*env)->GetFieldID(env, parsedTokenClass, "inner", "J");
return (HParsedToken *)((*env)->GetLongField(env, obj, parsedTokenInner));
}
JNIEXPORT jint JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getTokenTypeInternal
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
if(inner==NULL)
return (jint)0;
return (jint)(inner->token_type);
}
JNIEXPORT jint JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getIndex
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jint) (inner->index);
}
JNIEXPORT jbyte JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getBitOffset
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jbyte) (inner->bit_offset);
}
JNIEXPORT jbyteArray JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getBytesValue
(JNIEnv *env, jobject this)
{
jbyteArray outArray;
HPT_UNWRAP(env, this);
outArray = (*env)->NewByteArray(env, (jsize)inner->bytes.len);
(*env)->SetByteArrayRegion(env, outArray, (jsize) 0, (jsize)(inner->bytes.len), (jbyte *)(inner->bytes.token));
return outArray;
}
JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getSIntValue
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jlong) (inner->sint);
}
JNIEXPORT jlong JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getUIntValue
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jlong) (inner->uint);
}
JNIEXPORT jdouble JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getDoubleValue
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jdouble) (inner->dbl);
}
JNIEXPORT jfloat JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getFloatValue
(JNIEnv *env, jobject this)
{
HPT_UNWRAP(env, this);
return (jfloat) (inner->flt);
}
JNIEXPORT jobjectArray JNICALL Java_com_upstandinghackers_hammer_ParsedToken_getSeqValue
(JNIEnv *env, jobject this)
{
jsize i;
HPT_UNWRAP(env, this);
jsize returnSize = inner->seq->used;
jobject currentObject;
jclass returnClass;
FIND_CLASS(returnClass, env, "com/upstandinghackers/hammer/ParsedToken");
jobjectArray retVal = (*env)->NewObjectArray(env, returnSize, returnClass, NULL);
for(i = 0; i<returnSize; i++)
{
NEW_INSTANCE(currentObject, env, returnClass, inner->seq->elements[i]);
(*env)->SetObjectArrayElement(env, retVal, i, currentObject);
}
return retVal;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setTokenType
(JNIEnv *env, jobject this, jobject tokenType)
{
jclass tokenTypeClass;
jmethodID getValue;
jint typeVal;
HPT_UNWRAP(env, this);
FIND_CLASS(tokenTypeClass, env, "com/upstandinghackers/hammer/Hammer$TokenType");
getValue = (*env)->GetMethodID(env, tokenTypeClass, "getValue", "()I");
typeVal = (*env)->CallIntMethod(env, tokenType, getValue);
inner->token_type = (int32_t) typeVal; // unsafe cast, but enums should be of type int
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setIndex
(JNIEnv *env, jobject this, jint index)
{
HPT_UNWRAP(env, this);
inner->index = (size_t)index;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setBitOffset
(JNIEnv *env, jobject this, jbyte bit_offset)
{
HPT_UNWRAP(env, this);
inner->bit_offset = (char)bit_offset;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setBytesValue
(JNIEnv *env, jobject this, jbyteArray bytes_)
{
HBytes bytes;
HPT_UNWRAP(env, this);
bytes.token = (uint8_t *) ((*env)->GetByteArrayElements(env, bytes_, NULL));
bytes.len = (size_t) (*env)->GetArrayLength(env, bytes_);
inner->bytes = bytes;
inner->token_type = TT_BYTES;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setSIntValue
(JNIEnv *env, jobject this, jlong sint)
{
HPT_UNWRAP(env, this);
inner->token_type = TT_SINT;
inner->sint = (int64_t)sint;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setUIntValue
(JNIEnv *env, jobject this, jlong uint)
{
HPT_UNWRAP(env, this);
inner->token_type = TT_UINT;
inner->uint = (uint64_t)uint;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setDoubleValue
(JNIEnv *env, jobject this, jdouble dbl)
{
HPT_UNWRAP(env, this);
//token_type?
inner->dbl = (double)dbl;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setFloatValue
(JNIEnv *env, jobject this, jfloat flt)
{
HPT_UNWRAP(env, this);
//token_type?
inner->flt = (float)flt;
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_ParsedToken_setSeqValue
(JNIEnv *env, jobject this, jobjectArray values)
{
HArena *arena;
size_t len, i;
jobject currentValue;
HParsedToken *currentValueInner;
HCountedArray *seq;
HPT_UNWRAP(env, this);
len = (size_t) (*env)->GetArrayLength(env, values);
arena = h_new_arena(&system_allocator, 0);
seq = h_carray_new_sized(arena, len);
// unwrap each value and append it to the new HCountedArray
for(i = 0; i<len; i++)
{
currentValue = (*env)->GetObjectArrayElement(env, values, (jsize)i);
if(NULL == currentValue)
continue;
currentValueInner = unwrap_parsed_token(env, currentValue);
if(currentValueInner)
h_carray_append(seq, (void *)currentValueInner);
}
inner->token_type = TT_SEQUENCE;
inner->seq = seq;
}

View file

@ -0,0 +1,15 @@
#include "jhammer.h"
#include "com_upstandinghackers_hammer_Parser.h"
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_Parser_bindIndirect
(JNIEnv *env, jobject this, jobject parser)
{
h_bind_indirect(UNWRAP(env, this), UNWRAP(env, parser));
}
JNIEXPORT void JNICALL Java_com_upstandinghackers_hammer_Parser_free
(JNIEnv *env, jobject this)
{
//XXX NOT IMPLEMENTED
//h_free(UNWRAP(env, this));
}

31
jni/jhammer.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef JHAMMER_H
#define JHAMMER_H
#include <jni.h>
#include "internal.h"
#include <assert.h>
// Unsafe (non-asserting) helpers
#define FIND_CLASS_(env, class) (*env)->FindClass(env, class)
#define REFCONSTRUCTOR_(env, class) (*env)->GetMethodID(env, class, "<init>", "(J)V")
#define NEW_INSTANCE_(env, class, inner) (*env)->NewObject(env, class, REFCONSTRUCTOR_(env, class), (jlong)inner)
// Safer versions, assert that the result is not NULL
// If one of those asserts fails, it most likely means that there's a typo (wrong class name or method signature) or big trouble (OOM)
#define FIND_CLASS(target, env, class) target = FIND_CLASS_(env, class); assert(target != NULL)
#define REFCONSTRUCTOR(target, env, class) target = REFCONSTRUCTOR_(env, class); assert(target != NULL)
#define NEW_INSTANCE(target, env, class, inner) target = NEW_INSTANCE_(env, class, inner); assert(target != NULL)
// Since there's a LOT of wrapping/unwrapping HParsers, these macros make it a bit more readable
#define PARSER_CLASS "com/upstandinghackers/hammer/Parser"
#define PARSER_REF(env) (*env)->GetFieldID(env, FIND_CLASS_(env, PARSER_CLASS), "inner", "J")
#define RETURNWRAP(env, inner) jclass __cls=FIND_CLASS_(env, PARSER_CLASS); \
assert(__cls != NULL); \
jmethodID __constructor = REFCONSTRUCTOR_(env, __cls); \
assert(__constructor != NULL); \
return (*env)->NewObject(env, __cls, __constructor, (jlong)inner)
#define UNWRAP(env, object) (HParser *)((*env)->GetLongField(env, object, PARSER_REF(env)))
#endif

View file

@ -62,6 +62,8 @@ include ../common.mk
$(TESTS): CFLAGS += $(TEST_CFLAGS)
$(TESTS): LDFLAGS += $(TEST_LDFLAGS)
CFLAGS += -fPIC
all: libhammer.a
libhammer.a: $(HAMMER_PARTS)

View file

@ -167,14 +167,18 @@ typedef struct HBenchmarkResults_ {
rtype_t name(__VA_ARGS__, ...); \
rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...); \
rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap); \
rtype_t name##__v(__VA_ARGS__, va_list ap)
rtype_t name##__v(__VA_ARGS__, va_list ap); \
rtype_t name##__a(void *args[]); \
rtype_t name##__ma(HAllocator *mm__, void *args[])
// Note: this drops the attributes on the floor for the __v versions
#define HAMMER_FN_DECL_VARARGS_ATTR(attr, rtype_t, name, ...) \
rtype_t name(__VA_ARGS__, ...) attr; \
rtype_t name##__m(HAllocator* mm__, __VA_ARGS__, ...) attr; \
rtype_t name##__mv(HAllocator* mm__, __VA_ARGS__, va_list ap); \
rtype_t name##__v(__VA_ARGS__, va_list ap)
rtype_t name##__v(__VA_ARGS__, va_list ap); \
rtype_t name##__a(void *args[]); \
rtype_t name##__ma(HAllocator *mm__, void *args[])
// }}}

View file

@ -72,3 +72,27 @@ const HParser* h_choice__mv(HAllocator* mm__, const HParser* p, va_list ap_) {
return ret;
}
const HParser* h_choice__a(void *args[]) {
return h_choice__ma(&system_allocator, args);
}
const HParser* h_choice__ma(HAllocator* mm__, void *args[]) {
size_t len = -1; // because do...while
const HParser *arg;
do {
arg=((HParser **)args)[++len];
} while(arg);
HSequence *s = h_new(HSequence, 1);
s->p_array = h_new(const HParser *, len);
for (size_t i = 0; i < len; i++) {
s->p_array[i] = ((HParser **)args)[i];
}
s->len = len;
HParser *ret = h_new(HParser, 1);
ret->vtable = &choice_vt; ret->env = (void*)s;
return ret;
}

View file

@ -73,3 +73,28 @@ const HParser* h_sequence__mv(HAllocator* mm__, const HParser *p, va_list ap_) {
ret->vtable = &sequence_vt; ret->env = (void*)s;
return ret;
}
const HParser* h_sequence__a(void *args[]) {
return h_sequence__ma(&system_allocator, args);
}
const HParser* h_sequence__ma(HAllocator* mm__, void *args[]) {
size_t len = -1; // because do...while
const HParser *arg;
do {
arg=((HParser **)args)[++len];
} while(arg);
HSequence *s = h_new(HSequence, 1);
s->p_array = h_new(const HParser *, len);
for (size_t i = 0; i < len; i++) {
s->p_array[i] = ((HParser **)args)[i];
}
s->len = len;
HParser *ret = h_new(HParser, 1);
ret->vtable = &sequence_vt; ret->env = (void*)s;
return ret;
}