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