| #!/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)) |