blob: 437326ca2c281a9e6379feadab70e380568ddbe6 [file] [log] [blame]
Marius Renn65953da2012-03-27 10:44:45 -07001#!/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))