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 19import os 20import sys 21 22hFileTemplate = """/** 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 34jniFileTemplate = """/** 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 42extern "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 //////////////////////////////////////////////////////////////////////////////////// 58JNIEXPORT jint JNICALL 59Java_%s_getElementSize(JNIEnv* env, jobject thiz); 60 61%s 62 63#ifdef __cplusplus 64} 65#endif 66 67// Implementation ////////////////////////////////////////////////////////////////////////////////// 68jint Java_%s_getElementSize(JNIEnv* env, jobject thiz) { 69 return sizeof(%s); 70} 71 72%s 73""" 74 75javaFileTemplate = """/** 76 * This file is auto-generated by platform/system/media/mca/structgen.py! Do NOT modify! 77 **/ 78 79package %s; 80 81import android.filterfw.core.NativeBuffer; 82 83%s 84""" 85 86 87def 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 92def ToJNIPackage(package, jclassname): 93 return "%s_%s" % (package.replace(".", "_"), jclassname) 94 95def ToMacroDefName(cname, pname): 96 return "%s_%s" % (pname.replace(".", "_").upper(), cname.upper()) 97 98class 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 106class 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 170class 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 174class 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 178class 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 182class 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 332def 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 366if __name__ == "__main__": 367 sys.exit(main(sys.argv)) 368