Files
allwpilib/wpilibj/wpilibJavaJNI/nivision/gen_java.py
Peter Johnson ce7a56284f Fix a few major nivision Java wrapper issues.
- 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
2015-01-13 22:18:17 -08:00

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)