mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
- Fix sliceByteBuffer, getBytes, and putBytes implementations, which had functional errors. Also, getBytes and putBytes now use the ByteBuffer get/put byte[] functions, which should improve performance. - Don't generate wrappers for functions that are not available in the shared library. Change-Id: Iaf45814b34720d3fdcd58adf99ad9c3ff2703bc3
1981 lines
77 KiB
Python
1981 lines
77 KiB
Python
from __future__ import print_function
|
|
import sys
|
|
import os
|
|
import re
|
|
try:
|
|
import configparser
|
|
except ImportError:
|
|
import ConfigParser as configparser
|
|
|
|
from nivision_parse import *
|
|
|
|
# base, cast-out-pre, cast-out-post, cast-in-pre, cast-in-post
|
|
java_accessor_map = {
|
|
"B": ("", "", "", "", ""),
|
|
"C": ("Char", "", "", "", ""),
|
|
"S": ("Short", "", "", "", ""),
|
|
"I": ("Int", "", "", "", ""),
|
|
"J": ("Long", "", "", "", ""),
|
|
"F": ("Float", "", "", "", ""),
|
|
"D": ("Double", "", "", "", ""),
|
|
"Z": ("Boolean", "", "", "", ""),
|
|
"X": ("", "(short)(", " & 0xff)", "(byte)(", " & 0xff)"),
|
|
"Y": ("Short", "(int)(", " & 0xffff)", "(short)(", " & 0xffff)"),
|
|
}
|
|
|
|
java_size_map = {
|
|
"B": 1,
|
|
"C": 2,
|
|
"S": 2,
|
|
"I": 4,
|
|
"J": 8,
|
|
"F": 4,
|
|
"D": 8,
|
|
"Z": 1,
|
|
}
|
|
|
|
class JavaType:
|
|
def __init__(self, j_type, jn_type, jni_type, jni_sig, is_enum=False, is_struct=False, is_opaque=False, string_array=False, array_size=None):
|
|
self.j_type = j_type
|
|
self.jn_type = jn_type
|
|
self.jni_type = jni_type
|
|
self.jni_sig = jni_sig
|
|
self.is_enum = is_enum
|
|
self.is_struct = is_struct
|
|
self.is_opaque = is_opaque
|
|
self.string_array = string_array
|
|
self.array_size = array_size
|
|
|
|
def copy(self):
|
|
return JavaType(self.j_type, self.jn_type, self.jni_type, self.jni_sig,
|
|
is_enum=self.is_enum, is_struct=self.is_struct,
|
|
is_opaque=self.is_opaque,
|
|
string_array=self.string_array,
|
|
array_size=self.array_size)
|
|
|
|
def __repr__(self):
|
|
return "JavaType(%s, %s, %s, %s, is_enum=%s, is_struct=%s, is_opaque=%s, string_array=%s, array_size=%s)" % (
|
|
self.j_type, self.jn_type, self.jni_type, self.jni_sig,
|
|
self.is_enum, self.is_struct,
|
|
self.is_opaque, self.string_array, self.array_size)
|
|
|
|
java_types_map = {
|
|
("void", None): JavaType("void", "void", "void", None),
|
|
("env", None): JavaType("", "", "JNIEnv*", None),
|
|
("cls", None): JavaType("", "", "jclass", None),
|
|
("int", None): JavaType("int", "int", "jint", "I"),
|
|
("char", None): JavaType("byte", "byte", "jbyte", "B"),
|
|
("wchar_t", None): JavaType("char", "char", "jchar", "C"),
|
|
("unsigned char", None): JavaType("short", "short", "jshort", "X"),
|
|
("short", None): JavaType("short", "short", "jshort", "S"),
|
|
("unsigned short", None): JavaType("int", "int", "jint", "Y"),
|
|
("unsigned", None): JavaType("int", "int", "jint", "I"),
|
|
("unsigned int", None): JavaType("int", "int", "jint", "I"),
|
|
("uInt32", None): JavaType("int", "int", "jint", "I"),
|
|
("IMAQdxSession", None): JavaType("int", "int", "jint", "I"),
|
|
("bool32", None): JavaType("int", "int", "jint", "I"),
|
|
("long", None): JavaType("long", "long", "jlong", "J"),
|
|
("unsigned long", None): JavaType("long", "long", "jlong", "J"),
|
|
("__int64", None): JavaType("long", "long", "jlong", "J"),
|
|
("long long", None): JavaType("long", "long", "jlong", "J"),
|
|
("unsigned __int64", None): JavaType("long", "long", "jlong", "J"),
|
|
("__uint64", None): JavaType("long", "long", "jlong", "J"),
|
|
("unsigned long long", None): JavaType("long", "long", "jlong", "J"),
|
|
("float", None): JavaType("float", "float", "jfloat", "F"),
|
|
("double", None): JavaType("double", "double", "jdouble", "D"),
|
|
("long double", None): JavaType("double", "double", "jdouble", "D"),
|
|
("unsigned char*", None): JavaType("String", "String", "jstring", "Ljava/lang/String;"),
|
|
("char*", None): JavaType("String", "String", "jstring", "Ljava/lang/String;"),
|
|
("void*", None): JavaType("RawData", "long", "jlong", "J", is_opaque=True),
|
|
#("size_t", None): JavaType("long", "long", "jlong", "J"),
|
|
("String255", None): JavaType("String", "String", "jstring", "Ljava/lang/String;", string_array=True, array_size="256"),
|
|
("String255", ""): JavaType("String[]", "String[]", "jstringArray", "[Ljava/lang/String;", string_array=True, array_size="256"),
|
|
("char*", ""): JavaType("String[]", "String[]", "jstringArray", "[Ljava/lang/String;"),
|
|
("char", ""): JavaType("String", "String", "jstring", "Ljava/lang/String;", string_array=True, array_size=""),
|
|
("unsigned char", ""): JavaType("byte[]", "byte[]", "jbyteArray", "[B"),
|
|
("short", ""): JavaType("short[]", "short[]", "jshortArray", "[S"),
|
|
("int", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
|
|
("unsigned int", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
|
|
("uInt32", ""): JavaType("int[]", "int[]", "jintArray", "[I"),
|
|
("long", ""): JavaType("long[]", "long[]", "jlongArray", "[J"),
|
|
("float", ""): JavaType("float[]", "float[]", "jfloatArray", "[F"),
|
|
("double", ""): JavaType("double[]", "double[]", "jdoubleArray", "[D"),
|
|
}
|
|
|
|
def c_to_jtype(name, arr):
|
|
jtype = java_types_map.get((name, arr), None)
|
|
if jtype is not None:
|
|
return jtype
|
|
|
|
# sized array is treated the same as unsized
|
|
if arr is not None and arr != "":
|
|
jtype = c_to_jtype(name, "").copy()
|
|
jtype.array_size = arr
|
|
java_types_map[(name, arr)] = jtype # cache
|
|
return jtype
|
|
|
|
# Opaque structures
|
|
if name in opaque_structs:
|
|
if arr is None:
|
|
jtype = JavaType(name, "long", "jlong", "J", is_opaque=True)
|
|
else:
|
|
# FIXME
|
|
jtype = JavaType(name+"[]", "long[]", "jlongArray", "[J", is_opaque=True)
|
|
java_types_map[(name, arr)] = jtype # cache
|
|
return jtype
|
|
|
|
# Enums
|
|
if name in enums:
|
|
if arr is None:
|
|
jtype = JavaType(name, "int", "jint", "I", is_enum=True)
|
|
else:
|
|
# FIXME
|
|
jtype = JavaType(name+"[]", "int[]", "jintArray", "[I", is_enum=True)
|
|
java_types_map[(name, arr)] = jtype # cache
|
|
return jtype
|
|
|
|
# handle pointers as void* (FIXME)
|
|
if name[-1] == '*':
|
|
if name[:-1] not in structs and name[:-1] not in defined:
|
|
return java_types_map[("void*", None)]
|
|
return c_to_jtype(name[:-1], arr)
|
|
|
|
# Otherwise it's a normal structure object
|
|
if arr is None:
|
|
jtype = JavaType(name, "long", "jlong", "J", is_struct=True)
|
|
else:
|
|
# FIXME
|
|
jtype = JavaType(name+"[]", "long[]", "jlongArray", "[J", is_struct=True)
|
|
java_types_map[(name, arr)] = jtype
|
|
return jtype
|
|
|
|
class JavaEmitData:
|
|
def __init__(self):
|
|
self.construct = []
|
|
self.backingRead = []
|
|
self.read = []
|
|
self.writeBufs = []
|
|
self.write = []
|
|
self.backingWrite = []
|
|
self.toArg = ""
|
|
|
|
def addConstruct(self, s):
|
|
self.construct.extend(s.split('\n')[1 if s[0]=='\n' else 0:])
|
|
|
|
def addBackingRead(self, s):
|
|
self.backingRead.extend(s.split('\n')[1 if s[0]=='\n' else 0:])
|
|
|
|
def addRead(self, s):
|
|
self.read.extend(s.split('\n')[1 if s[0]=='\n' else 0:])
|
|
|
|
def addWriteBuf(self, s):
|
|
self.writeBufs.append(s)
|
|
|
|
def addWrite(self, s):
|
|
self.write.extend(s.split('\n')[1 if s[0]=='\n' else 0:])
|
|
|
|
def addBackingWrite(self, s):
|
|
self.backingWrite.extend(s.split('\n')[1 if s[0]=='\n' else 0:])
|
|
|
|
class JavaEmitArrayData(JavaEmitData):
|
|
def __init__(self):
|
|
JavaEmitData.__init__(self)
|
|
self.addConstruct("{fname} = new {ftype_one}[0];")
|
|
self.addBackingRead("int {size_fname} = {backing}.get{jaccessor}({size_foffset});")
|
|
self.addBackingWrite("{backing}.put{jaccessor}({size_foffset}, {fname}.length);")
|
|
|
|
# sized array of null-terminated strings
|
|
strzArrayEmitSized = JavaEmitArrayData()
|
|
strzArrayEmitSized.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
strzArrayEmitSized.addRead("""
|
|
{fname} = new String[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, {size_fname}*{pointer_sz});
|
|
for (int i=0, off=0; i<{size_fname}; i++, off += {pointer_sz}) {{
|
|
long addr = getPointer(bb, off);
|
|
if (addr == 0)
|
|
{fname}[i] = null;
|
|
else {{
|
|
ByteBuffer bb2 = newDirectByteBuffer(addr, 1000); // FIXME
|
|
while (bb2.get() != 0) {{}}
|
|
byte[] bytes = new byte[bb2.position()-1];
|
|
bb2.rewind();
|
|
getBytes(bb2, bytes, 0, bytes.length);
|
|
try {{
|
|
{fname}[i] = new String(bytes, "UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname}[i] = "";
|
|
}}
|
|
}}
|
|
}}
|
|
}}""")
|
|
strzArrayEmitSized.addWriteBuf("{buftype} {fname}_buf")
|
|
strzArrayEmitSized.addWriteBuf("{buftype}[] {fname}_bufs")
|
|
strzArrayEmitSized.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length*{pointer_sz}).order(ByteOrder.nativeOrder());
|
|
for (int i=0, off=0; i<{fname}.length; i++, off += {pointer_sz}) {{
|
|
if ({fname}[i] == null)
|
|
putPointer({fname}_buf, off, 0);
|
|
else {{
|
|
byte[] bytes;
|
|
try {{
|
|
bytes = {fname}[i].getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
bytes = new byte[0];
|
|
}}
|
|
{fname}_bufs[i] = ByteBuffer.allocateDirect(bytes.length+1);
|
|
putBytes({fname}_bufs[i], bytes, 0, bytes.length).put(bytes.length, (byte)0);
|
|
putPointer({fname}_buf, off, getByteBufferAddress({fname}_bufs[i]));
|
|
}}
|
|
}}""")
|
|
strzArrayEmitSized.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
|
|
# unsized array; final terminating zero determines the length
|
|
strzArrayEmitUnsized = JavaEmitData()
|
|
strzArrayEmitUnsized.addConstruct("{fname} = new {ftype_one}[0];")
|
|
strzArrayEmitUnsized.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
strzArrayEmitUnsized.addRead("""
|
|
{{
|
|
if ({fname}_addr == 0)
|
|
{fname} = new {ftype_one}[0];
|
|
else {{
|
|
// prescan to find length
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, 1000*{pointer_sz}); // FIXME
|
|
int size = 0;
|
|
for (int off=0; getPointer(bb, off) != 0; size++, off += {pointer_sz}) {{ }}
|
|
{fname} = new String[size];
|
|
for (int i=0, off=0; i<size; i++, off += {pointer_sz}) {{
|
|
long addr = getPointer(bb, off);
|
|
if (addr == 0)
|
|
{fname}[i] = null;
|
|
else {{
|
|
ByteBuffer bb2 = newDirectByteBuffer(addr, 1000); // FIXME
|
|
while (bb2.get() != 0) {{}}
|
|
byte[] bytes = new byte[bb2.position()-1];
|
|
bb2.rewind();
|
|
getBytes(bb2, 0, bytes.length);
|
|
try {{
|
|
{fname}[i] = new String(bytes, "UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname}[i] = "";
|
|
}}
|
|
}}
|
|
}}
|
|
}}
|
|
}}""")
|
|
strzArrayEmitUnsized.addWriteBuf("{buftype} {fname}_buf")
|
|
strzArrayEmitUnsized.addWriteBuf("{buftype}[] {fname}_bufs")
|
|
strzArrayEmitUnsized.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect(({fname}.length+1)*{pointer_sz}).order(ByteOrder.nativeOrder());
|
|
for (int i=0, off=0; i<{fname}.length; i++, off += {pointer_sz}) {{
|
|
if ({fname}[i] == null)
|
|
putPointer({fname}_buf, off, 0);
|
|
else {{
|
|
byte[] bytes;
|
|
try {{
|
|
bytes = {fname}[i].getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
bytes = new byte[0];
|
|
}}
|
|
{fname}_bufs[i] = ByteBuffer.allocateDirect(bytes.length+1);
|
|
putBytes({fname}_bufs[i], bytes, 0, bytes.length).put(bytes.length, (byte)0);
|
|
putPointer({fname}_buf, off, getByteBufferAddress({fname}_bufs[i]));
|
|
}}
|
|
}}
|
|
putPointer({fname}_buf, {fname}.length*{pointer_sz}, 0); // terminator""")
|
|
strzArrayEmitUnsized.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
|
|
# array of enum values
|
|
enumArrayEmit = JavaEmitArrayData()
|
|
enumArrayEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
enumArrayEmit.addRead("""
|
|
{fname} = new {ftype_one}[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, {size_fname}*%d);
|
|
for (int i=0, off=0; i<{size_fname}; i++, off += %d) {{
|
|
{fname}[i] = {ftype_one}.fromValue(bb.getInt(off));
|
|
}}
|
|
}}""" % (4, 4))
|
|
enumArrayEmit.addWriteBuf("{buftype} {fname}_buf")
|
|
enumArrayEmit.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length*%d).order(ByteOrder.nativeOrder());
|
|
for (int i=0, off=0; i<{fname}.length; i++, off += %d) {{
|
|
if ({fname} != null)
|
|
{fname}_buf.putInt(off, {fname}[i].getValue());
|
|
}}""" % (4, 4))
|
|
enumArrayEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
enumArrayEmit.toArg = "getByteBufferAddress({fname}_buf)"
|
|
|
|
# array of opaque structures
|
|
opaqueArrayEmit = JavaEmitArrayData()
|
|
opaqueArrayEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
opaqueArrayEmit.addRead("""
|
|
{fname} = new {ftype_one}[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, {size_fname}*{pointer_sz});
|
|
for (int i=0, off=0; i<{size_fname}; i++, off += {pointer_sz}) {{
|
|
{fname}[i] = new {ftype_one}(getPointer(bb, off), false);
|
|
}}
|
|
}}""")
|
|
opaqueArrayEmit.addWriteBuf("{buftype} {fname}_buf")
|
|
opaqueArrayEmit.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length*{pointer_sz}).order(ByteOrder.nativeOrder());
|
|
for (int i=0, off=0; i<{fname}.length; i++, off += {pointer_sz}) {{
|
|
putPointer({fname}_buf, off, {fname}[i]);
|
|
}}""")
|
|
opaqueArrayEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
opaqueArrayEmit.toArg = "getByteBufferAddress({fname}_buf)"
|
|
|
|
# array of String255
|
|
string255ArrayEmit = JavaEmitArrayData()
|
|
string255ArrayEmit.addBackingRead("""
|
|
{fname} = new String[{size_fname}];
|
|
if ({size_fname} > 0) {{
|
|
byte[] bytes = new byte[%d];
|
|
int len;
|
|
for (int i=0, off={foffset}; i<{size_fname}; i++, off += %d) {{
|
|
getBytes({backing}, bytes, off, %d);
|
|
for (len=0; len<bytes.length && bytes[len] != 0; len++) {{}}
|
|
try {{
|
|
{fname}[i] = new String(bytes, 0, len, "UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname}[i] = "";
|
|
}}
|
|
}}
|
|
}}""" % (256, 256, 256))
|
|
string255ArrayEmit.addBackingWrite("""
|
|
for (int i=0, off={foffset}; i<{size_fname}; i++, off += %d) {{
|
|
byte[] bytes;
|
|
try {{
|
|
bytes = {fname}.getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
bytes = new byte[0];
|
|
}}
|
|
putBytes({backing}, bytes, off, bytes.length);
|
|
for (int i=bytes.length; i<%d; i++)
|
|
{backing}.put(off+i, (byte)0); // fill with zero
|
|
}}""" % (256, 256))
|
|
|
|
# array of normal structures
|
|
structArrayEmit = JavaEmitArrayData()
|
|
structArrayEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
structArrayEmit.addRead("""
|
|
{fname} = new {ftype_one}[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, {size_fname}*{struct_sz});
|
|
for (int i=0, off=0; i<{size_fname}; i++, off += {struct_sz}) {{
|
|
{fname}[i] = new {ftype_one}(bb, off);
|
|
{fname}[i].read();
|
|
}}
|
|
}}""")
|
|
structArrayEmit.addWriteBuf("{buftype} {fname}_buf")
|
|
# FIXME: This can be optimized for the read->write case.
|
|
structArrayEmit.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length*{struct_sz}).order(ByteOrder.nativeOrder());
|
|
for (int i=0, off=0; i<{fname}.length; i++, off += {struct_sz}) {{
|
|
{fname}[i].setBuffer({fname}_buf, off);
|
|
{fname}[i].write();
|
|
}}""")
|
|
structArrayEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
structArrayEmit.toArg = "getByteBufferAddress({fname}_buf)"
|
|
|
|
# array of bytes
|
|
byteArrayEmit = JavaEmitArrayData()
|
|
byteArrayEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
byteArrayEmit.addRead("""
|
|
{fname} = new {ftype_one}[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
getBytes(newDirectByteBuffer({fname}_addr, {size_fname}), {fname}, 0, {size_fname});
|
|
}}""")
|
|
byteArrayEmit.addWriteBuf("{buftype} {fname}_buf")
|
|
byteArrayEmit.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length);
|
|
putBytes({fname}_buf, {fname}, 0, {fname}.length);""")
|
|
byteArrayEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
byteArrayEmit.toArg = "getByteBufferAddress({fname}_buf)"
|
|
|
|
# array of java types
|
|
jtypeArrayEmit = JavaEmitArrayData()
|
|
jtypeArrayEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
jtypeArrayEmit.addRead("""{fname} = new {ftype_one}[{size_fname}];
|
|
if ({size_fname} > 0 && {fname}_addr != 0) {{
|
|
newDirectByteBuffer({fname}_addr, {size_fname}*{struct_sz}).as{buftype}().get({fname});
|
|
}}""")
|
|
jtypeArrayEmit.addWriteBuf("ByteBuffer {fname}_buf")
|
|
jtypeArrayEmit.addWrite("""
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}.length*{struct_sz}).order(ByteOrder.nativeOrder());
|
|
{fname}_buf.as{buftype}().put({fname}).rewind();""")
|
|
jtypeArrayEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname}_buf);")
|
|
jtypeArrayEmit.toArg = "getByteBufferAddress({fname}_buf)"
|
|
|
|
# enum
|
|
enumEmit = JavaEmitData()
|
|
enumEmit.addBackingRead("{fname} = {ftype}.fromValue({backing}.getInt({foffset}));")
|
|
enumEmit.addBackingWrite("""if ({fname} != null)
|
|
{backing}.putInt({foffset}, {fname}.getValue());""")
|
|
enumEmit.toArg = "{fname}.getValue()"
|
|
|
|
# opaque structure
|
|
opaqueEmit = JavaEmitData()
|
|
opaqueEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
opaqueEmit.addRead("""if ({fname}_addr == 0)
|
|
{fname} = null;
|
|
else
|
|
{fname} = new {ftype}({fname}_addr, false);""")
|
|
opaqueEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname});")
|
|
opaqueEmit.toArg = "{fname}.getAddress()"
|
|
|
|
# inline normal structure
|
|
structEmit = JavaEmitData()
|
|
structEmit.addConstruct("{fname} = new {ftype}({backing}, {foffset});")
|
|
structEmit.addRead("{fname}.read();")
|
|
structEmit.addWrite("{fname}.write();")
|
|
structEmit.toArg = "{fname}.getAddress()"
|
|
|
|
# java type
|
|
jtypeEmit = JavaEmitData()
|
|
jtypeEmit.addBackingRead("{fname} = {jaccessor_cast_out_pre}{backing}.get{jaccessor}({foffset}){jaccessor_cast_out_post};")
|
|
jtypeEmit.addBackingWrite("{backing}.put{jaccessor}({foffset}, {jaccessor_cast_in_pre}{fname}{jaccessor_cast_in_post});")
|
|
|
|
# string - array of characters
|
|
strSizedEmit = JavaEmitData()
|
|
strSizedEmit.addBackingRead("""{{
|
|
byte[] bytes = new byte[{array_size}];
|
|
getBytes({backing}, bytes, {foffset}, {array_size});
|
|
int len;
|
|
for (len=0; len<bytes.length && bytes[len] != 0; len++) {{}}
|
|
try {{
|
|
{fname} = new String(bytes, 0, len, "UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname} = "";
|
|
}}
|
|
}}""")
|
|
strSizedEmit.addBackingWrite("""
|
|
if ({fname} != null) {{
|
|
byte[] bytes;
|
|
try {{
|
|
bytes = {fname}.getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
bytes = new byte[0];
|
|
}}
|
|
putBytes({backing}, bytes, {foffset}, bytes.length);
|
|
for (int i=bytes.length; i<{array_size}; i++)
|
|
{backing}.put(i, (byte)0); // fill with zero
|
|
}}""")
|
|
|
|
# null terminated string
|
|
strzEmit = JavaEmitData()
|
|
strzEmit.addBackingRead("long {fname}_addr = getPointer({backing}, {foffset});")
|
|
strzEmit.addRead("""if ({fname}_addr == 0)
|
|
{fname} = null;
|
|
else {{
|
|
ByteBuffer bb = newDirectByteBuffer({fname}_addr, 1000); // FIXME
|
|
while (bb.get() != 0) {{}}
|
|
byte[] bytes = new byte[bb.position()-1];
|
|
getBytes(bb, bytes, 0, bytes.length);
|
|
try {{
|
|
{fname} = new String(bytes, "UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname} = "";
|
|
}}
|
|
}}
|
|
""")
|
|
strzEmit.addWriteBuf("{buftype} {fname}_buf")
|
|
strzEmit.addWrite("""
|
|
if ({fname} != null) {{
|
|
byte[] {fname}_bytes;
|
|
try {{
|
|
{fname}_bytes = {fname}.getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
{fname}_bytes = new byte[0];
|
|
}}
|
|
{fname}_buf = ByteBuffer.allocateDirect({fname}_bytes.length+1);
|
|
putBytes({fname}_buf, {fname}_bytes, 0, {fname}_bytes.length).put({fname}_bytes.length, (byte)0);
|
|
}}""")
|
|
strzEmit.addBackingWrite("putPointer({backing}, {foffset}, {fname} == null ? 0 : getByteBufferAddress({fname}_buf));")
|
|
strzEmit.toArg = "{fname} == null ? 0 : getByteBufferAddress({fname}_buf)"
|
|
|
|
class JavaStructEmitHelper:
|
|
def __init__(self, emit, name, fields, sized_members=None):
|
|
self.emit = emit
|
|
self.name = name
|
|
self.fields = fields
|
|
|
|
self.exclude_members = set(self.config_get("exclude_members", "").split(','))
|
|
self.exclude_members |= set(x.split(':')[0] for x in self.config_get("uniontype", "").split(','))
|
|
self.union_members = {}
|
|
for v in self.config_get("uniontype", "").split(','):
|
|
if not v:
|
|
continue
|
|
vl = v.split(':')
|
|
self.union_members[vl[0]] = (vl[1], [tuple(y.strip() for y in x.split('=')) for x in vl[2:]])
|
|
|
|
if sized_members is not None:
|
|
self.sized_members = sized_members
|
|
else:
|
|
self.sized_members = dict(tuple(y.strip() for y in x.split(':')) for x in
|
|
self.config_get("arraysize", "").split(',') if x)
|
|
self.size_members = dict((x, None) for x in self.sized_members.values())
|
|
|
|
# get type of each sized member
|
|
for fname, ftype, arr, comment in fields:
|
|
if fname in self.size_members:
|
|
self.size_members[fname] = ftype
|
|
|
|
def config_get(self, option, fallback):
|
|
return self.emit.config_get(self.name, option, fallback)
|
|
|
|
def config_getboolean(self, section, option, fallback):
|
|
return self.emit.config_getboolean(self.name, option, fallback)
|
|
|
|
def config_struct_get(self, option):
|
|
return self.emit.config_struct.get(self.name, option)
|
|
|
|
def get_field_java_code(self, fname, ftype, arr, foffset, jfielddefs_private, backing="backing"):
|
|
"""Returns dict of fielddef, init, read, write, type
|
|
"""
|
|
if ftype.startswith("const"):
|
|
ftype = ftype[5:].strip()
|
|
if fname in self.sized_members:
|
|
# Change from pointer to array
|
|
if ftype[-1] == '*':
|
|
ftype = ftype[:-1]
|
|
arr = ""
|
|
size_fname = self.sized_members[fname]
|
|
size_jtype = c_to_jtype(self.size_members[size_fname], None)
|
|
size_foffset = self.config_struct_get(size_fname)
|
|
else:
|
|
size_fname=""
|
|
size_jtype=None
|
|
size_foffset=None
|
|
|
|
is_pointer = False
|
|
if ftype[-1] == '*' and ftype[:-1] in opaque_structs:
|
|
# silently strip pointer from native structs
|
|
ftype = ftype[:-1]
|
|
elif ftype[-1] == '*' and (ftype, arr) not in java_types_map:
|
|
# Not an array, but not inline either
|
|
ftype = ftype[:-1]
|
|
is_pointer = True
|
|
|
|
# Hopefully the base type now
|
|
jtype = c_to_jtype(ftype, arr)
|
|
|
|
struct_sz = None
|
|
buftype = "ByteBuffer"
|
|
array_size = jtype.array_size or ""
|
|
jaccessor = (None, None, None, None, None)
|
|
|
|
writeBufs = []
|
|
backingRead = []
|
|
read = []
|
|
write = []
|
|
backingWrite = []
|
|
construct = []
|
|
toArg = ""
|
|
|
|
typeemit = None
|
|
if jtype.jni_sig == "[Ljava/lang/String;":
|
|
# null-terminated strings
|
|
if size_fname:
|
|
jaccessor = java_accessor_map[size_jtype.jni_sig[0]]
|
|
typeemit = strzArrayEmitSized
|
|
else:
|
|
typeemit = strzArrayEmitUnsized
|
|
elif jtype.jni_sig[0] == '[':
|
|
if is_pointer: raise NotImplementedError("pointer to array")
|
|
if arr:
|
|
construct.append("{fname} = new {ftype_one}[%s];" % arr)
|
|
if jtype.is_opaque or jtype.is_enum:
|
|
raise NotImplementedError("array of opaque and enum not implemented")
|
|
elif jtype.is_struct:
|
|
struct_sz = self.emit.config_struct.get(jtype.j_type[:-2], "_SIZE_")
|
|
construct.extend(("""
|
|
for (int i=0, off={foffset}; i<%s; i++, off += {struct_sz})
|
|
{fname}[i] = new {ftype_one}({backing}, off);""" % arr).split('\n'))
|
|
read.extend(("""for ({ftype_one} it : {fname}) {{
|
|
it.read();
|
|
}}""").split('\n'))
|
|
write.extend(("""for ({ftype_one} it : {fname}) {{
|
|
it.write();
|
|
}}""").split('\n'))
|
|
else:
|
|
raise NotImplementedError("sized array of unknown type")
|
|
else:
|
|
jaccessor = java_accessor_map[size_jtype.jni_sig[0]]
|
|
if jtype.is_enum:
|
|
typeemit = enumArrayEmit
|
|
elif jtype.is_opaque:
|
|
typeemit = opaqueArrayEmit
|
|
elif ftype == "String255":
|
|
typeemit = string255ArrayEmit
|
|
elif jtype.is_struct:
|
|
struct_sz = self.emit.config_struct.get(jtype.j_type[:-2], "_SIZE_")
|
|
typeemit = structArrayEmit
|
|
elif jtype.jni_sig[1] == 'B':
|
|
typeemit = byteArrayEmit
|
|
elif jtype.jni_sig[1] in java_accessor_map:
|
|
buftype = "%sBuffer" % java_accessor_map[jtype.jni_sig[1]][0]
|
|
struct_sz = java_size_map[jtype.jni_sig[1]]
|
|
typeemit = jtypeArrayEmit
|
|
else:
|
|
raise ValueError("unrecognized jni signature '%s'" % jtype.jni_sig)
|
|
elif jtype.is_enum:
|
|
if is_pointer: raise NotImplementedError("pointer to enum")
|
|
typeemit = enumEmit
|
|
elif jtype.is_opaque or (jtype.is_struct and is_pointer):
|
|
typeemit = opaqueEmit
|
|
elif jtype.is_struct:
|
|
typeemit = structEmit
|
|
elif jtype.jni_sig[0] in java_accessor_map:
|
|
if is_pointer: raise NotImplementedError("pointer to raw")
|
|
jaccessor = java_accessor_map[jtype.jni_sig[0]]
|
|
typeemit = jtypeEmit
|
|
elif jtype.jni_sig == "Ljava/lang/String;":
|
|
if is_pointer: raise NotImplementedError("pointer to string")
|
|
if jtype.string_array:
|
|
typeemit = strSizedEmit
|
|
else:
|
|
typeemit = strzEmit
|
|
else:
|
|
raise ValueError("unrecognized jni signature '%s'" % jtype.jni_sig)
|
|
|
|
if typeemit is not None:
|
|
writeBufs.extend(typeemit.writeBufs)
|
|
construct.extend(typeemit.construct)
|
|
backingRead.extend(typeemit.backingRead)
|
|
read.extend(typeemit.read)
|
|
write.extend(typeemit.write)
|
|
backingWrite.extend(typeemit.backingWrite)
|
|
toArg = typeemit.toArg
|
|
|
|
for buf in writeBufs:
|
|
jfielddefs_private.append("private %s;" % buf.format(buftype=buftype, fname=fname))
|
|
jfielddef = 'public %s %s;' % (jtype.j_type, fname)
|
|
|
|
fargs = dict(fname=fname,
|
|
ftype=jtype.j_type,
|
|
ftype_one=jtype.j_type[:-2],
|
|
foffset=foffset,
|
|
size_fname=fname+"_"+size_fname,
|
|
size_foffset=size_foffset,
|
|
pointer_sz=self.emit.config_struct.get("_platform_", "pointer"),
|
|
struct_sz=struct_sz,
|
|
array_size=array_size,
|
|
buftype=buftype,
|
|
jaccessor=jaccessor[0],
|
|
jaccessor_cast_out_pre=jaccessor[1],
|
|
jaccessor_cast_out_post=jaccessor[2],
|
|
jaccessor_cast_in_pre=jaccessor[3],
|
|
jaccessor_cast_in_post=jaccessor[4],
|
|
backing=backing)
|
|
jconstruct = [x.format(**fargs) for x in construct]
|
|
jwritebufs = [x.format(**fargs) for x in writeBufs]
|
|
jbackingread = [x.format(**fargs) for x in backingRead]
|
|
jread = [x.format(**fargs) for x in read]
|
|
jwrite = [x.format(**fargs) for x in write]
|
|
jbackingwrite = [x.format(**fargs) for x in backingWrite]
|
|
jtoarg = toArg.format(**fargs)
|
|
|
|
return dict(fielddef=jfielddef,
|
|
construct=jconstruct,
|
|
write_bufs=jwritebufs,
|
|
backing_read=jbackingread,
|
|
read=jread,
|
|
write=jwrite,
|
|
backing_write=jbackingwrite,
|
|
to_arg=jtoarg,
|
|
type=jtype,
|
|
is_pointer=is_pointer,
|
|
arr=arr,
|
|
size_fname=size_fname,
|
|
size_jtype=size_jtype,
|
|
size_foffset=size_foffset)
|
|
|
|
def get_java_code(self):
|
|
jcargs = []
|
|
jcinit = []
|
|
jfielddefs = []
|
|
jfielddefs_private = []
|
|
jconstruct = []
|
|
jread = []
|
|
jwrite = []
|
|
|
|
# standard struct fields
|
|
for fname, ftype, arr, comment in self.fields:
|
|
if fname in self.size_members or fname in self.exclude_members:
|
|
continue # don't emit
|
|
|
|
if ":" in fname:
|
|
continue # TODO: bit field
|
|
foffset = self.config_struct_get(fname)
|
|
field = self.get_field_java_code(fname, ftype, arr, foffset, jfielddefs_private)
|
|
|
|
# XXX: hack to get short and float to work reasonably
|
|
if field["type"].j_type == "short":
|
|
jcargs.append("int {fname}".format(fname=fname))
|
|
jcinit.append("this.{fname} = (short){fname};".format(fname=fname))
|
|
elif field["type"].j_type == "float":
|
|
jcargs.append("double {fname}".format(fname=fname))
|
|
jcinit.append("this.{fname} = (float){fname};".format(fname=fname))
|
|
else:
|
|
jcargs.append("{ftype} {fname}".format(ftype=field["type"].j_type, fname=fname))
|
|
jcinit.append("this.{fname} = {fname};".format(fname=fname))
|
|
|
|
fielddef = field["fielddef"]
|
|
if comment is not None:
|
|
fielddef += ' // %s' % comment
|
|
jfielddefs.append(fielddef)
|
|
jconstruct.extend(field["construct"])
|
|
jread.extend(field["backing_read"])
|
|
jread.extend(field["read"])
|
|
jwrite.extend(field["write"])
|
|
jwrite.extend(field["backing_write"])
|
|
|
|
# typed union fields
|
|
jfielddefs_union_private = []
|
|
for union_name, (switchvalue_name, members) in self.union_members.items():
|
|
# get union structure name and type info
|
|
for fname, ftype, arr, comment in self.fields:
|
|
if fname == union_name:
|
|
union_ftype = ftype
|
|
elif fname == switchvalue_name:
|
|
switchvalue_ftype = ftype
|
|
unionfields = self.emit.unions[union_ftype]
|
|
|
|
# build map of union fields for faster lookup
|
|
ufieldmap = {}
|
|
for fname, ftype, arr, comment in unionfields:
|
|
ufieldmap[fname] = (ftype, arr, comment)
|
|
|
|
# common offset
|
|
foffset = self.config_struct_get(union_name)
|
|
|
|
for enumval, fname in members:
|
|
# find the rest of the info from the union fields
|
|
ftype, arr, comment = ufieldmap[fname]
|
|
|
|
field = self.get_field_java_code(fname, ftype, arr, foffset, jfielddefs_union_private)
|
|
|
|
fielddef = field["fielddef"]
|
|
read = field["backing_read"]
|
|
read.extend(field["read"])
|
|
write = field["write"]
|
|
write.extend(field["backing_write"])
|
|
if comment is not None:
|
|
fielddef += ' // %s' % comment
|
|
jfielddefs.append(fielddef)
|
|
jconstruct.extend(field["construct"])
|
|
if enumval.startswith("IMAQ_"):
|
|
enumval = enumval[5:]
|
|
ifcheck = "if (%s == %s.%s) " % (switchvalue_name, switchvalue_ftype, enumval)
|
|
if len(read[0]) > 0 and read[0][0] == '{':
|
|
read[0] = ifcheck + read[0]
|
|
else:
|
|
read = (" " + "\n ".join(read)).split('\n')
|
|
read.insert(0, ifcheck + "{")
|
|
read.append("}")
|
|
if len(write[0]) > 0 and write[0][0] == '{':
|
|
write[0] = ifcheck + write[0]
|
|
else:
|
|
write = (" " + "\n ".join(write)).split('\n')
|
|
write.insert(0, ifcheck + "{")
|
|
write.append("}")
|
|
|
|
jread.extend(read)
|
|
jwrite.extend(write)
|
|
|
|
jfielddefs.extend(jfielddefs_private)
|
|
|
|
# Java definition
|
|
p1 = """
|
|
public static class {name} extends DisposedStruct {{
|
|
{jfielddefs}
|
|
|
|
private void init() {{
|
|
{jconstruct}
|
|
}}
|
|
public {name}() {{
|
|
super({size});
|
|
init();
|
|
}}"""
|
|
|
|
if jcargs:
|
|
p2 = """
|
|
public {name}({jcargs}) {{
|
|
super({size});
|
|
{jcinit}
|
|
}}"""
|
|
else:
|
|
p2 = ""
|
|
|
|
p3 = """
|
|
protected {name}(ByteBuffer backing, int offset) {{
|
|
super(backing, offset, {size});
|
|
init();
|
|
}}
|
|
protected {name}(long nativeObj, boolean owned) {{
|
|
super(nativeObj, owned, {size});
|
|
init();
|
|
}}
|
|
protected void setBuffer(ByteBuffer backing, int offset) {{
|
|
super.setBuffer(backing, offset, {size});
|
|
}}
|
|
public void read() {{
|
|
{jread}
|
|
}}
|
|
public void write() {{
|
|
{jwrite}
|
|
}}
|
|
public int size() {{
|
|
return {size};
|
|
}}
|
|
}}"""
|
|
return "".join([p1,p2,p3]).format(
|
|
name=self.name,
|
|
jfielddefs="\n ".join(jfielddefs),
|
|
jread="\n ".join(jread),
|
|
jwrite="\n ".join(jwrite),
|
|
jconstruct="\n ".join(jconstruct),
|
|
jcargs=", ".join(jcargs),
|
|
jcinit="\n ".join(jcinit),
|
|
size=self.config_struct_get("_SIZE_"))
|
|
|
|
|
|
class JavaEmitter:
|
|
def __init__(self, outdir, config, config_struct, library_funcs):
|
|
self.outdir = outdir
|
|
self.config = config
|
|
self.config_struct = config_struct
|
|
self.library_funcs = library_funcs
|
|
self.package = "com.ni.vision"
|
|
self.classname = "NIVision"
|
|
self.classpath = self.package.replace(".", "/") + "/" + self.classname
|
|
|
|
self.unions = {}
|
|
self.errors = {}
|
|
|
|
with open(os.path.join(outdir, "VisionException.java"), "wt") as f:
|
|
print("""//
|
|
// This file is auto-generated by wpilibj/wpilibJavaJNI/nivision/gen_java.py
|
|
// Please do not edit!
|
|
//
|
|
|
|
package {package};
|
|
|
|
public class VisionException extends RuntimeException {{
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
public VisionException(String msg) {{
|
|
super(msg);
|
|
}}
|
|
|
|
@Override
|
|
public String toString() {{
|
|
return "VisionException [" + super.toString() + "]";
|
|
}}
|
|
}}""".format(package=self.package), file=f)
|
|
|
|
self.out = open(os.path.join(outdir, "NIVision.java"), "wt")
|
|
print("""//
|
|
// This file is auto-generated by wpilibj/wpilibJavaJNI/nivision/gen_java.py
|
|
// Please do not edit!
|
|
//
|
|
|
|
package {package};
|
|
|
|
import java.lang.reflect.*;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.nio.Buffer;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
|
|
public class {classname} {{
|
|
private {classname}() {{}}
|
|
|
|
private static native void imaqDispose(long addr);
|
|
|
|
private static Constructor<?> constructDirectByteBuffer;
|
|
private static Field bufferAddressField;
|
|
|
|
static {{
|
|
try {{
|
|
Class<?>[] cArg = new Class[2];
|
|
cArg[0] = long.class;
|
|
cArg[1] = int.class;
|
|
constructDirectByteBuffer = Class.forName("java.nio.DirectByteBuffer").getDeclaredConstructor(cArg);
|
|
constructDirectByteBuffer.setAccessible(true);
|
|
|
|
bufferAddressField = Buffer.class.getDeclaredField("address");
|
|
bufferAddressField.setAccessible(true);
|
|
}} catch (ReflectiveOperationException e) {{
|
|
throw new ExceptionInInitializerError(e);
|
|
}}
|
|
}}
|
|
|
|
private static ByteBuffer newDirectByteBuffer(long addr, int cap) {{
|
|
try {{
|
|
return ((ByteBuffer)(constructDirectByteBuffer.newInstance(addr, cap))).order(ByteOrder.nativeOrder());
|
|
}} catch (ReflectiveOperationException e) {{
|
|
throw new ExceptionInInitializerError(e);
|
|
}}
|
|
}}
|
|
|
|
private static long getByteBufferAddress(ByteBuffer bb) {{
|
|
try {{
|
|
return bufferAddressField.getLong(bb);
|
|
}} catch (IllegalAccessException e) {{
|
|
return 0;
|
|
}}
|
|
}}
|
|
|
|
public static ByteBuffer sliceByteBuffer(ByteBuffer bb, int offset, int size) {{
|
|
int pos = bb.position();
|
|
int lim = bb.limit();
|
|
bb.position(offset);
|
|
bb.limit(offset+size);
|
|
ByteBuffer new_bb = bb.slice().order(ByteOrder.nativeOrder());
|
|
bb.position(pos);
|
|
bb.limit(lim);
|
|
return new_bb;
|
|
}}
|
|
|
|
public static ByteBuffer getBytes(ByteBuffer bb, byte[] dst, int offset, int size) {{
|
|
int pos = bb.position();
|
|
bb.position(offset);
|
|
bb.get(dst, 0, size);
|
|
bb.position(pos);
|
|
return bb;
|
|
}}
|
|
|
|
public static ByteBuffer putBytes(ByteBuffer bb, byte[] src, int offset, int size) {{
|
|
int pos = bb.position();
|
|
bb.position(offset);
|
|
bb.put(src, 0, size);
|
|
bb.position(pos);
|
|
return bb;
|
|
}}
|
|
|
|
private static abstract class DisposedStruct {{
|
|
protected ByteBuffer backing;
|
|
private boolean owned;
|
|
protected DisposedStruct(int size) {{
|
|
backing = ByteBuffer.allocateDirect(size);
|
|
backing.order(ByteOrder.nativeOrder());
|
|
owned = false;
|
|
}}
|
|
protected DisposedStruct(ByteBuffer backing, int offset, int size) {{
|
|
this.backing = sliceByteBuffer(backing, offset, size);
|
|
owned = false;
|
|
}}
|
|
private DisposedStruct(long nativeObj, boolean owned, int size) {{
|
|
backing = newDirectByteBuffer(nativeObj, size);
|
|
this.owned = owned;
|
|
}}
|
|
public void free() {{
|
|
if (owned) {{
|
|
imaqDispose(getByteBufferAddress(backing));
|
|
owned = false;
|
|
backing = null;
|
|
}}
|
|
}}
|
|
@Override
|
|
protected void finalize() throws Throwable {{
|
|
if (owned)
|
|
imaqDispose(getByteBufferAddress(backing));
|
|
super.finalize();
|
|
}}
|
|
public long getAddress() {{
|
|
if (backing == null)
|
|
return 0;
|
|
write();
|
|
return getByteBufferAddress(backing);
|
|
}}
|
|
protected void setBuffer(ByteBuffer backing, int offset, int size) {{
|
|
this.backing = sliceByteBuffer(backing, offset, size);
|
|
}}
|
|
|
|
abstract public void read();
|
|
abstract public void write();
|
|
abstract public int size();
|
|
}}
|
|
|
|
private static abstract class OpaqueStruct {{
|
|
private long nativeObj;
|
|
private boolean owned;
|
|
protected OpaqueStruct() {{
|
|
nativeObj = 0;
|
|
owned = false;
|
|
}}
|
|
protected OpaqueStruct(long nativeObj, boolean owned) {{
|
|
this.nativeObj = nativeObj;
|
|
this.owned = owned;
|
|
}}
|
|
public void free() {{
|
|
if (owned && nativeObj != 0) {{
|
|
imaqDispose(nativeObj);
|
|
owned = false;
|
|
nativeObj = 0;
|
|
}}
|
|
}}
|
|
@Override
|
|
protected void finalize() throws Throwable {{
|
|
if (owned && nativeObj != 0)
|
|
imaqDispose(nativeObj);
|
|
super.finalize();
|
|
}}
|
|
public long getAddress() {{
|
|
return nativeObj;
|
|
}}
|
|
}}
|
|
|
|
public static class RawData {{
|
|
private ByteBuffer buf;
|
|
private boolean owned;
|
|
public RawData() {{
|
|
owned = false;
|
|
}}
|
|
public RawData(ByteBuffer buf) {{
|
|
this.buf = buf;
|
|
owned = false;
|
|
}}
|
|
private RawData(long nativeObj, boolean owned, int size) {{
|
|
buf = newDirectByteBuffer(nativeObj, size);
|
|
this.owned = owned;
|
|
}}
|
|
public void free() {{
|
|
if (owned) {{
|
|
imaqDispose(getByteBufferAddress(buf));
|
|
owned = false;
|
|
buf = null;
|
|
}}
|
|
}}
|
|
@Override
|
|
protected void finalize() throws Throwable {{
|
|
if (owned)
|
|
imaqDispose(getByteBufferAddress(buf));
|
|
super.finalize();
|
|
}}
|
|
public long getAddress() {{
|
|
if (buf == null)
|
|
return 0;
|
|
return getByteBufferAddress(buf);
|
|
}}
|
|
public ByteBuffer getBuffer() {{
|
|
return buf;
|
|
}}
|
|
public void setBuffer(ByteBuffer buf) {{
|
|
if (owned)
|
|
free();
|
|
this.buf = buf;
|
|
}}
|
|
}}""".format(package=self.package, classname=self.classname), file=self.out)
|
|
|
|
if int(self.config_struct.get("_platform_", "pointer")) == 4:
|
|
# 32-bit addressing
|
|
java_types_map[("size_t", None)] = JavaType("int", "int", "jint", "I")
|
|
print("""
|
|
private static long getPointer(ByteBuffer bb, int offset) {
|
|
return (long)bb.getInt(offset);
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, long address) {
|
|
bb.putInt(offset, (int)address);
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, ByteBuffer buf) {
|
|
if (buf == null)
|
|
bb.putInt(offset, 0);
|
|
else
|
|
bb.putInt(offset, (int)getByteBufferAddress(buf));
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, DisposedStruct struct) {
|
|
if (struct == null)
|
|
bb.putInt(offset, 0);
|
|
else
|
|
bb.putInt(offset, (int)struct.getAddress());
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, OpaqueStruct struct) {
|
|
if (struct == null)
|
|
bb.putInt(offset, 0);
|
|
else
|
|
bb.putInt(offset, (int)struct.getAddress());
|
|
}""", file=self.out)
|
|
else:
|
|
# 64-bit addressing
|
|
java_types_map[("size_t", None)] = JavaType("long", "long", "jlong", "J")
|
|
print("""
|
|
private static long getPointer(ByteBuffer bb, int offset) {
|
|
return bb.getLong(offset);
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, long address) {
|
|
bb.putLong(offset, address);
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, ByteBuffer buf) {
|
|
if (buf == null)
|
|
bb.putLong(offset, 0);
|
|
else
|
|
bb.putLong(offset, getByteBufferAddress(buf));
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, OpaqueStruct struct) {
|
|
if (struct == null)
|
|
bb.putLong(offset, 0);
|
|
else
|
|
bb.putLong(offset, struct.getAddress());
|
|
}
|
|
private static void putPointer(ByteBuffer bb, int offset, DisposedStruct struct) {
|
|
if (struct == null)
|
|
bb.putLong(offset, 0);
|
|
else
|
|
bb.putLong(offset, struct.getAddress());
|
|
}""", file=self.out)
|
|
|
|
self.outc = open(os.path.join(outdir, "NIVision.cpp"), "wt")
|
|
print("""//
|
|
// This file is auto-generated by wpilibj/wpilibJavaJNI/nivision/gen_java.py
|
|
// Please do not edit!
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <jni.h>
|
|
#include <nivision.h>
|
|
#include <NIIMAQdx.h>
|
|
|
|
static const char* getErrorText(int err);
|
|
|
|
// throw java exception
|
|
static void throwJavaException(JNIEnv *env) {{
|
|
jclass je = env->FindClass("{packagepath}/VisionException");
|
|
int err = imaqGetLastError();
|
|
const char* err_text = getErrorText(err);
|
|
char* full_err_msg = (char*)malloc(30+strlen(err_text));
|
|
sprintf(full_err_msg, "imaqError: %d: %s", err, err_text);
|
|
env->ThrowNew(je, full_err_msg);
|
|
free(full_err_msg);
|
|
}}
|
|
|
|
// throw IMAQdx java exception
|
|
static void dxthrowJavaException(JNIEnv *env, IMAQdxError err) {{
|
|
jclass je = env->FindClass("{packagepath}/VisionException");
|
|
const char* err_text = getErrorText(err);
|
|
char* full_err_msg = (char*)malloc(30+strlen(err_text));
|
|
sprintf(full_err_msg, "IMAQdxError: %d: %s", err, err_text);
|
|
env->ThrowNew(je, full_err_msg);
|
|
free(full_err_msg);
|
|
}}
|
|
|
|
extern "C" {{
|
|
|
|
JNIEXPORT void JNICALL Java_{package}_{classname}_imaqDispose(JNIEnv* , jclass , jlong addr)
|
|
{{
|
|
imaqDispose((void*)addr);
|
|
}}
|
|
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeU32(IMAQdxSession id, const char* name, uInt32* value)
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeU32, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeI64(IMAQdxSession id, const char* name, Int64* value)
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeI64, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeF64(IMAQdxSession id, const char* name, float64* value)
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeF64, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeString(IMAQdxSession id, const char* name, char value[IMAQDX_MAX_API_STRING_LENGTH])
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeString, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeEnum(IMAQdxSession id, const char* name, IMAQdxEnumItem* value)
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeEnumItem, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeBool(IMAQdxSession id, const char* name, bool32* value)
|
|
{{
|
|
return IMAQdxGetAttribute(id, name, IMAQdxValueTypeBool, (void*)value);
|
|
}}
|
|
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMinimumU32(IMAQdxSession id, const char* name, uInt32* value)
|
|
{{
|
|
return IMAQdxGetAttributeMinimum(id, name, IMAQdxValueTypeU32, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMinimumI64(IMAQdxSession id, const char* name, Int64* value)
|
|
{{
|
|
return IMAQdxGetAttributeMinimum(id, name, IMAQdxValueTypeI64, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMinimumF64(IMAQdxSession id, const char* name, float64* value)
|
|
{{
|
|
return IMAQdxGetAttributeMinimum(id, name, IMAQdxValueTypeF64, (void*)value);
|
|
}}
|
|
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMaximumU32(IMAQdxSession id, const char* name, uInt32* value)
|
|
{{
|
|
return IMAQdxGetAttributeMaximum(id, name, IMAQdxValueTypeU32, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMaximumI64(IMAQdxSession id, const char* name, Int64* value)
|
|
{{
|
|
return IMAQdxGetAttributeMaximum(id, name, IMAQdxValueTypeI64, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeMaximumF64(IMAQdxSession id, const char* name, float64* value)
|
|
{{
|
|
return IMAQdxGetAttributeMaximum(id, name, IMAQdxValueTypeF64, (void*)value);
|
|
}}
|
|
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeIncrementU32(IMAQdxSession id, const char* name, uInt32* value)
|
|
{{
|
|
return IMAQdxGetAttributeIncrement(id, name, IMAQdxValueTypeU32, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeIncrementI64(IMAQdxSession id, const char* name, Int64* value)
|
|
{{
|
|
return IMAQdxGetAttributeIncrement(id, name, IMAQdxValueTypeI64, (void*)value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxGetAttributeIncrementF64(IMAQdxSession id, const char* name, float64* value)
|
|
{{
|
|
return IMAQdxGetAttributeIncrement(id, name, IMAQdxValueTypeF64, (void*)value);
|
|
}}
|
|
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeU32(IMAQdxSession id, const char* name, uInt32 value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeU32, value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeI64(IMAQdxSession id, const char* name, Int64 value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeI64, value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeF64(IMAQdxSession id, const char* name, float64 value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeF64, value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeString(IMAQdxSession id, const char* name, const char* value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeString, value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeEnum(IMAQdxSession id, const char* name, const IMAQdxEnumItem* value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeU32, value->Value);
|
|
}}
|
|
static inline IMAQdxError NI_FUNC IMAQdxSetAttributeBool(IMAQdxSession id, const char* name, bool32 value)
|
|
{{
|
|
return IMAQdxSetAttribute(id, name, IMAQdxValueTypeBool, value);
|
|
}}
|
|
""".format(packagepath=self.package.replace(".", "/"),
|
|
package=self.package.replace(".", "_"),
|
|
classname=self.classname), file=self.outc)
|
|
|
|
self.block_comment("Opaque Structures")
|
|
for name in sorted(opaque_structs):
|
|
self.opaque_struct(name)
|
|
|
|
def finish(self):
|
|
print("}", file=self.out)
|
|
print("""}}
|
|
|
|
static const char* getErrorText(int err) {{
|
|
switch (err) {{
|
|
{errs}
|
|
default: return "Unknown error";
|
|
}}
|
|
}}""".format(errs="\n ".join('case %s: return "%s";' % (x, self.errors[x]) for x in sorted(self.errors))), file=self.outc)
|
|
|
|
def config_get(self, section, option, fallback):
|
|
try:
|
|
return self.config.get(section, option)
|
|
except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
|
|
return fallback
|
|
|
|
def config_getboolean(self, section, option, fallback):
|
|
try:
|
|
return self.config.getboolean(section, option)
|
|
except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
|
|
return fallback
|
|
|
|
def block_comment(self, comment):
|
|
print("""
|
|
/**
|
|
* {comment}
|
|
*/""".format(comment=comment), file=self.out)
|
|
print("""
|
|
/*
|
|
* {comment}
|
|
*/""".format(comment=comment), file=self.outc)
|
|
|
|
def opaque_struct(self, name):
|
|
print("""
|
|
public static class {name} extends OpaqueStruct {{
|
|
private {name}() {{}}
|
|
private {name}(long nativeObj, boolean owned) {{
|
|
super(nativeObj, owned);
|
|
}}
|
|
}}""".format(name=name), file=self.out)
|
|
|
|
def define(self, name, value, comment):
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
if name in opaque_structs:
|
|
return
|
|
clean = None
|
|
type = None
|
|
after_struct = False
|
|
if value == "TRUE":
|
|
clean = "true"
|
|
type = "boolean"
|
|
elif value == "FALSE":
|
|
clean = "false"
|
|
type = "boolean"
|
|
elif name.startswith("IMAQ_INIT_RGB") and value[0] == '{' and value[-1] == '}':
|
|
return
|
|
elif value.startswith("imaqMake"):
|
|
clean = "new " + value[8:]
|
|
type = value.split("(")[0][8:]
|
|
after_struct = True
|
|
elif value[0] == '"':
|
|
if len(value) == 2:
|
|
clean = "{ 0 }"
|
|
else:
|
|
clean = "{ %s,0 }" % ",".join("0x%x" % ord(c) for c in value[1:-1])
|
|
type = "byte[]"
|
|
elif number_re.match(value):
|
|
clean = value
|
|
type = "int"
|
|
elif constant_re.match(value):
|
|
clean = value
|
|
after_struct = value not in defined
|
|
|
|
if clean is None:
|
|
print("Invalid #define: %s" % name)
|
|
return
|
|
|
|
if name.startswith("ERR_"):
|
|
self.errors[name] = comment
|
|
return
|
|
|
|
# strip IMAQ_ prefix
|
|
if name.startswith("IMAQ_"):
|
|
name = name[5:]
|
|
|
|
code = " public static final {type} {name} = {value};" \
|
|
.format(type=type, name=name, value=clean)
|
|
if after_struct:
|
|
define_after_struct.append((name, code))
|
|
return
|
|
|
|
print(code, file=self.out)
|
|
defined.add(name)
|
|
|
|
def text(self, text):
|
|
print(text, file=self.out)
|
|
|
|
def static_const(self, name, ctype, value):
|
|
# strip IMAQ_ prefix
|
|
if name.startswith("IMAQ_"):
|
|
name = name[5:]
|
|
|
|
if hasattr(value, "__iter__"):
|
|
code = " public static final {ctype} {name} = new {ctype}({value});"
|
|
value = ", ".join(value)
|
|
else:
|
|
code = "{name} = {value};"
|
|
print(code.format(name=name, value=value, ctype=ctype),
|
|
file=self.out)
|
|
defined.add(name)
|
|
|
|
def enum(self, name, values):
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
if name in opaque_structs:
|
|
return
|
|
valuestrs = []
|
|
need_search = False
|
|
prev_value = -1
|
|
for vname, value, comment in values:
|
|
if vname.endswith("SIZE_GUARD"):
|
|
continue
|
|
if value is None:
|
|
# auto-increment
|
|
value = "%d" % (prev_value + 1)
|
|
value_i = int(value, 0)
|
|
if value_i < 0 or value_i != (prev_value + 1):
|
|
# need to do search instead of index for fromValue()
|
|
need_search = True
|
|
prev_value = value_i
|
|
|
|
if vname == "IMAQdxErrorSuccess":
|
|
continue
|
|
if vname.startswith("IMAQdxError"):
|
|
self.errors[vname] = comment
|
|
continue
|
|
|
|
if vname.startswith("IMAQ_"):
|
|
vname = vname[5:]
|
|
if vname.startswith("IMAQdx"):
|
|
vname = vname[6:]
|
|
if vname[0] in "0123456789":
|
|
vname = "C" + vname
|
|
valuestrs.append("%s(%s),%s" % (vname, value, " // %s" % comment if comment else ""))
|
|
defined.add(vname)
|
|
|
|
if not valuestrs:
|
|
return
|
|
|
|
print("""
|
|
public static enum {name} {{
|
|
{values}
|
|
;
|
|
private final int value;
|
|
private {name}(int value) {{
|
|
this.value = value;
|
|
}}
|
|
public static {name} fromValue(int val) {{""".format(name=name, values="\n ".join(valuestrs)), file=self.out)
|
|
if need_search:
|
|
print(""" for ({name} v : values()) {{
|
|
if (v.value == val)
|
|
return v;
|
|
}}
|
|
return null;""".format(name=name), file=self.out)
|
|
else:
|
|
print(""" try {{
|
|
return values()[val];
|
|
}} catch (ArrayIndexOutOfBoundsException e) {{
|
|
return null;
|
|
}}""".format(), file=self.out)
|
|
print(""" }}
|
|
public int getValue() {{
|
|
return value;
|
|
}}
|
|
}}""".format(), file=self.out)
|
|
defined.add(name)
|
|
enums.add(name)
|
|
|
|
def typedef(self, name, typedef, arr):
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
if name in opaque_structs:
|
|
return
|
|
if typedef.startswith("struct"):
|
|
return
|
|
elif typedef.startswith("union"):
|
|
return
|
|
elif (name, arr) not in java_types_map:
|
|
java_types_map[(name, arr)] = c_to_jtype(typedef, arr).copy()
|
|
if arr is None:
|
|
java_types_map[(name, "")] = c_to_jtype(typedef, "").copy()
|
|
defined.add(name)
|
|
|
|
def typedef_function(self, name, restype, params):
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
if name in opaque_structs:
|
|
return
|
|
raise NotImplementedError("typedef function not implemented")
|
|
|
|
def function(self, name, restype, params):
|
|
if name not in self.library_funcs:
|
|
return
|
|
if name == "IMAQdxEnumerateVideoModes":
|
|
# full custom code
|
|
print("""
|
|
public static class dxEnumerateVideoModesResult {{
|
|
public IMAQdxEnumItem[] videoModeArray;
|
|
public int currentMode;
|
|
private ByteBuffer videoModeArray_buf;
|
|
private dxEnumerateVideoModesResult(ByteBuffer rv_buf, ByteBuffer videoModeArray_buf) {{
|
|
this.videoModeArray_buf = videoModeArray_buf;
|
|
int count = rv_buf.getInt(0);
|
|
videoModeArray = new IMAQdxEnumItem[count];
|
|
for (int i=0, off=0; i<count; i++, off += {struct_sz}) {{
|
|
videoModeArray[i] = new IMAQdxEnumItem(videoModeArray_buf, off);
|
|
videoModeArray[i].read();
|
|
}}
|
|
currentMode = rv_buf.getInt(8);
|
|
}}
|
|
}}
|
|
|
|
public static dxEnumerateVideoModesResult IMAQdxEnumerateVideoModes(int id) {{
|
|
ByteBuffer rv_buf = ByteBuffer.allocateDirect(8+8).order(ByteOrder.nativeOrder());
|
|
long rv_addr = getByteBufferAddress(rv_buf);
|
|
_IMAQdxEnumerateVideoModes(id, 0, rv_addr+0, rv_addr+8);
|
|
int count = rv_buf.getInt(0);
|
|
ByteBuffer videoModeArray_buf = ByteBuffer.allocateDirect(count*{struct_sz}).order(ByteOrder.nativeOrder());
|
|
_IMAQdxEnumerateVideoModes(id, getByteBufferAddress(videoModeArray_buf), rv_addr+0, rv_addr+8);
|
|
dxEnumerateVideoModesResult rv = new dxEnumerateVideoModesResult(rv_buf, videoModeArray_buf);
|
|
return rv;
|
|
}}
|
|
private static native void _IMAQdxEnumerateVideoModes(int id, long videoModeArray, long count, long currentMode);""".format(struct_sz=self.config_struct.get("IMAQdxEnumItem", "_SIZE_")), file=self.out)
|
|
print("""
|
|
JNIEXPORT void JNICALL Java_{package}_{classname}__1IMAQdxEnumerateVideoModes(JNIEnv* env, jclass , jint id, jlong videoModeArray, jlong count, jlong currentMode)
|
|
{{
|
|
IMAQdxError rv = IMAQdxEnumerateVideoModes((IMAQdxSession)id, (IMAQdxVideoMode*)videoModeArray, (uInt32*)count, (uInt32*)currentMode);
|
|
if (rv != IMAQdxErrorSuccess) dxthrowJavaException(env, rv);
|
|
}}""".format(package=self.package.replace(".", "_"),
|
|
classname=self.classname), file=self.outc)
|
|
return
|
|
elif name == "IMAQdxGetImageData":
|
|
print("""
|
|
public static int IMAQdxGetImageData(int id, ByteBuffer buffer, IMAQdxBufferNumberMode mode, int desiredBufferNumber) {{
|
|
long buffer_addr = getByteBufferAddress(buffer);
|
|
int buffer_size = buffer.capacity();
|
|
return _IMAQdxGetImageData(id, buffer_addr, buffer_size, mode.getValue(), desiredBufferNumber);
|
|
}}
|
|
private static native int _IMAQdxGetImageData(int id, long buffer, int bufferSize, int mode, int desiredBufferNumber);""".format(), file=self.out)
|
|
print("""
|
|
JNIEXPORT jint JNICALL Java_{package}_{classname}__1IMAQdxGetImageData(JNIEnv* env, jclass , jint id, jlong buffer, jint bufferSize, jint mode, jint desiredBufferNumber)
|
|
{{
|
|
uInt32 actualBufferNumber;
|
|
IMAQdxError rv = IMAQdxGetImageData((IMAQdxSession)id, (void*)buffer, (uInt32)bufferSize, (IMAQdxBufferNumberMode)mode, (uInt32)desiredBufferNumber, &actualBufferNumber);
|
|
if (rv != IMAQdxErrorSuccess) dxthrowJavaException(env, rv);
|
|
return (jint)actualBufferNumber;
|
|
}}""".format(package=self.package.replace(".", "_"),
|
|
classname=self.classname), file=self.outc)
|
|
elif name == "imaqReadFile":
|
|
print("""
|
|
public static void imaqReadFile(Image image, String fileName) {{
|
|
ByteBuffer fileName_buf;
|
|
byte[] fileName_bytes;
|
|
try {{
|
|
fileName_bytes = fileName.getBytes("UTF-8");
|
|
}} catch (UnsupportedEncodingException e) {{
|
|
fileName_bytes = new byte[0];
|
|
}}
|
|
fileName_buf = ByteBuffer.allocateDirect(fileName_bytes.length+1);
|
|
putBytes(fileName_buf, fileName_bytes, 0, fileName_bytes.length).put(fileName_bytes.length, (byte)0);
|
|
_imaqReadFile(image.getAddress(), getByteBufferAddress(fileName_buf), 0, 0);
|
|
}}
|
|
private static native void _imaqReadFile(long image, long fileName, long colorTable, long numColors);""".format(), file=self.out)
|
|
print("""
|
|
JNIEXPORT void JNICALL Java_{package}_{classname}__1imaqReadFile(JNIEnv* env, jclass , jlong image, jlong fileName, jlong colorTable, jlong numColors)
|
|
{{
|
|
int rv = imaqReadFile((Image*)image, (const char*)fileName, (RGBValue*)colorTable, (int*)numColors);
|
|
if (rv == 0) throwJavaException(env);
|
|
}}""".format(package=self.package.replace(".", "_"),
|
|
classname=self.classname), file=self.outc)
|
|
return
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
|
|
# common return cases
|
|
retpointer = self.config_getboolean(name, "rvdisposed", fallback=False)
|
|
j_funcargs = []
|
|
jn_funcargs = []
|
|
jni_funcargs = [("env", java_types_map["env", None]),
|
|
("", java_types_map["cls", None])]
|
|
jn_passedargs = {}
|
|
|
|
paramtypes = {}
|
|
jinit = []
|
|
jfini = []
|
|
exceptioncheck = ""
|
|
retc = ""
|
|
jretc = ""
|
|
|
|
if restype == "int":
|
|
functype = "STDFUNC"
|
|
rettype = c_to_jtype("void", None)
|
|
exceptioncheck = "if (rv == 0) throwJavaException(env);"
|
|
elif restype == "IMAQdxError":
|
|
functype = "STDFUNC"
|
|
rettype = c_to_jtype("void", None)
|
|
exceptioncheck = "if (rv != IMAQdxErrorSuccess) dxthrowJavaException(env, rv);"
|
|
else:
|
|
if restype[-1] == "*":
|
|
functype = "STDPTRFUNC"
|
|
exceptioncheck = "if (!rv) throwJavaException(env);"
|
|
else:
|
|
functype = "RETFUNC"
|
|
|
|
if restype[-1] == "*" and restype[:-1] in opaque_structs:
|
|
# silently strip pointer from native structs
|
|
rettype = c_to_jtype(restype[:-1], None)
|
|
else:
|
|
rettype = c_to_jtype(restype, None)
|
|
|
|
# TODO: defaults
|
|
#defaults = dict((y.strip() for y in x.split(':')) for x in
|
|
# self.config_get(name, "defaults", "").split(',') if x)
|
|
|
|
sized_params = dict(tuple(y.strip() for y in x.split(':')) for x in
|
|
self.config_get(name, "arraysize", "").split(',') if x)
|
|
size_params = set(sized_params.values())
|
|
|
|
inparams = [x.strip() for x in self.config_get(name, "inparams", "").split(',') if x.strip()]
|
|
outparams = [x.strip() for x in self.config_get(name, "outparams", "").split(',') if x.strip()]
|
|
nullokparams = [x.strip() for x in self.config_get(name, "nullok", "").split(',') if x.strip()]
|
|
# guess additional output parameters
|
|
for pname, ptype, arr in params:
|
|
if (pname not in inparams
|
|
and pname not in outparams
|
|
and pname not in sized_params
|
|
and ptype
|
|
and not ptype.startswith("const")
|
|
and ptype[:-1] not in opaque_structs
|
|
and ptype[-1] == "*"):
|
|
outparams.append(pname)
|
|
|
|
retarraysize = self.config_get(name, "retarraysize", "").strip()
|
|
if retarraysize:
|
|
size_params.add(retarraysize)
|
|
#rettype = c_to_jtype(restype, "")
|
|
if retarraysize not in outparams:
|
|
outparams.append(retarraysize)
|
|
|
|
retsize = self.config_get(name, "retsize", "").strip()
|
|
if retsize:
|
|
size_params.add(retsize)
|
|
if retsize not in outparams:
|
|
outparams.append(retsize)
|
|
|
|
retowned = not self.config_getboolean(name, "retunowned", False)
|
|
|
|
# Input and output parameter code is generated with the help of
|
|
# "virtual" structures. The input parameters are collected in one
|
|
# structure, the output parameters in another. Only if there are
|
|
# multiple output parameters or an output array is the output
|
|
# structure actually generated into the Java code.
|
|
|
|
instruct_fields = [(pname, ptype, arr, "") for (pname, ptype, arr)
|
|
in params if pname != "void"]
|
|
helper = JavaStructEmitHelper(self, name, instruct_fields)
|
|
helper.config_struct_get = lambda o: "0"
|
|
|
|
# "pointer" type to use for JN/JNI
|
|
jtype_ptr = java_types_map[("long", None)]
|
|
|
|
jfielddefs_private = []
|
|
for fname, ftype, arr, comment in helper.fields:
|
|
#print(fname, ftype, arr)
|
|
is_outparam = (fname in outparams)
|
|
is_nullok = (fname in nullokparams) and not is_outparam
|
|
|
|
if is_outparam:
|
|
if ftype[-1] == '*':
|
|
ftype = ftype[:-1]
|
|
elif arr is None:
|
|
raise ValueError("outparam %s is not a pointer or array", fname)
|
|
field = helper.get_field_java_code(fname, ftype, arr, 0, jfielddefs_private, backing="%s_buf" % fname)
|
|
paramtypes[fname] = (ftype, arr, field["type"])
|
|
if is_outparam:
|
|
jn_funcargs.append((fname, jtype_ptr))
|
|
jni_funcargs.append((fname, jtype_ptr))
|
|
continue
|
|
|
|
write_bufs = field["write_bufs"]
|
|
write = field["write"]
|
|
jtype = field["type"]
|
|
arr = field["arr"]
|
|
is_pointer = field["is_pointer"]
|
|
to_arg = field["to_arg"]
|
|
|
|
# input parameter generation
|
|
if fname not in size_params:
|
|
j_funcargs.append((fname, jtype))
|
|
# for JN/JNI, force all pointer/arrays to simple "long" type
|
|
if ftype[-1] == '*' or jtype.string_array:
|
|
jn_funcargs.append((fname, jtype_ptr))
|
|
jni_funcargs.append((fname, jtype_ptr))
|
|
else:
|
|
jn_funcargs.append((fname, jtype))
|
|
jni_funcargs.append((fname, jtype))
|
|
|
|
# determine what to pass and how (e.g. jinit code)
|
|
if jtype.jni_sig == "[Ljava/lang/String;":
|
|
raise NotImplementedError("string array")
|
|
elif jtype.jni_sig[0] == '[':
|
|
if arr:
|
|
raise NotImplementedError("sized array")
|
|
else:
|
|
jinit.append("{size_jtype} {size_fname} = {fname}.length;".format(size_jtype=field["size_jtype"].j_type, size_fname=field["size_fname"], fname=fname))
|
|
jinit.extend("%s = null;" % x for x in write_bufs)
|
|
jinit.extend(write)
|
|
jn_passedargs[fname] = to_arg
|
|
elif jtype.is_enum:
|
|
jn_passedargs[fname] = to_arg
|
|
elif jtype.is_opaque:
|
|
if is_nullok:
|
|
to_arg = "%s == null ? 0 : %s" % (fname, to_arg)
|
|
jn_passedargs[fname] = to_arg
|
|
elif jtype.is_struct:
|
|
if is_nullok:
|
|
to_arg = "%s == null ? 0 : %s" % (fname, to_arg)
|
|
jn_passedargs[fname] = to_arg
|
|
elif jtype.jni_sig[0] in java_accessor_map:
|
|
jn_passedargs[fname] = fname
|
|
elif jtype.jni_sig == "Ljava/lang/String;":
|
|
if jtype.string_array:
|
|
jinit.append("ByteBuffer {fname}_buf = ByteBuffer.allocateDirect({array_size}).order(ByteOrder.nativeOrder());".format(fname=fname, array_size=256))
|
|
jinit.extend(field["backing_write"])
|
|
jn_passedargs[fname] = "{fname} == null ? 0 : getByteBufferAddress({fname}_buf)".format(fname=fname)
|
|
else:
|
|
jinit.extend("%s = null;" % x for x in write_bufs)
|
|
jinit.extend(write)
|
|
jn_passedargs[fname] = to_arg
|
|
else:
|
|
raise ValueError("unrecognized jni signature '%s'" % jtype.jni_sig)
|
|
|
|
jrettype = rettype.j_type
|
|
|
|
outstruct_name = None
|
|
#print(name, jrettype, outparams, retarraysize, retsize)
|
|
if outparams or retarraysize or retsize:
|
|
# create a return structure
|
|
outstruct_fields = []
|
|
outstruct_size = []
|
|
for (pname, ptype, arr) in params:
|
|
if pname not in outparams:
|
|
continue
|
|
if ptype[-1] == '*':
|
|
ptype = ptype[:-1]
|
|
outstruct_fields.append((pname, ptype, arr, ""))
|
|
if arr:
|
|
if ptype == "char":
|
|
outstruct_size.append(arr)
|
|
else:
|
|
raise NotImplementedError("non-char array")
|
|
else:
|
|
outstruct_size.append("8")
|
|
outstruct_sized_members = {}
|
|
outstruct_name = name[4:] + "Result"
|
|
|
|
# create a return buffer (TODO: optimize size)
|
|
jinit.append("ByteBuffer rv_buf = ByteBuffer.allocateDirect(%s).order(ByteOrder.nativeOrder());" % "+".join(outstruct_size))
|
|
jinit.append("long rv_addr = getByteBufferAddress(rv_buf);")
|
|
|
|
jconstruct_args = [("rv_buf", "ByteBuffer")]
|
|
jconstruct = []
|
|
if retarraysize:
|
|
jconstruct_args.append(("jn_rv", "long"))
|
|
jconstruct.append("array_addr = jn_rv;")
|
|
|
|
if retarraysize:
|
|
outstruct_fields.append(("array", restype, "", ""))
|
|
outstruct_sized_members["array"] = retarraysize
|
|
elif functype != "STDFUNC":
|
|
outstruct_fields.append(("val", restype, None, ""))
|
|
|
|
helper = JavaStructEmitHelper(self, outstruct_name, outstruct_fields,
|
|
sized_members=outstruct_sized_members)
|
|
helper.config_struct_get = lambda o: "0"
|
|
jfielddefs = []
|
|
jfielddefs_private = []
|
|
off = 0
|
|
for fname, ftype, arr, comment in helper.fields:
|
|
field = helper.get_field_java_code(fname, ftype, arr, off, jfielddefs_private, backing="rv_buf")
|
|
if fname == retarraysize:
|
|
jconstruct.append(field["fielddef"].replace("public ", "").replace(fname, "array_%s" % fname))
|
|
jconstruct.extend(x.replace(fname, "array_%s" % fname) for x in field["backing_read"])
|
|
jn_passedargs[fname] = "rv_addr+%d" % off
|
|
off += 8
|
|
continue
|
|
jfielddefs.append(field["fielddef"])
|
|
|
|
if fname == "array":
|
|
#jconstruct.extend(field["backing_read"])
|
|
jconstruct.extend(field["read"])
|
|
elif fname != "val":
|
|
jn_passedargs[fname] = "rv_addr+%d" % off
|
|
off += 8
|
|
jconstruct.extend(field["construct"])
|
|
jconstruct.extend(field["backing_read"])
|
|
jconstruct.extend(field["read"])
|
|
|
|
if retarraysize:
|
|
jfielddefs.append("private long array_addr;")
|
|
|
|
# optimize len(outparams) == 1 case to directly return it.
|
|
if len(outparams) == 1 and not retarraysize and rettype.j_type == "void":
|
|
jfini.extend(x.replace("public ", "") for x in jfielddefs)
|
|
jfini.extend(jconstruct)
|
|
jretc = "return %s;" % outparams[0]
|
|
jrettype = paramtypes[outparams[0]][2].j_type
|
|
#rettype = paramtypes[outparams[0]][2]
|
|
elif len(outparams) == 1 and retsize:
|
|
jfini.extend(x.replace("public ", "") for x in jfielddefs)
|
|
jfini.extend(jconstruct)
|
|
jfini.append("val = new {type}(jn_rv, {owned}, {size});".format(type=rettype.j_type, owned="true" if retowned else "false", size=retsize))
|
|
jretc = "return val;"
|
|
else:
|
|
defined.add(outstruct_name)
|
|
jfini.append("{struct_name} rv = new {struct_name}({args});".format(struct_name=outstruct_name, args=", ".join(x[0] for x in jconstruct_args)))
|
|
if retsize:
|
|
jfini.append("rv.val = new {type}(jn_rv, {owned}, rv.{size});".format(type=rettype.j_type, owned="true" if retowned else "false", size=retsize))
|
|
elif not retarraysize and functype != "STDFUNC":
|
|
jfini.append("rv.val = new {type}(jn_rv, {owned});".format(type=rettype.j_type, owned="true" if retowned else "false"))
|
|
|
|
jrettype = outstruct_name
|
|
if retarraysize:
|
|
rettype = c_to_jtype(outstruct_name, None)
|
|
#else:
|
|
# rettype = java_types_map[("void", None)]
|
|
|
|
print("""
|
|
public static class {struct_name} {{
|
|
{jfielddefs}
|
|
private {struct_name}({jconstruct_args}) {{
|
|
{jconstruct}
|
|
}}""".format(struct_name=outstruct_name,
|
|
jfielddefs="\n ".join(jfielddefs),
|
|
jconstruct_args=", ".join("%s %s" % (x[1], x[0]) for x in jconstruct_args),
|
|
jconstruct="\n ".join(jconstruct)),
|
|
file=self.out)
|
|
if retarraysize:
|
|
print("""
|
|
@Override
|
|
protected void finalize() throws Throwable {{
|
|
imaqDispose(array_addr);
|
|
super.finalize();
|
|
}}
|
|
}}""".format(struct_name=outstruct_name), file=self.out)
|
|
else:
|
|
print(" }", file=self.out)
|
|
|
|
jretc = "return rv;"
|
|
elif functype != "STDFUNC":
|
|
if rettype.is_enum:
|
|
jretc = "return {type}.fromValue(jn_rv);".format(type=rettype.j_type)
|
|
elif rettype.is_struct or rettype.is_opaque:
|
|
jretc = "return new {type}(jn_rv, {owned});".format(type=rettype.j_type, owned="true" if retowned else "false")
|
|
else:
|
|
jretc = "return jn_rv;"
|
|
|
|
#
|
|
# Java function
|
|
#
|
|
#assert name.startswith("imaq")
|
|
#name = name[4].lower() + name[5:]
|
|
|
|
print("""
|
|
public static {rettype} {name}({args}) {{
|
|
{init}
|
|
{rv}_{name}({passedargs});
|
|
{fini}{retcode}
|
|
}}""".format(rettype=jrettype,
|
|
name=name,
|
|
args=", ".join("%s %s" % (x[1].j_type, x[0]) for x in j_funcargs),
|
|
init="\n ".join(jinit),
|
|
fini="\n ".join(jfini),
|
|
rv="%s jn_rv = " % rettype.jn_type if rettype.jn_type != "void" else "",
|
|
retcode="\n "+jretc if jretc else "",
|
|
passedargs=", ".join(jn_passedargs[x[0]] if x[0] in jn_passedargs else "UNKNOWN" for x in jn_funcargs)),
|
|
file=self.out)
|
|
|
|
#
|
|
# Native Java function
|
|
#
|
|
print(""" private static native {rettype} _{name}({args});""".format(
|
|
rettype=rettype.jn_type, name=name,
|
|
args=", ".join("%s %s" % (x[1].jn_type, x[0]) for x in jn_funcargs)),
|
|
file=self.out)
|
|
|
|
#
|
|
# C function
|
|
#
|
|
print("""
|
|
/* J: {jrettype} {name}({jargs})
|
|
* JN: {jnrettype} {name}({jnargs})
|
|
* C: {restype} {name}({cparams})
|
|
*/""".format(name=name,
|
|
jrettype=rettype.j_type,
|
|
jargs=", ".join("%s %s" % (x[1].j_type, x[0]) for x in j_funcargs),
|
|
jnrettype=rettype.jn_type,
|
|
jnargs=", ".join("%s %s" % (x[1].jn_type, x[0]) for x in jn_funcargs),
|
|
restype=restype,
|
|
cparams=", ".join("%s %s" % (ptype, pname) for pname, ptype, arr in params)),
|
|
file=self.outc)
|
|
|
|
cargs = []
|
|
for pname, ptype, arr in params:
|
|
if pname == "void":
|
|
continue
|
|
if ptype in structs:
|
|
cargs.append("*((%s*)%s)" % (ptype, pname))
|
|
elif ptype.endswith("String255"):
|
|
cargs.append("(char *)%s" % pname)
|
|
elif arr:
|
|
cargs.append("(%s*)%s" % (ptype, pname))
|
|
else:
|
|
cargs.append("(%s)%s" % (ptype, pname))
|
|
|
|
callcfunc = "{restype} rv = {name}({args});".format(name=name,
|
|
restype=restype,
|
|
args=", ".join(cargs))
|
|
|
|
print("""
|
|
JNIEXPORT {rettype} JNICALL Java_{package}_{classname}__1{name}({args})
|
|
{{
|
|
{callfunc}
|
|
{exceptioncheck}{retcode}
|
|
}}""".format(rettype=rettype.jni_type,
|
|
package=self.package.replace(".", "_"),
|
|
classname=self.classname,
|
|
name=name.replace("_", "_1"),
|
|
args=", ".join("%s %s" % (x[1].jni_type, x[0]) for x in jni_funcargs),
|
|
callfunc=callcfunc,
|
|
exceptioncheck=exceptioncheck,
|
|
retcode="\n return (%s)rv;" % rettype.jni_type if rettype.jni_type != "void" else ""),
|
|
file=self.outc)
|
|
|
|
defined.add(name)
|
|
|
|
def struct(self, name, fields):
|
|
if self.config_getboolean(name, "exclude", fallback=False):
|
|
return
|
|
if name in opaque_structs:
|
|
return
|
|
defined.add(name)
|
|
|
|
helper = JavaStructEmitHelper(self, name, fields)
|
|
print(helper.get_java_code(), file=self.out)
|
|
|
|
def union(self, name, fields):
|
|
self.unions[name] = fields
|
|
|
|
def generate(srcdir, outdir, inputs):
|
|
emit = None
|
|
|
|
for fname, config_struct_path, configpath, funcs_path in inputs:
|
|
# read config files
|
|
config_struct = configparser.ConfigParser()
|
|
config_struct.read(config_struct_path)
|
|
config = configparser.ConfigParser()
|
|
config.read(configpath)
|
|
block_comment_exclude = set(x.strip() for x in
|
|
config.get("Block Comment", "exclude").splitlines())
|
|
|
|
library_funcs = set()
|
|
with open(funcs_path) as ff:
|
|
for line in ff:
|
|
library_funcs.add(line.strip())
|
|
|
|
# open input file
|
|
with open(fname) as inf:
|
|
# prescan for undefined structures
|
|
prescan_file(inf)
|
|
inf.seek(0)
|
|
|
|
if emit is None:
|
|
emit = JavaEmitter(outdir, config, config_struct, library_funcs)
|
|
else:
|
|
emit.config = config
|
|
emit.config_struct = config_struct
|
|
emit.library_funcs = library_funcs
|
|
|
|
# generate
|
|
parse_file(emit, inf, block_comment_exclude)
|
|
|
|
emit.finish()
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 5 or ((len(sys.argv)-1) % 4) != 0:
|
|
print("Usage: gen_wrap.py <header.h config_struct.ini config.ini funcs.txt>...")
|
|
exit(0)
|
|
|
|
inputs = []
|
|
for i in range(1, len(sys.argv), 4):
|
|
fname = sys.argv[i]
|
|
config_struct_name = sys.argv[i+1]
|
|
configname = sys.argv[i+2]
|
|
funcs_name = sys.argv[i+3]
|
|
inputs.append((fname, config_struct_name, configname, funcs_name))
|
|
|
|
generate("", "", inputs)
|