Home | History | Annotate | Download | only in mca
      1 #!/usr/bin/env python
      2 
      3 #
      4 # Copyright (C) 2011 The Android Open Source Project
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #      http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 #
     18 
     19 import os
     20 import sys
     21 
     22 hFileTemplate = """/**
     23  * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
     24  **/
     25 
     26 #ifndef %s
     27 #define %s
     28 
     29 %s
     30 
     31 #endif // %s
     32 """
     33 
     34 jniFileTemplate = """/**
     35  * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
     36  **/
     37 
     38 #include <stdint.h>
     39 #include "native/%s.h"
     40 
     41 #ifdef __cplusplus
     42 extern "C" {
     43 #endif
     44 
     45 #include "jni.h"
     46 
     47 // Helper functions ////////////////////////////////////////////////////////////////////////////////
     48 %s* Get%sAtIndex(JNIEnv* env, jobject buffer, int index) {
     49   jclass base_class = (*env)->FindClass(env, "android/filterfw/core/NativeBuffer");
     50   jfieldID ptr_field = (*env)->GetFieldID(env, base_class, "mDataPointer", "J");
     51   uintptr_t data_ptr = (*env)->GetLongField(env, buffer, ptr_field);
     52   %s* array = (%s*)data_ptr;
     53   (*env)->DeleteLocalRef(env, base_class);
     54   return &array[index];
     55 }
     56 
     57 // Declarations ////////////////////////////////////////////////////////////////////////////////////
     58 JNIEXPORT jint JNICALL
     59 Java_%s_getElementSize(JNIEnv* env, jobject thiz);
     60 
     61 %s
     62 
     63 #ifdef __cplusplus
     64 }
     65 #endif
     66 
     67 // Implementation //////////////////////////////////////////////////////////////////////////////////
     68 jint Java_%s_getElementSize(JNIEnv* env, jobject thiz) {
     69   return sizeof(%s);
     70 }
     71 
     72 %s
     73 """
     74 
     75 javaFileTemplate = """/**
     76  * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify!
     77  **/
     78 
     79 package %s;
     80 
     81 import android.filterfw.core.NativeBuffer;
     82 
     83 %s
     84 """
     85 
     86 
     87 def ToJavaName(cname, start_upper_at = 1):
     88   lower = cname.split("_")
     89   upper = [c.title() for c in lower]
     90   return "".join(lower[:start_upper_at] + upper[start_upper_at:])
     91 
     92 def ToJNIPackage(package, jclassname):
     93   return "%s_%s" % (package.replace(".", "_"), jclassname)
     94 
     95 def ToMacroDefName(cname, pname):
     96   return "%s_%s" % (pname.replace(".", "_").upper(), cname.upper())
     97 
     98 class ParseError:
     99   def __init__(self, lineno, message):
    100     self.lineno = lineno
    101     self.message = message
    102 
    103   def __str__(self):
    104     return "On line %d: %s" % (self.lineno, self.message)
    105 
    106 class FieldType_BasePOD:
    107   def __init__(self, name, structname, jclassname, package, javatype, ctype, jtype, defval):
    108     self.name = name
    109     self.structname = structname
    110     self.jclassname = jclassname
    111     self.package = package
    112     self.javatype = javatype
    113     self.ctype = ctype
    114     self.jtype = jtype
    115     self.defval = defval
    116 
    117   def cString(self):
    118     return "  %s %s;" % (self.ctype, self.name)
    119 
    120   def javaGetter(self):
    121     return "    public %s get%s(int index) {\n"\
    122            "        assertReadable();\n"\
    123            "        return nativeGet%s(index);\n"\
    124            "    }" % (self.javatype, ToJavaName(self.name, 0), ToJavaName(self.name, 0))
    125 
    126   def javaSetter(self):
    127     return "    public void set%s(int index, %s value) {\n"\
    128            "        assertWritable();\n"\
    129            "        nativeSet%s(index, value);\n"\
    130            "    }" % (ToJavaName(self.name, 0), self.javatype, ToJavaName(self.name, 0))
    131 
    132   def javaNativeGetter(self):
    133     return "    private native %s nativeGet%s(int index);"\
    134            % (self.javatype, ToJavaName(self.name, 0))
    135 
    136   def javaNativeSetter(self):
    137     return "    private native boolean nativeSet%s(int index, %s value);"\
    138            % (ToJavaName(self.name, 0), self.javatype)
    139 
    140   def jniGetterDefString(self):
    141     return "JNIEXPORT %s JNICALL\n" \
    142            "Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index);" \
    143            % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0))
    144 
    145   def jniGetterImplString(self):
    146     return \
    147       "%s Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index) {\n"\
    148       "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
    149       "  return instance ? instance->%s : %s;\n"\
    150       "}\n" % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
    151                self.structname, self.structname, self.name, self.defval)
    152 
    153   def jniSetterDefString(self):
    154     return "JNIEXPORT jboolean JNICALL\n" \
    155            "Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value);" \
    156            % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0), self.jtype)
    157 
    158   def jniSetterImplString(self):
    159     return \
    160       "jboolean Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value) {\n"\
    161       "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
    162       "  if (instance) {\n"\
    163       "    instance->%s = value;\n"\
    164       "    return JNI_TRUE;\n"\
    165       "  }\n"\
    166       "  return JNI_FALSE;\n"\
    167       "}\n" % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
    168                self.jtype, self.structname, self.structname, self.name)
    169 
    170 class FieldType_Float(FieldType_BasePOD):
    171   def __init__(self, name, structname, jclassname, package):
    172     FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "float", "float", "jfloat", "0.0")
    173 
    174 class FieldType_Int(FieldType_BasePOD):
    175   def __init__(self, name, structname, jclassname, package):
    176     FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "int", "int", "jint", "0")
    177 
    178 class FieldType_Long(FieldType_BasePOD):
    179   def __init__(self, name, structname, jclassname, package):
    180     FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "long", "long long", "jlong", "0")
    181 
    182 class StructSpec:
    183 
    184   def parseTextFile(self, filepath):
    185     # Init
    186     self.name = None
    187     self.package = None
    188     self.fields = []
    189     self.structname = None
    190     self.jclassname = None
    191     self.libname = None
    192 
    193     # Open the file
    194     txtfile = open(filepath)
    195 
    196     # Parse it line by line
    197     lineno = 0
    198     for line in txtfile:
    199       # Split line into components
    200       linecomps = line.split()
    201       if len(linecomps) == 0:
    202         continue
    203 
    204       # Execute command
    205       cmd = linecomps[0]
    206       if cmd == "@name":
    207         self.commandArgAssert(linecomps, 1, lineno)
    208         self.name = linecomps[1]
    209         if not self.structname:
    210           self.structname = self.name
    211         if not self.jclassname:
    212           self.jclassname = self.name
    213       elif cmd == "@package":
    214         self.commandArgAssert(linecomps, 1, lineno)
    215         self.package = linecomps[1]
    216       elif cmd == "@libname":
    217         self.commandArgAssert(linecomps, 1, lineno)
    218         self.libname = linecomps[1]
    219       elif cmd == "@structname":
    220         self.commandArgAssert(linecomps, 1, lineno)
    221         self.structname = linecomps[1]
    222       elif cmd == "@javaclassname":
    223         self.commandArgAssert(linecomps, 1, lineno)
    224         self.jclassname = linecomps[1]
    225       elif cmd == "@field":
    226         self.commandArgAssert(linecomps, 2, lineno)
    227         typestr = linecomps[1]
    228         if typestr == "int":
    229           fieldtype = FieldType_Int(linecomps[2], self.structname, self.jclassname, self.package)
    230         elif typestr == "long":
    231           fieldtype = FieldType_Long(linecomps[2], self.structname, self.jclassname, self.package)
    232         elif typestr == "float":
    233           fieldtype = FieldType_Float(linecomps[2], self.structname, self.jclassname, self.package)
    234         else:
    235           raise ParseError(lineno, "Unknown field type '%s'!" % typestr)
    236         self.fields.append(fieldtype)
    237       else:
    238         raise ParseError(lineno, "Unknown command: '%s'!" % cmd)
    239 
    240       lineno = lineno + 1
    241 
    242     # Make sure we have all required info
    243     if not self.name:
    244       raise ParseError(lineno, "Required field '@name' missing!")
    245     elif not self.package:
    246       raise ParseError(lineno, "Required field '@package' missing!")
    247     elif not self.libname:
    248       raise ParseError(lineno, "Required field '@libname' missing!")
    249 
    250     # Normalize values
    251     if self.libname[:3] == "lib":
    252       self.libname = self.libname[3:]
    253 
    254   def commandArgAssert(self, linecomps, expectedcount, lineno):
    255     foundcount = len(linecomps) - 1
    256     if foundcount < expectedcount:
    257       raise ParseError(lineno, "Not enough arguments specifed for command '%s'! Expected %d, " \
    258                        "but got only %d!" % (linecomps[0], expectedcount, foundcount))
    259     elif foundcount > expectedcount + 1:
    260       raise ParseError(lineno, "Too many arguments specifed for command '%s'! Expected %d, " \
    261                        "but got %d!" % (linecomps[0], expectedcount, foundcount))
    262 
    263 
    264   def cStructString(self):
    265     cfields = [f.cString() for f in self.fields]
    266     return "typedef struct Struct%s {\n%s\n} %s;\n" % (self.structname,\
    267                                                        "\n".join(cfields),\
    268                                                        self.structname)
    269 
    270   def javaClassString(self):
    271     jgetters = [f.javaGetter() for f in self.fields]
    272     jsetters = [f.javaSetter() for f in self.fields]
    273     jnativesetters = [f.javaNativeSetter() for f in self.fields]
    274     jnativegetters = [f.javaNativeGetter() for f in self.fields]
    275     return "public class %s extends NativeBuffer {\n\n"\
    276            "    public %s() {\n"\
    277            "        super();\n"\
    278            "    }\n"\
    279            "\n"\
    280            "    public %s(int count) {\n"\
    281            "        super(count);\n"\
    282            "    }\n"\
    283            "\n"\
    284            "    public native int getElementSize();\n"\
    285            "\n"\
    286            "%s\n\n"\
    287            "%s\n\n"\
    288            "%s\n\n"\
    289            "%s\n\n"\
    290            "    static {\n"\
    291            "        System.loadLibrary(\"%s\");\n"\
    292            "    }\n"\
    293            "\n"\
    294            "};\n" % (self.jclassname,\
    295                      self.jclassname,\
    296                      self.jclassname,\
    297                      "\n\n".join(jgetters),\
    298                      "\n\n".join(jsetters),\
    299                      "\n\n".join(jnativegetters),\
    300                      "\n\n".join(jnativesetters),\
    301                      self.libname)
    302 
    303   def jniDeclString(self):
    304     jnigetters = [f.jniGetterDefString() for f in self.fields]
    305     jnisetters = [f.jniSetterDefString() for f in self.fields]
    306     return "\n\n".join(jnigetters + jnisetters)
    307 
    308   def jniImplString(self):
    309     jnigetters = [f.jniGetterImplString() for f in self.fields]
    310     jnisetters = [f.jniSetterImplString() for f in self.fields]
    311     return "\n\n".join(jnigetters + jnisetters)
    312 
    313   def hFileString(self):
    314     defname = ToMacroDefName(self.structname, self.package)
    315     return hFileTemplate % (defname, defname, self.cStructString(), defname)
    316 
    317   def javaFileString(self):
    318     return javaFileTemplate % (self.package, self.javaClassString())
    319 
    320   def jniFileString(self):
    321     return jniFileTemplate % (self.structname.lower(),\
    322                               self.structname,\
    323                               self.structname,\
    324                               self.structname,\
    325                               self.structname,\
    326                               ToJNIPackage(self.package, self.jclassname),\
    327                               self.jniDeclString(),\
    328                               ToJNIPackage(self.package, self.jclassname),\
    329                               self.structname,
    330                               self.jniImplString())
    331 
    332 def main(argv):
    333   if len(argv) != 2:
    334     print("Usage: %s <file.struct>" % argv[0])
    335     return -1
    336 
    337   filepath = argv[1]
    338 
    339   structspec = StructSpec()
    340   structspec.parseTextFile(filepath)
    341 
    342   hfilename = "%s.h" % structspec.structname.lower()
    343   javafilename = "%s.java" % structspec.jclassname
    344   jnifilename = "jni_%s.c" % structspec.structname.lower()
    345 
    346   javapackagepath = structspec.package.replace('.','/')
    347 
    348   rootdir = os.path.dirname(filepath)
    349   hfilepath = "%s/../native/%s" % (rootdir, hfilename)
    350   javafilepath = "%s/../java/%s/%s" % (rootdir, javapackagepath, javafilename)
    351   jnifilepath = "%s/../jni/%s" % (rootdir, jnifilename)
    352 
    353   hfile = open(hfilepath, 'w')
    354   hfile.write(structspec.hFileString())
    355   hfile.close()
    356 
    357   javafile = open(javafilepath, 'w')
    358   javafile.write(structspec.javaFileString())
    359   javafile.close()
    360 
    361   jnifile = open(jnifilepath, 'w')
    362   jnifile.write(structspec.jniFileString())
    363   jnifile.close()
    364 
    365 
    366 if __name__ == "__main__":
    367   sys.exit(main(sys.argv))
    368