15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Extracts native methods from a Java file and generates the JNI bindings.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)If you change this, please run and update the tests."""
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import collections
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import errno
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import string
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from string import Template
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import textwrap
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import zipfile
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21116680a4aac90f2aa7413d9095a592090648e557Ben MurdochCHROMIUM_SRC = os.path.join(
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
23116680a4aac90f2aa7413d9095a592090648e557Ben MurdochBUILD_ANDROID_GYP = os.path.join(
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CHROMIUM_SRC, 'build', 'android', 'gyp')
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdochsys.path.append(BUILD_ANDROID_GYP)
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom util import build_utils
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ParseError(Exception):
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Exception thrown when we can't parse the input file."""
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, description, *context_lines):
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Exception.__init__(self)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.description = description
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.context_lines = context_lines
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = '\n'.join(self.context_lines)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Param(object):
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a param for a method, either java or native."""
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.datatype = kwargs['datatype']
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NativeMethod(object):
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a C/C++ method that is called by Java code"""
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.params:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params) is list
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params[0]) is Param
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.params and
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        self.params[0].datatype == kwargs.get('ptr_type', 'int') and
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.params[0].name.startswith('native')):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'method'
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.p0_type = self.params[0].name[len('native'):]
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kwargs.get('native_class_name'):
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.p0_type = kwargs['native_class_name']
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'function'
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CalledByNative(object):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a java method exported to c/c++"""
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.system_class = kwargs['system_class']
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.unchecked = kwargs['unchecked']
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.signature = kwargs.get('signature')
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_constructor = kwargs.get('is_constructor', False)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.env_call = GetEnvCall(self.is_constructor, self.static,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               self.return_type)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static_cast = GetStaticCastForReturnType(self.return_type)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ConstantField(object):
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, **kwargs):
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.name = kwargs['name']
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.value = kwargs['value']
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def JavaDataTypeToC(java_type):
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a C datatype for the given java type."""
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_pod_type_map = {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'int': 'jint',
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'byte': 'jbyte',
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'char': 'jchar',
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'short': 'jshort',
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'boolean': 'jboolean',
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'long': 'jlong',
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'double': 'jdouble',
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'float': 'jfloat',
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_type_map = {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'void': 'void',
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'String': 'jstring',
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'java/lang/String': 'jstring',
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'java/lang/Class': 'jclass',
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if java_type in java_pod_type_map:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_pod_type_map[java_type]
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type in java_type_map:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_type_map[java_type]
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type.endswith('[]'):
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if java_type[:-2] in java_pod_type_map:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return java_pod_type_map[java_type[:-2]] + 'Array'
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  elif java_type.startswith('Class'):
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Checking just the start of the name, rather than a direct comparison,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # in order to handle generics.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 'jclass'
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobject'
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)def JavaDataTypeToCForCalledByNativeParam(java_type):
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  """Returns a C datatype to be when calling from native."""
138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if java_type == 'int':
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return 'JniIntWrapper'
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else:
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return JavaDataTypeToC(java_type)
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def JavaReturnValueToC(java_type):
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Returns a valid C return value for the given java type."""
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  java_pod_type_map = {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'int': '0',
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'byte': '0',
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'char': '0',
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'short': '0',
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'boolean': 'false',
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'long': '0',
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'double': '0',
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'float': '0',
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'void': ''
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return java_pod_type_map.get(java_type, 'NULL')
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JniParams(object):
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _imports = []
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _fully_qualified_class = ''
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _package = ''
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _inner_classes = []
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  _remappings = []
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  _implicit_imports = []
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetFullyQualifiedClass(fully_qualified_class):
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._fully_qualified_class = 'L' + fully_qualified_class
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def AddAdditionalImport(class_name):
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    assert class_name.endswith('.class')
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    raw_class_name = class_name[:-len('.class')]
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if '.' in raw_class_name:
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise SyntaxError('%s cannot be used in @JNIAdditionalImport. '
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        'Only import unqualified outer classes.' % class_name)
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    new_import = 'L%s/%s' % (JniParams._package, raw_class_name)
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if new_import in JniParams._imports:
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise SyntaxError('Do not use JNIAdditionalImport on an already '
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        'imported class: %s' % (new_import.replace('/', '.')))
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    JniParams._imports += [new_import]
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  @staticmethod
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtractImportsAndInnerClasses(contents):
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if not JniParams._package:
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise RuntimeError('SetFullyQualifiedClass must be called before '
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         'ExtractImportsAndInnerClasses')
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = contents.replace('\n', '')
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_import = re.compile(r'import.*?(?P<class>\S*?);')
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_import, contents):
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_inner, contents):
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inner = match.group('name')
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not JniParams._fully_qualified_class.endswith(inner):
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     inner]
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    re_additional_imports = re.compile(
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        r'@JNIAdditionalImport\(\s*{?(?P<class_names>.*?)}?\s*\)')
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for match in re.finditer(re_additional_imports, contents):
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      for class_name in match.group('class_names').split(','):
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        JniParams.AddAdditionalImport(class_name.strip())
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def ParseJavaPSignature(signature_line):
2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    prefix = 'Signature: '
2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):]
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @staticmethod
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def JavaToJni(param):
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Converts a java param into a JNI signature type."""
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod_param_map = {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'int': 'I',
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'boolean': 'Z',
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'char': 'C',
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'short': 'S',
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'long': 'J',
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'double': 'D',
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'float': 'F',
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'byte': 'B',
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'void': 'V',
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    object_param_list = [
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Boolean',
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Integer',
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Long',
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Object',
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/String',
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'Ljava/lang/Class',
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prefix = ''
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Array?
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while param[-2:] == '[]':
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prefix += '['
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:-2]
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generic?
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '<' in param:
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:param.index('<')]
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if param in pod_param_map:
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return prefix + pod_param_map[param]
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '/' in param:
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Coming from javap, use the fully qualified param directly.
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return prefix + 'L' + JniParams.RemapClassName(param) + ';'
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for qualified_name in (object_param_list +
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           [JniParams._fully_qualified_class] +
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           JniParams._inner_classes):
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (qualified_name.endswith('/' + param) or
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name.endswith('$' + param.replace('.', '$')) or
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name == 'L' + param):
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it from an import? (e.g. referecing Class from import pkg.Class;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # note that referencing an inner class Inner from import pkg.Class.Inner
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # is not supported).
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for qualified_name in JniParams._imports:
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if qualified_name.endswith('/' + param):
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Ensure it's not an inner class.
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        components = qualified_name.split('/')
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if len(components) > 2 and components[-2][0].isupper():
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          raise SyntaxError('Inner class (%s) can not be imported '
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'and used by JNI (%s). Please import the outer '
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'class and use Outer.Inner instead.' %
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            (qualified_name, param))
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it an inner class from an outer class import? (e.g. referencing
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Class.Inner from import pkg.Class).
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if '.' in param:
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      components = param.split('.')
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      outer = '/'.join(components[:-1])
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      inner = components[-1]
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for qualified_name in JniParams._imports:
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if qualified_name.endswith('/' + outer):
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          return (prefix + JniParams.RemapClassName(qualified_name) +
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  '$' + inner + ';')
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      raise SyntaxError('Inner class (%s) can not be '
284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        'used directly by JNI. Please import the outer '
285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        'class, probably:\n'
286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        'import %s.%s;' %
287effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        (param, JniParams._package.replace('/', '.'),
288effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         outer.replace('/', '.')))
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    JniParams._CheckImplicitImports(param)
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Type not found, falling back to same package as this class.
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return (prefix + 'L' +
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
297010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  def _CheckImplicitImports(param):
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    # Ensure implicit imports, such as java.lang.*, are not being treated
299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    # as being in the same package.
300010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if not JniParams._implicit_imports:
301010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      # This file was generated from android.jar and lists
302010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      # all classes that are implicitly imported.
303010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      with file(os.path.join(os.path.dirname(sys.argv[0]),
304010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                             'android_jar.classes'), 'r') as f:
305010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        JniParams._implicit_imports = f.readlines()
306010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    for implicit_import in JniParams._implicit_imports:
307010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      implicit_import = implicit_import.strip().replace('.class', '')
308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      implicit_import = implicit_import.replace('/', '.')
309010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if implicit_import.endswith('.' + param):
310010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        raise SyntaxError('Ambiguous class (%s) can not be used directly '
311010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                          'by JNI.\nPlease import it, probably:\n\n'
312010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                          'import %s;' %
313010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                          (param, implicit_import))
314010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
316010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  @staticmethod
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Signature(params, returns, wrap):
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the JNI signature for the given datatypes."""
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items = ['(']
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(param.datatype) for param in params]
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [')']
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(returns)]
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if wrap:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n' + '\n'.join(['"' + item + '"' for item in items])
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '"' + ''.join(items) + '"'
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Parse(params):
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Parses the params into a list of Param objects."""
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not params:
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return []
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for p in [p.strip() for p in params.split(',')]:
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      items = p.split(' ')
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'final' in items:
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        items.remove('final')
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = Param(
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          datatype=items[0],
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      )
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [param]
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def RemapClassName(class_name):
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Remaps class names using the jarjar mapping table."""
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for old, new in JniParams._remappings:
3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if old.endswith('**') and old[:-2] in class_name:
3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        return class_name.replace(old[:-2], new, 1)
3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if '*' not in old and class_name.endswith(old):
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return class_name.replace(old, new, 1)
3536d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return class_name
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def SetJarJarMappings(mappings):
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Parse jarjar mappings from a string."""
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    JniParams._remappings = []
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for line in mappings.splitlines():
3616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      rule = line.split()
3626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if rule[0] != 'rule':
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        continue
3646d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      _, src, dest = rule
3656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      src = src.replace('.', '/')
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      dest = dest.replace('.', '/')
3676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if src.endswith('**'):
3686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        src_real_name = src[:-2]
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      else:
3706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        assert not '*' in src
3716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        src_real_name = src
3726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
3736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if dest.endswith('@0'):
3746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2] + src_real_name))
3756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      elif dest.endswith('@1'):
3766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        assert '**' in src
377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2]))
3786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      else:
3796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        assert not '@' in dest
3806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        JniParams._remappings.append((src, dest))
381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJNINamespace(contents):
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  m = re.findall(re_jni_namespace, contents)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not m:
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return m[0]
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_package = re.compile('.*?package (.*?);')
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  matches = re.findall(re_package, contents)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not matches:
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (matches[0].replace('.', '/') + '/' +
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.path.splitext(os.path.basename(java_file_name))[0])
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)def ExtractNatives(contents, ptr_type):
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a list of dict containing information about a native method."""
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents = contents.replace('\n', '')
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  natives = []
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_native = re.compile(r'(@NativeClassQualifiedName'
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         '\(\"(?P<native_class_name>.*?)\"\)\s+)?'
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\))\s+)?'
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*native '
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         '(?P<return_type>\S*) '
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         '(?P<name>native\w+)\((?P<params>.*?)\);')
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(re_native, contents):
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native = NativeMethod(
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('qualifiers'),
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('java_class_name'),
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        native_class_name=match.group('native_class_name'),
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return_type=match.group('return_type'),
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name').replace('native', ''),
4170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        params=JniParams.Parse(match.group('params')),
4180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        ptr_type=ptr_type)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    natives += [native]
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return natives
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetStaticCastForReturnType(return_type):
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  type_map = { 'String' : 'jstring',
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'java/lang/String' : 'jstring',
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'boolean[]': 'jbooleanArray',
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'byte[]': 'jbyteArray',
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'char[]': 'jcharArray',
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'short[]': 'jshortArray',
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'int[]': 'jintArray',
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'long[]': 'jlongArray',
43246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)               'float[]': 'jfloatArray',
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'double[]': 'jdoubleArray' }
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ret = type_map.get(return_type, None)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ret:
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if return_type.endswith('[]'):
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return None
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetEnvCall(is_constructor, is_static, return_type):
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Maps the types availabe via env->Call__Method."""
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_constructor:
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'NewObject'
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env_call_map = {'boolean': 'Boolean',
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'byte': 'Byte',
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'char': 'Char',
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'short': 'Short',
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'int': 'Int',
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'long': 'Long',
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'float': 'Float',
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'void': 'Void',
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'double': 'Double',
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'Object': 'Object',
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  call = env_call_map.get(return_type, 'Object')
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_static:
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    call = 'Static' + call
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 'Call' + call + 'Method'
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledParam(datatype):
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled identifier for the datatype."""
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(datatype) <= 2:
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return datatype.replace('[', 'A')
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = ''
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for i in range(1, len(datatype)):
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = datatype[i]
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if c == '[':
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += 'A'
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += c.upper()
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledMethodName(name, params, return_type):
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled method name for the given signature.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     The returned name can be used as a C identifier and will be unique for all
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     valid overloads of the same method.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     name: string.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     params: list of Param.
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     return_type: string.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A mangled name.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_items = []
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for datatype in [return_type] + [x.datatype for x in params]:
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_name = name + '_'.join(mangled_items)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mangled_name
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MangleCalledByNatives(called_by_natives):
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Mangles all the overloads from the call_by_natives list."""
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_counts = collections.defaultdict(
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lambda: collections.defaultdict(lambda: 0))
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = called_by_native.name
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_counts[java_class_name][name] += 1
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_name = called_by_native.name
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_id_var_name = method_name
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if method_counts[java_class_name][method_name] > 1:
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method_id_var_name = GetMangledMethodName(method_name,
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.params,
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.return_type)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native.method_id_var_name = method_id_var_name
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return called_by_natives
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match the JNI return types that should be included in a
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ScopedJavaLocalRef.
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match a string like "@CalledByNative public void foo(int bar)".
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_CALLED_BY_NATIVE = re.compile(
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<prefix>[\w ]*?)'
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    '\s*(?P<return_type>\S+?)'
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<name>\w+)'
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s*\((?P<params>[^\)]*)\)')
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractCalledByNatives(contents):
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Parses all methods annotated with @CalledByNative.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents: the contents of the java file.
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A list of dict with information about the annotated methods.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TODO(bulach): return a CalledByNative object.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseError: if unable to parse.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  called_by_natives = []
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives += [CalledByNative(
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        system_class=False,
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unchecked='Unchecked' in match.group('Unchecked'),
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('prefix'),
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('annotation') or '',
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_type=match.group('return_type'),
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name'),
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        params=JniParams.Parse(match.group('params')))]
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Check for any @CalledByNative occurrences that weren't matched.
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '@CalledByNative' in line1:
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ParseError('could not parse @CalledByNative method signature',
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       line1, line2)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MangleCalledByNatives(called_by_natives)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaP(object):
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses 'javap' to parse a .class file and generate the JNI header file."""
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, options):
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.contents = contents
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.namespace = options.namespace
570a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for line in contents:
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      class_name = re.match(
572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)',
573a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          line)
574a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if class_name:
575a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.fully_qualified_class = class_name.group('class_name')
576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        break
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
57858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
57958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # away the <...> and use the raw class name that Java 6 would've given us.
58058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = self.fully_qualified_class.split('/')[-1]
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.namespace:
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.namespace = 'JNI_' + self.java_class_name
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '\((?P<params>.*?)\)')
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = []
5881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_method, content)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static='static' in match.group('prefix'),
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=match.group('return_type').replace('.', '/'),
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=match.group('name'),
5991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
6001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
6011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    re_constructor = re.compile('(.*?)public ' +
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                self.fully_qualified_class.replace('/', '.') +
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                '\((?P<params>.*?)\)')
6041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_constructor, content)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static=False,
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=self.fully_qualified_class,
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name='Constructor',
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
6161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_constructor=True)]
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
619a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.constant_fields = []
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    re_constant_field = re.compile('.*?public static final int (?P<name>.*?);')
622a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    re_constant_field_value = re.compile(
623a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)')
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
625a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      match = re.match(re_constant_field, content)
626a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if not match:
627a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        continue
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      value = re.match(re_constant_field_value, contents[lineno + 2])
629a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if not value:
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        value = re.match(re_constant_field_value, contents[lineno + 3])
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if value:
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.constant_fields.append(
633a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            ConstantField(name=match.group('name'),
634a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          value=value.group('value')))
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.inl_header_file_generator = InlHeaderFileGenerator(
6374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        self.namespace, self.fully_qualified_class, [],
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.called_by_natives, self.constant_fields, options)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.inl_header_file_generator.GetContent()
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromClass(class_file, options):
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class_name = os.path.splitext(os.path.basename(class_file))[0]
646a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    p = subprocess.Popen(args=[options.javap, '-c', '-verbose',
647a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               '-s', class_name],
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         cwd=os.path.dirname(class_file),
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdout=subprocess.PIPE,
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stderr=subprocess.PIPE)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, _ = p.communicate()
6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return jni_from_javap
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaSource(object):
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses the given java source file to generate the JNI header file."""
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
659a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  # Match single line comments, multiline comments, character literals, and
660a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  # double-quoted strings.
661a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  _comment_remover_regex = re.compile(
662a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
663a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      re.DOTALL | re.MULTILINE)
664a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
6654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, fully_qualified_class, options):
666a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    contents = self._RemoveComments(contents)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(fully_qualified_class)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.ExtractImportsAndInnerClasses(contents)
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    jni_namespace = ExtractJNINamespace(contents) or options.namespace
6700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    natives = ExtractNatives(contents, options.ptr_type)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives = ExtractCalledByNatives(contents)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(natives) == 0 and len(called_by_natives) == 0:
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise SyntaxError('Unable to find any JNI methods for %s.' %
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        fully_qualified_class)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inl_header_file_generator = InlHeaderFileGenerator(
6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        jni_namespace, fully_qualified_class, natives, called_by_natives,
677a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        [], options)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.content = inl_header_file_generator.GetContent()
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
680a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  @classmethod
681a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  def _RemoveComments(cls, contents):
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We need to support both inline and block comments, and we need to handle
683a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # strings that contain '//' or '/*'.
684a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # parser. Maybe we could ditch JNIFromJavaSource and just always use
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # http://code.google.com/p/chromium/issues/detail?id=138941
688a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    def replacer(match):
689a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      # Replace matches that are comments with nothing; return literals/strings
690a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      # unchanged.
691a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      s = match.group(0)
692a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      if s.startswith('/'):
693a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        return ''
694a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      else:
695a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        return s
696a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return cls._comment_remover_regex.sub(replacer, contents)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.content
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
7024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromFile(java_file_name, options):
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = file(java_file_name).read()
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               contents)
7064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return JNIFromJavaSource(contents, fully_qualified_class, options)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InlHeaderFileGenerator(object):
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates an inline header file for JNI integration."""
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, namespace, fully_qualified_class, natives,
713a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               called_by_natives, constant_fields, options):
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.namespace = namespace
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = fully_qualified_class
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.class_name = self.fully_qualified_class.split('/')[-1]
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.natives = natives
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = called_by_natives
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
720a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.constant_fields = constant_fields
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.options = options
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.init_native = self.ExtractInitNative(options)
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def ExtractInitNative(self, options):
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for native in self.natives:
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if options.jni_init_native_name == 'native' + native.name:
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.natives.remove(native)
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return native
7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return None
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the content of the JNI binding file."""
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
73403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is autogenerated by
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${SCRIPT_NAME}
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${FULLY_QUALIFIED_CLASS}
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef ${HEADER_GUARD}
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ${HEADER_GUARD}
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <jni.h>
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${INCLUDES}
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
751010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/android/jni_int_wrapper.h"
752010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 1: forward declarations.
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLASS_PATH_DEFINITIONS
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$METHOD_ID_DEFINITIONS
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$OPEN_NAMESPACE
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$FORWARD_DECLARATIONS
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)$CONSTANT_FIELDS
763a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 2: method stubs.
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$METHOD_STUBS
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 3: RegisterNatives.
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$JNI_NATIVE_METHODS
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$REGISTER_NATIVES
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLOSE_NAMESPACE
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$JNI_REGISTER_NATIVES
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // ${HEADER_GUARD}
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'SCRIPT_NAME': self.options.script_name,
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
780a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        'CONSTANT_FIELDS': self.GetConstantFieldsString(),
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_STUBS': self.GetMethodStubsString(),
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'REGISTER_NATIVES': self.GetRegisterNativesString(),
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'HEADER_GUARD': self.header_guard,
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'INCLUDES': self.GetIncludesString(),
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return WrapOutput(template.substitute(values))
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitionsString(self):
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += [self.GetClassPathDefinitions()]
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetMethodIDDefinitionsString(self):
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the definition of method ids for the called by native methods."""
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.eager_called_by_natives:
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for called_by_native in self.called_by_natives:
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      values = {
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += [template.substitute(values)]
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join(ret)
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclarationsString(self):
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type != 'method':
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetForwardDeclaration(native)]
8176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports and ret:
8186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
821a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetConstantFieldsString(self):
822a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not self.constant_fields:
823a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return ''
824a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ret = ['enum Java_%s_constant_fields {' % self.class_name]
825a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for c in self.constant_fields:
826a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ret += ['  %s = %s,' % (c.name, c.value)]
827a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ret += ['};']
828a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return '\n'.join(ret)
829a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodStubsString(self):
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code corresponding to method stubs."""
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type == 'method':
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret += [self.GetNativeMethodStubString(native)]
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.options.eager_called_by_natives:
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += self.GetEagerCalledByNativeMethodStubs()
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += self.GetLazyCalledByNativeMethodStubs()
8406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
8416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports and ret:
8426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetLazyCalledByNativeMethodStubs(self):
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return [self.GetLazyCalledByNativeMethodStub(called_by_native)
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            for called_by_native in self.called_by_natives]
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEagerCalledByNativeMethodStubs(self):
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.called_by_natives:
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += ['namespace {']
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for called_by_native in self.called_by_natives:
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += ['}  // namespace']
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ret
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetIncludesString(self):
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.includes:
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    includes = self.options.includes.split(',')
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join('#include "%s"' % x for x in includes)
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodsString(self, clazz):
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (native.java_class_name == clazz or
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (not native.java_class_name and clazz == self.class_name)):
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetKMethodArrayEntry(native)]
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def SubstituteNativeMethods(self, template):
8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes = self.GetUniqueClasses(self.natives)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes[self.class_name] = self.fully_qualified_class
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kmethods = self.GetKMethodsString(clazz)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kmethods:
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        values = {'JAVA_CLASS': clazz,
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'KMETHODS': kmethods}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [template.substitute(values)]
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not ret: return ''
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n' + '\n'.join(ret)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetJNINativeMethodsString(self):
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation of the array of native methods."""
8886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
8896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ''
8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
8925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${KMETHODS}
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.SubstituteNativeMethods(template)
8965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterCalledByNativesImplString(self):
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code for registering the called by native methods."""
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.eager_called_by_natives:
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
9055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """)
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for called_by_native in self.called_by_natives:
9095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      values = {
9105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
9115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
9125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += [template.substitute(values)]
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join(ret)
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterNativesString(self):
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code for RegisterNatives."""
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
9205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${REGISTER_NATIVES_SIGNATURE} {
9215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${CLASSES}
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${NATIVES}
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${CALLED_BY_NATIVES}
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    signature = 'static bool RegisterNativesImpl(JNIEnv* env'
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.init_native:
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      signature += ', jclass clazz)'
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      signature += ')'
9325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    natives = self.GetRegisterNativesImplString()
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    called_by_natives = self.GetRegisterCalledByNativesImplString()
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = {'REGISTER_NATIVES_SIGNATURE': signature,
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'CLASSES': self.GetFindClasses(),
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'NATIVES': natives,
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'CALLED_BY_NATIVES': called_by_natives,
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             }
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterNativesImplString(self):
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the shared implementation for RegisterNatives."""
9446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
9456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return ''
9466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
9485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
9495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (env->RegisterNatives(${JAVA_CLASS}_clazz(env),
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           kMethods${JAVA_CLASS},
9525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           kMethods${JAVA_CLASS}Size) < 0) {
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    jni_generator::HandleRegistrationError(
95403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        env, ${JAVA_CLASS}_clazz(env), __FILE__);
9555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
9565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
9585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.SubstituteNativeMethods(template)
9595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetJNIRegisterNativesString(self):
9615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation for the JNI registration of native methods."""
9625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.init_native:
9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
9645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
9665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" JNIEXPORT bool JNICALL
9675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ${NAMESPACE}RegisterNativesImpl(env, clazz);
9695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
9716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
9736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = JniParams.RemapClassName(self.fully_qualified_class)
9746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = java_name.replace('_', '_1').replace('/', '_')
9756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else:
9766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = self.fully_qualified_class.replace('/', '_')
9776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
9785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    namespace = ''
9795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.namespace:
9805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      namespace = self.namespace + '::'
9816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    values = {'FULLY_QUALIFIED_CLASS': java_name,
9825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'INIT_NATIVE_NAME': 'native' + self.init_native.name,
9835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'NAMESPACE': namespace,
9845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
9855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             }
9865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
9875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetOpenNamespaceString(self):
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['namespace %s {' % ns
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCloseNamespaceString(self):
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['}  // namespace %s' % ns
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces.reverse()
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces) + '\n'
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetJNIFirstParam(self, native):
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if native.type == 'method':
10065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret = ['jobject jcaller']
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif native.type == 'function':
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.static:
10095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret = ['jclass jcaller']
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
10115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret = ['jobject jcaller']
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetParamsInDeclaration(self, native):
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the params for the stub declaration.
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      native: the native dictionary describing the method.
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string containing the params.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ',\n    '.join(self.GetJNIFirstParam(native) +
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          [JavaDataTypeToC(param.datatype) + ' ' +
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           param.name
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           for param in native.params])
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
1029010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return ',\n    '.join([
1030010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' +
1031010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        param.name
1032010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        for param in called_by_native.params])
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclaration(self, native):
10356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    template_str = """
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
10376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)"""
10386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
10396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      template_str += """
10406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)__attribute__((visibility("default")))
10416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) {
10426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return ${NAME}(${PARAMS_IN_CALL});
10436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
10446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)"""
10456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    template = Template(template_str)
10466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    params_in_call = []
10476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if not self.options.pure_native_methods:
10486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      params_in_call = ['env', 'jcaller']
10496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
10506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
10516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    java_name = JniParams.RemapClassName(self.fully_qualified_class)
10526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    java_name = java_name.replace('_', '_1').replace('/', '_')
10536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if native.java_class_name:
10546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name += '_00024' + native.java_class_name
10556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'RETURN': JavaDataTypeToC(native.return_type),
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'NAME': native.name,
10586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              'JAVA_NAME': java_name,
10596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              'PARAMS': self.GetParamsInDeclaration(native),
10606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              'PARAMS_IN_CALL': params_in_call}
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetNativeMethodStubString(self, native):
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns stubs for native methods."""
10656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
10666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      template_str = """\
10676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)__attribute__((visibility("default")))
10686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env,
10696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    ${PARAMS_IN_DECLARATION}) {"""
10706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else:
10716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      template_str = """\
10726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
10736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    template_str += """
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
10755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
10765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)"""
10796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
10806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    template = Template(template_str)
10815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    params = []
10825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.pure_native_methods:
10835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params = ['env', 'jcaller']
10845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(native.return_type)
10875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    optional_error_return = JavaReturnValueToC(native.return_type)
10885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if optional_error_return:
10895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      optional_error_return = ', ' + optional_error_return
10905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    post_call = ''
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = '.Release()'
10936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
10946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
10956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = JniParams.RemapClassName(self.fully_qualified_class)
10966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = java_name.replace('_', '_1').replace('/', '_')
10976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if native.java_class_name:
10986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        java_name += '_00024' + native.java_class_name
10996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else:
11006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      java_name = ''
11016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN': return_type,
11045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'OPTIONAL_ERROR_RETURN': optional_error_return,
11056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        'JAVA_NAME': java_name,
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'NAME': native.name,
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAM0_NAME': native.params[0].name,
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'P0_TYPE': native.p0_type,
11105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PARAMS_IN_CALL': params_in_call,
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  def GetArgument(self, param):
1116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return ('as_jint(' + param.name + ')'
1117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            if param.datatype == 'int' else param.name)
1118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
1119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  def GetArgumentsInCall(self, params):
1120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    """Return a string of arguments to call from native into Java"""
1121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return [self.GetArgument(p) for p in params]
1122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
11235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetCalledByNativeValues(self, called_by_native):
11245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Fills in necessary values for the CalledByNative methods."""
112503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    java_class = called_by_native.java_class_name or self.class_name
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static or called_by_native.is_constructor:
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ''
112803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      first_param_in_call = ('%s_clazz(env)' % java_class)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ', jobject obj'
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_call = 'obj'
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        called_by_native)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if params_in_declaration:
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_in_declaration = ', ' + params_in_declaration
1136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    params_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params))
11375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if params_in_call:
11385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params_in_call = ', ' + params_in_call
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pre_call = ''
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    post_call = ''
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static_cast:
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = ')'
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_exception = ''
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not called_by_native.unchecked:
11465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      check_exception = 'jni_generator::CheckException(env);'
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(called_by_native.return_type)
11485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    optional_error_return = JavaReturnValueToC(called_by_native.return_type)
11495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if optional_error_return:
11505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      optional_error_return = ', ' + optional_error_return
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_declaration = ''
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_clause = ''
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if return_type != 'void':
11545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pre_call = ' ' + pre_call
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return_declaration = return_type + ' ret ='
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
11575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ' + return_type + '(env, ret);'
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ret;'
11615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return {
116203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        'JAVA_CLASS': java_class,
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_TYPE': return_type,
11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'OPTIONAL_ERROR_RETURN': optional_error_return,
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_DECLARATION': return_declaration,
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_CLAUSE': return_clause,
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': params_in_declaration,
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PRE_CALL': pre_call,
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call,
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'ENV_CALL': called_by_native.env_call,
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_CALL': first_param_in_call,
11735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PARAMS_IN_CALL': params_in_call,
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CHECK_EXCEPTION': check_exception,
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEagerCalledByNativeMethodStub(self, called_by_native):
11805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation of the called by native method."""
11815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""
11825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
11835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
11845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
11855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
11865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_CLAUSE}
11875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}""")
11885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = self.GetCalledByNativeValues(called_by_native)
11895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
11905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetLazyCalledByNativeMethodStub(self, called_by_native):
11925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns a string."""
11935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_signature_template = Template("""\
11945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
11955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
11965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_header_template = Template("""\
11975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
11985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_header_with_unused_template = Template("""\
11995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} __attribute__ ((unused));
12005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
12015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""
12025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
12035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_HEADER}
12045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  /* Must call RegisterNativesImpl()  */
12055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
120603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
12075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  jmethodID method_id =
12085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ${GET_METHOD_ID_IMPL}
12095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_DECLARATION}
12105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
12115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          method_id${PARAMS_IN_CALL})${POST_CALL};
12125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${CHECK_EXCEPTION}
12135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_CLAUSE}
12145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}""")
12155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = self.GetCalledByNativeValues(called_by_native)
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values['FUNCTION_SIGNATURE'] = (
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        function_signature_template.substitute(values))
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.system_class:
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = (
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          function_header_with_unused_template.substitute(values))
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodArrayEntry(self, native):
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'NAME': native.name,
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'JNI_SIGNATURE': JniParams.Signature(native.params,
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   native.return_type,
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   True)}
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetUniqueClasses(self, origin):
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = {self.class_name: self.fully_qualified_class}
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for entry in origin:
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      class_name = self.class_name
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_class_path = self.fully_qualified_class
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if entry.java_class_name:
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        class_name = entry.java_class_name
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jni_class_path = self.fully_qualified_class + '$' + class_name
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret[class_name] = jni_class_path
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitions(self):
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the ClassPath constants."""
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native_classes = self.GetUniqueClasses(self.natives)
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
12526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.options.native_exports:
12536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      all_classes = called_by_native_classes
12546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else:
12556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      all_classes = native_classes
12566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      all_classes.update(called_by_native_classes)
12576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
1261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]),
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ''
126503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
126603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    class_getter_methods = []
126703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if self.options.native_exports:
126803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      template = Template("""\
126903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Leaking this jclass as we cannot use LazyInstance from some threads.
127003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)base::subtle::AtomicWord g_${JAVA_CLASS}_clazz = 0;
127103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define ${JAVA_CLASS}_clazz(env) \
127203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
127303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)&g_${JAVA_CLASS}_clazz)""")
127403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    else:
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template = Template("""\
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Leaking this jclass as we cannot use LazyInstance from some threads.
127703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)jclass g_${JAVA_CLASS}_clazz = NULL;
127803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
127903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
128003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    for clazz in called_by_native_classes:
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
128503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFindClasses(self):
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the imlementation of FindClass for all known classes."""
12905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.init_native:
129103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if self.options.native_exports:
129203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        template = Template("""\
129303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
129403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
129503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      else:
129603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        template = Template("""\
12975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
12985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
129903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      if self.options.native_exports:
130003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        return '\n'
13015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
1303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in self.GetUniqueClasses(self.called_by_natives):
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {'JAVA_CLASS': clazz}
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodIDImpl(self, called_by_native):
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the implementation of GetMethodID."""
13125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.options.eager_called_by_natives:
13135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
13145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)env->Get${STATIC_METHOD_PART}MethodID(
131503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ${JAVA_CLASS}_clazz(env),
13165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "${JNI_NAME}", ${JNI_SIGNATURE});""")
13175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
13185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::android::MethodID::LazyGet<
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::android::MethodID::TYPE_${STATIC}>(
132103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      env, ${JAVA_CLASS}_clazz(env),
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "${JNI_NAME}",
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ${JNI_SIGNATURE},
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_name = called_by_native.name
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_return_type = called_by_native.return_type
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.is_constructor:
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_name = '<init>'
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_return_type = 'void'
13311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if called_by_native.signature:
13321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = called_by_native.signature
13331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else:
13341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = JniParams.Signature(called_by_native.params,
13351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      jni_return_type,
13361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      True)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JNI_NAME': jni_name,
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
13425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
13431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        'JNI_SIGNATURE': signature,
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WrapOutput(output):
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = []
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in output.splitlines():
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Do not wrap lines under 80 characters or preprocessor directives.
13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(line) < 80 or line.lstrip()[:1] == '#':
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped = line.rstrip()
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(ret) == 0 or len(ret[-1]) or len(stripped):
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret.append(stripped)
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subsequent_indent =  first_line_indent + ' ' * 4
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line.startswith('//'):
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        subsequent_indent = '//' + subsequent_indent
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper = textwrap.TextWrapper(width=80,
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     subsequent_indent=subsequent_indent,
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     break_long_words=False)
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret += ['']
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return '\n'.join(ret)
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJarInputFile(jar_file, input_file, out_dir):
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Extracts input file from jar and returns the filename.
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The input file is extracted to the same directory that the generated jni
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers will be placed in.  This is passed as an argument to script.
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jar_file: the jar file containing the input files to extract.
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_files: the list of files to extract from the jar file.
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: the name of the directories to extract to.
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the name of extracted input file.
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  jar_file = zipfile.ZipFile(jar_file)
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
13862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try:
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(out_dir)
13882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  except OSError as e:
13892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if e.errno != errno.EEXIST:
13902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with open(extracted_file_name, 'w') as outfile:
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(jar_file.read(input_file))
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extracted_file_name
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GenerateJNIHeader(input_file, output_file, options):
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if os.path.splitext(input_file)[1] == '.class':
14014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_javap.GetContent()
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
14044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
14054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          input_file, options)
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_java_source.GetContent()
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except ParseError, e:
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print e
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.exit(1)
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if output_file:
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
14134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if options.optimize_generation and os.path.exists(output_file):
14142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      with file(output_file, 'r') as f:
14152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        existing_content = f.read()
14162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if existing_content == content:
14172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with file(output_file, 'w') as f:
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write(content)
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print output
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GetScriptName():
14254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
14264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base_index = 0
14274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for idx, value in enumerate(script_components):
14284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if value == 'base' or value == 'third_party':
14294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base_index = idx
14304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break
14314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os.sep.join(script_components[base_index:])
14324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
14334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(argv):
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage = """usage: %prog [OPTIONS]
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script will parse the given java source code extracting the native
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declarations and print the header file to stdout (or a file).
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See SampleForTests.java for more details.
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser = optparse.OptionParser(usage=usage)
1441116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  build_utils.AddDepfileOption(option_parser)
1442116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
144346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  option_parser.add_option('-j', '--jar_file', dest='jar_file',
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Extract the list of input files from'
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' a specified jar file.'
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' Uses javap to extract the methods from a'
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' pre-compiled class. --input should point'
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' to pre-compiled Java .class files.')
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-n', dest='namespace',
14505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='Uses as a namespace in the generated header '
14515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'instead of the javap class name, or when there is '
14525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'no JNINamespace annotation in the java source.')
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--input_file',
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Single input file name. The output file name '
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           'will be derived from it. Must be used with '
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--output_dir.')
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--output_dir',
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='The output directory. Must be used with '
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--input')
14602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  option_parser.add_option('--optimize_generation', type="int",
14612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           default=0, help='Whether we should optimize JNI '
14622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'generation by not regenerating files if they have '
14632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'not changed.')
1464868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  option_parser.add_option('--jarjar',
1465868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           help='Path to optional jarjar rules file.')
14664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  option_parser.add_option('--script_name', default=GetScriptName(),
14674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           help='The name of this script in the generated '
14684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           'header.')
14695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--includes',
14705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The comma-separated list of header files to '
14715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'include in the generated header.')
14725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--pure_native_methods',
14735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           action='store_true', dest='pure_native_methods',
14745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='When true, the native methods will be called '
14755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'without any JNI-specific arguments.')
14760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  option_parser.add_option('--ptr_type', default='int',
14770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           type='choice', choices=['int', 'long'],
14780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           help='The type used to represent native pointers in '
14790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'Java code. For 32-bit, use int; '
14800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'for 64-bit, use long.')
14815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--jni_init_native_name', default='',
14825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The name of the JNI registration method that '
14835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'is used to initialize all native methods. If a '
14845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'method with this name is not present in the Java '
14855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'source file, setting this option is a no-op. When '
14865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'a method with this name is found however, the '
14875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'naming convention Java_<packageName>_<className> '
14885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'will limit the initialization to only the '
14895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'top-level class.')
14905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--eager_called_by_natives',
14915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           action='store_true', dest='eager_called_by_natives',
14925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='When true, the called-by-native methods will '
14935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'be initialized in a non-atomic way.')
14945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--cpp', default='cpp',
14955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The path to cpp command.')
14965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--javap', default='javap',
14975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The path to javap command.')
14986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  option_parser.add_option('--native_exports', action='store_true',
14996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                           help='Native method registration through .so '
15006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                           'exports.')
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = option_parser.parse_args(argv)
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.jar_file:
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = ExtractJarInputFile(options.jar_file, options.input_file,
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     options.output_dir)
15054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  elif options.input_file:
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = options.input_file
15074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else:
15084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    option_parser.print_help()
15094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    print '\nError: Must specify --jar_file or --input_file.'
15104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 1
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_file = None
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.output_dir:
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_name = os.path.splitext(os.path.basename(input_file))[0]
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
1515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if options.jarjar:
1516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    with open(options.jarjar) as f:
1517868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      JniParams.SetJarJarMappings(f.read())
15184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GenerateJNIHeader(input_file, output_file, options)
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1520116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if options.depfile:
1521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    build_utils.WriteDepfile(
1522116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        options.depfile,
1523116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        build_utils.GetPythonDependencies())
1524116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main(sys.argv))
1528