368 lines
12 KiB
Python
Executable File
368 lines
12 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
#
|
|
# Copyright (C) 2011 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
import os
|
|
import sys
|
|
|
|
hFileTemplate = """/**
|
|
* This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
|
|
**/
|
|
|
|
#ifndef %s
|
|
#define %s
|
|
|
|
%s
|
|
|
|
#endif // %s
|
|
"""
|
|
|
|
jniFileTemplate = """/**
|
|
* This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
|
|
**/
|
|
|
|
#include <stdint.h>
|
|
#include "native/%s.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "jni.h"
|
|
|
|
// Helper functions ////////////////////////////////////////////////////////////////////////////////
|
|
%s* Get%sAtIndex(JNIEnv* env, jobject buffer, int index) {
|
|
jclass base_class = (*env)->FindClass(env, "android/filterfw/core/NativeBuffer");
|
|
jfieldID ptr_field = (*env)->GetFieldID(env, base_class, "mDataPointer", "J");
|
|
uintptr_t data_ptr = (*env)->GetLongField(env, buffer, ptr_field);
|
|
%s* array = (%s*)data_ptr;
|
|
(*env)->DeleteLocalRef(env, base_class);
|
|
return &array[index];
|
|
}
|
|
|
|
// Declarations ////////////////////////////////////////////////////////////////////////////////////
|
|
JNIEXPORT jint JNICALL
|
|
Java_%s_getElementSize(JNIEnv* env, jobject thiz);
|
|
|
|
%s
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
// Implementation //////////////////////////////////////////////////////////////////////////////////
|
|
jint Java_%s_getElementSize(JNIEnv* env, jobject thiz) {
|
|
return sizeof(%s);
|
|
}
|
|
|
|
%s
|
|
"""
|
|
|
|
javaFileTemplate = """/**
|
|
* This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
|
|
**/
|
|
|
|
package %s;
|
|
|
|
import android.filterfw.core.NativeBuffer;
|
|
|
|
%s
|
|
"""
|
|
|
|
|
|
def ToJavaName(cname, start_upper_at = 1):
|
|
lower = cname.split("_")
|
|
upper = [c.title() for c in lower]
|
|
return "".join(lower[:start_upper_at] + upper[start_upper_at:])
|
|
|
|
def ToJNIPackage(package, jclassname):
|
|
return "%s_%s" % (package.replace(".", "_"), jclassname)
|
|
|
|
def ToMacroDefName(cname, pname):
|
|
return "%s_%s" % (pname.replace(".", "_").upper(), cname.upper())
|
|
|
|
class ParseError:
|
|
def __init__(self, lineno, message):
|
|
self.lineno = lineno
|
|
self.message = message
|
|
|
|
def __str__(self):
|
|
return "On line %d: %s" % (self.lineno, self.message)
|
|
|
|
class FieldType_BasePOD:
|
|
def __init__(self, name, structname, jclassname, package, javatype, ctype, jtype, defval):
|
|
self.name = name
|
|
self.structname = structname
|
|
self.jclassname = jclassname
|
|
self.package = package
|
|
self.javatype = javatype
|
|
self.ctype = ctype
|
|
self.jtype = jtype
|
|
self.defval = defval
|
|
|
|
def cString(self):
|
|
return " %s %s;" % (self.ctype, self.name)
|
|
|
|
def javaGetter(self):
|
|
return " public %s get%s(int index) {\n"\
|
|
" assertReadable();\n"\
|
|
" return nativeGet%s(index);\n"\
|
|
" }" % (self.javatype, ToJavaName(self.name, 0), ToJavaName(self.name, 0))
|
|
|
|
def javaSetter(self):
|
|
return " public void set%s(int index, %s value) {\n"\
|
|
" assertWritable();\n"\
|
|
" nativeSet%s(index, value);\n"\
|
|
" }" % (ToJavaName(self.name, 0), self.javatype, ToJavaName(self.name, 0))
|
|
|
|
def javaNativeGetter(self):
|
|
return " private native %s nativeGet%s(int index);"\
|
|
% (self.javatype, ToJavaName(self.name, 0))
|
|
|
|
def javaNativeSetter(self):
|
|
return " private native boolean nativeSet%s(int index, %s value);"\
|
|
% (ToJavaName(self.name, 0), self.javatype)
|
|
|
|
def jniGetterDefString(self):
|
|
return "JNIEXPORT %s JNICALL\n" \
|
|
"Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index);" \
|
|
% (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0))
|
|
|
|
def jniGetterImplString(self):
|
|
return \
|
|
"%s Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index) {\n"\
|
|
" %s* instance = Get%sAtIndex(env, thiz, index);\n"\
|
|
" return instance ? instance->%s : %s;\n"\
|
|
"}\n" % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
|
|
self.structname, self.structname, self.name, self.defval)
|
|
|
|
def jniSetterDefString(self):
|
|
return "JNIEXPORT jboolean JNICALL\n" \
|
|
"Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value);" \
|
|
% (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0), self.jtype)
|
|
|
|
def jniSetterImplString(self):
|
|
return \
|
|
"jboolean Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value) {\n"\
|
|
" %s* instance = Get%sAtIndex(env, thiz, index);\n"\
|
|
" if (instance) {\n"\
|
|
" instance->%s = value;\n"\
|
|
" return JNI_TRUE;\n"\
|
|
" }\n"\
|
|
" return JNI_FALSE;\n"\
|
|
"}\n" % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
|
|
self.jtype, self.structname, self.structname, self.name)
|
|
|
|
class FieldType_Float(FieldType_BasePOD):
|
|
def __init__(self, name, structname, jclassname, package):
|
|
FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "float", "float", "jfloat", "0.0")
|
|
|
|
class FieldType_Int(FieldType_BasePOD):
|
|
def __init__(self, name, structname, jclassname, package):
|
|
FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "int", "int", "jint", "0")
|
|
|
|
class FieldType_Long(FieldType_BasePOD):
|
|
def __init__(self, name, structname, jclassname, package):
|
|
FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "long", "long long", "jlong", "0")
|
|
|
|
class StructSpec:
|
|
|
|
def parseTextFile(self, filepath):
|
|
# Init
|
|
self.name = None
|
|
self.package = None
|
|
self.fields = []
|
|
self.structname = None
|
|
self.jclassname = None
|
|
self.libname = None
|
|
|
|
# Open the file
|
|
txtfile = open(filepath)
|
|
|
|
# Parse it line by line
|
|
lineno = 0
|
|
for line in txtfile:
|
|
# Split line into components
|
|
linecomps = line.split()
|
|
if len(linecomps) == 0:
|
|
continue
|
|
|
|
# Execute command
|
|
cmd = linecomps[0]
|
|
if cmd == "@name":
|
|
self.commandArgAssert(linecomps, 1, lineno)
|
|
self.name = linecomps[1]
|
|
if not self.structname:
|
|
self.structname = self.name
|
|
if not self.jclassname:
|
|
self.jclassname = self.name
|
|
elif cmd == "@package":
|
|
self.commandArgAssert(linecomps, 1, lineno)
|
|
self.package = linecomps[1]
|
|
elif cmd == "@libname":
|
|
self.commandArgAssert(linecomps, 1, lineno)
|
|
self.libname = linecomps[1]
|
|
elif cmd == "@structname":
|
|
self.commandArgAssert(linecomps, 1, lineno)
|
|
self.structname = linecomps[1]
|
|
elif cmd == "@javaclassname":
|
|
self.commandArgAssert(linecomps, 1, lineno)
|
|
self.jclassname = linecomps[1]
|
|
elif cmd == "@field":
|
|
self.commandArgAssert(linecomps, 2, lineno)
|
|
typestr = linecomps[1]
|
|
if typestr == "int":
|
|
fieldtype = FieldType_Int(linecomps[2], self.structname, self.jclassname, self.package)
|
|
elif typestr == "long":
|
|
fieldtype = FieldType_Long(linecomps[2], self.structname, self.jclassname, self.package)
|
|
elif typestr == "float":
|
|
fieldtype = FieldType_Float(linecomps[2], self.structname, self.jclassname, self.package)
|
|
else:
|
|
raise ParseError(lineno, "Unknown field type '%s'!" % typestr)
|
|
self.fields.append(fieldtype)
|
|
else:
|
|
raise ParseError(lineno, "Unknown command: '%s'!" % cmd)
|
|
|
|
lineno = lineno + 1
|
|
|
|
# Make sure we have all required info
|
|
if not self.name:
|
|
raise ParseError(lineno, "Required field '@name' missing!")
|
|
elif not self.package:
|
|
raise ParseError(lineno, "Required field '@package' missing!")
|
|
elif not self.libname:
|
|
raise ParseError(lineno, "Required field '@libname' missing!")
|
|
|
|
# Normalize values
|
|
if self.libname[:3] == "lib":
|
|
self.libname = self.libname[3:]
|
|
|
|
def commandArgAssert(self, linecomps, expectedcount, lineno):
|
|
foundcount = len(linecomps) - 1
|
|
if foundcount < expectedcount:
|
|
raise ParseError(lineno, "Not enough arguments specifed for command '%s'! Expected %d, " \
|
|
"but got only %d!" % (linecomps[0], expectedcount, foundcount))
|
|
elif foundcount > expectedcount + 1:
|
|
raise ParseError(lineno, "Too many arguments specifed for command '%s'! Expected %d, " \
|
|
"but got %d!" % (linecomps[0], expectedcount, foundcount))
|
|
|
|
|
|
def cStructString(self):
|
|
cfields = [f.cString() for f in self.fields]
|
|
return "typedef struct Struct%s {\n%s\n} %s;\n" % (self.structname,\
|
|
"\n".join(cfields),\
|
|
self.structname)
|
|
|
|
def javaClassString(self):
|
|
jgetters = [f.javaGetter() for f in self.fields]
|
|
jsetters = [f.javaSetter() for f in self.fields]
|
|
jnativesetters = [f.javaNativeSetter() for f in self.fields]
|
|
jnativegetters = [f.javaNativeGetter() for f in self.fields]
|
|
return "public class %s extends NativeBuffer {\n\n"\
|
|
" public %s() {\n"\
|
|
" super();\n"\
|
|
" }\n"\
|
|
"\n"\
|
|
" public %s(int count) {\n"\
|
|
" super(count);\n"\
|
|
" }\n"\
|
|
"\n"\
|
|
" public native int getElementSize();\n"\
|
|
"\n"\
|
|
"%s\n\n"\
|
|
"%s\n\n"\
|
|
"%s\n\n"\
|
|
"%s\n\n"\
|
|
" static {\n"\
|
|
" System.loadLibrary(\"%s\");\n"\
|
|
" }\n"\
|
|
"\n"\
|
|
"};\n" % (self.jclassname,\
|
|
self.jclassname,\
|
|
self.jclassname,\
|
|
"\n\n".join(jgetters),\
|
|
"\n\n".join(jsetters),\
|
|
"\n\n".join(jnativegetters),\
|
|
"\n\n".join(jnativesetters),\
|
|
self.libname)
|
|
|
|
def jniDeclString(self):
|
|
jnigetters = [f.jniGetterDefString() for f in self.fields]
|
|
jnisetters = [f.jniSetterDefString() for f in self.fields]
|
|
return "\n\n".join(jnigetters + jnisetters)
|
|
|
|
def jniImplString(self):
|
|
jnigetters = [f.jniGetterImplString() for f in self.fields]
|
|
jnisetters = [f.jniSetterImplString() for f in self.fields]
|
|
return "\n\n".join(jnigetters + jnisetters)
|
|
|
|
def hFileString(self):
|
|
defname = ToMacroDefName(self.structname, self.package)
|
|
return hFileTemplate % (defname, defname, self.cStructString(), defname)
|
|
|
|
def javaFileString(self):
|
|
return javaFileTemplate % (self.package, self.javaClassString())
|
|
|
|
def jniFileString(self):
|
|
return jniFileTemplate % (self.structname.lower(),\
|
|
self.structname,\
|
|
self.structname,\
|
|
self.structname,\
|
|
self.structname,\
|
|
ToJNIPackage(self.package, self.jclassname),\
|
|
self.jniDeclString(),\
|
|
ToJNIPackage(self.package, self.jclassname),\
|
|
self.structname,
|
|
self.jniImplString())
|
|
|
|
def main(argv):
|
|
if len(argv) != 2:
|
|
print("Usage: %s <file.struct>" % argv[0])
|
|
return -1
|
|
|
|
filepath = argv[1]
|
|
|
|
structspec = StructSpec()
|
|
structspec.parseTextFile(filepath)
|
|
|
|
hfilename = "%s.h" % structspec.structname.lower()
|
|
javafilename = "%s.java" % structspec.jclassname
|
|
jnifilename = "jni_%s.c" % structspec.structname.lower()
|
|
|
|
javapackagepath = structspec.package.replace('.','/')
|
|
|
|
rootdir = os.path.dirname(filepath)
|
|
hfilepath = "%s/../native/%s" % (rootdir, hfilename)
|
|
javafilepath = "%s/../java/%s/%s" % (rootdir, javapackagepath, javafilename)
|
|
jnifilepath = "%s/../jni/%s" % (rootdir, jnifilename)
|
|
|
|
hfile = open(hfilepath, 'w')
|
|
hfile.write(structspec.hFileString())
|
|
hfile.close()
|
|
|
|
javafile = open(javafilepath, 'w')
|
|
javafile.write(structspec.javaFileString())
|
|
javafile.close()
|
|
|
|
jnifile = open(jnifilepath, 'w')
|
|
jnifile.write(structspec.jniFileString())
|
|
jnifile.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv))
|