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, ctype, jtype, defval):
    108     self.name = name
    109     self.structname = structname
    110     self.jclassname = jclassname
    111     self.package = package
    112     self.ctype = ctype
    113     self.jtype = jtype
    114     self.defval = defval
    115 
    116   def cString(self):
    117     return "  %s %s;" % (self.ctype, self.name)
    118 
    119   def javaGetter(self):
    120     return "    public %s get%s(int index) {\n"\
    121            "        assertReadable();\n"\
    122            "        return nativeGet%s(index);\n"\
    123            "    }" % (self.ctype, ToJavaName(self.name, 0), ToJavaName(self.name, 0))
    124 
    125   def javaSetter(self):
    126     return "    public void set%s(int index, %s value) {\n"\
    127            "        assertWritable();\n"\
    128            "        nativeSet%s(index, value);\n"\
    129            "    }" % (ToJavaName(self.name, 0), self.ctype, ToJavaName(self.name, 0))
    130 
    131   def javaNativeGetter(self):
    132     return "    private native %s nativeGet%s(int index);"\
    133            % (self.ctype, ToJavaName(self.name, 0))
    134 
    135   def javaNativeSetter(self):
    136     return "    private native boolean nativeSet%s(int index, %s value);"\
    137            % (ToJavaName(self.name, 0), self.ctype)
    138 
    139   def jniGetterDefString(self):
    140     return "JNIEXPORT %s JNICALL\n" \
    141            "Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index);" \
    142            % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0))
    143 
    144   def jniGetterImplString(self):
    145     return \
    146       "%s Java_%s_nativeGet%s(JNIEnv* env, jobject thiz, jint index) {\n"\
    147       "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
    148       "  return instance ? instance->%s : %s;\n"\
    149       "}\n" % (self.jtype, ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
    150                self.structname, self.structname, self.name, self.defval)
    151 
    152   def jniSetterDefString(self):
    153     return "JNIEXPORT jboolean JNICALL\n" \
    154            "Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value);" \
    155            % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0), self.jtype)
    156 
    157   def jniSetterImplString(self):
    158     return \
    159       "jboolean Java_%s_nativeSet%s(JNIEnv* env, jobject thiz, jint index, %s value) {\n"\
    160       "  %s* instance = Get%sAtIndex(env, thiz, index);\n"\
    161       "  if (instance) {\n"\
    162       "    instance->%s = value;\n"\
    163       "    return JNI_TRUE;\n"\
    164       "  }\n"\
    165       "  return JNI_FALSE;\n"\
    166       "}\n" % (ToJNIPackage(self.package, self.jclassname), ToJavaName(self.name, 0),\
    167                self.jtype, self.structname, self.structname, self.name)
    168 
    169 class FieldType_Float(FieldType_BasePOD):
    170   def __init__(self, name, structname, jclassname, package):
    171     FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "float", "jfloat", "0.0")
    172 
    173 class FieldType_Int(FieldType_BasePOD):
    174   def __init__(self, name, structname, jclassname, package):
    175     FieldType_BasePOD.__init__(self, name, structname, jclassname, package, "int", "jint", "0")
    176 
    177 class StructSpec:
    178 
    179   def parseTextFile(self, filepath):
    180     # Init
    181     self.name = None
    182     self.package = None
    183     self.fields = []
    184     self.structname = None
    185     self.jclassname = None
    186     self.libname = None
    187 
    188     # Open the file
    189     txtfile = open(filepath)
    190 
    191     # Parse it line by line
    192     lineno = 0
    193     for line in txtfile:
    194       # Split line into components
    195       linecomps = line.split()
    196       if len(linecomps) == 0:
    197         continue
    198 
    199       # Execute command
    200       cmd = linecomps[0]
    201       if cmd == "@name":
    202         self.commandArgAssert(linecomps, 1, lineno)
    203         self.name = linecomps[1]
    204         if not self.structname:
    205           self.structname = self.name
    206         if not self.jclassname:
    207           self.jclassname = self.name
    208       elif cmd == "@package":
    209         self.commandArgAssert(linecomps, 1, lineno)
    210         self.package = linecomps[1]
    211       elif cmd == "@libname":
    212         self.commandArgAssert(linecomps, 1, lineno)
    213         self.libname = linecomps[1]
    214       elif cmd == "@structname":
    215         self.commandArgAssert(linecomps, 1, lineno)
    216         self.structname = linecomps[1]
    217       elif cmd == "@javaclassname":
    218         self.commandArgAssert(linecomps, 1, lineno)
    219         self.jclassname = linecomps[1]
    220       elif cmd == "@field":
    221         self.commandArgAssert(linecomps, 2, lineno)
    222         typestr = linecomps[1]
    223         if typestr == "int":
    224           fieldtype = FieldType_Int(linecomps[2], self.structname, self.jclassname, self.package)
    225         elif typestr == "float":
    226           fieldtype = FieldType_Float(linecomps[2], self.structname, self.jclassname, self.package)
    227         else:
    228           raise ParseError(lineno, "Unknown field type '%s'!" % typestr)
    229         self.fields.append(fieldtype)
    230       else:
    231         raise ParseError(lineno, "Unknown command: '%s'!" % cmd)
    232 
    233       lineno = lineno + 1
    234 
    235     # Make sure we have all required info
    236     if not self.name:
    237       raise ParseError(lineno, "Required field '@name' missing!")
    238     elif not self.package:
    239       raise ParseError(lineno, "Required field '@package' missing!")
    240     elif not self.libname:
    241       raise ParseError(lineno, "Required field '@libname' missing!")
    242 
    243     # Normalize values
    244     if self.libname[:3] == "lib":
    245       self.libname = self.libname[3:]
    246 
    247   def commandArgAssert(self, linecomps, expectedcount, lineno):
    248     foundcount = len(linecomps) - 1
    249     if foundcount < expectedcount:
    250       raise ParseError(lineno, "Not enough arguments specifed for command '%s'! Expected %d, " \
    251                        "but got only %d!" % (linecomps[0], expectedcount, foundcount))
    252     elif foundcount > expectedcount + 1:
    253       raise ParseError(lineno, "Too many arguments specifed for command '%s'! Expected %d, " \
    254                        "but got %d!" % (linecomps[0], expectedcount, foundcount))
    255 
    256 
    257   def cStructString(self):
    258     cfields = [f.cString() for f in self.fields]
    259     return "typedef struct Struct%s {\n%s\n} %s;\n" % (self.structname,\
    260                                                        "\n".join(cfields),\
    261                                                        self.structname)
    262 
    263   def javaClassString(self):
    264     jgetters = [f.javaGetter() for f in self.fields]
    265     jsetters = [f.javaSetter() for f in self.fields]
    266     jnativesetters = [f.javaNativeSetter() for f in self.fields]
    267     jnativegetters = [f.javaNativeGetter() for f in self.fields]
    268     return "public class %s extends NativeBuffer {\n\n"\
    269            "    public %s() {\n"\
    270            "        super();\n"\
    271            "    }\n"\
    272            "\n"\
    273            "    public %s(int count) {\n"\
    274            "        super(count);\n"\
    275            "    }\n"\
    276            "\n"\
    277            "    public native int getElementSize();\n"\
    278            "\n"\
    279            "%s\n\n"\
    280            "%s\n\n"\
    281            "%s\n\n"\
    282            "%s\n\n"\
    283            "    static {\n"\
    284            "        System.loadLibrary(\"%s\");\n"\
    285            "    }\n"\
    286            "\n"\
    287            "};\n" % (self.jclassname,\
    288                      self.jclassname,\
    289                      self.jclassname,\
    290                      "\n\n".join(jgetters),\
    291                      "\n\n".join(jsetters),\
    292                      "\n\n".join(jnativegetters),\
    293                      "\n\n".join(jnativesetters),\
    294                      self.libname)
    295 
    296   def jniDeclString(self):
    297     jnigetters = [f.jniGetterDefString() for f in self.fields]
    298     jnisetters = [f.jniSetterDefString() for f in self.fields]
    299     return "\n\n".join(jnigetters + jnisetters)
    300 
    301   def jniImplString(self):
    302     jnigetters = [f.jniGetterImplString() for f in self.fields]
    303     jnisetters = [f.jniSetterImplString() for f in self.fields]
    304     return "\n\n".join(jnigetters + jnisetters)
    305 
    306   def hFileString(self):
    307     defname = ToMacroDefName(self.structname, self.package)
    308     return hFileTemplate % (defname, defname, self.cStructString(), defname)
    309 
    310   def javaFileString(self):
    311     return javaFileTemplate % (self.package, self.javaClassString())
    312 
    313   def jniFileString(self):
    314     return jniFileTemplate % (self.structname.lower(),\
    315                               self.structname,\
    316                               self.structname,\
    317                               self.structname,\
    318                               self.structname,\
    319                               ToJNIPackage(self.package, self.jclassname),\
    320                               self.jniDeclString(),\
    321                               ToJNIPackage(self.package, self.jclassname),\
    322                               self.structname,
    323                               self.jniImplString())
    324 
    325 def main(argv):
    326   if len(argv) != 2:
    327     print("Usage: %s <file.struct>" % argv[0])
    328     return -1
    329 
    330   filepath = argv[1]
    331 
    332   structspec = StructSpec()
    333   structspec.parseTextFile(filepath)
    334 
    335   hfilename = "%s.h" % structspec.structname.lower()
    336   javafilename = "%s.java" % structspec.jclassname
    337   jnifilename = "jni_%s.c" % structspec.structname.lower()
    338 
    339   javapackagepath = structspec.package.replace('.','/')
    340 
    341   rootdir = os.path.dirname(filepath)
    342   hfilepath = "%s/../native/%s" % (rootdir, hfilename)
    343   javafilepath = "%s/../java/%s/%s" % (rootdir, javapackagepath, javafilename)
    344   jnifilepath = "%s/../jni/%s" % (rootdir, jnifilename)
    345 
    346   hfile = open(hfilepath, 'w')
    347   hfile.write(structspec.hFileString())
    348   hfile.close()
    349 
    350   javafile = open(javafilepath, 'w')
    351   javafile.write(structspec.javaFileString())
    352   javafile.close()
    353 
    354   jnifile = open(jnifilepath, 'w')
    355   jnifile.write(structspec.jniFileString())
    356   jnifile.close()
    357 
    358 
    359 if __name__ == "__main__":
    360   sys.exit(main(sys.argv))
    361