1#!/usr/bin/python3 2# 3# Copyright 2020, The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""Converts a method to a descriptor or vice-versa. 17 18eg: 19 20% echo 'void myclass.foobar(long, java.lang.Object)' | method-to-descriptor.py 21Lmyclass;->foobar(jLjaga/lang/Object;)V 22% echo 'Lmyclass;->foobar(j)V' | method2descriptor.py -r 23void myclass.foobar(long) 24""" 25 26import argparse 27import sys 28 29 30def GetStdinLineIter(): 31 """reads from stdin""" 32 return map(str.strip, sys.stdin) 33 34 35def readDescriptor(s): 36 """Reads a single descriptor and returns the string starting at the point after the descriptor""" 37 if s[0] == "[": 38 inner, rest = readDescriptor(s[1:]) 39 return "[" + inner, rest 40 elif s[0] == "L": 41 type_end = s.index(";") 42 return s[:type_end + 1], s[type_end + 1:] 43 else: 44 assert s[0] in {"B", "C", "D", "F", "I", "J", "S", "Z", "V"}, s[0] 45 return s[0], s[1:] 46 47 48# Descriptor to name for basic types 49TYPE_MAP = { 50 "V": "void", 51 "B": "byte", 52 "C": "char", 53 "D": "double", 54 "F": "float", 55 "I": "int", 56 "J": "long", 57 "S": "short", 58 "Z": "boolean" 59} 60 61# Name to descriptor 62DESC_MAP = dict((y, x) for x, y in TYPE_MAP.items()) 63 64def TypeDescriptorToName(desc): 65 """Turn a single type descirptor into a name""" 66 if desc[0] == "[": 67 inner = TypeDescriptorToName(desc[1:]) 68 return inner + "[]" 69 elif desc[0] == "L": 70 assert desc[-1] == ";", desc 71 return desc[1:-1].replace("/", ".") 72 else: 73 return TYPE_MAP[desc] 74 75def DescriptorToName(desc): 76 """Turn a method descriptor into a name""" 77 class_name, rest = readDescriptor(desc) 78 assert rest[0:2] == "->", desc 79 rest = rest[2:] 80 args_start = rest.index("(") 81 func_name = rest[:args_start] 82 rest = rest[args_start + 1:] 83 args = [] 84 while rest[0] != ")": 85 cur_arg, rest = readDescriptor(rest) 86 args.append(cur_arg) 87 rest = rest[1:] 88 return_type, rest = readDescriptor(rest) 89 assert rest.strip() == "", desc 90 return "{} {}.{}({})".format( 91 TypeDescriptorToName(return_type), TypeDescriptorToName(class_name), 92 func_name, ",".join(map(TypeDescriptorToName, args))) 93 94def SingleNameToDescriptor(name): 95 if name in DESC_MAP: 96 return DESC_MAP[name] 97 elif name.endswith("[]"): 98 return "[" + SingleNameToDescriptor(name[:-2]) 99 elif name == "": 100 return "" 101 else: 102 return "L" + name.replace(".", "/") + ";" 103 104 105def NameToDescriptor(desc): 106 return_name = desc.split()[0] 107 name_and_args = desc.split()[1] 108 args_start = name_and_args.index("(") 109 names = name_and_args[0:args_start] 110 meth_split = names.rfind(".") 111 class_name = names[:meth_split] 112 meth_name = names[meth_split + 1:] 113 args = map(str.strip, name_and_args[args_start + 1:-1].split(",")) 114 return "{}->{}({}){}".format( 115 SingleNameToDescriptor(class_name), meth_name, 116 "".join(map(SingleNameToDescriptor, args)), 117 SingleNameToDescriptor(return_name)) 118 119 120def main(): 121 parser = argparse.ArgumentParser( 122 "method-to-descriptor.py", 123 description="Convert a java method-name/stream into it's descriptor or vice-versa." 124 ) 125 parser.add_argument( 126 "-r", 127 "--reverse", 128 dest="reverse", 129 action="store_true", 130 default=False, 131 help="reverse. Go from descriptor to method-declaration") 132 parser.add_argument("method", help="what to change", nargs="*") 133 args = parser.parse_args() 134 if args.method != []: 135 inputs = iter(args.method) 136 else: 137 inputs = GetStdinLineIter() 138 for name in inputs: 139 if args.reverse: 140 print(DescriptorToName(name)) 141 else: 142 print(NameToDescriptor(name)) 143 144 145if __name__ == "__main__": 146 main() 147