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