Source code for apkutils.dex.jvm.writeclass

# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from .. import flags
from ..byteio import Writer
from . import constantpool, writebytecode, error
from .optimization import options

[docs]def writeField(pool, stream, field): stream.u16(field.access & flags.FIELD_FLAGS) stream.u16(pool.utf8(field.id.name)) stream.u16(pool.utf8(field.id.desc)) if field.constant_value is not None: stream.u16(1) stream.u16(pool.utf8(b"ConstantValue")) stream.u32(2) ctype, val = field.constant_value # Ignore dalvik constant type and use actual field type instead index = { b'Z': pool.int, b'B': pool.int, b'S': pool.int, b'C': pool.int, b'I': pool.int, b'F': pool.float, b'J': pool.long, b'D': pool.double, b'Ljava/lang/String;': pool.string, b'Ljava/lang/Class;': pool.class_, }[field.id.desc](val) stream.u16(index) else: stream.u16(0) # no attributes
[docs]def writeMethod(pool, stream, method, code_attr_data): stream.u16(method.access & flags.METHOD_FLAGS) stream.u16(pool.utf8(method.id.name)) stream.u16(pool.utf8(method.id.desc)) if code_attr_data is not None: code_attr_data = code_attr_data.toBytes() stream.u16(1) stream.u16(pool.utf8(b"Code")) stream.u32(len(code_attr_data)) stream.write(code_attr_data) else: stream.u16(0) # no attributes
[docs]def writeMethods(pool, stream, methods, opts): code_irs = [] for method in methods: code_irs.append(writebytecode.getCodeIR(pool, method, opts=opts)) code_attrs = writebytecode.finishCodeAttrs(pool, code_irs, opts=opts) stream.u16(len(methods)) for method in methods: writeMethod(pool, stream, method, code_attrs.get(method))
[docs]def classFileAfterPool(cls, opts): stream = Writer() if opts.split_pool: pool = constantpool.SplitConstantPool() else: pool = constantpool.SimpleConstantPool() cls.parseData() access = cls.access & flags.CLASS_FLAGS if not access & flags.ACC_INTERFACE: # Not necessary for correctness, but this works around a bug in dx access |= flags.ACC_SUPER stream.u16(access) # access stream.u16(pool.class_(cls.name)) # this super_ = pool.class_(cls.super) if cls.super is not None else 0 stream.u16(super_) # super # interfaces stream.u16(len(cls.interfaces)) for interface in cls.interfaces: stream.u16(pool.class_(interface)) # fields stream.u16(len(cls.data.fields)) for field in cls.data.fields: writeField(pool, stream, field) # methods writeMethods(pool, stream, cls.data.methods, opts=opts) # attributes stream.u16(0) return pool, stream
[docs]def toClassFile(cls, opts): stream = Writer() stream.u32(0xCAFEBABE) # bytecode version 49.0 stream.u16(0) stream.u16(49) # Optimistically try translating without optimization to speed things up # if the resulting code is too big, retry with optimization try: pool, rest_stream = classFileAfterPool(cls, opts=opts) except error.ClassfileLimitExceeded: # print('Retrying {} with optimization enabled'.format(cls.name)) pool, rest_stream = classFileAfterPool(cls, opts=options.ALL) # write constant pool pool.write(stream) # write rest of file stream.write(rest_stream.toBytes()) return stream.toBytes()