mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
- sliceByteBuffer() was not setting native order on the duplicated buffer. This caused all array-copyin functions to generate bad values. - Correctly handle unsigned byte and unsigned short values. These could read/write to bad locations previously. - Implement custom version of imaqReadFile() to always pass in NULL for the colorTable. Eventually a more-complete version should be written. Also this works around a crash in imaqGetErrorText() by not calling it from throwJavaException(). It's not clear why imaqGetErrorText() is crashing at present (my best guess is there's still something fishy with multiple C++ lib versions getting loaded somehow), as this used to work. Instead, the exception now just gives the error code without the error message, which is not user friendly but at least doesn't crash. This will be fixed in a future commit by creating our own version of imaqGetErrorText() based on the information available in the header file. Change-Id: I4d099e62ee41f8e2a50089806561be191cb5d9d7
1946 lines
76 KiB
Python
1946 lines
76 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):
|
|
self.outdir = outdir
|
|
self.config = config
|
|
self.config_struct = config_struct
|
|
self.package = "com.ni.vision"
|
|
self.classname = "NIVision"
|
|
self.classpath = self.package.replace(".", "/") + "/" + self.classname
|
|
|
|
self.unions = {}
|
|
|
|
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) {{
|
|
ByteBuffer new_bb = bb.duplicate().order(ByteOrder.nativeOrder());
|
|
new_bb.position(offset);
|
|
new_bb.limit(size);
|
|
return new_bb;
|
|
}}
|
|
|
|
public static ByteBuffer getBytes(ByteBuffer bb, byte[] dst, int offset, int size) {{
|
|
for (int i=offset; i<offset+size; i++)
|
|
dst[i] = bb.get(i);
|
|
return bb;
|
|
}}
|
|
|
|
public static ByteBuffer putBytes(ByteBuffer bb, byte[] src, int offset, int size) {{
|
|
for (int i=offset; i<offset+size; i++)
|
|
bb.put(i, src[i]);
|
|
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>
|
|
|
|
// throw java exception
|
|
static void throwJavaException(JNIEnv *env) {{
|
|
jclass je = env->FindClass("{packagepath}/VisionException");
|
|
int err = imaqGetLastError();
|
|
//char* err_text = imaqGetErrorText(err);
|
|
//char* full_err_msg = (char*)malloc(30+strlen(err_text));
|
|
//sprintf(full_err_msg, "imaqError: %d: %s", err, err_text);
|
|
//imaqDispose(err_text);
|
|
char* full_err_msg = (char*)malloc(30);
|
|
sprintf(full_err_msg, "imaqError: %d", err);
|
|
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");
|
|
char* err_text = (char*)malloc(200);
|
|
IMAQdxGetErrorString(err, err_text, 200);
|
|
char* full_err_msg = (char*)malloc(250);
|
|
sprintf(full_err_msg, "IMAQdxError: %d: %s", err, err_text);
|
|
free(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("}", 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
|
|
if name.startswith("ERR_"):
|
|
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
|
|
|
|
# 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 vname.startswith("IMAQ_"):
|
|
vname = vname[5:]
|
|
if vname.startswith("IMAQdx"):
|
|
vname = vname[6:]
|
|
if vname[0] in "0123456789":
|
|
vname = "C" + vname
|
|
if value is None:
|
|
# auto-increment
|
|
value = "%d" % (prev_value + 1)
|
|
valuestrs.append("%s(%s),%s" % (vname, value, " // %s" % comment if comment else ""))
|
|
defined.add(vname)
|
|
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
|
|
|
|
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 == "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 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())
|
|
|
|
# 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)
|
|
else:
|
|
emit.config = config
|
|
emit.config_struct = config_struct
|
|
|
|
# generate
|
|
parse_file(emit, inf, block_comment_exclude)
|
|
|
|
emit.finish()
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 4 or ((len(sys.argv)-1) % 3) != 0:
|
|
print("Usage: gen_wrap.py <header.h config_struct.ini config.ini>...")
|
|
exit(0)
|
|
|
|
inputs = []
|
|
for i in range(1, len(sys.argv), 3):
|
|
fname = sys.argv[i]
|
|
config_struct_name = sys.argv[i+1]
|
|
configname = sys.argv[i+2]
|
|
inputs.append((fname, config_struct_name, configname))
|
|
|
|
generate("", "", inputs)
|