|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 import argparse |
|
6 import re |
|
7 |
|
8 STUB_TEMPLATE = ''' |
|
9 typedef %(returnType)s (*%(functionName)s_t)(%(paramTypes)s); |
|
10 static %(functionName)s_t f_%(functionName)s; |
|
11 extern "C" NS_EXPORT %(returnType)s JNICALL |
|
12 %(functionName)s(%(parameterList)s) { |
|
13 if (!f_%(functionName)s) { |
|
14 arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), |
|
15 "JNI Function called before it was loaded"); |
|
16 return %(returnValue)s; |
|
17 } |
|
18 %(returnKeyword)s f_%(functionName)s(%(arguments)s); |
|
19 } |
|
20 ''' |
|
21 BINDING_TEMPLATE = ' xul_dlsym("%(functionName)s", &f_%(functionName)s);\n' |
|
22 |
|
23 |
|
24 class Generator: |
|
25 """ |
|
26 Class to convert a javah-produced JNI stub file into stubs/bindings files |
|
27 for inclusion into mozglue. |
|
28 """ |
|
29 def __init__(self, outputfile): |
|
30 self.outputfile = outputfile |
|
31 |
|
32 def write(self, guard, stuff): |
|
33 self.outputfile.write('#ifdef %s\n' % guard) |
|
34 self.outputfile.write(stuff) |
|
35 self.outputfile.write('#endif\n\n') |
|
36 |
|
37 def process(self, inputfile): |
|
38 self.outputfile.write('/* WARNING - This file is autogenerated by ' |
|
39 + 'mobile/android/base/jni-generator.py. ' |
|
40 + 'Do not edit manually! */\n') |
|
41 |
|
42 # this matches lines such as: |
|
43 # JNIEXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume |
|
44 # and extracts the return type and the function name |
|
45 nameRegex = re.compile('''JNIEXPORT \s+ |
|
46 (?P<returnType>\S+) \s+ |
|
47 JNICALL \s+ |
|
48 (?P<functionName>\S+)''', re.VERBOSE) |
|
49 |
|
50 # this matches lines such as: |
|
51 # (JNIEnv *, jclass); |
|
52 # and extracts everything within the parens; this will be split |
|
53 # on commas to get the argument types. |
|
54 paramsRegex = re.compile('\((.*)\);') |
|
55 |
|
56 for line in inputfile: |
|
57 line = line.strip() |
|
58 |
|
59 match = re.match(nameRegex, line) |
|
60 if match: |
|
61 returnType = match.group('returnType') |
|
62 functionName = match.group('functionName') |
|
63 |
|
64 match = re.match(paramsRegex, line) |
|
65 if match: |
|
66 paramTypes = re.split('\s*,\s*', match.group(1)) |
|
67 paramNames = ['arg%d' % i for i in range(0, len(paramTypes))] |
|
68 if returnType == 'void': |
|
69 returnValue = '' |
|
70 elif returnType in ('jobject', 'jstring'): |
|
71 returnValue = 'nullptr' |
|
72 elif returnType in ('jint', 'jfloat', 'jdouble', 'jlong'): |
|
73 returnValue = '0' |
|
74 elif returnType == 'jboolean': |
|
75 returnValue = 'false' |
|
76 else: |
|
77 raise Exception(('Unsupported JNI return type %s found; ' |
|
78 + 'please update mobile/android/base/' |
|
79 + 'jni-generator.py to handle this case!') |
|
80 % returnType) |
|
81 |
|
82 self.write('JNI_STUBS', STUB_TEMPLATE % { |
|
83 'returnType': returnType, |
|
84 'functionName': functionName, |
|
85 'paramTypes': ', '.join(paramTypes), |
|
86 'parameterList': ', '.join('%s %s' % param |
|
87 for param in zip(paramTypes, paramNames)), |
|
88 'arguments': ', '.join(paramNames), |
|
89 'returnValue': returnValue, |
|
90 'returnKeyword': 'return' if returnType != 'void' else ''}) |
|
91 self.write('JNI_BINDINGS', BINDING_TEMPLATE % { |
|
92 'functionName': functionName}) |
|
93 |
|
94 |
|
95 def main(): |
|
96 parser = argparse.ArgumentParser( |
|
97 description='Generate mozglue bindings for JNI functions.') |
|
98 parser.add_argument('inputfile', type=argparse.FileType('r')) |
|
99 parser.add_argument('outputfile', type=argparse.FileType('w')) |
|
100 args = parser.parse_args() |
|
101 gen = Generator(args.outputfile) |
|
102 try: |
|
103 gen.process(args.inputfile) |
|
104 finally: |
|
105 args.outputfile.close() |
|
106 args.inputfile.close() |
|
107 |
|
108 if __name__ == '__main__': |
|
109 main() |