jni_generator.py revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ParseError(Exception):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Exception thrown when we can't parse the input file."""
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, description, *context_lines):
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Exception.__init__(self)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.description = description
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.context_lines = context_lines
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = '\n'.join(self.context_lines)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Param(object):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a param for a method, either java or native."""
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.datatype = kwargs['datatype']
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NativeMethod(object):
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a C/C++ method that is called by Java code"""
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.params:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params) is list
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params[0]) is Param
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.params and
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        self.params[0].datatype == kwargs.get('ptr_type', 'int') and
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.params[0].name.startswith('native')):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'method'
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.p0_type = self.params[0].name[len('native'):]
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kwargs.get('native_class_name'):
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.p0_type = kwargs['native_class_name']
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'function'
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CalledByNative(object):
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a java method exported to c/c++"""
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.system_class = kwargs['system_class']
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.unchecked = kwargs['unchecked']
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.signature = kwargs.get('signature')
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_constructor = kwargs.get('is_constructor', False)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.env_call = GetEnvCall(self.is_constructor, self.static,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               self.return_type)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static_cast = GetStaticCastForReturnType(self.return_type)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def JavaDataTypeToC(java_type):
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a C datatype for the given java type."""
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_pod_type_map = {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'int': 'jint',
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'byte': 'jbyte',
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'char': 'jchar',
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'short': 'jshort',
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'boolean': 'jboolean',
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'long': 'jlong',
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'double': 'jdouble',
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'float': 'jfloat',
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_type_map = {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'void': 'void',
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'String': 'jstring',
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'java/lang/String': 'jstring',
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'Class': 'jclass',
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'java/lang/Class': 'jclass',
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if java_type in java_pod_type_map:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_pod_type_map[java_type]
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type in java_type_map:
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_type_map[java_type]
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type.endswith('[]'):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if java_type[:-2] in java_pod_type_map:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return java_pod_type_map[java_type[:-2]] + 'Array'
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobject'
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JniParams(object):
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _imports = []
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _fully_qualified_class = ''
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _package = ''
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _inner_classes = []
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  _remappings = []
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetFullyQualifiedClass(fully_qualified_class):
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._fully_qualified_class = 'L' + fully_qualified_class
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtractImportsAndInnerClasses(contents):
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = contents.replace('\n', '')
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_import = re.compile(r'import.*?(?P<class>\S*?);')
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_import, contents):
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_inner, contents):
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inner = match.group('name')
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not JniParams._fully_qualified_class.endswith(inner):
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     inner]
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def ParseJavaPSignature(signature_line):
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    prefix = 'Signature: '
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):]
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @staticmethod
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def JavaToJni(param):
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Converts a java param into a JNI signature type."""
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod_param_map = {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'int': 'I',
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'boolean': 'Z',
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'char': 'C',
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'short': 'S',
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'long': 'J',
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'double': 'D',
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'float': 'F',
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'byte': 'B',
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'void': 'V',
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    object_param_list = [
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Boolean',
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Integer',
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Long',
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Object',
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/String',
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'Ljava/lang/Class',
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prefix = ''
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Array?
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while param[-2:] == '[]':
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prefix += '['
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:-2]
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generic?
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '<' in param:
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:param.index('<')]
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if param in pod_param_map:
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return prefix + pod_param_map[param]
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '/' in param:
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Coming from javap, use the fully qualified param directly.
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return prefix + 'L' + JniParams.RemapClassName(param) + ';'
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for qualified_name in (object_param_list +
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           [JniParams._fully_qualified_class] +
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           JniParams._inner_classes):
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (qualified_name.endswith('/' + param) or
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name.endswith('$' + param.replace('.', '$')) or
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name == 'L' + param):
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it from an import? (e.g. referecing Class from import pkg.Class;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # note that referencing an inner class Inner from import pkg.Class.Inner
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # is not supported).
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for qualified_name in JniParams._imports:
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if qualified_name.endswith('/' + param):
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Ensure it's not an inner class.
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        components = qualified_name.split('/')
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if len(components) > 2 and components[-2][0].isupper():
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          raise SyntaxError('Inner class (%s) can not be imported '
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'and used by JNI (%s). Please import the outer '
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'class and use Outer.Inner instead.' %
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            (qualified_name, param))
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it an inner class from an outer class import? (e.g. referencing
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Class.Inner from import pkg.Class).
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if '.' in param:
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      components = param.split('.')
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      outer = '/'.join(components[:-1])
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      inner = components[-1]
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for qualified_name in JniParams._imports:
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if qualified_name.endswith('/' + outer):
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          return (prefix + JniParams.RemapClassName(qualified_name) +
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  '$' + inner + ';')
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Type not found, falling back to same package as this class.
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return (prefix + 'L' +
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Signature(params, returns, wrap):
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the JNI signature for the given datatypes."""
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items = ['(']
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(param.datatype) for param in params]
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [')']
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(returns)]
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if wrap:
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n' + '\n'.join(['"' + item + '"' for item in items])
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '"' + ''.join(items) + '"'
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Parse(params):
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Parses the params into a list of Param objects."""
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not params:
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return []
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for p in [p.strip() for p in params.split(',')]:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      items = p.split(' ')
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'final' in items:
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        items.remove('final')
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = Param(
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          datatype=items[0],
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      )
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [param]
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def RemapClassName(class_name):
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Remaps class names using the jarjar mapping table."""
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for old, new in JniParams._remappings:
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if old in class_name:
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return class_name.replace(old, new, 1)
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return class_name
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def SetJarJarMappings(mappings):
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Parse jarjar mappings from a string."""
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    JniParams._remappings = []
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for line in mappings.splitlines():
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      keyword, src, dest = line.split()
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if keyword != 'rule':
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        continue
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      assert src.endswith('.**')
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      src = src[:-2].replace('.', '/')
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      dest = dest.replace('.', '/')
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if dest.endswith('@0'):
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2] + src))
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      else:
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        assert dest.endswith('@1')
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2]))
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJNINamespace(contents):
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  m = re.findall(re_jni_namespace, contents)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not m:
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return m[0]
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_package = re.compile('.*?package (.*?);')
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  matches = re.findall(re_package, contents)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not matches:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (matches[0].replace('.', '/') + '/' +
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.path.splitext(os.path.basename(java_file_name))[0])
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)def ExtractNatives(contents, ptr_type):
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a list of dict containing information about a native method."""
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents = contents.replace('\n', '')
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  natives = []
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_native = re.compile(r'(@NativeClassQualifiedName'
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '\(\"(?P<native_class_name>.*?)\"\))?\s*'
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*'
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native '
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         '(?P<return_type>\S*?) '
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '(?P<name>\w+?)\((?P<params>.*?)\);')
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(re_native, contents):
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native = NativeMethod(
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('qualifiers'),
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('java_class_name'),
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        native_class_name=match.group('native_class_name'),
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return_type=match.group('return_type'),
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name').replace('native', ''),
3100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        params=JniParams.Parse(match.group('params')),
3110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        ptr_type=ptr_type)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    natives += [native]
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return natives
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetStaticCastForReturnType(return_type):
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  type_map = { 'String' : 'jstring',
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'java/lang/String' : 'jstring',
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'boolean[]': 'jbooleanArray',
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'byte[]': 'jbyteArray',
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'char[]': 'jcharArray',
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'short[]': 'jshortArray',
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'int[]': 'jintArray',
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'long[]': 'jlongArray',
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'double[]': 'jdoubleArray' }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ret = type_map.get(return_type, None)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ret:
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if return_type.endswith('[]'):
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return None
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetEnvCall(is_constructor, is_static, return_type):
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Maps the types availabe via env->Call__Method."""
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_constructor:
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'NewObject'
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env_call_map = {'boolean': 'Boolean',
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'byte': 'Byte',
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'char': 'Char',
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'short': 'Short',
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'int': 'Int',
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'long': 'Long',
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'float': 'Float',
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'void': 'Void',
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'double': 'Double',
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'Object': 'Object',
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  call = env_call_map.get(return_type, 'Object')
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_static:
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    call = 'Static' + call
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 'Call' + call + 'Method'
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledParam(datatype):
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled identifier for the datatype."""
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(datatype) <= 2:
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return datatype.replace('[', 'A')
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = ''
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for i in range(1, len(datatype)):
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = datatype[i]
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if c == '[':
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += 'A'
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += c.upper()
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledMethodName(name, params, return_type):
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled method name for the given signature.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     The returned name can be used as a C identifier and will be unique for all
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     valid overloads of the same method.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     name: string.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     params: list of Param.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     return_type: string.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A mangled name.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_items = []
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for datatype in [return_type] + [x.datatype for x in params]:
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_name = name + '_'.join(mangled_items)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mangled_name
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MangleCalledByNatives(called_by_natives):
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Mangles all the overloads from the call_by_natives list."""
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_counts = collections.defaultdict(
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lambda: collections.defaultdict(lambda: 0))
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = called_by_native.name
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_counts[java_class_name][name] += 1
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_name = called_by_native.name
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_id_var_name = method_name
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if method_counts[java_class_name][method_name] > 1:
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method_id_var_name = GetMangledMethodName(method_name,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.params,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.return_type)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native.method_id_var_name = method_id_var_name
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return called_by_natives
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match the JNI return types that should be included in a
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ScopedJavaLocalRef.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match a string like "@CalledByNative public void foo(int bar)".
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_CALLED_BY_NATIVE = re.compile(
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<prefix>[\w ]*?)'
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    '\s*(?P<return_type>\S+?)'
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<name>\w+)'
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s*\((?P<params>[^\)]*)\)')
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractCalledByNatives(contents):
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Parses all methods annotated with @CalledByNative.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents: the contents of the java file.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A list of dict with information about the annotated methods.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TODO(bulach): return a CalledByNative object.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseError: if unable to parse.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  called_by_natives = []
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives += [CalledByNative(
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        system_class=False,
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unchecked='Unchecked' in match.group('Unchecked'),
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('prefix'),
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('annotation') or '',
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_type=match.group('return_type'),
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name'),
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        params=JniParams.Parse(match.group('params')))]
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Check for any @CalledByNative occurrences that weren't matched.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '@CalledByNative' in line1:
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ParseError('could not parse @CalledByNative method signature',
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       line1, line2)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MangleCalledByNatives(called_by_natives)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaP(object):
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses 'javap' to parse a .class file and generate the JNI header file."""
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, options):
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.contents = contents
4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.namespace = options.namespace
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.fully_qualified_class = re.match(
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        '.*?(class|interface) (?P<class_name>.*?)( |{)',
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        contents[1]).group('class_name')
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
46658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
46758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # away the <...> and use the raw class name that Java 6 would've given us.
46858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = self.fully_qualified_class.split('/')[-1]
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.namespace:
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.namespace = 'JNI_' + self.java_class_name
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '\((?P<params>.*?)\)')
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = []
4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_method, content)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static='static' in match.group('prefix'),
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=match.group('return_type').replace('.', '/'),
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=match.group('name'),
4871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
4881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
4891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    re_constructor = re.compile('(.*?)public ' +
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                self.fully_qualified_class.replace('/', '.') +
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                '\((?P<params>.*?)\)')
4921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_constructor, content)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static=False,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=self.fully_qualified_class,
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name='Constructor',
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
5041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_constructor=True)]
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.inl_header_file_generator = InlHeaderFileGenerator(
5084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        self.namespace, self.fully_qualified_class, [],
5094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        self.called_by_natives, options)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.inl_header_file_generator.GetContent()
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromClass(class_file, options):
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class_name = os.path.splitext(os.path.basename(class_file))[0]
5171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    p = subprocess.Popen(args=['javap', '-s', class_name],
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         cwd=os.path.dirname(class_file),
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdout=subprocess.PIPE,
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stderr=subprocess.PIPE)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, _ = p.communicate()
5224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return jni_from_javap
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaSource(object):
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses the given java source file to generate the JNI header file."""
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, fully_qualified_class, options):
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = self._RemoveComments(contents)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(fully_qualified_class)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.ExtractImportsAndInnerClasses(contents)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_namespace = ExtractJNINamespace(contents)
5340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    natives = ExtractNatives(contents, options.ptr_type)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives = ExtractCalledByNatives(contents)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(natives) == 0 and len(called_by_natives) == 0:
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise SyntaxError('Unable to find any JNI methods for %s.' %
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        fully_qualified_class)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inl_header_file_generator = InlHeaderFileGenerator(
5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        jni_namespace, fully_qualified_class, natives, called_by_natives,
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        options)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.content = inl_header_file_generator.GetContent()
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _RemoveComments(self, contents):
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We need to support both inline and block comments, and we need to handle
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # strings that contain '//' or '/*'. Rather than trying to do all that with
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # regexps, we just pipe the contents through the C preprocessor. We tell cpp
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the file has already been preprocessed, so it just removes comments and
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # doesn't try to parse #include, #pragma etc.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # parser. Maybe we could ditch JNIFromJavaSource and just always use
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # http://code.google.com/p/chromium/issues/detail?id=138941
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p = subprocess.Popen(args=['cpp', '-fpreprocessed'],
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdin=subprocess.PIPE,
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdout=subprocess.PIPE,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stderr=subprocess.PIPE)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, _ = p.communicate(contents)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return stdout
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.content
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromFile(java_file_name, options):
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = file(java_file_name).read()
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               contents)
5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return JNIFromJavaSource(contents, fully_qualified_class, options)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InlHeaderFileGenerator(object):
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates an inline header file for JNI integration."""
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, namespace, fully_qualified_class, natives,
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)               called_by_natives, options):
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.namespace = namespace
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = fully_qualified_class
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.class_name = self.fully_qualified_class.split('/')[-1]
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.natives = natives
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = called_by_natives
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.script_name = options.script_name
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the content of the JNI binding file."""
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is autogenerated by
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${SCRIPT_NAME}
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${FULLY_QUALIFIED_CLASS}
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef ${HEADER_GUARD}
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ${HEADER_GUARD}
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <jni.h>
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/jni_android.h"
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/android/scoped_java_ref.h"
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::android::ScopedJavaLocalRef;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 1: forward declarations.
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLASS_PATH_DEFINITIONS
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$OPEN_NAMESPACE
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$FORWARD_DECLARATIONS
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 2: method stubs.
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$METHOD_STUBS
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 3: RegisterNatives.
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool RegisterNativesImpl(JNIEnv* env) {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$REGISTER_NATIVES_IMPL
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLOSE_NAMESPACE
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // ${HEADER_GUARD}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
6324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'SCRIPT_NAME': self.script_name,
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_STUBS': self.GetMethodStubsString(),
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString(),
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'HEADER_GUARD': self.header_guard,
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return WrapOutput(template.substitute(values))
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitionsString(self):
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += [self.GetClassPathDefinitions()]
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclarationsString(self):
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type != 'method':
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetForwardDeclaration(native)]
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodStubsString(self):
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type == 'method':
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetNativeMethodStub(native)]
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for called_by_native in self.called_by_natives:
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [self.GetCalledByNativeMethodStub(called_by_native)]
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodsString(self, clazz):
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (native.java_class_name == clazz or
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (not native.java_class_name and clazz == self.class_name)):
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetKMethodArrayEntry(native)]
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetRegisterNativesImplString(self):
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the implementation for RegisterNatives."""
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${KMETHODS}
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           kMethods${JAVA_CLASS},
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           kMethods${JAVA_CLASS}Size) < 0) {
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = [self.GetFindClasses()]
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes = self.GetUniqueClasses(self.natives)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes[self.class_name] = self.fully_qualified_class
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kmethods = self.GetKMethodsString(clazz)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kmethods:
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        values = {'JAVA_CLASS': clazz,
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'KMETHODS': kmethods}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [template.substitute(values)]
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not ret: return ''
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n' + '\n'.join(ret)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetOpenNamespaceString(self):
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['namespace %s {' % ns
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCloseNamespaceString(self):
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['}  // namespace %s' % ns
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces.reverse()
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces) + '\n'
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetJNIFirstParam(self, native):
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if native.type == 'method':
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = ['jobject obj']
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif native.type == 'function':
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.static:
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret = ['jclass clazz']
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret = ['jobject obj']
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetParamsInDeclaration(self, native):
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the params for the stub declaration.
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      native: the native dictionary describing the method.
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string containing the params.
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ',\n    '.join(self.GetJNIFirstParam(native) +
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          [JavaDataTypeToC(param.datatype) + ' ' +
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           param.name
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           for param in native.params])
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ',\n    '.join([JavaDataTypeToC(param.datatype) + ' ' +
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           param.name
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           for param in called_by_native.params])
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclaration(self, native):
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'RETURN': JavaDataTypeToC(native.return_type),
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'NAME': native.name,
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'PARAMS': self.GetParamsInDeclaration(native)}
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetNativeMethodStub(self, native):
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns stubs for native methods."""
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(${PARAM0_NAME}) << "${NAME}";
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return native->${NAME}(env, obj${PARAMS_IN_CALL})${POST_CALL};
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_for_call = ', '.join(p.name for p in native.params[1:])
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if params_for_call:
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_for_call = ', ' + params_for_call
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(native.return_type)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_return_type = 'ScopedJavaLocalRef<' + return_type + '>'
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = '.Release()'
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_return_type = return_type
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = ''
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN': return_type,
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'SCOPED_RETURN': scoped_return_type,
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'NAME': native.name,
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAM0_NAME': native.params[0].name,
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'P0_TYPE': native.p0_type,
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_CALL': params_for_call,
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCalledByNativeMethodStub(self, called_by_native):
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a string."""
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_signature_template = Template("""\
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_header_template = Template("""\
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function_header_with_unused_template = Template("""\
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${FUNCTION_SIGNATURE} __attribute__ ((unused));
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${FUNCTION_HEADER}
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Must call RegisterNativesImpl()  */
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(g_${JAVA_CLASS}_clazz);
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  jmethodID method_id =
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ${GET_METHOD_ID_IMPL}
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${RETURN_DECLARATION}
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method_id${PARAMS_IN_CALL})${POST_CALL};
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${CHECK_EXCEPTION}
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${RETURN_CLAUSE}
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}""")
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static or called_by_native.is_constructor:
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ''
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_call = ('g_%s_clazz' %
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             (called_by_native.java_class_name or
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              self.class_name))
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ', jobject obj'
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_call = 'obj'
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        called_by_native)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if params_in_declaration:
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_in_declaration = ', ' + params_in_declaration
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_for_call = ', '.join(param.name
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                for param in called_by_native.params)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if params_for_call:
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_for_call = ', ' + params_for_call
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pre_call = ''
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    post_call = ''
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static_cast:
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = ')'
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_exception = ''
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not called_by_native.unchecked:
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      check_exception = 'base::android::CheckException(env);'
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(called_by_native.return_type)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_declaration = ''
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_clause = ''
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if return_type != 'void':
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_call = '  ' + pre_call
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return_declaration = return_type + ' ret ='
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_type = 'ScopedJavaLocalRef<' + return_type + '>'
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ' + return_type + '(env, ret);'
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ret;'
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD': called_by_native.name,
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_TYPE': return_type,
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_DECLARATION': return_declaration,
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_CLAUSE': return_clause,
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': params_in_declaration,
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'STATIC': 'Static' if called_by_native.static else '',
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PRE_CALL': pre_call,
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call,
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'ENV_CALL': called_by_native.env_call,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_CALL': first_param_in_call,
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_CALL': params_for_call,
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CHECK_EXCEPTION': check_exception,
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values['FUNCTION_SIGNATURE'] = (
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        function_signature_template.substitute(values))
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.system_class:
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = (
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          function_header_with_unused_template.substitute(values))
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodArrayEntry(self, native):
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'NAME': native.name,
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'JNI_SIGNATURE': JniParams.Signature(native.params,
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   native.return_type,
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   True)}
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetUniqueClasses(self, origin):
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = {self.class_name: self.fully_qualified_class}
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for entry in origin:
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      class_name = self.class_name
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_class_path = self.fully_qualified_class
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if entry.java_class_name:
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        class_name = entry.java_class_name
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jni_class_path = self.fully_qualified_class + '$' + class_name
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret[class_name] = jni_class_path
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitions(self):
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the ClassPath constants."""
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native_classes = self.GetUniqueClasses(self.natives)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes = native_classes
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes.update(called_by_native_classes)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
903868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]),
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ''
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in called_by_native_classes:
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template = Template("""\
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Leaking this jclass as we cannot use LazyInstance from some threads.
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jclass g_${JAVA_CLASS}_clazz = NULL;""")
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFindClasses(self):
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the imlementation of FindClass for all known classes."""
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
921c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in self.GetUniqueClasses(self.called_by_natives):
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {'JAVA_CLASS': clazz}
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodIDImpl(self, called_by_native):
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the implementation of GetMethodID."""
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::android::MethodID::LazyGet<
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::android::MethodID::TYPE_${STATIC}>(
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env, g_${JAVA_CLASS}_clazz,
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "${JNI_NAME}",
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ${JNI_SIGNATURE},
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_name = called_by_native.name
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_return_type = called_by_native.return_type
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.is_constructor:
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_name = '<init>'
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_return_type = 'void'
9431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if called_by_native.signature:
9441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = called_by_native.signature
9451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else:
9461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = JniParams.Signature(called_by_native.params,
9471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      jni_return_type,
9481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      True)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JNI_NAME': jni_name,
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
9541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        'JNI_SIGNATURE': signature,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WrapOutput(output):
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = []
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in output.splitlines():
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Do not wrap lines under 80 characters or preprocessor directives.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(line) < 80 or line.lstrip()[:1] == '#':
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped = line.rstrip()
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(ret) == 0 or len(ret[-1]) or len(stripped):
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret.append(stripped)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subsequent_indent =  first_line_indent + ' ' * 4
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line.startswith('//'):
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        subsequent_indent = '//' + subsequent_indent
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper = textwrap.TextWrapper(width=80,
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     subsequent_indent=subsequent_indent,
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     break_long_words=False)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret += ['']
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return '\n'.join(ret)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJarInputFile(jar_file, input_file, out_dir):
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Extracts input file from jar and returns the filename.
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The input file is extracted to the same directory that the generated jni
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers will be placed in.  This is passed as an argument to script.
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jar_file: the jar file containing the input files to extract.
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_files: the list of files to extract from the jar file.
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: the name of the directories to extract to.
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the name of extracted input file.
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  jar_file = zipfile.ZipFile(jar_file)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try:
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(out_dir)
9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  except OSError as e:
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if e.errno != errno.EEXIST:
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with open(extracted_file_name, 'w') as outfile:
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(jar_file.read(input_file))
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extracted_file_name
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GenerateJNIHeader(input_file, output_file, options):
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if os.path.splitext(input_file)[1] == '.class':
10124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_javap.GetContent()
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
10154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
10164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          input_file, options)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_java_source.GetContent()
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except ParseError, e:
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print e
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.exit(1)
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if output_file:
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
10244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if options.optimize_generation and os.path.exists(output_file):
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      with file(output_file, 'r') as f:
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        existing_content = f.read()
10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if existing_content == content:
10282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with file(output_file, 'w') as f:
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write(content)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print output
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GetScriptName():
10364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
10374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base_index = 0
10384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for idx, value in enumerate(script_components):
10394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if value == 'base' or value == 'third_party':
10404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base_index = idx
10414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break
10424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os.sep.join(script_components[base_index:])
10434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
10444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(argv):
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage = """usage: %prog [OPTIONS]
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script will parse the given java source code extracting the native
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declarations and print the header file to stdout (or a file).
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See SampleForTests.java for more details.
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser = optparse.OptionParser(usage=usage)
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-j', dest='jar_file',
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Extract the list of input files from'
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' a specified jar file.'
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' Uses javap to extract the methods from a'
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' pre-compiled class. --input should point'
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' to pre-compiled Java .class files.')
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-n', dest='namespace',
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Uses as a namespace in the generated header,'
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' instead of the javap class name.')
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--input_file',
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Single input file name. The output file name '
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           'will be derived from it. Must be used with '
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--output_dir.')
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--output_dir',
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='The output directory. Must be used with '
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--input')
10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  option_parser.add_option('--optimize_generation', type="int",
10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           default=0, help='Whether we should optimize JNI '
10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'generation by not regenerating files if they have '
10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'not changed.')
1072868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  option_parser.add_option('--jarjar',
1073868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           help='Path to optional jarjar rules file.')
10744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  option_parser.add_option('--script_name', default=GetScriptName(),
10754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           help='The name of this script in the generated '
10764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           'header.')
10770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  option_parser.add_option('--ptr_type', default='int',
10780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           type='choice', choices=['int', 'long'],
10790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           help='The type used to represent native pointers in '
10800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'Java code. For 32-bit, use int; '
10810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'for 64-bit, use long.')
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = option_parser.parse_args(argv)
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.jar_file:
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = ExtractJarInputFile(options.jar_file, options.input_file,
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     options.output_dir)
10864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  elif options.input_file:
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = options.input_file
10884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else:
10894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    option_parser.print_help()
10904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    print '\nError: Must specify --jar_file or --input_file.'
10914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 1
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_file = None
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.output_dir:
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_name = os.path.splitext(os.path.basename(input_file))[0]
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
1096868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if options.jarjar:
1097868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    with open(options.jarjar) as f:
1098868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      JniParams.SetJarJarMappings(f.read())
10994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GenerateJNIHeader(input_file, output_file, options)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main(sys.argv))
1104