# This file is part of Androguard.
#
# Copyright (C) 2012/2013/2014, <NAME> <desnos at t0t0.fr>
# 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 androguard.core import bytecode
from androguard.core.bytecodes.apk import APK
from androguard.core.androconf import CONF, debug, warning, is_android_raw
from androguard.util import read

import sys
import re
import struct
from struct import pack, unpack, calcsize

DEX_FILE_MAGIC_35 = 'dex\n035\x00'
DEX_FILE_MAGIC_36 = 'dex\n036\x00'
ODEX_FILE_MAGIC_35 = 'dey\n035\x00'
ODEX_FILE_MAGIC_36 = 'dey\n036\x00'


TYPE_MAP_ITEM = {
                        0x0:      "TYPE_HEADER_ITEM",
                        0x1:      "TYPE_STRING_ID_ITEM",
                        0x2:      "TYPE_TYPE_ID_ITEM",
                        0x3:      "TYPE_PROTO_ID_ITEM",
                        0x4:      "TYPE_FIELD_ID_ITEM",
                        0x5:      "TYPE_METHOD_ID_ITEM",
                        0x6:      "TYPE_CLASS_DEF_ITEM",
                        0x1000:    "TYPE_MAP_LIST",
                        0x1001:    "TYPE_TYPE_LIST",
                        0x1002:    "TYPE_ANNOTATION_SET_REF_LIST",
                        0x1003:    "TYPE_ANNOTATION_SET_ITEM",
                        0x2000:    "TYPE_CLASS_DATA_ITEM",
                        0x2001:    "TYPE_CODE_ITEM",
                        0x2002:    "TYPE_STRING_DATA_ITEM",
                        0x2003:    "TYPE_DEBUG_INFO_ITEM",
                        0x2004:    "TYPE_ANNOTATION_ITEM",
                        0x2005:    "TYPE_ENCODED_ARRAY_ITEM",
                        0x2006:    "TYPE_ANNOTATIONS_DIRECTORY_ITEM",
                     }

ACCESS_FLAGS = [
    (0x1, 'public'),
    (0x2, 'private'),
    (0x4, 'protected'),
    (0x8, 'static'),
    (0x10, 'final'),
    (0x20, 'synchronized'),
    (0x40, 'bridge'),
    (0x80, 'varargs'),
    (0x100, 'native'),
    (0x200, 'interface'),
    (0x400, 'abstract'),
    (0x800, 'strictfp'),
    (0x1000, 'synthetic'),
    (0x4000, 'enum'),
    (0x8000, 'unused'),
    (0x10000, 'constructor'),
    (0x20000, 'synchronized'),
]

TYPE_DESCRIPTOR = {
    'V': 'void',
    'Z': 'boolean',
    'B': 'byte',
    'S': 'short',
    'C': 'char',
    'I': 'int',
    'J': 'long',
    'F': 'float',
    'D': 'double',
}

def get_access_flags_string(value):
  """
      Transform an access flags to the corresponding string

      :param value: the value of the access flags
      :type value: int

      :rtype: string
  """
  buff = ""
  for i in ACCESS_FLAGS:
    if (i[0] & value) == i[0]:
      buff += i[1] + " "

  if buff != "":
    return buff[:-1]
  return buff


def get_type(atype, size=None):
    """
      Retrieve the type of a descriptor (e.g : I)
    """
    if atype.startswith('java.lang'):
        atype = atype.replace('java.lang.', '')
    res = TYPE_DESCRIPTOR.get(atype.lstrip('java.lang'))
    if res is None:
        if atype[0] == 'L':
            res = atype[1:-1].replace('/', '.')
        elif atype[0] == '[':
            if size is None:
                res = '%s[]' % get_type(atype[1:])
            else:
                res = '%s[%s]' % (get_type(atype[1:]), size)
        else:
            res = atype
    return res


MATH_DVM_OPCODES = {        "add." : '+',
                            "div." : '/',
                            "mul." : '*',
                            "or." : '|',
                            "sub." : '-',
                            "and." : '&',
                            "xor." : '^',
                            "shl." : "<<",
                            "shr." : ">>",
                    }

FIELD_READ_DVM_OPCODES = [ ".get" ]
FIELD_WRITE_DVM_OPCODES = [ ".put" ]

BREAK_DVM_OPCODES = [ "invoke.", "move.", ".put", "if." ]

BRANCH_DVM_OPCODES = [ "throw", "throw.", "if.", "goto", "goto.", "return", "return.", "packed-switch$",  "sparse-switch$" ]

def clean_name_instruction( instruction ):
    op_value = instruction.get_op_value()

    # goto range
    if op_value >= 0x28 and op_value <= 0x2a:
        return "goto"

    return instruction.get_name()

def static_operand_instruction( instruction ):
    buff = ""

    if isinstance(instruction, Instruction):
      # get instructions without registers
      for val in instruction.get_literals():
          buff += "%s" % val

    op_value = instruction.get_op_value()
    if op_value == 0x1a or op_value == 0x1b:
        buff += instruction.get_string()

    return buff

html_escape_table = {
    "&": "&amp;",
    '"': "&quot;",
    "'": "&apos;",
    ">": "&gt;",
    "<": "&lt;",
}

def readuleb128(buff):
    result = ord( buff.read(1) )
    if result > 0x7f:
        cur = ord( buff.read(1) )
        result = (result & 0x7f) | ((cur & 0x7f) << 7)
        if cur > 0x7f:
            cur = ord( buff.read(1) )
            result |= (cur & 0x7f) << 14
            if cur > 0x7f:
                cur = ord( buff.read(1) )
                result |= (cur & 0x7f) << 21
                if cur > 0x7f:
                    cur = ord( buff.read(1) )
                    if cur > 0x0f:
                      warning("possible error while decoding number")
                    result |= cur << 28

    return result

def readusleb128(buff):
    result = ord( buff.read(1) )
    if result > 0x7f:
        cur = ord( buff.read(1) )
        result = (result & 0x7f) | ((cur & 0x7f) << 7)
        if cur > 0x7f:
            cur = ord( buff.read(1) )
            result |= (cur & 0x7f) << 14
            if cur > 0x7f:
                cur = ord( buff.read(1) )
                result |= (cur & 0x7f) << 21
                if cur > 0x7f:
                    cur = ord( buff.read(1) )
                    result |= cur << 28

    return result

def readuleb128p1(buff):
  return readuleb128( buff ) - 1

def readsleb128(buff):
  result = 0
  shift = 0

  for x in range(0, 5):
     cur = ord( buff.read(1) )
     result |= (cur & 0x7f) << shift
     shift += 7

     if not cur & 0x80:
        bit_left = max(32 - shift, 0)
        result = result << bit_left
        if result > 0x7fffffff:
            result = (0x7fffffff & result) - 0x80000000
        result = result >> bit_left
        break

  return result

def get_sbyte(buff):
  return unpack( '=b', buff.read(1) )[0]

def writeuleb128(value):
    remaining = value >> 7

    buff = ""
    while remaining > 0:
        buff += pack( "=B", ((value & 0x7f) | 0x80) )

        value = remaining
        remaining >>= 7

    buff += pack( "=B", value & 0x7f )
    return buff

def writesleb128(value):
    remaining = value >> 7
    hasMore = True
    end = 0
    buff = ""

    if (value & (-sys.maxint - 1)) == 0:
        end = 0
    else:
        end = -1

    while hasMore:
        hasMore = (remaining != end) or ((remaining & 1) != ((value >> 6) & 1))
        tmp = 0
        if hasMore:
            tmp = 0x80

        buff += pack( "=B", (value & 0x7f) | (tmp) )
        value = remaining
        remaining >>= 7

    return buff

def determineNext(i, end, m):
    op_value = i.get_op_value()

    # throw + return*
    if (op_value == 0x27) or (0x0e <= op_value <= 0x11):
        return [ -1 ]
    # goto
    elif 0x28 <= op_value <= 0x2a:
        off = i.get_ref_off() * 2
        return [ off + end ]
    # if
    elif 0x32 <= op_value <= 0x3d:
        off = i.get_ref_off() * 2
        return [ end + i.get_length(), off + (end) ]
    # sparse/packed
    elif op_value in (0x2b, 0x2c):
        x = []

        x.append( end + i.get_length() )

        code = m.get_code().get_bc()
        off = i.get_ref_off() * 2

        data = code.get_ins_off( off + end )

        if data != None:
            for target in data.get_targets():
                x.append( target*2 + end )

        return x
    return []

def determineException(vm, m):
    # no exceptions !
    if m.get_code().get_tries_size() <= 0:
        return []

    h_off = {}

    handler_catch_list = m.get_code().get_handlers()

    for try_item in m.get_code().get_tries():
        offset_handler = try_item.get_handler_off() + handler_catch_list.get_off()
        if offset_handler in h_off:
          h_off[ offset_handler ].append( [ try_item ] )
        else:
          h_off[ offset_handler ] = []
          h_off[ offset_handler ].append( [ try_item ] )

    #print m.get_name(), "\t HANDLER_CATCH_LIST SIZE", handler_catch_list.size, handler_catch_list.get_offset()
    for handler_catch in handler_catch_list.get_list():
        if handler_catch.get_off() not in h_off:
            continue

        for i in h_off[ handler_catch.get_off() ]:
          i.append( handler_catch )

    exceptions = []
    #print m.get_name(), h_off
    for i in h_off:
      for value in h_off[ i ]:
        try_value = value[0]

        z = [ try_value.get_start_addr() * 2, (try_value.get_start_addr() * 2) + (try_value.get_insn_count() * 2) - 1 ]

        handler_catch = value[1]
        if handler_catch.get_size() <= 0:
            z.append( [ "Ljava/lang/Throwable;", handler_catch.get_catch_all_addr() * 2 ] )

        for handler in handler_catch.get_handlers():
            z.append( [ vm.get_cm_type( handler.get_type_idx() ), handler.get_addr() * 2 ] )

        exceptions.append( z )

    #print m.get_name(), exceptions
    return exceptions

class HeaderItem(object):
    """
        This class can parse an header_item of a dex file

        :param buff: a string which represents a Buff object of the header_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.magic = unpack("=Q", buff.read(8))[0]
        self.checksum = unpack("=i", buff.read(4))[0]
        self.signature = unpack("=20s", buff.read(20))[0]
        self.file_size = unpack("=I", buff.read(4))[0]
        self.header_size = unpack("=I", buff.read(4))[0]
        self.endian_tag = unpack("=I", buff.read(4))[0]
        self.link_size = unpack("=I", buff.read(4))[0]
        self.link_off = unpack("=I", buff.read(4))[0]
        self.map_off = unpack("=I", buff.read(4))[0]
        self.string_ids_size = unpack("=I", buff.read(4))[0]
        self.string_ids_off = unpack("=I", buff.read(4))[0]
        self.type_ids_size = unpack("=I", buff.read(4))[0]
        self.type_ids_off = unpack("=I", buff.read(4))[0]
        self.proto_ids_size = unpack("=I", buff.read(4))[0]
        self.proto_ids_off = unpack("=I", buff.read(4))[0]
        self.field_ids_size = unpack("=I", buff.read(4))[0]
        self.field_ids_off = unpack("=I", buff.read(4))[0]
        self.method_ids_size = unpack("=I", buff.read(4))[0]
        self.method_ids_off = unpack("=I", buff.read(4))[0]
        self.class_defs_size = unpack("=I", buff.read(4))[0]
        self.class_defs_off = unpack("=I", buff.read(4))[0]
        self.data_size = unpack("=I", buff.read(4))[0]
        self.data_off = unpack("=I", buff.read(4))[0]

        self.map_off_obj = None
        self.string_off_obj = None
        self.type_off_obj = None
        self.proto_off_obj = None
        self.field_off_obj = None
        self.method_off_obj = None
        self.class_off_obj = None
        self.data_off_obj = None

    def reload(self):
      pass

    def get_obj(self):
      if self.map_off_obj == None:
        self.map_off_obj = self.__CM.get_item_by_offset( self.map_off )

      if self.string_off_obj == None:
        self.string_off_obj = self.__CM.get_item_by_offset( self.string_ids_off )

      if self.type_off_obj == None:
        self.type_off_obj = self.__CM.get_item_by_offset( self.type_ids_off )

      if self.proto_off_obj == None:
        self.proto_off_obj = self.__CM.get_item_by_offset( self.proto_ids_off )

      if self.field_off_obj == None:
        self.field_off_obj = self.__CM.get_item_by_offset( self.field_ids_off )

      if self.method_off_obj == None:
        self.method_off_obj = self.__CM.get_item_by_offset( self.method_ids_off )

      if self.class_off_obj == None:
        self.class_off_obj = self.__CM.get_item_by_offset( self.class_defs_off )

      if self.data_off_obj == None:
        self.data_off_obj = self.__CM.get_item_by_offset( self.data_off )

      self.map_off = self.map_off_obj.get_off()

      self.string_ids_size = len(self.string_off_obj)
      self.string_ids_off = self.string_off_obj[0].get_off()

      self.type_ids_size = len(self.type_off_obj.type)
      self.type_ids_off = self.type_off_obj.get_off()

      self.proto_ids_size = len(self.proto_off_obj.proto)
      self.proto_ids_off = self.proto_off_obj.get_off()

      self.field_ids_size = len(self.field_off_obj.elem)
      self.field_ids_off = self.field_off_obj.get_off()

      self.method_ids_size = len(self.method_off_obj.methods)
      self.method_ids_off = self.method_off_obj.get_off()

      self.class_defs_size = len(self.class_off_obj.class_def)
      self.class_defs_off = self.class_off_obj.get_off()

      self.data_size = len(self.data_off_obj.map_item)
      self.data_off = self.data_off_obj.get_off()

      return pack("=Q", self.magic) +                                 \
             pack("=i", self.checksum) +                              \
             pack("=20s", self.signature) +                           \
             pack("=I", self.file_size) +                             \
             pack("=I", self.header_size) +                           \
             pack("=I", self.endian_tag) +                            \
             pack("=I", self.link_size) +                             \
             pack("=I", self.link_off) +                              \
             pack("=I", self.map_off) +              \
             pack("=I", self.string_ids_size) +      \
             pack("=I", self.string_ids_off) +       \
             pack("=I", self.type_ids_size) +        \
             pack("=I", self.type_ids_off) +         \
             pack("=I", self.proto_ids_size) +       \
             pack("=I", self.proto_ids_off) +        \
             pack("=I", self.field_ids_size) +       \
             pack("=I", self.field_ids_off) +        \
             pack("=I", self.method_ids_size) +      \
             pack("=I", self.method_ids_off) +       \
             pack("=I", self.class_defs_size) +      \
             pack("=I", self.class_defs_off) +       \
             pack("=I", self.data_size) +            \
             pack("=I", self.data_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_raw())

    def show(self):
        bytecode._PrintSubBanner("Header Item")
        bytecode._PrintDefault("magic=%s, checksum=%s, signature=%s\n" % (self.magic, self.checksum, self.signature))
        bytecode._PrintDefault("file_size=%x, header_size=%x, endian_tag=%x\n" % (self.file_size, self.header_size, self.endian_tag))
        bytecode._PrintDefault("link_size=%x, link_off=%x\n" % (self.link_size, self.link_off))
        bytecode._PrintDefault("map_off=%x\n" % (self.map_off))
        bytecode._PrintDefault("string_ids_size=%x, string_ids_off=%x\n" % (self.string_ids_size, self.string_ids_off))
        bytecode._PrintDefault("type_ids_size=%x, type_ids_off=%x\n" % (self.type_ids_size, self.type_ids_off))
        bytecode._PrintDefault("proto_ids_size=%x, proto_ids_off=%x\n" % (self.proto_ids_size, self.proto_ids_off))
        bytecode._PrintDefault("field_ids_size=%x, field_ids_off=%x\n" % (self.field_ids_size, self.field_ids_off))
        bytecode._PrintDefault("method_ids_size=%x, method_ids_off=%x\n" % (self.method_ids_size, self.method_ids_off))
        bytecode._PrintDefault("class_defs_size=%x, class_defs_off=%x\n" % (self.class_defs_size, self.class_defs_off))
        bytecode._PrintDefault("data_size=%x, data_off=%x\n" % (self.data_size, self.data_off))

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

class AnnotationOffItem(object):
    """
        This class can parse an annotation_off_item of a dex file

        :param buff: a string which represents a Buff object of the annotation_off_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self,  buff, cm):
        self.__CM = cm
        self.annotation_off = unpack("=I", buff.read( 4 ) )[0]

    def show(self):
        bytecode._PrintSubBanner("Annotation Off Item")
        bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotation_off)

    def get_obj(self):
        if self.annotation_off != 0:
          self.annotation_off = self.__CM.get_obj_by_offset( self.annotation_off ).get_off()

        return pack("=I", self.annotation_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class AnnotationSetItem(object):
    """
        This class can parse an annotation_set_item of a dex file

        :param buff: a string which represents a Buff object of the annotation_set_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()
        self.annotation_off_item = []

        self.size = unpack("=I", buff.read( 4 ) )[0]
        for i in range(0, self.size):
            self.annotation_off_item.append( AnnotationOffItem(buff, cm) )

    def get_annotation_off_item(self):
        """
            Return the offset from the start of the file to an annotation

            :rtype: a list of :class:`AnnotationOffItem`
        """
        return self.annotation_off_item

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        pass

    def show(self):
        bytecode._PrintSubBanner("Annotation Set Item")
        for i in self.annotation_off_item:
            i.show()

    def get_obj(self):
        return pack("=I", self.size)

    def get_raw(self):
        return self.get_obj() + ''.join(i.get_raw() for i in self.annotation_off_item)

    def get_length(self):
      length = len(self.get_obj())

      for i in self.annotation_off_item:
        length += i.get_length()

      return length

class AnnotationSetRefItem(object):
    """
        This class can parse an annotation_set_ref_item of a dex file

        :param buff: a string which represents a Buff object of the annotation_set_ref_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self,  buff, cm):
        self.__CM = cm
        self.annotations_off = unpack("=I", buff.read( 4 ) )[0]

    def get_annotations_off(self):
      """
          Return the offset from the start of the file to the referenced annotation set or
          0 if there are no annotations for this element.

          :rtype: int
      """
      return self.annotations_off

    def show(self):
        bytecode._PrintSubBanner("Annotation Set Ref Item")
        bytecode._PrintDefault("annotation_off=0x%x\n" % self.annotation_off)

    def get_obj(self):
        if self.annotations_off != 0:
          self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off()

        return pack("=I", self.annotations_off)

    def get_raw(self):
        return self.get_obj()

class AnnotationSetRefList(object):
    """
        This class can parse an annotation_set_ref_list_item of a dex file

        :param buff: a string which represents a Buff object of the annotation_set_ref_list_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.__CM = cm
        self.list = []

        self.size = unpack("=I", buff.read( 4 ) )[0]
        for i in range(0, self.size):
            self.list.append( AnnotationSetRefItem(buff, cm) )

    def get_list(self):
      """
          Return elements of the list

          :rtype: :class:`AnnotationSetRefItem`
      """
      return self.list

    def get_off(self):
      return self.offset

    def set_off(self, off):
      self.offset = off

    def reload(self):
        pass

    def show(self):
        bytecode._PrintSubBanner("Annotation Set Ref List Item")
        for i in self.list:
            i.show()

    def get_obj(self):
        return [ i for i in self.list ]

    def get_raw(self):
        return pack("=I", self.size) + ''.join(i.get_raw() for i in self.list)

    def get_length(self):
        return len(self.get_raw())

class FieldAnnotation(object):
    """
        This class can parse a field_annotation of a dex file

        :param buff: a string which represents a Buff object of the field_annotation
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.__CM = cm
        self.field_idx = unpack("=I", buff.read( 4 ) )[0]
        self.annotations_off = unpack("=I", buff.read( 4 ) )[0]

    def get_field_idx(self):
      """
          Return the index into the field_ids list for the identity of the field being annotated

          :rtype: int
      """
      return self.get_field_idx

    def get_annotations_off(self):
      """
          Return the offset from the start of the file to the list of annotations for the field

          :rtype: int
      """
      return self.annotations_off

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def show(self):
        bytecode._PrintSubBanner("Field Annotation")
        bytecode._PrintDefault( "field_idx=0x%x annotations_off=0x%x\n" % (self.field_idx, self.annotations_off) )

    def get_obj(self):
        if self.annotations_off != 0:
          self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off()

        return pack("=I", self.field_idx) + pack("=I", self.annotations_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
        return len(self.get_raw())

class MethodAnnotation(object):
    """
        This class can parse a method_annotation of a dex file

        :param buff: a string which represents a Buff object of the method_annotation
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.__CM = cm
        self.method_idx = unpack("=I", buff.read( 4 ) )[0]
        self.annotations_off = unpack("=I", buff.read( 4 ) )[0]

    def get_method_idx(self):
      """
          Return the index into the method_ids list for the identity of the method being annotated

          :rtype: int
      """
      return self.get_method_idx

    def get_annotations_off(self):
      """
          Return the offset from the start of the file to the list of annotations for the method

          :rtype: int
      """
      return self.annotations_off

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def show(self):
        bytecode._PrintSubBanner("Method Annotation")
        bytecode._PrintDefault( "method_idx=0x%x annotations_off=0x%x\n" % (self.method_idx, self.annotations_off) )

    def get_obj(self):
        if self.annotations_off != 0:
          self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off()

        return pack("=I", self.method_idx) + pack("=I", self.annotations_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_raw())

class ParameterAnnotation(object):
    """
        This class can parse a parameter_annotation of a dex file

        :param buff: a string which represents a Buff object of the parameter_annotation
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.__CM = cm
        self.method_idx = unpack("=I", buff.read( 4 ) )[0]
        self.annotations_off = unpack("=I", buff.read( 4 ) )[0]

    def get_method_idx(self):
      """
          Return the index into the method_ids list for the identity of the method whose parameters are being annotated

          :rtype: int
      """
      return self.get_method_idx

    def get_annotations_off(self):
      """
          Return the offset from the start of the file to the list of annotations for the method parameters

          :rtype: int
      """
      return self.annotations_off

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def show(self):
        bytecode._PrintSubBanner("Parameter Annotation")
        bytecode._PrintDefault( "method_idx=0x%x annotations_off=0x%x\n" % (self.method_idx, self.annotations_off) )

    def get_obj(self):
        if self.annotations_off != 0:
          self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off()

        return pack("=I", self.method_idx) + pack("=I", self.annotations_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_raw())

class AnnotationsDirectoryItem(object):
    """
        This class can parse an annotations_directory_item of a dex file

        :param buff: a string which represents a Buff object of the annotations_directory_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.class_annotations_off = unpack("=I", buff.read(4))[0]
        self.annotated_fields_size = unpack("=I", buff.read(4))[0]
        self.annotated_methods_size = unpack("=I", buff.read(4))[0]
        self.annotated_parameters_size = unpack("=I", buff.read(4))[0]

        self.field_annotations = []
        for i in range(0, self.annotated_fields_size):
            self.field_annotations.append( FieldAnnotation( buff, cm ) )

        self.method_annotations = []
        for i in range(0, self.annotated_methods_size):
            self.method_annotations.append( MethodAnnotation( buff, cm ) )

        self.parameter_annotations = []
        for i in range(0, self.annotated_parameters_size):
            self.parameter_annotations.append( ParameterAnnotation( buff, cm ) )

    def get_class_annotations_off(self):
      """
          Return the offset from the start of the file to the annotations made directly on the class,
          or 0 if the class has no direct annotations

          :rtype: int
      """
      return self.class_annotations_off


    def get_annotated_fields_size(self):
      """
          Return the count of fields annotated by this item

          :rtype: int
      """
      return self.annotated_fields_size

    def get_annotated_methods_size(self):
      """
          Return the count of methods annotated by this item

          :rtype: int
      """
      return self.annotated_methods_size

    def get_annotated_parameters_size(self):
      """
          Return the count of method parameter lists annotated by this item

          :rtype: int
      """
      return self.annotated_parameters_size

    def get_field_annotations(self):
      """
          Return the list of associated field annotations

          :rtype: a list of :class:`FieldAnnotation`
      """
      return self.field_annotations

    def get_method_annotations(self):
      """
          Return the list of associated method annotations

          :rtype: a list of :class:`MethodAnnotation`
      """
      return self.method_annotations


    def get_parameter_annotations(self):
      """
          Return the list of associated method parameter annotations

          :rtype: a list of :class:`ParameterAnnotation`
      """
      return self.parameter_annotations

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        pass

    def show(self):
        bytecode._PrintSubBanner("Annotations Directory Item")
        bytecode._PrintDefault("class_annotations_off=0x%x annotated_fields_size=%d annotated_methods_size=%d annotated_parameters_size=%d\n" %
                              ( self.class_annotations_off,
                                self.annotated_fields_size,
                                self.annotated_methods_size,
                                self.annotated_parameters_size))

        for i in self.field_annotations:
            i.show()

        for i in self.method_annotations:
            i.show()

        for i in self.parameter_annotations:
            i.show()

    def get_obj(self):
        if self.class_annotations_off != 0:
          self.class_annotations_off = self.__CM.get_obj_by_offset( self.class_annotations_off ).get_off()

        return pack("=I", self.class_annotations_off) +     \
               pack("=I", self.annotated_fields_size) +               \
               pack("=I", self.annotated_methods_size) +    \
               pack("=I", self.annotated_parameters_size)

    def get_raw(self):
        return self.get_obj() + \
               ''.join(i.get_raw() for i in self.field_annotations)  +      \
               ''.join(i.get_raw() for i in self.method_annotations) +     \
               ''.join(i.get_raw() for i in self.parameter_annotations)

    def get_length(self):
      length = len( self.get_obj() )
      for i in self.field_annotations:
        length += i.get_length()

      for i in self.method_annotations:
        length += i.get_length()

      for i in self.parameter_annotations:
        length += i.get_length()

      return length

class TypeItem(object):
    """
        This class can parse a type_item of a dex file

        :param buff: a string which represents a Buff object of the type_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.type_idx = unpack("=H", buff.read(2))[0]

    def get_type_idx(self):
      """
          Return the index into the type_ids list

          :rtype: int
      """
      return self.type_idx

    def get_string(self):
        """
          Return the type string

          :rtype: string
        """
        return self.__CM.get_type( self.type_idx )

    def show(self):
        bytecode._PrintSubBanner("Type Item")
        bytecode._PrintDefault("type_idx=%d\n" % self.type_idx)

    def get_obj(self):
        return pack("=H", self.type_idx)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class TypeList(object):
    """
        This class can parse a type_list of a dex file

        :param buff: a string which represents a Buff object of the type_list
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.pad = ""
        if self.offset % 4 != 0:
            self.pad = buff.read( self.offset % 4 )

        self.len_pad = len(self.pad)

        self.size = unpack("=I", buff.read( 4 ) )[0]

        self.list = []
        for i in range(0, self.size):
            self.list.append( TypeItem( buff, cm ) )

    def get_pad(self):
      """
          Return the alignment string

          :rtype: string
      """
      return self.pad

    def get_type_list_off(self):
        """
            Return the offset of the item

            :rtype: int
        """
        return self.offset + self.len_pad

    def get_string(self):
        """
            Return the concatenation of all strings

            :rtype: string
        """
        return ' '.join(i.get_string() for i in self.list)

    def get_size(self):
      """
          Return the size of the list, in entries

          :rtype: int
      """
      return self.size

    def get_list(self):
      """
          Return the list of TypeItem

          :rtype: a list of :class:`TypeItem` objects
      """
      return self.list

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset + self.len_pad

    def reload(self):
        pass

    def show(self):
        bytecode._PrintSubBanner("Type List")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.list:
            i.show()

    def get_obj(self):
        return self.pad + pack("=I", self.size)

    def get_raw(self):
        return self.get_obj() + ''.join(i.get_raw() for i in self.list)

    def get_length(self):
      length = len(self.get_obj())

      for i in self.list:
        length += i.get_length()

      return length

DBG_END_SEQUENCE                    = 0x00 #    (none)  terminates a debug info sequence for a code_item
DBG_ADVANCE_PC                      = 0x01 #     uleb128 addr_diff       addr_diff: amount to add to address register    advances the address register without emitting a positions entry
DBG_ADVANCE_LINE                    = 0x02 #    sleb128 line_diff       line_diff: amount to change line register by    advances the line register without emitting a positions entry
DBG_START_LOCAL                     = 0x03 #   uleb128 register_num
                                                    #    uleb128p1 name_idx
                                                    #    uleb128p1 type_idx
                                                    #         register_num: register that will contain local name_idx: string index of the name
                                                    #         type_idx: type index of the type  introduces a local variable at the current address. Either name_idx or type_idx may be NO_INDEX to indicate that that value is unknown.
DBG_START_LOCAL_EXTENDED            = 0x04 #   uleb128 register_num uleb128p1 name_idx uleb128p1 type_idx uleb128p1 sig_idx
                                                    #         register_num: register that will contain local
                                                    #         name_idx: string index of the name
                                                    #         type_idx: type index of the type
                                                    #         sig_idx: string index of the type signature
                                                    # introduces a local with a type signature at the current address. Any of name_idx, type_idx, or sig_idx may be NO_INDEX to indicate that that value is unknown. (
                                                    # If sig_idx is -1, though, the same data could be represented more efficiently using the opcode DBG_START_LOCAL.)
                                                    # Note: See the discussion under "dalvik.annotation.Signature" below for caveats about handling signatures.
DBG_END_LOCAL                       = 0x05 #    uleb128 register_num
                                                    #           register_num: register that contained local
                                                    #           marks a currently-live local variable as out of scope at the current address
DBG_RESTART_LOCAL                   = 0x06 #     uleb128 register_num
                                                    #           register_num: register to restart re-introduces a local variable at the current address.
                                                    #           The name and type are the same as the last local that was live in the specified register.
DBG_SET_PROLOGUE_END                = 0x07 #     (none)  sets the prologue_end state machine register, indicating that the next position entry that is added should be considered the end of a
                                                    #               method prologue (an appropriate place for a method breakpoint). The prologue_end register is cleared by any special (>= 0x0a) opcode.
DBG_SET_EPILOGUE_BEGIN              = 0x08 #    (none)  sets the epilogue_begin state machine register, indicating that the next position entry that is added should be considered the beginning
                                                    #               of a method epilogue (an appropriate place to suspend execution before method exit). The epilogue_begin register is cleared by any special (>= 0x0a) opcode.
DBG_SET_FILE                        = 0x09 #   uleb128p1 name_idx
                                                    #           name_idx: string index of source file name; NO_INDEX if unknown indicates that all subsequent line number entries make reference to this source file name,
                                                    #           instead of the default name specified in code_item
DBG_Special_Opcodes_BEGIN           = 0x0a #    (none)  advances the line and address registers, emits a position entry, and clears prologue_end and epilogue_begin. See below for description.
DBG_Special_Opcodes_END             = 0xff
DBG_LINE_BASE                       = -4
DBG_LINE_RANGE                      = 15


class DBGBytecode(object):
    def __init__(self, cm, op_value):
        self.CM = cm
        self.op_value = op_value
        self.format = []

    def get_op_value(self):
        return self.op_value

    def add(self, value, ttype):
        self.format.append( (value, ttype) )

    def get_value(self):
        if self.get_op_value() == DBG_START_LOCAL:
            return self.CM.get_string(self.format[1][0])
        elif self.get_op_value() == DBG_START_LOCAL_EXTENDED:
            return self.CM.get_string(self.format[1][0])

        return None

    def show(self):
      bytecode._PrintSubBanner("DBGBytecode")
      bytecode._PrintDefault("op_value=%x format=%s value=%s\n" % (self.op_value, str(self.format), self.get_value()))

    def get_obj(self):
        return []

    def get_raw(self):
        buff = self.op_value.get_value_buff()
        for i in self.format:
            if i[1] == "u":
                buff += writeuleb128( i[0] )
            elif i[1] == "s":
                buff += writesleb128( i[0] )
        return buff

class DebugInfoItem(object):
    def __init__(self, buff, cm):
        self.CM = cm

        self.offset = buff.get_idx()

        self.line_start = readuleb128( buff )
        self.parameters_size = readuleb128( buff )

        #print "line", self.line_start, "params", self.parameters_size

        self.parameter_names = []
        for i in range(0, self.parameters_size):
            self.parameter_names.append( readuleb128p1( buff ) )

        self.bytecodes = []
        bcode = DBGBytecode( self.CM, unpack("=B", buff.read(1))[0] )
        self.bytecodes.append( bcode )

        while bcode.get_op_value() != DBG_END_SEQUENCE:
            bcode_value = bcode.get_op_value()

            if bcode_value == DBG_ADVANCE_PC:
                bcode.add( readuleb128( buff ), "u" )
            elif bcode_value == DBG_ADVANCE_LINE:
                bcode.add( readsleb128( buff ), "s" )
            elif bcode_value == DBG_START_LOCAL:
                bcode.add( readusleb128( buff ), "u" )
                bcode.add( readuleb128p1( buff ), "u1" )
                bcode.add( readuleb128p1( buff ), "u1" )
            elif bcode_value == DBG_START_LOCAL_EXTENDED:
                bcode.add( readusleb128( buff ), "u" )
                bcode.add( readuleb128p1( buff ), "u1" )
                bcode.add( readuleb128p1( buff ), "u1" )
                bcode.add( readuleb128p1( buff ), "u1" )
            elif bcode_value == DBG_END_LOCAL:
                bcode.add( readusleb128( buff ), "u" )
            elif bcode_value == DBG_RESTART_LOCAL:
                bcode.add( readusleb128( buff ), "u" )
            elif bcode_value == DBG_SET_PROLOGUE_END:
                pass
            elif bcode_value == DBG_SET_EPILOGUE_BEGIN:
                pass
            elif bcode_value == DBG_SET_FILE:
                bcode.add( readuleb128p1( buff ), "u1" )
            else : #bcode_value >= DBG_Special_Opcodes_BEGIN and bcode_value <= DBG_Special_Opcodes_END:
                pass

            bcode = DBGBytecode( self.CM, unpack("=B", buff.read(1))[0] )
            self.bytecodes.append( bcode )

    def reload(self):
        pass

    def get_parameters_size(self):
        return self.parameters_size

    def get_line_start(self):
        return self.line_start

    def get_parameter_names(self):
        return self.parameter_names

    def get_translated_parameter_names(self):
        l = []
        for i in self.parameter_names:
            if i == -1:
                l.append( None )
            else:
                l.append( self.CM.get_string( i ) )
        return l

    def get_bytecodes(self):
        return self.bytecodes

    def show(self):
        bytecode._PrintSubBanner("Debug Info Item")
        bytecode._PrintDefault("line_start=%d parameters_size=%d\n" % (self.line_start, self.parameters_size))
        nb = 0
        for i in self.parameter_names:
          bytecode._PrintDefault("parameter_names[%d]=%s\n" % (nb, self.CM.get_string( i )))
          nb += 1

        for i in self.bytecodes:
          i.show()

    def get_raw(self):
        return [ bytecode.Buff( self.__offset, writeuleb128( self.line_start ) + \
                                                            writeuleb128( self.parameters_size ) + \
                                                            ''.join(writeuleb128(i) for i in self.parameter_names) + \
                                                            ''.join(i.get_raw() for i in self.bytecodes) ) ]

    def get_off(self):
        return self.offset

VALUE_BYTE      = 0x00    # (none; must be 0)      ubyte[1]         signed one-byte integer value
VALUE_SHORT     = 0x02    # size - 1 (0..1)  ubyte[size]    signed two-byte integer value, sign-extended
VALUE_CHAR      = 0x03    # size - 1 (0..1)  ubyte[size]    unsigned two-byte integer value, zero-extended
VALUE_INT       = 0x04    # size - 1 (0..3)  ubyte[size]    signed four-byte integer value, sign-extended
VALUE_LONG      = 0x06    # size - 1 (0..7)  ubyte[size]    signed eight-byte integer value, sign-extended
VALUE_FLOAT     = 0x10    # size - 1 (0..3)  ubyte[size]    four-byte bit pattern, zero-extended to the right, and interpreted as an IEEE754 32-bit floating point value
VALUE_DOUBLE    = 0x11    # size - 1 (0..7)  ubyte[size]    eight-byte bit pattern, zero-extended to the right, and interpreted as an IEEE754 64-bit floating point value
VALUE_STRING    = 0x17    # size - 1 (0..3)  ubyte[size]    unsigned (zero-extended) four-byte integer value, interpreted as an index into the string_ids section and representing a string value
VALUE_TYPE      = 0x18    # size - 1 (0..3)  ubyte[size]    unsigned (zero-extended) four-byte integer value, interpreted as an index into the type_ids section and representing a reflective type/class value
VALUE_FIELD     = 0x19    # size - 1 (0..3)  ubyte[size]    unsigned (zero-extended) four-byte integer value, interpreted as an index into the field_ids section and representing a reflective field value
VALUE_METHOD    = 0x1a    # size - 1 (0..3)  ubyte[size]    unsigned (zero-extended) four-byte integer value, interpreted as an index into the method_ids section and representing a reflective method value
VALUE_ENUM      = 0x1b    # size - 1 (0..3)  ubyte[size]    unsigned (zero-extended) four-byte integer value, interpreted as an index into the field_ids section and representing the value of an enumerated type constant
VALUE_ARRAY     = 0x1c    # (none; must be 0)      encoded_array  an array of values, in the format specified by "encoded_array Format" below. The size of the value is implicit in the encoding.
VALUE_ANNOTATION  = 0x1d  # (none; must be 0)      encoded_annotation     a sub-annotation, in the format specified by "encoded_annotation Format" below. The size of the value is implicit in the encoding.
VALUE_NULL      = 0x1e    # (none; must be 0)      (none)  null reference value
VALUE_BOOLEAN   = 0x1f    # boolean (0..1) (none)  one-bit value; 0 for false and 1 for true. The bit is represented in the value_arg.


class DebugInfoItemEmpty(object):
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()
        self.__buff = buff
        self.__raw = ""

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        offset = self.offset

        n = self.__CM.get_next_offset_item( offset )

        s_idx = self.__buff.get_idx()
        self.__buff.set_idx( offset )
        self.__raw = self.__buff.read( n - offset )
        self.__buff.set_idx( s_idx )

    def show(self):
        pass

    def get_obj(self):
        return []

    def get_raw(self):
        return self.__raw

    def get_length(self):
      return len(self.__raw)

class EncodedArray(object):
    """
        This class can parse an encoded_array of a dex file

        :param buff: a string which represents a Buff object of the encoded_array
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.size = readuleb128( buff )

        self.values = []
        for i in range(0, self.size):
            self.values.append( EncodedValue(buff, cm) )

    def get_size(self):
      """
          Return the number of elements in the array

          :rtype: int
      """
      return self.size

    def get_values(self):
        """
            Return a series of size encoded_value byte sequences in the format specified by this section,
            concatenated sequentially

            :rtype: a list of :class:`EncodedValue` objects
        """
        return self.values

    def show(self):
        bytecode._PrintSubBanner("Encoded Array")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.values:
            i.show()

    def get_obj(self):
        return writeuleb128( self.size )

    def get_raw(self):
        return self.get_obj() + ''.join(i.get_raw() for i in self.values)

    def get_length(self):
      length = len(self.get_obj())
      for i in self.values:
        length += i.get_length()

      return length

class EncodedValue(object):
    """
        This class can parse an encoded_value of a dex file

        :param buff: a string which represents a Buff object of the encoded_value
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.val = unpack("=B", buff.read(1))[0]
        self.value_arg = self.val >> 5
        self.value_type = self.val & 0x1f

        self.raw_value = None
        self.value = ""

        #  TODO: parse floats/doubles correctly
        if self.value_type >= VALUE_SHORT and self.value_type < VALUE_STRING:
            self.value, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
        elif self.value_type == VALUE_STRING:
            id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
            self.value = cm.get_raw_string(id)
        elif self.value_type == VALUE_TYPE:
            id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
            self.value = cm.get_type(id)
        elif self.value_type == VALUE_FIELD:
            id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
            self.value = cm.get_field(id)
        elif self.value_type == VALUE_METHOD:
            id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
            self.value = cm.get_method(id)
        elif self.value_type == VALUE_ENUM:
            id, self.raw_value = self._getintvalue(buff.read( self.value_arg + 1 ))
            self.value = cm.get_field(id)
        elif self.value_type == VALUE_ARRAY:
            self.value = EncodedArray( buff, cm )
        elif self.value_type == VALUE_ANNOTATION:
            self.value = EncodedAnnotation( buff, cm )
        elif self.value_type == VALUE_BYTE:
            self.value = buff.read( 1 )
        elif self.value_type == VALUE_NULL:
            self.value = None
        elif self.value_type == VALUE_BOOLEAN:
            if self.value_arg:
                self.value = True
            else:
                self.value = False
        else:
            bytecode.Exit( "Unknown value 0x%x" % self.value_type )

    def get_value(self):
      """
          Return the bytes representing the value, variable in length and interpreted differently for different value_type bytes,
          though always little-endian

          :rtype: an object representing the value
      """
      return self.value

    def get_value_type(self):
      return self.value_type

    def get_value_arg(self):
      return self.value_arg

    def _getintvalue(self, buf):
        ret = 0
        shift = 0
        for b in buf:
            ret |= b << shift
            shift += 8

        return ret, buf

    def show(self):
        bytecode._PrintSubBanner("Encoded Value")
        bytecode._PrintDefault("val=%x value_arg=%x value_type=%x\n" % (self.val, self.value_arg, self.value_type))

    def get_obj(self):
        if isinstance(self.value, str) == False:
            return [ self.value ]
        return []

    def get_raw(self):
        if self.raw_value == None:
            return pack("=B", self.val) + bytecode.object_to_str( self.value )
        else:
            return pack("=B", self.val) + bytecode.object_to_str( self.raw_value )

    def get_length(self):
      if self.raw_value == None:
        return len(pack("=B", self.val)) + len(bytecode.object_to_str( self.value ))
      else:
        return len(pack("=B", self.val)) + len(bytecode.object_to_str( self.raw_value ))

class AnnotationElement(object):
    """
        This class can parse an annotation_element of a dex file

        :param buff: a string which represents a Buff object of the annotation_element
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.name_idx = readuleb128( buff )
        self.value = EncodedValue( buff, cm )

    def get_name_idx(self):
      """
          Return the element name, represented as an index into the string_ids section

          :rtype: int
      """
      return self.name_idx

    def get_value(self):
      """
          Return the element value (EncodedValue)

          :rtype: a :class:`EncodedValue` object
      """
      return self.value

    def show(self):
        bytecode._PrintSubBanner("Annotation Element")
        bytecode._PrintDefault("name_idx=%d\n" % self.name_idx)
        self.value.show()

    def get_obj(self):
        return writeuleb128(self.name_idx)

    def get_raw(self):
        return self.get_obj() + self.value.get_raw()

    def get_length(self):
      return len(self.get_obj()) + self.value.get_length()

class EncodedAnnotation(object):
    """
        This class can parse an encoded_annotation of a dex file

        :param buff: a string which represents a Buff object of the encoded_annotation
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.type_idx = readuleb128( buff )
        self.size = readuleb128( buff )

        self.elements = []
        for i in range(0, self.size):
            self.elements.append( AnnotationElement( buff, cm ) )

    def get_type_idx(self):
      """
          Return the type of the annotation. This must be a class (not array or primitive) type

          :rtype: int
      """
      return self.type_idx

    def get_size(self):
      """
          Return the number of name-value mappings in this annotation

          :rtype:int
      """
      return self.size

    def get_elements(self):
      """
          Return the elements of the annotation, represented directly in-line (not as offsets)

          :rtype: a list of :class:`AnnotationElement` objects
      """
      return self.elements

    def show(self):
        bytecode._PrintSubBanner("Encoded Annotation")
        bytecode._PrintDefault("type_idx=%d size=%d\n" % (self.type_idx, self.size))

        for i in self.elements:
            i.show()

    def get_obj(self):
        return [ i for i in self.elements ]

    def get_raw(self):
        return writeuleb128(self.type_idx) + writeuleb128(self.size) + ''.join(i.get_raw() for i in self.elements)

    def get_length(self):
      length = len(writeuleb128(self.type_idx) + writeuleb128(self.size))

      for i in self.elements:
        length += i.get_length()

      return length

class AnnotationItem(object):
    """
        This class can parse an annotation_item of a dex file

        :param buff: a string which represents a Buff object of the annotation_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.visibility = unpack("=B", buff.read(1))[0]
        self.annotation = EncodedAnnotation(buff, cm)

    def get_visibility(self):
      """
          Return the intended visibility of this annotation

          :rtype: int
      """
      return self.visibility

    def get_annotation(self):
      """
          Return the encoded annotation contents

          :rtype: a :class:`EncodedAnnotation` object
      """
      return self.annotation

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        pass

    def show(self):
        bytecode._PrintSubBanner("Annotation Item")
        bytecode._PrintDefault("visibility=%d\n" % self.visibility)
        self.annotation.show()

    def get_obj(self):
        return [ self.annotation ]

    def get_raw(self):
        return pack("=B", self.visibility) + self.annotation.get_raw()

    def get_length(self):
      length = len(pack("=B", self.visibility))

      length += self.annotation.get_length()

      return length

class EncodedArrayItem(object):
    """
        This class can parse an encoded_array_item of a dex file

        :param buff: a string which represents a Buff object of the encoded_array_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()
        self.value = EncodedArray( buff, cm )

    def get_value(self):
      """
          Return the bytes representing the encoded array value

          :rtype: a :class:`EncodedArray` object
      """
      return self.value

    def set_off(self, off):
      self.offset = off

    def reload(self):
        pass

    def get_value(self):
      return self.value

    def show(self):
        bytecode._PrintSubBanner("Encoded Array Item")
        self.value.show()

    def get_obj(self):
        return [ self.value ]

    def get_raw(self):
        return self.value.get_raw()

    def get_length(self):
      return self.value.get_length()

    def get_off(self):
      return self.offset


def utf8_to_string(buff, length):
    chars = []

    for _ in range(length):
        first_char = ord(buff.read(1))
        value = first_char >> 4
        if value in (0x00, 0x01, 0x02, 0x03,
                     0x04, 0x05, 0x06, 0x07):
            if first_char == 0:
                warning('at offset %x: single zero byte illegal' % buff.get_idx())
            chars.append(chr(first_char))
        elif value in (0x0c, 0x0d):
            second_char = ord(buff.read(1))
            if (second_char & 0xc0) != 0x80:
                warning('bad utf8 at offset: %x' % buff.get_idx())
            value = ((first_char & 0x1f) << 6) | (second_char & 0x3f)
            if value != 0 and value < 0x80:
                warning('at offset {0}: utf8 should have been represented with one byte encoding'.format(buff.get_idx()))
            chars.append(chr(value))
        elif value == 0x0e:
            second_char = ord(buff.read(1))
            if second_char & 0xc0 != 0x80:
                warning('bad utf8 byte %x at offset %x' % (second_char, buff.get_idx()))
            third_char = ord(buff.read(1))
            if third_char & 0xc0 != 0x80:
                warning('bad utf8 byte %x at offset %x' % (third_char, buff.get_idx()))
            value = ((first_char & 0x0f) << 12) | ((second_char & 0x3f) << 6) | (third_char & 0x3f)
            if value < 0x800:
                warning('at offset %x: utf8 should have been represented with two-byte encoding' % buff.get_idx())
            chars.append(chr(value))
        else:
            warning('at offset %x: illegal utf8' % buff.get_idx())
    #print(chars)
    return ''.join(chars).encode('utf-8', 'ignore')


class StringDataItem(object):
    """
        This class can parse a string_data_item of a dex file

        :param buff: a string which represents a Buff object of the string_data_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.utf16_size = readuleb128( buff )

        self.data = utf8_to_string(buff, self.utf16_size)
        expected = buff.read(1)
        #if expected != '\x00':
            #warning('\x00 expected at offset: {0}, found: {1}'.format(buff.get_idx(), expected))

    def get_utf16_size(self):
      """
          Return the size of this string, in UTF-16 code units

          :rtype:int
      """
      return self.utf16_size

    def get_data(self):
      """
          Return a series of MUTF-8 code units (a.k.a. octets, a.k.a. bytes) followed by a byte of value 0

          :rtype: string
      """
      return self.data

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        pass

    def get(self):
        return self.data

    def show(self):
        bytecode._PrintSubBanner("String Data Item")
        bytecode._PrintDefault("utf16_size=%d data=%s\n" % (self.utf16_size, repr( self.data )))

    def get_obj(self):
        return []

    def get_raw(self):
        return writeuleb128( self.utf16_size ) + self.data

    def get_length(self):
      return len(writeuleb128( self.utf16_size )) + len(self.data)

class StringIdItem(object):
    """
        This class can parse a string_id_item of a dex file

        :param buff: a string which represents a Buff object of the string_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.string_data_off = unpack("=I", buff.read(4))[0]

    def get_string_data_off(self):
        """
            Return the offset from the start of the file to the string data for this item

            :rtype: int
        """
        return self.string_data_off

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
      pass

    def show(self):
        bytecode._PrintSubBanner("String Id Item")
        bytecode._PrintDefault("string_data_off=%x\n" % self.string_data_off)

    def get_obj(self):
        if self.string_data_off != 0:
          self.string_data_off = self.__CM.get_string_by_offset( self.string_data_off ).get_off()

        return pack("=I", self.string_data_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class TypeIdItem(object):
    """
        This class can parse a type_id_item of a dex file

        :param buff: a string which represents a Buff object of the type_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.descriptor_idx = unpack("=I", buff.read( 4 ) )[0]
        self.descriptor_idx_value = None

    def get_descriptor_idx(self):
        """
            Return the index into the string_ids list for the descriptor string of this type

            :rtype: int
        """
        return self.descriptor_idx

    def get_descriptor_idx_value(self):
      """
          Return the string associated to the descriptor

          :rtype: string
      """
      return self.descriptor_idx_value

    def reload(self):
        self.descriptor_idx_value = self.__CM.get_string( self.descriptor_idx )

    def show(self):
        bytecode._PrintSubBanner("Type Id Item")
        bytecode._PrintDefault("descriptor_idx=%d descriptor_idx_value=%s\n" % (self.descriptor_idx, self.descriptor_idx_value))

    def get_obj(self):
        return pack("=I", self.descriptor_idx)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class TypeHIdItem(object):
    """
        This class can parse a list of type_id_item of a dex file

        :param buff: a string which represents a Buff object of the list of type_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.type = []
        for i in range(0, size):
            self.type.append( TypeIdItem( buff, cm ) )

    def get_type(self):
      """
          Return the list of type_id_item

          :rtype: a list of :class:`TypeIdItem` objects
      """
      return self.type

    def get(self, idx):
        try:
            return self.type[ idx ].get_descriptor_idx()
        except IndexError:
            return -1

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def reload(self):
        for i in self.type:
            i.reload()

    def show(self):
        bytecode._PrintSubBanner("Type List Item")
        for i in self.type:
            i.show()

    def get_obj(self):
        return [ i for i in self.type ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.type)

    def get_length(self):
      length = 0
      for i in self.type:
        length += i.get_length()
      return length

class ProtoIdItem(object):
    """
        This class can parse a proto_id_item of a dex file

        :param buff: a string which represents a Buff object of the proto_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.shorty_idx = unpack("=I", buff.read(4))[0]
        self.return_type_idx = unpack("=I", buff.read(4))[0]
        self.parameters_off = unpack("=I", buff.read(4))[0]


        self.shorty_idx_value = None
        self.return_type_idx_value = None
        self.parameters_off_value = None

    def reload(self):
        self.shorty_idx_value = self.__CM.get_string( self.shorty_idx )
        self.return_type_idx_value = self.__CM.get_type( self.return_type_idx )
        params = self.__CM.get_type_list( self.parameters_off )
        self.parameters_off_value = '({})'.format(b' '.join(params))

    def get_shorty_idx(self):
        """
            Return the index into the string_ids list for the short-form descriptor string of this prototype

            :rtype: int
        """
        return self.shorty_idx

    def get_return_type_idx(self):
        """
            Return the index into the type_ids list for the return type of this prototype

            :rtype: int
        """
        return self.return_type_idx

    def get_parameters_off(self):
        """
            Return the offset from the start of the file to the list of parameter types for this prototype, or 0 if this prototype has no parameters

            :rtype: int
        """
        return self.parameters_off

    def get_shorty_idx_value(self):
        """
            Return the string associated to the shorty_idx

            :rtype: string
        """
        return self.shorty_idx_value

    def get_return_type_idx_value(self):
        """
            Return the string associated to the return_type_idx

            :rtype: string
        """
        return self.return_type_idx_value

    def get_parameters_off_value(self):
        """
            Return the string associated to the parameters_off

            :rtype: string
        """
        return self.parameters_off_value

    def show(self):
        bytecode._PrintSubBanner("Proto Item")
        bytecode._PrintDefault("shorty_idx=%d return_type_idx=%d parameters_off=%d\n" % (self.shorty_idx, self.return_type_idx, self.parameters_off))
        bytecode._PrintDefault("shorty_idx_value=%s return_type_idx_value=%s parameters_off_value=%s\n" %
                                (self.shorty_idx_value, self.return_type_idx_value, self.parameters_off_value))


    def get_obj(self):
        if self.parameters_off != 0:
          self.parameters_off = self.__CM.get_obj_by_offset( self.parameters_off ).get_off()

        return pack("=I", self.shorty_idx) + pack("=I", self.return_type_idx) + pack("=I", self.parameters_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class ProtoHIdItem(object):
    """
        This class can parse a list of proto_id_item of a dex file

        :param buff: a string which represents a Buff object of the list of proto_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.proto = []

        for i in range(0, size):
            self.proto.append( ProtoIdItem(buff, cm) )

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def get(self, idx):
        try:
            return self.proto[ idx ]
        except IndexError:
            return ProtoIdItemInvalid()

    def reload(self):
        for i in self.proto:
            i.reload()

    def show(self):
        bytecode._PrintSubBanner("Proto List Item")
        for i in self.proto:
            i.show()

    def get_obj(self):
        return [ i for i in self.proto ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.proto)

    def get_length(self):
      length = 0
      for i in self.proto:
        length += i.get_length()
      return length

class FieldIdItem(object):
    """
        This class can parse a field_id_item of a dex file

        :param buff: a string which represents a Buff object of the field_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.class_idx = unpack("=H", buff.read(2))[0]
        self.type_idx = unpack("=H", buff.read(2))[0]
        self.name_idx = unpack("=I", buff.read(4))[0]

        self.class_idx_value = None
        self.type_idx_value = None
        self.name_idx_value = None

    def reload(self):
        self.class_idx_value = self.__CM.get_type( self.class_idx )
        self.type_idx_value = self.__CM.get_type( self.type_idx )
        self.name_idx_value = self.__CM.get_string( self.name_idx )

    def get_class_idx(self):
      """
          Return the index into the type_ids list for the definer of this field

          :rtype: int
      """
      return self.class_idx

    def get_type_idx(self):
      """
          Return the index into the type_ids list for the type of this field

          :rtype: int
      """
      return self.type_idx

    def get_name_idx(self):
      """
          Return the index into the string_ids list for the name of this field

          :rtype: int
      """
      return self.name_idx

    def get_class_name(self):
        """
            Return the class name of the field

            :rtype: string
        """
        return self.class_idx_value

    def get_type(self):
        """
            Return the type of the field

            :rtype: string
        """
        return self.type_idx_value

    def get_descriptor(self):
        """
            Return the descriptor of the field

            :rtype: string
        """
        return self.type_idx_value

    def get_name(self):
        """
            Return the name of the field

            :rtype: string
        """
        return self.name_idx_value

    def get_list(self):
        return [ self.get_class_name(), self.get_type(), self.get_name() ]

    def show(self):
        bytecode._PrintSubBanner("Field Id Item")
        bytecode._PrintDefault("class_idx=%d type_idx=%d name_idx=%d\n" % (self.class_idx, self.type_idx, self.name_idx))
        bytecode._PrintDefault("class_idx_value=%s type_idx_value=%s name_idx_value=%s\n" % (self.class_idx_value, self.type_idx_value, self.name_idx_value))

    def get_obj(self):
      return  pack("=H", self.class_idx) + \
              pack("=H", self.type_idx) + \
              pack("=I", self.name_idx)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class FieldHIdItem(object):
    """
        This class can parse a list of field_id_item of a dex file

        :param buff: a string which represents a Buff object of the list of field_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.offset = buff.get_idx()

        self.elem = []
        for i in range(0, size):
            self.elem.append( FieldIdItem(buff, cm) )

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def gets(self):
        return self.elem

    def get(self, idx):
        try:
            return self.elem[ idx ]
        except IndexError:
            return FieldIdItemInvalid()

    def reload(self):
        for i in self.elem:
            i.reload()

    def show(self):
        nb = 0
        for i in self.elem:
            print (nb)
            i.show()
            nb = nb + 1

    def get_obj(self):
        return [ i for i in self.elem ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.elem)

    def get_length(self):
      length = 0
      for i in self.elem:
        length += i.get_length()
      return length


class MethodIdItem(object):
    """
        This class can parse a method_id_item of a dex file

        :param buff: a string which represents a Buff object of the method_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.class_idx = unpack("=H", buff.read(2))[0]
        self.proto_idx = unpack("=H", buff.read(2))[0]
        self.name_idx = unpack("=I", buff.read(4))[0]

        self.class_idx_value = None
        self.proto_idx_value = None
        self.name_idx_value = None

    def reload(self):
        self.class_idx_value = self.__CM.get_type( self.class_idx )
        self.proto_idx_value = self.__CM.get_proto( self.proto_idx )
        self.name_idx_value = self.__CM.get_string( self.name_idx )

    def get_class_idx(self):
        """
            Return the index into the type_ids list for the definer of this method

            :rtype: int
        """
        return self.class_idx

    def get_proto_idx(self):
        """
            Return the index into the proto_ids list for the prototype of this method

            :rtype: int
        """
        return self.proto_idx

    def get_name_idx(self):
        """
            Return the index into the string_ids list for the name of this method

            :rtype: int
        """
        return self.name_idx

    def get_class_name(self):
      """
          Return the class name of the method

          :rtype: string
      """
      return self.class_idx_value

    def get_proto(self):
        """
            Return the prototype of the method

            :rtype: string
        """
        return self.proto_idx_value

    def get_descriptor(self):
      """
          Return the descriptor

          :rtype: string
      """
      proto = self.get_proto()
      return proto[0] + proto[1]

    def get_real_descriptor(self):
      """
          Return the real descriptor (i.e. without extra spaces)

          :rtype: string
      """
      proto = self.get_proto()
      return proto[0].replace(' ','') + proto[1]

    def get_name(self):
        """
            Return the name of the method

            :rtype: string
        """
        return self.name_idx_value

    def get_list(self):
        return [ self.get_class_name(), self.get_name(), self.get_proto() ]

    def get_triple(self):
        return self.get_class_name()[1:-1], self.get_name(), self.get_real_descriptor()

    def show(self):
        bytecode._PrintSubBanner("Method Id Item")
        bytecode._PrintDefault("class_idx=%d proto_idx=%d name_idx=%d\n" % (self.class_idx, self.proto_idx, self.name_idx))
        bytecode._PrintDefault("class_idx_value=%s proto_idx_value=%s name_idx_value=%s\n" % (self.class_idx_value, self.proto_idx_value, self.name_idx_value))

    def get_obj(self):
        return pack("H", self.class_idx) + pack("H", self.proto_idx) + pack("I", self.name_idx)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class MethodHIdItem(object):
    """
        This class can parse a list of method_id_item of a dex file

        :param buff: a string which represents a Buff object of the list of method_id_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.methods = []
        for i in range(0, size):
            self.methods.append( MethodIdItem(buff, cm) )

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def get(self, idx):
        try:
            return self.methods[ idx ]
        except IndexError:
            return MethodIdItemInvalid()

    def reload(self):
        for i in self.methods:
            i.reload()

    def show(self):
        print ("METHOD_ID_ITEM")
        nb = 0
        for i in self.methods:
            print (nb)
            i.show()
            nb = nb + 1

    def get_obj(self):
        return [ i for i in self.methods ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.methods)

    def get_length(self):
      length = 0
      for i in self.methods:
        length += i.get_length()
      return length

class ProtoIdItemInvalid(object):
    def get_params(self):
        return "AG:IPI:invalid_params;"

    def get_shorty(self):
        return "(AG:IPI:invalid_shorty)"

    def get_return_type(self):
        return "(AG:IPI:invalid_return_type)"

    def show(self):
        print ("AG:IPI:invalid_proto_item", self.get_shorty(), self.get_return_type(), self.get_params())

class FieldIdItemInvalid(object):
    def get_class_name(self):
        return "AG:IFI:invalid_class_name;"

    def get_type(self):
        return "(AG:IFI:invalid_type)"

    def get_descriptor(self):
        return "(AG:IFI:invalid_descriptor)"

    def get_name(self):
        return "AG:IFI:invalid_name"

    def get_list(self):
        return [ self.get_class_name(), self.get_type(), self.get_name() ]

    def show(self):
        print ("AG:IFI:invalid_field_item")

class MethodIdItemInvalid(object):
    def get_class_name(self):
        return "AG:IMI:invalid_class_name;"

    def get_descriptor(self):
      return "(AG:IMI:invalid_descriptor)"

    def get_proto(self):
        return "()AG:IMI:invalid_proto"

    def get_name(self):
        return "AG:IMI:invalid_name"

    def get_list(self):
        return [ self.get_class_name(), self.get_name(), self.get_proto() ]

    def show(self):
        print ("AG:IMI:invalid_method_item")


class EncodedField(object):
    """
        This class can parse an encoded_field of a dex file

        :param buff: a string which represents a Buff object of the encoded field
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.CM = cm
        self.offset = buff.get_idx()

        self.field_idx_diff = readuleb128( buff )
        self.access_flags = readuleb128( buff )

        self.field_idx = 0

        self.name = None
        self.proto = None
        self.class_name = None

        self.init_value = None
        self.access_flags_string = None

    def reload(self):
        name = self.CM.get_field( self.field_idx )
        self.class_name = name[0]
        self.name = name[2]
        self.proto = ''.join(str(i) for i in name[1])

    def set_init_value(self, value):
        """
            Setup the init value object of the field

            :param value: the init value
            :type value: :class:`EncodedValue`
        """
        self.init_value = value

    def get_init_value(self):
      """
          Return the init value object of the field

          :rtype: :class:`EncodedValue`
      """
      return self.init_value

    def adjust_idx(self, val):
        self.field_idx = self.field_idx_diff + val


    def get_field_idx_diff(self):
        """
            Return the index into the field_ids list for the identity of this field (includes the name and descriptor),
            represented as a difference from the index of previous element in the list

            :rtype: int
        """
        return self.field_idx_diff

    def get_field_idx(self):
        """
            Return the real index of the method

            :rtype: int
        """
        return self.field_idx

    def get_access_flags(self):
        """
          Return the access flags of the field

          :rtype: int
        """
        return self.access_flags

    def get_class_name(self):
        """
            Return the class name of the field

            :rtype: string
        """
        return self.class_name

    def get_descriptor(self):
        """
            Return the descriptor of the field

            :rtype: string
        """
        return self.proto

    def get_name(self):
        """
            Return the name of the field

            :rtype: string
        """
        return self.name

    def get_access_flags_string(self):
        """
            Return the access flags string of the field

            :rtype: string
        """
        if self.access_flags_string == None:
            self.access_flags_string = get_access_flags_string( self.get_access_flags() )

            if self.access_flags_string == "":
                self.access_flags_string = "0x%x" % self.get_access_flags()
        return self.access_flags_string

    def set_name(self, value):
        self.CM.set_hook_field_name(self, value)
        self.reload()

    def get_obj(self):
        return []

    def get_raw(self):
        return writeuleb128( self.field_idx_diff ) + writeuleb128( self.access_flags )

    def get_size(self):
      return len(self.get_raw())

    def show(self):
        """
            Display the information about the field
        """
        colors = bytecode.disable_print_colors()
        self.pretty_show()
        bytecode.enable_print_colors(colors)

    def pretty_show(self):
        """
            Display the information (with a pretty print) about the field
        """
        bytecode._PrintSubBanner("Field Information")
        bytecode._PrintDefault("%s->%s %s [access_flags=%s]\n" % ( self.get_class_name(), self.get_name(), self.get_descriptor(), self.get_access_flags_string() ))

        init_value = self.get_init_value()
        if init_value != None:
            bytecode._PrintDefault( "\tinit value: %s\n" % str( init_value.get_value() ) )

        self.show_dref()

    def show_dref(self):
        """
            Display where this field is read or written
        """
        try:
            bytecode._PrintSubBanner("DREF")
            bytecode._PrintDRef("R", self.DREFr.items)
            bytecode._PrintDRef("W", self.DREFw.items)
            bytecode._PrintSubBanner()
        except AttributeError:
            pass

    def __str__(self):
        return "%s->%s %s [access_flags=%s]\n" % (self.get_class_name(), self.get_name(), self.get_descriptor(), self.get_access_flags_string())

class EncodedMethod(object):
    """
        This class can parse an encoded_method of a dex file

        :param buff: a string which represents a Buff object of the encoded_method
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.CM = cm
        self.offset = buff.get_idx()

        self.method_idx_diff = readuleb128( buff )  #: method index diff in the corresponding section
        self.access_flags = readuleb128( buff )     #: access flags of the method
        self.code_off = readuleb128( buff )         #: offset of the code section

        self.method_idx = 0

        self.name = None
        self.proto = None
        self.class_name = None

        self.code = None

        self.access_flags_string = None

        self.notes = []

    def adjust_idx(self, val):
        self.method_idx = self.method_idx_diff + val

    def get_method_idx(self):
        """
            Return the real index of the method

            :rtype: int
        """
        return self.method_idx

    def get_method_idx_diff(self):
      """
          Return index into the method_ids list for the identity of this method (includes the name and descriptor),
          represented as a difference from the index of previous element in the lis

          :rtype: int
      """
      return self.method_idx_diff

    def get_access_flags(self):
        """
          Return the access flags of the method

          :rtype: int
        """
        return self.access_flags

    def get_code_off(self):
      """
          Return the offset from the start of the file to the code structure for this method,
          or 0 if this method is either abstract or native

          :rtype: int
      """
      return self.code_off

    def get_access_flags_string(self):
        """
            Return the access flags string of the method

            :rtype: string
        """
        if self.access_flags_string == None:
            self.access_flags_string = get_access_flags_string( self.get_access_flags() )

            if self.access_flags_string == "":
                self.access_flags_string = "0x%x" % self.get_access_flags()
        return self.access_flags_string

    def reload(self):
        v = self.CM.get_method( self.method_idx )

        self.class_name = v[0]
        self.name = v[1]
        self.proto = ''.join(str(i) for i in v[2])

        self.code = self.CM.get_code( self.code_off )

    def get_locals(self):
        ret = self.proto.split(')')
        params = ret[0][1:].split()

        return self.code.get_registers_size() - len(params) - 1

    def get_information(self):
        info = {}
        if self.code:
          nb = self.code.get_registers_size()
          proto = self.get_descriptor()

          ret = proto.split(')')
          params = ret[0][1:].split()

          ret = proto.split(')')
          params = ret[0][1:].split()
          if params:
            info["registers"] = (0, nb - len(params) - 1)
            j = 0
            info["params"] = []
            for i in range(nb - len(params), nb):
              info["params"].append((i, get_type(params[j])))
              j += 1
          else:
            info["registers"] = (0, nb - 1)

          info["return"] = get_type(ret[1])
        return info

    def each_params_by_register(self, nb, proto):
        bytecode._PrintSubBanner("Params")

        ret = proto.split(')')
        params = ret[0][1:].split()
        if params:
            bytecode._PrintDefault("- local registers: v%d...v%d\n" % (0, nb - len(params) - 1))
            j = 0
            for i in range(nb - len(params), nb):
                bytecode._PrintDefault("- v%d: %s\n" % (i, get_type(params[j])))
                j += 1
        else:
            bytecode._PrintDefault("local registers: v%d...v%d\n" % (0, nb - 1))

        bytecode._PrintDefault("- return: %s\n" % get_type(ret[1]))
        bytecode._PrintSubBanner()

    def __str__(self):
        return "%s->%s%s [access_flags=%s]" % (self.get_class_name(),
                                               self.get_name(),
                                               self.get_descriptor(),
                                               self.get_access_flags_string())

    def show_info(self):
        """
            Display the basic information about the method
        """
        bytecode._PrintSubBanner("Method Information")
        bytecode._PrintDefault("%s->%s%s [access_flags=%s]\n" % ( self.get_class_name(), self.get_name(), self.get_descriptor(), self.get_access_flags_string() ))

    def show(self):
        """
            Display the information about the method
        """
        colors = bytecode.disable_print_colors()
        self.pretty_show()
        bytecode.enable_print_colors(colors)

    def pretty_show(self):
        """
            Display the information (with a pretty print) about the method
        """
        self.show_info()
        self.show_notes()
        if self.code != None:
            self.each_params_by_register( self.code.get_registers_size(), self.get_descriptor() )
            if self.CM.get_vmanalysis() == None:
                self.code.show()
            else:
                self.code.pretty_show( self.CM.get_vmanalysis().get_method( self ) )
                self.show_xref()

    def show_xref(self):
        """
            Display where the method is called or which method is called
        """
        try:
            bytecode._PrintSubBanner("XREF")
            bytecode._PrintXRef("F", self.XREFfrom.items)
            bytecode._PrintXRef("T", self.XREFto.items)
            bytecode._PrintSubBanner()
        except AttributeError:
            pass

    def show_notes(self):
      """
          Display the notes about the method
      """
      if self.notes != []:
        bytecode._PrintSubBanner("Notes")
        for i in self.notes:
          bytecode._PrintNote(i)
        bytecode._PrintSubBanner()

    def source(self):
        """
            Return the source code of this method

            :rtype: string
        """
        self.CM.decompiler_ob.display_source(self)

    def get_source(self):
      return self.CM.decompiler_ob.get_source_method(self)

    def get_length(self):
        """
          Return the length of the associated code of the method

          :rtype: int
        """
        if self.code != None:
            return self.code.get_length()
        return 0

    def get_code(self):
        """
          Return the code object associated to the method

          :rtype: :class:`DalvikCode` object
        """
        return self.code

    def get_instructions(self):
        """
            Get the instructions

            :rtype: a generator of each :class:`Instruction` (or a cached list of instructions if you have setup instructions)
        """
        if self.code == None:
          return []
        return self.code.get_bc().get_instructions()

    def set_instructions(self, instructions):
        """
            Set the instructions

            :param instructions: the list of instructions
            :type instructions: a list of :class:`Instruction`
        """
        if self.code == None:
          return []
        return self.code.get_bc().set_instructions(instructions)

    def get_instruction(self, idx, off=None):
        """
            Get a particular instruction by using (default) the index of the address if specified

            :param idx: index of the instruction (the position in the list of the instruction)
            :type idx: int
            :param off: address of the instruction
            :type off: int

            :rtype: an :class:`Instruction` object
        """
        if self._code != None:
            return self.code.get_bc().get_instruction(idx, off)
        return None

    def get_debug(self):
        """
          Return the debug object associated to this method

          :rtype: :class:`DebugInfoItem`
        """
        if self.code == None:
            return None
        return self.code.get_debug()

    def get_descriptor(self):
        """
          Return the descriptor of the method

          :rtype: string
        """
        return self.proto

    def get_class_name(self):
        """
          Return the class name of the method

          :rtype: string
        """
        return self.class_name

    def get_name(self):
        """
          Return the name of the method

          :rtype: string
        """
        return self.name

    def get_triple(self):
        return self.CM.get_method_ref( self.method_idx ).get_triple()

    def add_inote(self, msg, idx, off=None):
        """
            Add a message to a specific instruction by using (default) the index of the address if specified

            :param msg: the message
            :type msg: string
            :param idx: index of the instruction (the position in the list of the instruction)
            :type idx: int
            :param off: address of the instruction
            :type off: int
        """
        if self.code != None:
            self.code.add_inote(msg, idx, off)

    def add_note(self, msg):
        """
            Add a message to this method

            :param msg: the message
            :type msg: string
        """
        self.notes.append( msg )

    def set_code_idx(self, idx):
        """
            Set the start address of the buffer to disassemble

            :param idx: the index
            :type idx: int
        """
        if self.code != None:
            self.code.set_idx( idx )

    def set_name(self, value):
        self.CM.set_hook_method_name( self, value )
        self.reload()

    def get_raw(self):
        if self.code != None:
          self.code_off = self.code.get_off()

        return writeuleb128( self.method_idx_diff ) + writeuleb128( self.access_flags ) + writeuleb128( self.code_off )

    def get_size(self):
      return len(self.get_raw())

class ClassDataItem(object):
    """
        This class can parse a class_data_item of a dex file

        :param buff: a string which represents a Buff object of the class_data_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.static_fields_size = readuleb128( buff )
        self.instance_fields_size = readuleb128( buff )
        self.direct_methods_size = readuleb128( buff )
        self.virtual_methods_size = readuleb128( buff )

        self.static_fields = []
        self.instance_fields = []
        self.direct_methods = []
        self.virtual_methods = []

        self._load_elements( self.static_fields_size, self.static_fields, EncodedField, buff, cm )
        self._load_elements( self.instance_fields_size, self.instance_fields, EncodedField, buff, cm )
        self._load_elements( self.direct_methods_size, self.direct_methods, EncodedMethod, buff, cm )
        self._load_elements( self.virtual_methods_size, self.virtual_methods, EncodedMethod, buff, cm )

    def get_static_fields_size(self):
      """
          Return the number of static fields defined in this item

          :rtype: int
      """
      return self.static_fields_size

    def get_instance_fields_size(self):
      """
          Return the number of instance fields defined in this item

          :rtype: int
      """
      return self.instance_fields_size

    def get_direct_methods_size(self):
      """
          Return the number of direct methods defined in this item

          :rtype: int
      """
      return self.direct_methods_size

    def get_virtual_methods_size(self):
      """
          Return the number of virtual methods defined in this item

          :rtype: int
      """
      return self.virtual_methods_size

    def get_static_fields(self):
      """
          Return the defined static fields, represented as a sequence of encoded elements

          :rtype: a list of :class:`EncodedField` objects
      """
      return self.static_fields

    def get_instance_fields(self):
      """
          Return the defined instance fields, represented as a sequence of encoded elements

          :rtype: a list of :class:`EncodedField` objects
      """
      return self.instance_fields

    def get_direct_methods(self):
      """
          Return the defined direct (any of static, private, or constructor) methods, represented as a sequence of encoded elements

          :rtype: a list of :class:`EncodedMethod` objects
      """
      return self.direct_methods

    def get_virtual_methods(self):
      """
          Return the defined virtual (none of static, private, or constructor) methods, represented as a sequence of encoded elements

          :rtype: a list of :class:`EncodedMethod` objects
      """
      return self.virtual_methods

    def get_methods(self):
        """
            Return direct and virtual methods

            :rtype: a list of :class:`EncodedMethod` objects
        """
        return [ x for x in self.direct_methods ] + [ x for x in self.virtual_methods ]

    def get_fields(self):
        """
            Return static and instance fields

            :rtype: a list of :class:`EncodedField` objects
        """
        return [ x for x in self.static_fields ] + [ x for x in self.instance_fields ]


    def set_off(self, off):
      self.offset = off

    def set_static_fields(self, value):
        if value != None:
            values = value.get_values()
            if len(values) <= len(self.static_fields):
                for i in range(0, len(values)):
                    self.static_fields[i].set_init_value( values[i] )

    def _load_elements(self, size, l, Type, buff, cm):
        prev = 0
        for i in range(0, size):
            el = Type(buff, cm)
            el.adjust_idx( prev )

            if isinstance(el, EncodedField):
              prev = el.get_field_idx()
            else:
              prev = el.get_method_idx()

            l.append( el )

    def reload(self):
        for i in self.static_fields:
            i.reload()

        for i in self.instance_fields:
            i.reload()

        for i in self.direct_methods:
            i.reload()

        for i in self.virtual_methods:
            i.reload()

    def show(self):
        self.pretty_show()

    def pretty_show(self):
        bytecode._PrintSubBanner("Class Data Item")
        bytecode._PrintDefault("static_fields_size=%d instance_fields_size=%d direct_methods_size=%d virtual_methods_size=%d\n" % \
                (self.static_fields_size, self.instance_fields_size, self.direct_methods_size, self.virtual_methods_size))

        bytecode._PrintSubBanner("Static Fields")
        for i in self.static_fields:
            i.show()

        bytecode._PrintSubBanner("Instance Fields")
        for i in self.instance_fields:
            i.show()

        bytecode._PrintSubBanner("Direct Methods")
        for i in self.direct_methods:
            i.pretty_show()

        bytecode._PrintSubBanner("Virtual Methods")
        for i in self.virtual_methods:
            i.pretty_show()

    def get_obj(self):
        return [ i for i in self.static_fields ] + \
                 [ i for i in self.instance_fields ] + \
                 [ i for i in self.direct_methods ] + \
                 [ i for i in self.virtual_methods ]

    def get_raw(self):
        buff = writeuleb128( self.static_fields_size ) + \
                 writeuleb128( self.instance_fields_size ) + \
                 writeuleb128( self.direct_methods_size ) + \
                 writeuleb128( self.virtual_methods_size ) + \
                 ''.join(i.get_raw() for i in self.static_fields) + \
                 ''.join(i.get_raw() for i in self.instance_fields) + \
                 ''.join(i.get_raw() for i in self.direct_methods) + \
                 ''.join(i.get_raw() for i in self.virtual_methods)

        return buff

    def get_length(self):
      length = len(writeuleb128( self.static_fields_size )) +   \
              len(writeuleb128( self.instance_fields_size )) +  \
              len(writeuleb128( self.direct_methods_size )) +   \
              len(writeuleb128( self.virtual_methods_size ))

      for i in self.static_fields:
        length += i.get_size()

      for i in self.instance_fields:
        length += i.get_size()

      for i in self.direct_methods:
        length += i.get_size()

      for i in self.virtual_methods:
        length += i.get_size()

      return length

    def get_off(self):
      return self.offset


class ClassDefItem(object):
    """
        This class can parse a class_def_item of a dex file

        :param buff: a string which represents a Buff object of the class_def_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.class_idx = unpack("=I", buff.read(4))[0]
        self.access_flags = unpack("=I", buff.read(4))[0]
        self.superclass_idx = unpack("=I", buff.read(4))[0]
        self.interfaces_off = unpack("=I", buff.read(4))[0]
        self.source_file_idx = unpack("=I", buff.read(4))[0]
        self.annotations_off = unpack("=I", buff.read(4))[0]
        self.class_data_off = unpack("=I", buff.read(4))[0]
        self.static_values_off = unpack("=I", buff.read(4))[0]

        self.interfaces = []
        self.class_data_item = None
        self.static_values = None

        self.name = None
        self.sname = None
        self.access_flags_string = None

    def reload(self):
        self.name = self.__CM.get_type( self.class_idx )
        self.sname = self.__CM.get_type( self.superclass_idx )
        self.interfaces = self.__CM.get_type_list( self.interfaces_off )

        if self.class_data_off != 0:
            self.class_data_item = self.__CM.get_class_data_item( self.class_data_off )
            self.class_data_item.reload()

        if self.static_values_off != 0:
            self.static_values = self.__CM.get_encoded_array_item ( self.static_values_off )

            if self.class_data_item != None:
                self.class_data_item.set_static_fields( self.static_values.get_value() )

    def __str__(self):
        return "%s->%s" % (self.get_superclassname(),
                           self.get_name())

    def get_methods(self):
        """
            Return all methods of this class

            :rtype: a list of :class:`EncodedMethod` objects
        """
        if self.class_data_item != None:
            return self.class_data_item.get_methods()
        return []

    def get_fields(self):
        """
            Return all fields of this class

            :rtype: a list of :class:`EncodedField` objects
        """
        if self.class_data_item != None:
            return self.class_data_item.get_fields()
        return []

    def get_class_idx(self):
        """
            Return the index into the type_ids list for this class

            :rtype: int
        """
        return self.class_idx

    def get_access_flags(self):
        """
            Return the access flags for the class (public, final, etc.)

            :rtype: int
        """
        return self.access_flags

    def get_superclass_idx(self):
        """
            Return the index into the type_ids list for the superclass

            :rtype: int
        """
        return self.superclass_idx

    def get_interfaces_off(self):
        """
            Return the offset from the start of the file to the list of interfaces, or 0 if there are none

            :rtype: int
        """
        return self.interfaces_off

    def get_source_file_idx(self):
        """
            Return the index into the string_ids list for the name of the file containing the original
            source for (at least most of) this class, or the special value NO_INDEX to represent a lack of this information

            :rtype: int
        """
        return self.source_file_idx

    def get_annotations_off(self):
        """
            Return the offset from the start of the file to the annotations structure for this class,
            or 0 if there are no annotations on this class.

            :rtype: int
        """
        return self.annotations_off

    def get_class_data_off(self):
        """
            Return the offset from the start of the file to the associated class data for this item,
            or 0 if there is no class data for this class

            :rtype: int
        """
        return self.class_data_off

    def get_static_values_off(self):
        """
            Return the offset from the start of the file to the list of initial values for static fields,
            or 0 if there are none (and all static fields are to be initialized with 0 or null)

            :rtype: int
        """
        return self.static_values_off


    def get_class_data(self):
        """
            Return the associated class_data_item

            :rtype: a :class:`ClassDataItem` object
        """
        return self.class_data_item

    def get_name(self):
        """
            Return the name of this class

            :rtype: int
        """
        return self.name

    def get_superclassname(self):
        """
            Return the name of the super class

            :rtype: string
        """
        return self.sname

    def get_interfaces(self):
      """
          Return the name of the interface

          :rtype: string
      """
      return self.interfaces

    def get_access_flags_string(self):
        """
            Return the access flags string of the class

            :rtype: string
        """
        if self.access_flags_string == None:
            self.access_flags_string = get_access_flags_string( self.get_access_flags() )

            if self.access_flags_string == "":
                self.access_flags_string = "0x%x" % self.get_access_flags()
        return self.access_flags_string

    def show(self):
        bytecode._PrintSubBanner("Class Def Item")
        bytecode._PrintDefault("name=%s, sname=%s, interfaces=%s, access_flags=%s\n" %
                              (self.name,
                               self.sname,
                               self.interfaces,
                               self.get_access_flags_string()))
        bytecode._PrintDefault("class_idx=%d, superclass_idx=%d, interfaces_off=%x, source_file_idx=%d, annotations_off=%x, class_data_off=%x, static_values_off=%x\n" %
                              (self.class_idx,
                               self.superclass_idx,
                               self.interfaces_off,
                               self.source_file_idx,
                               self.annotations_off,
                               self.class_data_off,
                               self.static_values_off))
        self.show_xref()

    def show_xref(self):
        """
            Display where the method is called or which method is called
        """
        try:
            bytecode._PrintSubBanner("XREF")
            bytecode._PrintXRef("F", self.XREFfrom.items)
            bytecode._PrintSubBanner()
        except AttributeError:
            pass

    def source(self):
        """
            Return the source code of the entire class

            :rtype: string
        """
        self.__CM.decompiler_ob.display_all(self)

    def get_source(self):
      return self.__CM.decompiler_ob.get_source_class(self)

    def get_source_ext(self):
      return self.__CM.decompiler_ob.get_source_class_ext(self)

    def get_ast(self):
      return self.__CM.decompiler_ob.get_ast_class(self)

    def set_name(self, value):
        self.__CM.set_hook_class_name( self, value )

    def get_obj(self):
      if self.interfaces_off != 0:
        self.interfaces_off = self.__CM.get_obj_by_offset( self.interfaces_off ).get_off()

      if self.annotations_off != 0:
        self.annotations_off = self.__CM.get_obj_by_offset( self.annotations_off ).get_off()

      if self.class_data_off != 0:
        self.class_data_off = self.__CM.get_obj_by_offset( self.class_data_off ).get_off()

      if self.static_values_off != 0:
        self.static_values_off = self.__CM.get_obj_by_offset( self.static_values_off ).get_off()

      return  pack("=I", self.class_idx) +          \
              pack("=I", self.access_flags) +       \
              pack("=I", self.superclass_idx) +     \
              pack("=I", self.interfaces_off) +     \
              pack("=I", self.source_file_idx) +    \
              pack("=I", self.annotations_off) +    \
              pack("=I", self.class_data_off) +     \
              pack("=I", self.static_values_off)

    def get_raw(self):
        return self.get_obj()

    def get_length(self):
      return len(self.get_obj())

class ClassHDefItem(object):
    """
        This class can parse a list of class_def_item of a dex file

        :param buff: a string which represents a Buff object of the list of class_def_item
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.class_def = []

        for i in range(0, size):
            idx = buff.get_idx()

            class_def = ClassDefItem( buff, cm )
            self.class_def.append( class_def )

            buff.set_idx( idx + calcsize("=IIIIIIII") )

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def get_class_idx(self, idx):
      for i in self.class_def:
          if i.get_class_idx() == idx:
            return i
      return None

    def get_method(self, name_class, name_method):
        l = []

        for i in self.class_def:
            if i.get_name() == name_class:
                for j in i.get_methods():
                    if j.get_name() == name_method:
                        l.append(j)

        return l

    def get_names(self):
        return [ x.get_name() for x in self.class_def ]

    def reload(self):
        for i in self.class_def:
            i.reload()

    def show(self):
        for i in self.class_def:
            i.show()

    def get_obj(self):
        return [ i for i in self.class_def ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.class_def)

    def get_length(self):
      length = 0
      for i in self.class_def:
        length += i.get_length()
      return length

class EncodedTypeAddrPair(object):
    """
        This class can parse an encoded_type_addr_pair of a dex file

        :param buff: a string which represents a Buff object of the encoded_type_addr_pair
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff):
        self.type_idx = readuleb128( buff )
        self.addr = readuleb128( buff )

    def get_type_idx(self):
        """
            Return the index into the type_ids list for the type of the exception to catch

            :rtype: int
        """
        return self.type_idx

    def get_addr(self):
        """
            Return the bytecode address of the associated exception handler

            :rtype: int
        """
        return self.addr

    def get_obj(self):
        return []

    def show(self):
        bytecode._PrintSubBanner("Encoded Type Addr Pair")
        bytecode._PrintDefault("type_idx=%d addr=%x\n" % (self.type_idx, self.addr))

    def get_raw(self):
        return writeuleb128( self.type_idx ) + writeuleb128( self.addr )

    def get_length(self):
      return len(self.get_raw())

class EncodedCatchHandler(object):
    """
        This class can parse an encoded_catch_handler of a dex file

        :param buff: a string which represents a Buff object of the encoded_catch_handler
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.size = readsleb128( buff )

        self.handlers = []

        for i in range(0, abs(self.size)):
            self.handlers.append( EncodedTypeAddrPair(buff) )

        if self.size <= 0:
            self.catch_all_addr = readuleb128( buff )

    def get_size(self):
        """
            Return the number of catch types in this list

            :rtype: int
        """
        return self.size

    def get_handlers(self):
        """
            Return the stream of abs(size) encoded items, one for each caught type, in the order that the types should be tested.

            :rtype: a list of :class:`EncodedTypeAddrPair` objects
        """
        return self.handlers

    def get_catch_all_addr(self):
        """
            Return the bytecode address of the catch-all handler. This element is only present if size is non-positive.

            :rtype: int
        """
        return self.catch_all_addr

    def get_off(self):
      return self.offset

    def set_off(self, off):
      self.offset = off

    def show(self):
        bytecode._PrintSubBanner("Encoded Catch Handler")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.handlers:
            i.show()

        if self.size <= 0:
            bytecode._PrintDefault("catch_all_addr=%x\n" % self.catch_all_addr)

    def get_raw(self):
        buff = writesleb128( self.size ) + ''.join(i.get_raw() for i in self.handlers)

        if self.size <= 0:
            buff += writeuleb128( self.catch_all_addr )

        return buff

    def get_length(self):
      length = len(writesleb128( self.size ))

      for i in self.handlers:
        length += i.get_length()

      if self.size <= 0:
        length += len(writeuleb128( self.catch_all_addr ))

      return length

class EncodedCatchHandlerList(object):
    """
        This class can parse an encoded_catch_handler_list of a dex file

        :param buff: a string which represents a Buff object of the encoded_catch_handler_list
        :type buff: Buff object
        :param cm: a ClassManager object
        :type cm: :class:`ClassManager`
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.size = readuleb128( buff )
        self.list = []

        for i in range(0, self.size):
            self.list.append( EncodedCatchHandler(buff, cm) )


    def get_size(self):
      """
          Return the size of this list, in entries

          :rtype: int
      """
      return self.size

    def get_list(self):
        """
            Return the actual list of handler lists, represented directly (not as offsets), and concatenated sequentially

            :rtype: a list of :class:`EncodedCatchHandler` objects
        """
        return self.list

    def show(self):
        bytecode._PrintSubBanner("Encoded Catch Handler List")
        bytecode._PrintDefault("size=%d\n" % self.size)

        for i in self.list:
            i.show()

    def get_off(self):
      return self.offset

    def set_off(self, off):
      self.offset = off

    def get_obj(self):
        return writeuleb128( self.size )

    def get_raw(self):
        return self.get_obj() + ''.join(i.get_raw() for i in self.list)

    def get_length(self):
      length = len(self.get_obj())

      for i in self.list:
        length += i.get_length()
      return length


KIND_METH           = 0
KIND_STRING         = 1
KIND_FIELD          = 2
KIND_TYPE           = 3
VARIES              = 4
INLINE_METHOD       = 5
VTABLE_OFFSET       = 6
FIELD_OFFSET        = 7
KIND_RAW_STRING     = 8

OPERAND_REGISTER = 0
OPERAND_LITERAL = 1
OPERAND_RAW = 2
OPERAND_OFFSET = 3
OPERAND_KIND = 0x100

def get_kind(cm, kind, value):
  """
    Return the value of the 'kind' argument

    :param cm: a ClassManager object
    :type cm: :class:`ClassManager`
    :param kind: the type of the 'kind' argument
    :type kind: int
    :param value: the value of the 'kind' argument
    :type value: int

    :rtype: string
  """
  if kind == KIND_METH:
    method = cm.get_method_ref(value)
    class_name = method.get_class_name()
    name = method.get_name()
    descriptor = method.get_descriptor()

    return "%s->%s%s" % (class_name, name, descriptor)

  elif kind == KIND_STRING:
    return repr(cm.get_string(value))

  elif kind == KIND_RAW_STRING:
    return cm.get_string(value)

  elif kind == KIND_FIELD:
    class_name, proto, field_name = cm.get_field(value)
    return "%s->%s %s" % (class_name, field_name, proto)

  elif kind == KIND_TYPE:
    return cm.get_type(value)

  elif kind == VTABLE_OFFSET:
    return "vtable[0x%x]" % value

  elif kind == FIELD_OFFSET:
    return "field[0x%x]" % value

  elif kind == INLINE_METHOD:
    buff = "inline[0x%x]" % value

    # FIXME: depends of the android version ...
    if len(INLINE_METHODS) > value:
        elem = INLINE_METHODS[value]
        buff += " %s->%s%s" % (elem[0], elem[1], elem[2])

    return buff

  return None


class Instruction(object):
    """
        This class represents a dalvik instruction
    """
    def get_kind(self):
        """
            Return the 'kind' argument of the instruction

            :rtype: int
        """
        if self.OP > 0xff:
          if self.OP >= 0xf2ff:
            return DALVIK_OPCODES_OPTIMIZED[self.OP][1][1]
          return DALVIK_OPCODES_EXTENDED_WIDTH[self.OP][1][1]
        return DALVIK_OPCODES_FORMAT[self.OP][1][1]

    def get_name(self):
        """
            Return the name of the instruction

            :rtype: string
        """
        if self.OP > 0xff:
          if self.OP >= 0xf2ff:
            return DALVIK_OPCODES_OPTIMIZED[self.OP][1][0]
          return DALVIK_OPCODES_EXTENDED_WIDTH[self.OP][1][0]
        return DALVIK_OPCODES_FORMAT[self.OP][1][0]

    def get_op_value(self):
        """
            Return the value of the opcode

            :rtype: int
        """
        return self.OP

    def get_literals(self):
        """
            Return the associated literals

            :rtype: list of int
        """
        return []

    def show(self, idx):
        """
            Print the instruction
        """
        print (self.get_name() + " " + self.get_output(idx))

    def show_buff(self, idx):
        """
            Return the display of the instruction

            :rtype: string
        """
        return self.get_output(idx)

    def get_translated_kind(self):
        """
            Return the translated value of the 'kind' argument

            :rtype: string
        """
        return get_kind(self.cm, self.get_kind(), self.get_ref_kind())

    def get_output(self, idx=-1):
      """
          Return an additional output of the instruction

          :rtype: string
      """
      raise("not implemented")

    def get_operands(self, idx=-1):
      """
          Return all operands

          :rtype: list
      """
      raise("not implemented")

    def get_length(self):
      """
          Return the length of the instruction

          :rtype: int
      """
      raise("not implemented")

    def get_raw(self):
      """
          Return the object in a raw format

          :rtype: string
      """
      raise("not implemented")

    def get_ref_kind(self):
      """
          Return the value of the 'kind' argument

          :rtype: value
      """
      raise("not implemented")

    def get_formatted_operands(self):
      return None


class InstructionInvalid(Instruction):
    """
        This class represents an invalid instruction
    """
    def __init__(self, cm, buff):
      super(InstructionInvalid, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff

      #debug("OP:%x" % (self.OP))

    def get_name(self):
        """
            Return the name of the instruction

            :rtype: string
        """
        return "AG:invalid_instruction"

    def get_output(self, idx=-1):
      return "(OP:%x)" % self.OP

    def get_operands(self, idx=-1):
      return []

    def get_length(self):
      return 2

    def get_raw(self):
      return pack("=H", self.OP)


class FillArrayData(object):
    """
        This class can parse a FillArrayData instruction

        :param buff: a Buff object which represents a buffer where the instruction is stored
    """
    def __init__(self, buff):
        self.notes = []

        self.format_general_size = calcsize("=HHI")
        self.ident = unpack("=H", buff[0:2])[0]
        self.element_width = unpack("=H", buff[2:4])[0]
        self.size = unpack("=I", buff[4:8])[0]

        buf_len = self.size * self.element_width
        if buf_len % 2:
            buf_len += 1

        self.data = buff[self.format_general_size:self.format_general_size + buf_len]

    def add_note(self, msg):
      """
        Add a note to this instruction

        :param msg: the message
        :type msg: objects (string)
      """
      self.notes.append(msg)

    def get_notes(self):
      """
        Get all notes from this instruction

        :rtype: a list of objects
      """
      return self.notes

    def get_op_value(self):
      """
        Get the value of the opcode

        :rtype: int
      """
      return self.ident

    def get_data(self):
        """
            Return the data of this instruction (the payload)

            :rtype: string
        """
        return self.data

    def get_output(self, idx=-1):
        """
            Return an additional output of the instruction

            :rtype: string
        """
        buff = ""

        data = self.get_data()

        buff += repr(data) + " | "
        for i in range(0, len(data)):
          buff += "\\x%02x" % ord(data[i])

        return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_RAW, repr(self.get_data()))]

    def get_formatted_operands(self):
      return None

    def get_name(self):
        """
            Return the name of the instruction

            :rtype: string
        """
        return "fill-array-data-payload"

    def show_buff(self, pos):
        """
            Return the display of the instruction

            :rtype: string
        """
        buff = self.get_name() + " "

        for i in range(0, len(self.data)):
            buff += "\\x%02x" % ord(self.data[i])
        return buff

    def show(self, pos):
        """
            Print the instruction
        """
        print (self.show_buff(pos))
        
    def get_length(self):
        """
            Return the length of the instruction

            :rtype: int
        """
        return ((self.size * self.element_width + 1) / 2 + 4) * 2

    def get_raw(self):
        return pack("=H", self.ident) + pack("=H", self.element_width) + pack("=I", self.size) + self.data


class SparseSwitch(object):
    """
        This class can parse a SparseSwitch instruction

        :param buff: a Buff object which represents a buffer where the instruction is stored
    """
    def __init__(self, buff):
        self.notes = []

        self.format_general_size = calcsize("=HH")
        self.ident = unpack("=H", buff[0:2])[0]
        self.size = unpack("=H", buff[2:4])[0]

        self.keys = []
        self.targets = []

        idx = self.format_general_size
        for i in range(0, self.size):
            self.keys.append(unpack('=l', buff[idx:idx + 4])[0])
            idx += 4

        for i in range(0, self.size):
            self.targets.append(unpack('=l', buff[idx:idx + 4])[0])
            idx += 4

    def add_note(self, msg):
      """
        Add a note to this instruction

        :param msg: the message
        :type msg: objects (string)
      """
      self.notes.append(msg)

    def get_notes(self):
      """
        Get all notes from this instruction

        :rtype: a list of objects
      """
      return self.notes

    def get_op_value(self):
        """
          Get the value of the opcode

          :rtype: int
        """
        return self.ident

    def get_keys(self):
        """
            Return the keys of the instruction

            :rtype: a list of long
        """
        return self.keys

    def get_values(self):
      return self.get_keys()

    def get_targets(self):
        """
            Return the targets (address) of the instruction

            :rtype: a list of long
        """
        return self.targets

    def get_output(self, idx=-1):
      """
          Return an additional output of the instruction

          :rtype: string
      """
      return " ".join("%x" % i for i in self.keys)

    def get_operands(self, idx=-1):
      """
          Return an additional output of the instruction

          :rtype: string
      """
      return []

    def get_formatted_operands(self):
      return None

    def get_name(self):
        """
            Return the name of the instruction

            :rtype: string
        """
        return "sparse-switch-payload"

    def show_buff(self, pos):
        """
            Return the display of the instruction

            :rtype: string
        """
        buff = self.get_name() + " "
        for i in range(0, len(self.keys)):
            buff += "%x:%x " % (self.keys[i], self.targets[i])

        return buff

    def show(self, pos):
        """
            Print the instruction
        """
        print (self.show_buff(pos))

    def get_length(self):
        return self.format_general_size + (self.size * calcsize('<L')) * 2

    def get_raw(self):
        return pack("=H", self.ident) + pack("=H", self.size) + ''.join(pack("=l", i) for i in self.keys) + ''.join(pack("=l", i) for i in self.targets)


class PackedSwitch(object):
    """
        This class can parse a PackedSwitch instruction

        :param buff: a Buff object which represents a buffer where the instruction is stored
    """
    def __init__(self, buff):
        self.notes = []

        self.format_general_size = calcsize("=HHI")

        self.ident = unpack("=H", buff[0:2])[0]
        self.size = unpack("=H", buff[2:4])[0]
        self.first_key = unpack("=i", buff[4:8])[0]

        self.targets = []

        idx = self.format_general_size

        max_size = self.size
        if (max_size * 4) > len(buff):
            max_size = len(buff) - idx - 8

        for i in range(0, max_size):
            self.targets.append(unpack('=l', buff[idx:idx + 4])[0])
            idx += 4

    def add_note(self, msg):
      """
        Add a note to this instruction

        :param msg: the message
        :type msg: objects (string)
      """
      self.notes.append(msg)

    def get_notes(self):
      """
        Get all notes from this instruction

        :rtype: a list of objects
      """
      return self.notes

    def get_op_value(self):
        """
          Get the value of the opcode

          :rtype: int
        """
        return self.ident

    def get_keys(self):
        """
            Return the keys of the instruction

            :rtype: a list of long
        """
        return [(self.first_key + i) for i in range(0, len(self.targets))]

    def get_values(self):
        return self.get_keys()

    def get_targets(self):
        """
            Return the targets (address) of the instruction

            :rtype: a list of long
        """
        return self.targets

    def get_output(self, idx=-1):
      """
          Return an additional output of the instruction

          :rtype: string
      """
      return " ".join("%x" % (self.first_key + i) for i in range(0, len(self.targets)))

    def get_operands(self, idx=-1):
      """
          Return an additional output of the instruction

          :rtype: string
      """
      return []

    def get_formatted_operands(self):
      return None

    def get_name(self):
        """
            Return the name of the instruction

            :rtype: string
        """
        return "packed-switch-payload"

    def show_buff(self, pos):
        """
            Return the display of the instruction

            :rtype: string
        """
        buff = self.get_name() + " "
        buff += "%x:" % self.first_key

        for i in self.targets:
            buff += " %x" % i

        return buff

    def show(self, pos):
        """
            Print the instruction
        """
        print (self.show_buff(pos))

    def get_length(self):
        return self.format_general_size + (self.size * calcsize('=L'))

    def get_raw(self):
        return pack("=H", self.ident) + pack("=H", self.size) + pack("=i", self.first_key) + ''.join(pack("=l", i) for i in self.targets)


class Instruction35c(Instruction):
    """
        This class represents all instructions which have the 35c format
    """
    def __init__(self, cm, buff):
      super(Instruction35c, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.G = (i16 >> 8) & 0xf
      self.A = (i16 >> 12) & 0xf
      self.BBBB = unpack("=H", buff[2:4])[0]

      i16 = unpack("=H", buff[4:6])[0]
      self.C = i16 & 0xf
      self.D = (i16 >> 4) & 0xf
      self.E = (i16 >> 8) & 0xf
      self.F = (i16 >> 12) & 0xf

    def get_output(self, idx=-1):
      buff = ""
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 0:
        buff += "%s" % (kind)
      elif self.A == 1:
        buff += "v%d, %s" % (self.C, kind)
      elif self.A == 2:
        buff += "v%d, v%d, %s" % (self.C, self.D, kind)
      elif self.A == 3:
        buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
      elif self.A == 4:
        buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind)
      elif self.A == 5:
        buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind)

      return buff

    def get_operands(self, idx=-1):
      l = []
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 0:
        l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind))
      elif self.A == 1:
        l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 2:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 3:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 4:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 5:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])

      return l

    def get_length(self):
      return 6

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C)


class Instruction10x(Instruction):
    """
        This class represents all instructions which have the 10x format
    """
    def __init__(self, cm, buff):
      super(Instruction10x, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff

      #log_andro.debug("OP:%x %s" % (self.OP, args[0]))

    def get_output(self, idx=-1):
      return ""

    def get_operands(self, idx=-1):
      return []

    def get_length(self):
      return 2

    def get_raw(self):
      return pack("=H", self.OP)


class Instruction21h(Instruction):
    """
        This class represents all instructions which have the 21h format
    """
    def __init__(self, cm, buff):
      super(Instruction21h, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=h", buff[2:4])[0]

      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

      self.formatted_operands = []

      if self.OP == 0x15:
        self.formatted_operands.append(unpack('=f', '\x00\x00' + pack('=h', self.BBBB))[0])
      elif self.OP == 0x19:
        self.formatted_operands.append(unpack('=d', '\x00\x00\x00\x00\x00\x00' + pack('=h', self.BBBB))[0])

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, %d" % (self.AA, self.BBBB)

      if self.formatted_operands != []:
        buff += " # %s" % (str(self.formatted_operands))

      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBB)]

    def get_formatted_operands(self):
      return self.formatted_operands

    def get_literals(self):
      return [self.BBBB]

    def get_raw(self):
      return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB)


class Instruction11n(Instruction):
    """
        This class represents all instructions which have the 11n format
    """
    def __init__(self, cm, buff):
      super(Instruction11n, self).__init__()

      i16 = unpack("=h", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12)

      #log_andro.debug("OP:%x %s A:%x B:%x" % (self.OP, args[0], self.A, self.B))

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, %d" % (self.A, self.B)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.A), (OPERAND_LITERAL, self.B)]

    def get_literals(self):
      return [self.B]

    def get_length(self):
      return 2

    def get_raw(self):
      return pack("=h", (self.B << 12) | (self.A << 8) | self.OP)


class Instruction21c(Instruction):
    """
        This class represents all instructions which have the 21c format
    """
    def __init__(self, cm, buff):
      super(Instruction21c, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]
      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      buff += "v%d, %s" % (self.AA, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)
      return [(OPERAND_REGISTER, self.AA), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]

    def get_ref_kind(self):
      return self.BBBB

    def get_string(self):
      return get_kind(self.cm, self.get_kind(), self.BBBB)

    def get_raw_string(self):
      return get_kind(self.cm, KIND_RAW_STRING, self.BBBB)

    def get_raw(self):
      return pack("=HH", (self.AA << 8) | self.OP, self.BBBB)


class Instruction21s(Instruction):
    """
        This class represents all instructions which have the 21s format
    """
    def __init__(self, cm, buff):
      super(Instruction21s, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=h", buff[2:4])[0]

      self.formatted_operands = []

      if self.OP == 0x16:
        self.formatted_operands.append(unpack('=d', pack('=d', self.BBBB))[0])

      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, %d" % (self.AA, self.BBBB)

      if self.formatted_operands != []:
        buff += " # %s" % str(self.formatted_operands)

      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBB)]

    def get_literals(self):
      return [self.BBBB]

    def get_formatted_operands(self):
      return self.formatted_operands

    def get_raw(self):
      return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB)


class Instruction22c(Instruction):
    """
        This class represents all instructions which have the 22c format
    """
    def __init__(self, cm, buff):
      super(Instruction22c, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12) & 0xf
      self.CCCC = unpack("=H", buff[2:4])[0]

      #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      kind = get_kind(self.cm, self.get_kind(), self.CCCC)
      buff += "v%d, v%d, %s" % (self.A, self.B, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.CCCC)
      return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (self.get_kind() + OPERAND_KIND, self.CCCC, kind)]

    def get_ref_kind(self):
      return self.CCCC

    def get_raw(self):
      return pack("=HH", (self.B << 12) | (self.A << 8) | (self.OP), self.CCCC)


class Instruction22cs(Instruction):
    """
        This class represents all instructions which have the 22cs format
    """
    def __init__(self, cm, buff):
      super(Instruction22cs, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12) & 0xf
      self.CCCC = unpack("=H", buff[2:4])[0]

      #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      kind = get_kind(self.cm, self.get_kind(), self.CCCC)
      buff += "v%d, v%d, %s" % (self.A, self.B, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.CCCC)
      return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (self.get_kind() + OPERAND_KIND, self.CCCC, kind)]

    def get_ref_kind(self):
      return self.CCCC

    def get_raw(self):
      return pack("=HH", (self.B << 12) | (self.A << 8) | (self.OP), self.CCCC)


class Instruction31t(Instruction):
    """
        This class represents all instructions which have the 31t format
    """
    def __init__(self, cm, buff):
      super(Instruction31t, self).__init__()
      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBBBBBB = unpack("=i", buff[2:6])[0]
      #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, +%x (0x%x)" % (self.AA, self.BBBBBBBB, self.BBBBBBBB * 2 + idx)

      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBB)]

    def get_ref_off(self):
      return self.BBBBBBBB

    def get_raw(self):
      return pack("=Hi", (self.AA << 8) | self.OP, self.BBBBBBBB)


class Instruction31c(Instruction):
    """
        This class represents all instructions which have the 31c format
    """
    def __init__(self, cm, buff):
      super(Instruction31c, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBBBBBB = unpack("=I", buff[2:6])[0]
      #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
      buff += "v%d, %s" % (self.AA, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
      return [(OPERAND_REGISTER, self.AA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)]

    def get_ref_kind(self):
      return self.BBBBBBBB

    def get_string(self):
      """
          Return the string associated to the 'kind' argument

          :rtype: string
      """
      return get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

    def get_raw_string(self):
      return get_kind(self.cm, KIND_RAW_STRING, self.BBBBBBBB)

    def get_raw(self):
      return pack("=HI", (self.AA << 8) | self.OP, self.BBBBBBBB)


class Instruction12x(Instruction):
    """
        This class represents all instructions which have the 12x format
    """
    def __init__(self, cm, buff):
      super(Instruction12x, self).__init__()

      i16 = unpack("=h", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12) & 0xf

      #log_andro.debug("OP:%x %s A:%x B:%x" % (self.OP, args[0], self.A, self.B))

    def get_length(self):
      return 2

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d" % (self.A, self.B)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B)]

    def get_raw(self):
      return pack("=H", (self.B << 12) | (self.A << 8) | (self.OP))


class Instruction11x(Instruction):
    """
        This class represents all instructions which have the 11x format
    """
    def __init__(self, cm, buff):
      super(Instruction11x, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      #log_andro.debug("OP:%x %s AA:%x" % (self.OP, args[0], self.AA))

    def get_length(self):
      return 2

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d" % (self.AA)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA)]

    def get_raw(self):
      return pack("=H", (self.AA << 8) | self.OP)


class Instruction51l(Instruction):
    """
        This class represents all instructions which have the 51l format
    """
    def __init__(self, cm, buff):
      super(Instruction51l, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBBBBBBBBBBBBBB = unpack("=q", buff[2:10])[0]

      self.formatted_operands = []

      if self.OP == 0x18:
        self.formatted_operands.append(unpack('=d', pack('=q', self.BBBBBBBBBBBBBBBB))[0])

      #log_andro.debug("OP:%x %s AA:%x BBBBBBBBBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBBBBBBBBBB))

    def get_length(self):
      return 10

    def get_output(self, idx=-1):
      buff = ""

      buff += "v%d, %d" % (self.AA, self.BBBBBBBBBBBBBBBB)

      if self.formatted_operands:
        buff += " # %s" % str(self.formatted_operands)

      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBBBBBBBBBB)]

    def get_formatted_operands(self):
      return self.formatted_operands

    def get_literals(self):
      return [self.BBBBBBBBBBBBBBBB]

    def get_raw(self):
      return pack("=Hq", (self.AA << 8) | self.OP, self.BBBBBBBBBBBBBBBB)


class Instruction31i(Instruction):
    """
        This class represents all instructions which have the 3li format
    """
    def __init__(self, cm, buff):
      super(Instruction31i, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBBBBBB = unpack("=i", buff[2:6])[0]

      self.formatted_operands = []

      if self.OP == 0x14:
        self.formatted_operands.append(unpack("=f", pack("=i", self.BBBBBBBB))[0])

      elif self.OP == 0x17:
        self.formatted_operands.append(unpack('=d', pack('=d', self.BBBBBBBB))[0])

      #log_andro.debug("OP:%x %s AA:%x BBBBBBBBB:%x" % (self.OP, args[0], self.AA, self.BBBBBBBB))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, %d" % (self.AA, self.BBBBBBBB)

      if self.formatted_operands:
        buff += " # %s" % str(self.formatted_operands)

      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_LITERAL, self.BBBBBBBB)]

    def get_formatted_operands(self):
      return self.formatted_operands

    def get_literals(self):
      return [self.BBBBBBBB]

    def get_raw(self):
      return pack("=Hi", (self.AA << 8) | self.OP, self.BBBBBBBB)


class Instruction22x(Instruction):
    """
        This class represents all instructions which have the 22x format
    """
    def __init__(self, cm, buff):
      super(Instruction22x, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]

      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d" % (self.AA, self.BBBB)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BBBB)]

    def get_raw(self):
      return pack("=HH", (self.AA << 8) | self.OP, self.BBBB)


class Instruction23x(Instruction):
    """
        This class represents all instructions which have the 23x format
    """
    def __init__(self, cm, buff):
      super(Instruction23x, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      i16 = unpack("=H", buff[2:4])[0]
      self.BB = i16 & 0xff
      self.CC = (i16 >> 8) & 0xff

      #log_andro.debug("OP:%x %s AA:%x BB:%x CC:%x" % (self.OP, args[0], self.AA, self.BB, self.CC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d, v%d" % (self.AA, self.BB, self.CC)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BB), (OPERAND_REGISTER, self.CC)]

    def get_raw(self):
      return pack("=HH", (self.AA << 8) | self.OP, (self.CC << 8) | self.BB)


class Instruction20t(Instruction):
    """
        This class represents all instructions which have the 20t format
    """
    def __init__(self, cm, buff):
      super(Instruction20t, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AAAA = unpack("=h", buff[2:4])[0]

      #log_andro.debug("OP:%x %s AAAA:%x" % (self.OP, args[0], self.AAAA))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "%+x" % (self.AAAA)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_OFFSET, self.AAAA)]

    def get_ref_off(self):
      return self.AAAA

    def get_raw(self):
      return pack("=Hh", self.OP, self.AAAA)


class Instruction21t(Instruction):
    """
        This class represents all instructions which have the 21t format
    """
    def __init__(self, cm, buff):
      super(Instruction21t, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=h", buff[2:4])[0]

      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, %+x" % (self.AA, self.BBBB)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_OFFSET, self.BBBB)]

    def get_ref_off(self):
      return self.BBBB

    def get_raw(self):
      return pack("=Hh", (self.AA << 8) | self.OP, self.BBBB)


class Instruction10t(Instruction):
    """
        This class represents all instructions which have the 10t format
    """
    def __init__(self, cm, buff):
      super(Instruction10t, self).__init__()

      self.OP = unpack("=B", buff[0:1])[0]
      self.AA = unpack("=b", buff[1:2])[0]

      #log_andro.debug("OP:%x %s AA:%x" % (self.OP, args[0], self.AA))

    def get_length(self):
      return 2

    def get_output(self, idx=-1):
      buff = ""
      buff += "%+x" % (self.AA)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_OFFSET, self.AA)]

    def get_ref_off(self):
      return self.AA

    def get_raw(self):
      return pack("=Bb", self.OP, self.AA)


class Instruction22t(Instruction):
    """
        This class represents all instructions which have the 22t format
    """
    def __init__(self, cm, buff):
      super(Instruction22t, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12) & 0xf
      self.CCCC = unpack("=h", buff[2:4])[0]

      #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d, %+x" % (self.A, self.B, self.CCCC)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (OPERAND_OFFSET, self.CCCC)]

    def get_ref_off(self):
      return self.CCCC

    def get_raw(self):
      return pack("=Hh", (self.B << 12) | (self.A << 8) | self.OP, self.CCCC)


class Instruction22s(Instruction):
    """
        This class represents all instructions which have the 22s format
    """
    def __init__(self, cm, buff):
      super(Instruction22s, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.A = (i16 >> 8) & 0xf
      self.B = (i16 >> 12) & 0xf
      self.CCCC = unpack("=h", buff[2:4])[0]

      #log_andro.debug("OP:%x %s A:%x B:%x CCCC:%x" % (self.OP, args[0], self.A, self.B, self.CCCC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d, %d" % (self.A, self.B, self.CCCC)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.A), (OPERAND_REGISTER, self.B), (OPERAND_LITERAL, self.CCCC)]

    def get_literals(self):
      return [self.CCCC]

    def get_raw(self):
      return pack("=Hh", (self.B << 12) | (self.A << 8) | self.OP, self.CCCC)


class Instruction22b(Instruction):
    """
        This class represents all instructions which have the 22b format
    """
    def __init__(self, cm, buff):
      super(Instruction22b, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BB = unpack("=B", buff[2:3])[0]
      self.CC = unpack("=b", buff[3:4])[0]

      #log_andro.debug("OP:%x %s AA:%x BB:%x CC:%x" % (self.OP, args[0], self.AA, self.BB, self.CC))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d, %d" % (self.AA, self.BB, self.CC)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AA), (OPERAND_REGISTER, self.BB), (OPERAND_LITERAL, self.CC)]

    def get_literals(self):
      return [self.CC]

    def get_raw(self):
      return pack("=Hh", (self.AA << 8) | self.OP, (self.CC << 8) | self.BB)


class Instruction30t(Instruction):
    """
        This class represents all instructions which have the 30t format
    """
    def __init__(self, cm, buff):
      super(Instruction30t, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff

      self.AAAAAAAA = unpack("=i", buff[2:6])[0]

      #log_andro.debug("OP:%x %s AAAAAAAA:%x" % (self.OP, args[0], self.AAAAAAAA))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""
      buff += "%+x" % (self.AAAAAAAA)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_OFFSET, self.AAAAAAAA)]

    def get_ref_off(self):
      return self.AAAAAAAA

    def get_raw(self):
      return pack("=Hi", self.OP, self.AAAAAAAA)


class Instruction3rc(Instruction):
    """
        This class represents all instructions which have the 3rc format
    """
    def __init__(self, cm, buff):
      super(Instruction3rc, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]
      self.CCCC = unpack("=H", buff[4:6])[0]

      self.NNNN = self.CCCC + self.AA - 1

      #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        buff += "v%d, %s" % (self.CCCC, kind)
      else:
        buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]
      else:
        l = []
        for i in range(self.CCCC, self.NNNN):
          l.append((OPERAND_REGISTER, i))

        l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind))
        return l

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC)


class Instruction32x(Instruction):
    """
        This class represents all instructions which have the 32x format
    """
    def __init__(self, cm, buff):
      super(Instruction32x, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AAAA = unpack("=H", buff[2:4])[0]
      self.BBBB = unpack("=H", buff[4:6])[0]

      #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBB))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""
      buff += "v%d, v%d" % (self.AAAA, self.BBBB)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_REGISTER, self.AAAA), (OPERAND_REGISTER, self.BBBB)]

    def get_raw(self):
      return pack("=HHH", self.OP, self.AAAA, self.BBBB)


class Instruction20bc(Instruction):
    """
        This class represents all instructions which have the 20bc format
    """
    def __init__(self, cm, buff):
      super(Instruction20bc, self).__init__()

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]

      #log_andro.debug("OP:%x %s AA:%x BBBBB:%x" % (self.OP, args[0], self.AA, self.BBBB))

    def get_length(self):
      return 4

    def get_output(self, idx=-1):
      buff = ""
      buff += "%d, %d" % (self.AA, self.BBBB)
      return buff

    def get_operands(self, idx=-1):
      return [(OPERAND_LITERAL, self.AA), (OPERAND_LITERAL, self.BBBB)]

    def get_raw(self):
      return pack("=HH", (self.AA << 8) | self.OP, self.BBBB)


class Instruction35mi(Instruction):
    """
        This class represents all instructions which have the 35mi format
    """
    def __init__(self, cm, buff):
      super(Instruction35mi, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.G = (i16 >> 8) & 0xf
      self.A = (i16 >> 12) & 0xf
      self.BBBB = unpack("=H", buff[2:4])[0]

      i16 = unpack("=H", buff[4:6])[0]
      self.C = i16 & 0xf
      self.D = (i16 >> 4) & 0xf
      self.E = (i16 >> 8) & 0xf
      self.F = (i16 >> 12) & 0xf

      #log_andro.debug("OP:%x %s G:%x A:%x BBBB:%x C:%x D:%x E:%x F:%x" % (self.OP, args[0], self.G, self.A, self.BBBB, self.C, self.D, self.E, self.F))

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 1:
        buff += "v%d, %s" % (self.C, kind)
      elif self.A == 2:
        buff += "v%d, v%d, %s" % (self.C, self.D, kind)
      elif self.A == 3:
        buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
      elif self.A == 4:
        buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind)
      elif self.A == 5:
        buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind)

      return buff

    def get_operands(self, idx=-1):
      l = []
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 1:
        l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 2:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 3:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 4:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 5:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])

      return l

    def get_length(self):
      return 6

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C)


class Instruction35ms(Instruction):
    """
        This class represents all instructions which have the 35ms format
    """
    def __init__(self, cm, buff):
      super(Instruction35ms, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.G = (i16 >> 8) & 0xf
      self.A = (i16 >> 12) & 0xf
      self.BBBB = unpack("=H", buff[2:4])[0]

      i16 = unpack("=H", buff[4:6])[0]
      self.C = i16 & 0xf
      self.D = (i16 >> 4) & 0xf
      self.E = (i16 >> 8) & 0xf
      self.F = (i16 >> 12) & 0xf

      #log_andro.debug("OP:%x %s G:%x A:%x BBBB:%x C:%x D:%x E:%x F:%x" % (self.OP, args[0], self.G, self.A, self.BBBB, self.C, self.D, self.E, self.F))

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 1:
        buff += "v%d, %s" % (self.C, kind)
      elif self.A == 2:
        buff += "v%d, v%d, %s" % (self.C, self.D, kind)
      elif self.A == 3:
        buff += "v%d, v%d, v%d, %s" % (self.C, self.D, self.E, kind)
      elif self.A == 4:
        buff += "v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, kind)
      elif self.A == 5:
        buff += "v%d, v%d, v%d, v%d, v%d, %s" % (self.C, self.D, self.E, self.F, self.G, kind)

      return buff

    def get_operands(self, idx=-1):
      l = []
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.A == 1:
        l.extend([(OPERAND_REGISTER, self.C), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 2:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 3:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 4:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])
      elif self.A == 5:
        l.extend([(OPERAND_REGISTER, self.C), (OPERAND_REGISTER, self.D), (OPERAND_REGISTER, self.E), (OPERAND_REGISTER, self.F), (OPERAND_REGISTER, self.G), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)])

      return l

    def get_length(self):
      return 6

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.A << 12) | (self.G << 8) | self.OP, self.BBBB, (self.F << 12) | (self.E << 8) | (self.D << 4) | self.C)


class Instruction3rmi(Instruction):
    """
        This class represents all instructions which have the 3rmi format
    """
    def __init__(self, cm, buff):
      super(Instruction3rmi, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]
      self.CCCC = unpack("=H", buff[4:6])[0]

      self.NNNN = self.CCCC + self.AA - 1

      #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        buff += "v%d, %s" % (self.CCCC, kind)
      else:
        buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]
      else:
        l = []
        for i in range(self.CCCC, self.NNNN):
          l.append((OPERAND_REGISTER, i))

        l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind))
        return l

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC)


class Instruction3rms(Instruction):
    """
        This class represents all instructions which have the 3rms format
    """
    def __init__(self, cm, buff):
      super(Instruction3rms, self).__init__()
      self.cm = cm

      i16 = unpack("=H", buff[0:2])[0]
      self.OP = i16 & 0xff
      self.AA = (i16 >> 8) & 0xff

      self.BBBB = unpack("=H", buff[2:4])[0]
      self.CCCC = unpack("=H", buff[4:6])[0]

      self.NNNN = self.CCCC + self.AA - 1

      #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AA, self.BBBB, self.CCCC, self.NNNN))

    def get_length(self):
      return 6

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        buff += "v%d, %s" % (self.CCCC, kind)
      else:
        buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBB)

      if self.CCCC == self.NNNN:
        return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]
      else:
        l = []
        for i in range(self.CCCC, self.NNNN):
          l.append((OPERAND_REGISTER, i))

        l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind))
        return l

    def get_ref_kind(self):
      return self.BBBB

    def get_raw(self):
      return pack("=HHH", (self.AA << 8) | self.OP, self.BBBB, self.CCCC)


class Instruction41c(Instruction):
    """
        This class represents all instructions which have the 41c format
    """
    def __init__(self, cm, buff):
      super(Instruction41c, self).__init__()
      self.cm = cm

      self.OP = unpack("=H", buff[0:2])[0]
      self.BBBBBBBB = unpack("=I", buff[2:6])[0]

      self.AAAA = unpack("=H", buff[6:8])[0]

      #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBBBBBB))

    def get_length(self):
      return 8

    def get_output(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

      buff = ""
      buff += "v%d, %s" % (self.AAAA, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
      return [(OPERAND_REGISTER, self.AAAA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)]

    def get_ref_kind(self):
      return self.BBBBBBBB

    def get_raw(self):
      return pack("=HIH", self.OP, self.BBBBBBBB, self.AAAA)


class Instruction40sc(Instruction):
    """
        This class represents all instructions which have the 40sc format
    """
    def __init__(self, cm, buff):
      super(Instruction40sc, self).__init__()
      self.cm = cm

      self.OP = unpack("=H", buff[0:2])[0]
      self.BBBBBBBB = unpack("=I", buff[2:6])[0]
      self.AAAA = unpack("=H", buff[6:8])[0]

      #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBBBBBB))

    def get_length(self):
      return 8

    def get_output(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

      buff = ""
      buff += "%d, %s" % (self.AAAA, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)
      return [(OPERAND_LITERAL, self.AAAA), (self.get_kind() + OPERAND_KIND, self.BBBBBBBB, kind)]

    def get_ref_kind(self):
      return self.BBBBBBBB

    def get_raw(self):
      return pack("=HIH", self.OP, self.BBBBBBBB, self.AAAA)


class Instruction52c(Instruction):
    """
        This class represents all instructions which have the 52c format
    """
    def __init__(self, cm, buff):
      super(Instruction52c, self).__init__()
      self.cm = cm

      self.OP = unpack("=H", buff[0:2])[0]
      self.CCCCCCCC = unpack("=I", buff[2:6])[0]
      self.AAAA = unpack("=H", buff[6:8])[0]
      self.BBBB = unpack("=H", buff[8:10])[0]

      #log_andro.debug("OP:%x %s AAAAA:%x BBBBB:%x" % (self.OP, args[0], self.AAAA, self.BBBB))

    def get_length(self):
      return 10

    def get_output(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC)

      buff = ""
      buff += "v%d, v%d, %s" % (self.AAAA, self.BBBB, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.CCCCCCCC)
      return [(OPERAND_LITERAL, self.AAAA), (OPERAND_LITERAL, self.BBBB), (self.get_kind() + OPERAND_KIND, self.CCCCCCCC, kind)]

    def get_ref_kind(self):
      return self.CCCCCCCC

    def get_raw(self):
      return pack("=HIHH", self.OP, self.CCCCCCCC, self.AAAA, self.BBBB)


class Instruction5rc(Instruction):
    """
        This class represents all instructions which have the 5rc format
    """
    def __init__(self, cm, buff):
      super(Instruction5rc, self).__init__()
      self.cm = cm

      self.OP = unpack("=H", buff[0:2])[0]
      self.BBBBBBBB = unpack("=I", buff[2:6])[0]
      self.AAAA = unpack("=H", buff[6:8])[0]
      self.CCCC = unpack("=H", buff[8:10])[0]

      self.NNNN = self.CCCC + self.AAAA - 1

      #log_andro.debug("OP:%x %s AA:%x BBBB:%x CCCC:%x NNNN:%d" % (self.OP, args[0], self.AAAA, self.BBBBBBBB, self.CCCC, self.NNNN))

    def get_length(self):
      return 10

    def get_output(self, idx=-1):
      buff = ""

      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

      if self.CCCC == self.NNNN:
        buff += "v%d, %s" % (self.CCCC, kind)
      else:
        buff += "v%d ... v%d, %s" % (self.CCCC, self.NNNN, kind)
      return buff

    def get_operands(self, idx=-1):
      kind = get_kind(self.cm, self.get_kind(), self.BBBBBBBB)

      if self.CCCC == self.NNNN:
        return [(OPERAND_REGISTER, self.CCCC), (self.get_kind() + OPERAND_KIND, self.BBBB, kind)]
      else:
        l = []
        for i in range(self.CCCC, self.NNNN):
          l.append((OPERAND_REGISTER, i))

        l.append((self.get_kind() + OPERAND_KIND, self.BBBB, kind))
        return l

    def get_ref_kind(self):
      return self.BBBBBBBB

    def get_raw(self):
      return pack("=HIHH", self.OP, self.BBBBBBBB, self.AAAA, self.CCCC)


DALVIK_OPCODES_FORMAT = {
  0x00 : [Instruction10x, [ "nop" ] ],
  0x01 : [Instruction12x, [ "move" ] ],
  0x02 : [Instruction22x, [ "move/from16" ] ],
  0x03 : [Instruction32x, [ "move/16" ] ],
  0x04 : [Instruction12x, [ "move-wide" ] ],
  0x05 : [Instruction22x, [ "move-wide/from16" ] ],
  0x06 : [Instruction32x, [ "move-wide/16" ] ],
  0x07 : [Instruction12x, [ "move-object" ] ],
  0x08 : [Instruction22x, [ "move-object/from16" ] ],
  0x09 : [Instruction32x, [ "move-object/16" ] ],
  0x0a : [Instruction11x, [ "move-result" ] ],
  0x0b : [Instruction11x, [ "move-result-wide" ] ],
  0x0c : [Instruction11x, [ "move-result-object" ] ],
  0x0d : [Instruction11x, [ "move-exception" ] ],
  0x0e : [Instruction10x, [ "return-void" ] ],
  0x0f : [Instruction11x, [ "return" ] ],
  0x10 : [Instruction11x, [ "return-wide" ] ],
  0x11 : [Instruction11x, [ "return-object" ] ],
  0x12 : [Instruction11n, [ "const/4" ] ],
  0x13 : [Instruction21s, [ "const/16" ] ],
  0x14 : [Instruction31i, [ "const" ] ],
  0x15 : [Instruction21h, [ "const/high16" ] ],
  0x16 : [Instruction21s, [ "const-wide/16" ] ],
  0x17 : [Instruction31i, [ "const-wide/32" ] ],
  0x18 : [Instruction51l, [ "const-wide" ] ],
  0x19 : [Instruction21h, [ "const-wide/high16" ] ],
  0x1a : [Instruction21c, [ "const-string", KIND_STRING ] ],
  0x1b : [Instruction31c, [ "const-string/jumbo", KIND_STRING ] ],
  0x1c : [Instruction21c, [ "const-class", KIND_TYPE ] ],
  0x1d : [Instruction11x, [ "monitor-enter" ] ],
  0x1e : [Instruction11x, [ "monitor-exit" ] ],
  0x1f : [Instruction21c, [ "check-cast", KIND_TYPE ] ],
  0x20 : [Instruction22c, [ "instance-of", KIND_TYPE ] ],
  0x21 : [Instruction12x, [ "array-length" ] ],
  0x22 : [Instruction21c, [ "new-instance", KIND_TYPE ] ],
  0x23 : [Instruction22c, [ "new-array", KIND_TYPE ] ],

  0x24 : [Instruction35c, [ "filled-new-array", KIND_TYPE ] ],
  0x25 : [Instruction3rc, [ "filled-new-array/range", KIND_TYPE ] ],
  0x26 : [Instruction31t, [ "fill-array-data" ] ],

  0x27 : [Instruction11x, [ "throw" ] ],

  0x28 : [Instruction10t, [ "goto" ] ],
  0x29 : [Instruction20t, [ "goto/16" ] ],
  0x2a : [Instruction30t, [ "goto/32" ] ],

  0x2b : [Instruction31t, [ "packed-switch" ] ],
  0x2c : [Instruction31t, [ "sparse-switch" ] ],

  0x2d : [Instruction23x, [ "cmpl-float"  ] ],
  0x2e : [Instruction23x, [ "cmpg-float" ] ],
  0x2f : [Instruction23x, [ "cmpl-double" ] ],
  0x30 : [Instruction23x, [ "cmpg-double" ] ],
  0x31 : [Instruction23x, [ "cmp-long" ] ],

  0x32 : [Instruction22t, [ "if-eq" ] ],
  0x33 : [Instruction22t, [ "if-ne" ] ],
  0x34 : [Instruction22t, [ "if-lt" ] ],
  0x35 : [Instruction22t, [ "if-ge" ] ],
  0x36 : [Instruction22t, [ "if-gt" ] ],
  0x37 : [Instruction22t, [ "if-le" ] ],

  0x38 : [Instruction21t, [ "if-eqz" ] ],
  0x39 : [Instruction21t, [ "if-nez" ] ],
  0x3a : [Instruction21t, [ "if-ltz" ] ],
  0x3b : [Instruction21t, [ "if-gez" ] ],
  0x3c : [Instruction21t, [ "if-gtz" ] ],
  0x3d : [Instruction21t, [ "if-lez" ] ],

  #unused
  0x3e : [Instruction10x, [ "nop" ] ],
  0x3f : [Instruction10x, [ "nop" ] ],
  0x40 : [Instruction10x, [ "nop" ] ],
  0x41 : [Instruction10x, [ "nop" ] ],
  0x42 : [Instruction10x, [ "nop" ] ],
  0x43 : [Instruction10x, [ "nop" ] ],

  0x44 : [Instruction23x, [ "aget" ] ],
  0x45 : [Instruction23x, [ "aget-wide" ] ],
  0x46 : [Instruction23x, [ "aget-object" ] ],
  0x47 : [Instruction23x, [ "aget-boolean" ] ],
  0x48 : [Instruction23x, [ "aget-byte" ] ],
  0x49 : [Instruction23x, [ "aget-char" ] ],
  0x4a : [Instruction23x, [ "aget-short" ] ],
  0x4b : [Instruction23x, [ "aput" ] ],
  0x4c : [Instruction23x, [ "aput-wide" ] ],
  0x4d : [Instruction23x, [ "aput-object" ] ],
  0x4e : [Instruction23x, [ "aput-boolean" ] ],
  0x4f : [Instruction23x, [ "aput-byte" ] ],
  0x50 : [Instruction23x, [ "aput-char" ] ],
  0x51 : [Instruction23x, [ "aput-short" ] ],

  0x52 : [Instruction22c, [ "iget", KIND_FIELD ] ],
  0x53 : [Instruction22c, [ "iget-wide", KIND_FIELD ] ],
  0x54 : [Instruction22c, [ "iget-object", KIND_FIELD ] ],
  0x55 : [Instruction22c, [ "iget-boolean", KIND_FIELD ] ],
  0x56 : [Instruction22c, [ "iget-byte", KIND_FIELD ] ],
  0x57 : [Instruction22c, [ "iget-char", KIND_FIELD ] ],
  0x58 : [Instruction22c, [ "iget-short", KIND_FIELD ] ],
  0x59 : [Instruction22c, [ "iput", KIND_FIELD ] ],
  0x5a : [Instruction22c, [ "iput-wide", KIND_FIELD ] ],
  0x5b : [Instruction22c, [ "iput-object", KIND_FIELD ] ],
  0x5c : [Instruction22c, [ "iput-boolean", KIND_FIELD ] ],
  0x5d : [Instruction22c, [ "iput-byte", KIND_FIELD ] ],
  0x5e : [Instruction22c, [ "iput-char", KIND_FIELD ] ],
  0x5f : [Instruction22c, [ "iput-short", KIND_FIELD ] ],


  0x60 : [Instruction21c, [ "sget", KIND_FIELD ] ],
  0x61 : [Instruction21c, [ "sget-wide", KIND_FIELD ] ],
  0x62 : [Instruction21c, [ "sget-object", KIND_FIELD ] ],
  0x63 : [Instruction21c, [ "sget-boolean", KIND_FIELD ] ],
  0x64 : [Instruction21c, [ "sget-byte", KIND_FIELD ] ],
  0x65 : [Instruction21c, [ "sget-char", KIND_FIELD ] ],
  0x66 : [Instruction21c, [ "sget-short", KIND_FIELD ] ],
  0x67 : [Instruction21c, [ "sput", KIND_FIELD ] ],
  0x68 : [Instruction21c, [ "sput-wide", KIND_FIELD ] ],
  0x69 : [Instruction21c, [ "sput-object", KIND_FIELD ] ],
  0x6a : [Instruction21c, [ "sput-boolean", KIND_FIELD ] ],
  0x6b : [Instruction21c, [ "sput-byte", KIND_FIELD ] ],
  0x6c : [Instruction21c, [ "sput-char", KIND_FIELD ] ],
  0x6d : [Instruction21c, [ "sput-short", KIND_FIELD ] ],


  0x6e : [Instruction35c, [ "invoke-virtual", KIND_METH ] ],
  0x6f : [Instruction35c, [ "invoke-super", KIND_METH ] ],
  0x70 : [Instruction35c, [ "invoke-direct", KIND_METH ] ],
  0x71 : [Instruction35c, [ "invoke-static", KIND_METH ] ],
  0x72 : [Instruction35c, [ "invoke-interface", KIND_METH ] ],

  # unused
  0x73 : [Instruction10x, [ "nop" ] ],

  0x74 : [Instruction3rc, [ "invoke-virtual/range", KIND_METH ] ],
  0x75 : [Instruction3rc, [ "invoke-super/range", KIND_METH ] ],
  0x76 : [Instruction3rc, [ "invoke-direct/range", KIND_METH ] ],
  0x77 : [Instruction3rc, [ "invoke-static/range", KIND_METH ] ],
  0x78 : [Instruction3rc, [ "invoke-interface/range", KIND_METH ] ],

  # unused
  0x79 : [Instruction10x, [ "nop" ] ],
  0x7a : [Instruction10x, [ "nop" ] ],


  0x7b : [Instruction12x, [ "neg-int" ] ],
  0x7c : [Instruction12x, [ "not-int" ] ],
  0x7d : [Instruction12x, [ "neg-long" ] ],
  0x7e : [Instruction12x, [ "not-long" ] ],
  0x7f : [Instruction12x, [ "neg-float" ] ],
  0x80 : [Instruction12x, [ "neg-double" ] ],
  0x81 : [Instruction12x, [ "int-to-long" ] ],
  0x82 : [Instruction12x, [ "int-to-float" ] ],
  0x83 : [Instruction12x, [ "int-to-double" ] ],
  0x84 : [Instruction12x, [ "long-to-int" ] ],
  0x85 : [Instruction12x, [ "long-to-float" ] ],
  0x86 : [Instruction12x, [ "long-to-double" ] ],
  0x87 : [Instruction12x, [ "float-to-int" ] ],
  0x88 : [Instruction12x, [ "float-to-long" ] ],
  0x89 : [Instruction12x, [ "float-to-double" ] ],
  0x8a : [Instruction12x, [ "double-to-int" ] ],
  0x8b : [Instruction12x, [ "double-to-long" ] ],
  0x8c : [Instruction12x, [ "double-to-float" ] ],
  0x8d : [Instruction12x, [ "int-to-byte" ] ],
  0x8e : [Instruction12x, [ "int-to-char" ] ],
  0x8f : [Instruction12x, [ "int-to-short" ] ],


  0x90 : [Instruction23x, [ "add-int" ] ],
  0x91 : [Instruction23x, [ "sub-int" ] ],
  0x92 : [Instruction23x, [ "mul-int" ] ],
  0x93 : [Instruction23x, [ "div-int" ] ],
  0x94 : [Instruction23x, [ "rem-int" ] ],
  0x95 : [Instruction23x, [ "and-int" ] ],
  0x96 : [Instruction23x, [ "or-int" ] ],
  0x97 : [Instruction23x, [ "xor-int" ] ],
  0x98 : [Instruction23x, [ "shl-int" ] ],
  0x99 : [Instruction23x, [ "shr-int" ] ],
  0x9a : [Instruction23x, [ "ushr-int" ] ],
  0x9b : [Instruction23x, [ "add-long" ] ],
  0x9c : [Instruction23x, [ "sub-long" ] ],
  0x9d : [Instruction23x, [ "mul-long" ] ],
  0x9e : [Instruction23x, [ "div-long" ] ],
  0x9f : [Instruction23x, [ "rem-long" ] ],
  0xa0 : [Instruction23x, [ "and-long" ] ],
  0xa1 : [Instruction23x, [ "or-long" ] ],
  0xa2 : [Instruction23x, [ "xor-long" ] ],
  0xa3 : [Instruction23x, [ "shl-long" ] ],
  0xa4 : [Instruction23x, [ "shr-long" ] ],
  0xa5 : [Instruction23x, [ "ushr-long" ] ],
  0xa6 : [Instruction23x, [ "add-float" ] ],
  0xa7 : [Instruction23x, [ "sub-float" ] ],
  0xa8 : [Instruction23x, [ "mul-float" ] ],
  0xa9 : [Instruction23x, [ "div-float" ] ],
  0xaa : [Instruction23x, [ "rem-float" ] ],
  0xab : [Instruction23x, [ "add-double" ] ],
  0xac : [Instruction23x, [ "sub-double" ] ],
  0xad : [Instruction23x, [ "mul-double" ] ],
  0xae : [Instruction23x, [ "div-double" ] ],
  0xaf : [Instruction23x, [ "rem-double" ] ],


  0xb0 : [Instruction12x, [ "add-int/2addr" ] ],
  0xb1 : [Instruction12x, [ "sub-int/2addr" ] ],
  0xb2 : [Instruction12x, [ "mul-int/2addr" ] ],
  0xb3 : [Instruction12x, [ "div-int/2addr" ] ],
  0xb4 : [Instruction12x, [ "rem-int/2addr" ] ],
  0xb5 : [Instruction12x, [ "and-int/2addr" ] ],
  0xb6 : [Instruction12x, [ "or-int/2addr" ] ],
  0xb7 : [Instruction12x, [ "xor-int/2addr" ] ],
  0xb8 : [Instruction12x, [ "shl-int/2addr" ] ],
  0xb9 : [Instruction12x, [ "shr-int/2addr" ] ],
  0xba : [Instruction12x, [ "ushr-int/2addr" ] ],
  0xbb : [Instruction12x, [ "add-long/2addr" ] ],
  0xbc : [Instruction12x, [ "sub-long/2addr" ] ],
  0xbd : [Instruction12x, [ "mul-long/2addr" ] ],
  0xbe : [Instruction12x, [ "div-long/2addr" ] ],
  0xbf : [Instruction12x, [ "rem-long/2addr" ] ],
  0xc0 : [Instruction12x, [ "and-long/2addr" ] ],
  0xc1 : [Instruction12x, [ "or-long/2addr" ] ],
  0xc2 : [Instruction12x, [ "xor-long/2addr" ] ],
  0xc3 : [Instruction12x, [ "shl-long/2addr" ] ],
  0xc4 : [Instruction12x, [ "shr-long/2addr" ] ],
  0xc5 : [Instruction12x, [ "ushr-long/2addr" ] ],
  0xc6 : [Instruction12x, [ "add-float/2addr" ] ],
  0xc7 : [Instruction12x, [ "sub-float/2addr" ] ],
  0xc8 : [Instruction12x, [ "mul-float/2addr" ] ],
  0xc9 : [Instruction12x, [ "div-float/2addr" ] ],
  0xca : [Instruction12x, [ "rem-float/2addr" ] ],
  0xcb : [Instruction12x, [ "add-double/2addr" ] ],
  0xcc : [Instruction12x, [ "sub-double/2addr" ] ],
  0xcd : [Instruction12x, [ "mul-double/2addr" ] ],
  0xce : [Instruction12x, [ "div-double/2addr" ] ],
  0xcf : [Instruction12x, [ "rem-double/2addr" ] ],

  0xd0 : [Instruction22s, [ "add-int/lit16" ] ],
  0xd1 : [Instruction22s, [ "rsub-int" ] ],
  0xd2 : [Instruction22s, [ "mul-int/lit16" ] ],
  0xd3 : [Instruction22s, [ "div-int/lit16" ] ],
  0xd4 : [Instruction22s, [ "rem-int/lit16" ] ],
  0xd5 : [Instruction22s, [ "and-int/lit16" ] ],
  0xd6 : [Instruction22s, [ "or-int/lit16" ] ],
  0xd7 : [Instruction22s, [ "xor-int/lit16" ] ],


  0xd8 : [Instruction22b, [ "add-int/lit8" ] ],
  0xd9 : [Instruction22b, [ "rsub-int/lit8" ] ],
  0xda : [Instruction22b, [ "mul-int/lit8" ] ],
  0xdb : [Instruction22b, [ "div-int/lit8" ] ],
  0xdc : [Instruction22b, [ "rem-int/lit8" ] ],
  0xdd : [Instruction22b, [ "and-int/lit8" ] ],
  0xde : [Instruction22b, [ "or-int/lit8" ] ],
  0xdf : [Instruction22b, [ "xor-int/lit8" ] ],
  0xe0 : [Instruction22b, [ "shl-int/lit8" ] ],
  0xe1 : [Instruction22b, [ "shr-int/lit8" ] ],
  0xe2 : [Instruction22b, [ "ushr-int/lit8" ] ],


  # expanded opcodes
  0xe3 : [Instruction22c, [ "iget-volatile", KIND_FIELD ] ],
  0xe4 : [Instruction22c, [ "iput-volatile", KIND_FIELD ] ],
  0xe5 : [Instruction21c, [ "sget-volatile", KIND_FIELD ] ],
  0xe6 : [Instruction21c, [ "sput-volatile", KIND_FIELD ] ],
  0xe7 : [Instruction22c, [ "iget-object-volatile", KIND_FIELD ] ],
  0xe8 : [Instruction22c, [ "iget-wide-volatile", KIND_FIELD ] ],
  0xe9 : [Instruction22c, [ "iput-wide-volatile", KIND_FIELD ] ],
  0xea : [Instruction21c, [ "sget-wide-volatile", KIND_FIELD ] ],
  0xeb : [Instruction21c, [ "sput-wide-volatile", KIND_FIELD ] ],

  0xec : [Instruction10x,   [ "breakpoint" ] ],
  0xed : [Instruction20bc,  [ "throw-verification-error", VARIES ] ],
  0xee : [Instruction35mi,  [ "execute-inline", INLINE_METHOD ] ],
  0xef : [Instruction3rmi,  [ "execute-inline/range", INLINE_METHOD ] ],
  0xf0 : [Instruction35c,   [ "invoke-object-init/range", KIND_METH ] ],
  0xf1 : [Instruction10x,   [ "return-void-barrier" ] ],

  0xf2 : [Instruction22cs,  [ "iget-quick", FIELD_OFFSET ] ],
  0xf3 : [Instruction22cs,  [ "iget-wide-quick", FIELD_OFFSET ] ],
  0xf4 : [Instruction22cs,  [ "iget-object-quick", FIELD_OFFSET ] ],
  0xf5 : [Instruction22cs,  [ "iput-quick", FIELD_OFFSET ] ],
  0xf6 : [Instruction22cs,  [ "iput-wide-quick", FIELD_OFFSET ] ],
  0xf7 : [Instruction22cs,  [ "iput-object-quick", FIELD_OFFSET ] ],
  0xf8 : [Instruction35ms,  [ "invoke-virtual-quick", VTABLE_OFFSET ] ],
  0xf9 : [Instruction3rms,  [ "invoke-virtual-quick/range", VTABLE_OFFSET ] ],
  0xfa : [Instruction35ms,  [ "invoke-super-quick", VTABLE_OFFSET ] ],
  0xfb : [Instruction3rms,  [ "invoke-super-quick/range", VTABLE_OFFSET ] ],
  0xfc : [Instruction22c,   [ "iput-object-volatile", KIND_FIELD ] ],
  0xfd : [Instruction21c,   [ "sget-object-volatile", KIND_FIELD ] ],
  0xfe : [Instruction21c,   [ "sput-object-volatile", KIND_FIELD ] ],
}

DALVIK_OPCODES_PAYLOAD = {
    0x0100 : [PackedSwitch],
    0x0200 : [SparseSwitch],
    0x0300 : [FillArrayData],
}

INLINE_METHODS = [
    [ "Lorg/apache/harmony/dalvik/NativeTestTarget;", "emptyInlineMethod", "()V" ],

    [ "Ljava/lang/String;", "charAt", "(I)C" ],
    [ "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" ],
    [ "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" ],
    [ "Ljava/lang/String;", "fastIndexOf", "(II)I" ],
    [ "Ljava/lang/String;", "isEmpty", "()Z" ],
    [ "Ljava/lang/String;", "length", "()I" ],

    [ "Ljava/lang/Math;", "abs", "(I)I" ],
    [ "Ljava/lang/Math;", "abs", "(J)J" ],
    [ "Ljava/lang/Math;", "abs", "(F)F" ],
    [ "Ljava/lang/Math;", "abs", "(D)D" ],
    [ "Ljava/lang/Math;", "min", "(II)I" ],
    [ "Ljava/lang/Math;", "max", "(II)I" ],
    [ "Ljava/lang/Math;", "sqrt", "(D)D" ],
    [ "Ljava/lang/Math;", "cos", "(D)D" ],
    [ "Ljava/lang/Math;", "sin", "(D)D" ],

    [ "Ljava/lang/Float;", "floatToIntBits", "(F)I" ],
    [ "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" ],
    [ "Ljava/lang/Float;", "intBitsToFloat", "(I)F" ],
    [ "Ljava/lang/Double;", "doubleToLongBits", "(D)J" ],
    [ "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" ],
    [ "Ljava/lang/Double;", "longBitsToDouble", "(J)D" ],
]

DALVIK_OPCODES_EXTENDED_WIDTH = {
    0x00ff: [ Instruction41c, ["const-class/jumbo", KIND_TYPE ] ],
    0x01ff: [ Instruction41c, ["check-cast/jumbo", KIND_TYPE ] ],

    0x02ff: [ Instruction52c, ["instance-of/jumbo", KIND_TYPE ] ],

    0x03ff: [ Instruction41c, ["new-instance/jumbo", KIND_TYPE ] ],

    0x04ff: [ Instruction52c, ["new-array/jumbo", KIND_TYPE ] ],

    0x05ff: [ Instruction5rc, ["filled-new-array/jumbo", KIND_TYPE ] ],

    0x06ff: [ Instruction52c, ["iget/jumbo", KIND_FIELD ] ],
    0x07ff: [ Instruction52c, ["iget-wide/jumbo", KIND_FIELD ] ],
    0x08ff: [ Instruction52c, ["iget-object/jumbo", KIND_FIELD ] ],
    0x09ff: [ Instruction52c, ["iget-boolean/jumbo", KIND_FIELD ] ],
    0x0aff: [ Instruction52c, ["iget-byte/jumbo", KIND_FIELD ] ],
    0x0bff: [ Instruction52c, ["iget-char/jumbo", KIND_FIELD ] ],
    0x0cff: [ Instruction52c, ["iget-short/jumbo", KIND_FIELD ] ],
    0x0dff: [ Instruction52c, ["iput/jumbo", KIND_FIELD ] ],
    0x0eff: [ Instruction52c, ["iput-wide/jumbo", KIND_FIELD ] ],
    0x0fff: [ Instruction52c, ["iput-object/jumbo", KIND_FIELD ] ],
    0x10ff: [ Instruction52c, ["iput-boolean/jumbo", KIND_FIELD ] ],
    0x11ff: [ Instruction52c, ["iput-byte/jumbo", KIND_FIELD ] ],
    0x12ff: [ Instruction52c, ["iput-char/jumbo", KIND_FIELD ] ],
    0x13ff: [ Instruction52c, ["iput-short/jumbo", KIND_FIELD ] ],

    0x14ff: [ Instruction41c, ["sget/jumbo", KIND_FIELD ] ],
    0x15ff: [ Instruction41c, ["sget-wide/jumbo", KIND_FIELD ] ],
    0x16ff: [ Instruction41c, ["sget-object/jumbo", KIND_FIELD ] ],
    0x17ff: [ Instruction41c, ["sget-boolean/jumbo", KIND_FIELD ] ],
    0x18ff: [ Instruction41c, ["sget-byte/jumbo", KIND_FIELD ] ],
    0x19ff: [ Instruction41c, ["sget-char/jumbo", KIND_FIELD ] ],
    0x1aff: [ Instruction41c, ["sget-short/jumbo", KIND_FIELD ] ],
    0x1bff: [ Instruction41c, ["sput/jumbo", KIND_FIELD ] ],
    0x1cff: [ Instruction41c, ["sput-wide/jumbo", KIND_FIELD ] ],
    0x1dff: [ Instruction41c, ["sput-object/jumbo", KIND_FIELD ] ],
    0x1eff: [ Instruction41c, ["sput-boolean/jumbo", KIND_FIELD ] ],
    0x1fff: [ Instruction41c, ["sput-byte/jumbo", KIND_FIELD ] ],
    0x20ff: [ Instruction41c, ["sput-char/jumbo", KIND_FIELD ] ],
    0x21ff: [ Instruction41c, ["sput-short/jumbo", KIND_FIELD ] ],

    0x22ff: [ Instruction5rc, ["invoke-virtual/jumbo", KIND_METH ] ],
    0x23ff: [ Instruction5rc, ["invoke-super/jumbo", KIND_METH ] ],
    0x24ff: [ Instruction5rc, ["invoke-direct/jumbo", KIND_METH ] ],
    0x25ff: [ Instruction5rc, ["invoke-static/jumbo", KIND_METH ] ],
    0x26ff: [ Instruction5rc, ["invoke-interface/jumbo", KIND_METH ] ],
}

DALVIK_OPCODES_OPTIMIZED = {
    0xf2ff : [ Instruction5rc, ["invoke-object-init/jumbo", KIND_METH ] ],

    0xf3ff : [ Instruction52c, ["iget-volatile/jumbo", KIND_FIELD ] ],
    0xf4ff : [ Instruction52c, ["iget-wide-volatile/jumbo", KIND_FIELD ] ],
    0xf5ff : [ Instruction52c, ["iget-object-volatile/jumbo ", KIND_FIELD ] ],
    0xf6ff : [ Instruction52c, ["iput-volatile/jumbo", KIND_FIELD ] ],
    0xf7ff : [ Instruction52c, ["iput-wide-volatile/jumbo", KIND_FIELD ] ],
    0xf8ff : [ Instruction52c, ["iput-object-volatile/jumbo", KIND_FIELD ] ],
    0xf9ff : [ Instruction41c, ["sget-volatile/jumbo", KIND_FIELD ] ],
    0xfaff : [ Instruction41c, ["sget-wide-volatile/jumbo", KIND_FIELD ] ],
    0xfbff : [ Instruction41c, ["sget-object-volatile/jumbo", KIND_FIELD ] ],
    0xfcff : [ Instruction41c, ["sput-volatile/jumbo", KIND_FIELD ] ],
    0xfdff : [ Instruction41c, ["sput-wide-volatile/jumbo", KIND_FIELD ] ],
    0xfeff : [ Instruction41c, ["sput-object-volatile/jumbo", KIND_FIELD ] ],

    0xffff : [ Instruction40sc, ["throw-verification-error/jumbo", VARIES ] ],
}


class Unresolved(Instruction):
  def __init__(self, cm, data):
    self.cm = cm
    self.data = data

  def get_name(self):
    return "unresolved"

  def get_operands(self, idx=-1):
    return [(OPERAND_KIND + KIND_STRING, -1, "AG:OP: invalid opcode " + repr(self.data))]

  def get_op_value(self):
    return -1

  def get_output(self, idx=-1):
    return repr(self.data)

  def get_length(self):
    return len(self.data)

  def get_raw(self):
    return self.data


def get_instruction(cm, op_value, buff, odex=False):
  try:
    if not odex and (op_value >= 0xe3 and op_value <= 0xfe):
      return InstructionInvalid(cm, buff)

    try:
      return DALVIK_OPCODES_FORMAT[op_value][0](cm, buff)
    except KeyError:
      return InstructionInvalid(cm, buff)
  except:
      return Unresolved(cm, buff)


def get_extented_instruction(cm, op_value, buff):
  return DALVIK_OPCODES_EXTENDED_WIDTH[op_value][0]( cm, buff )


def get_optimized_instruction(cm, op_value, buff):
  return DALVIK_OPCODES_OPTIMIZED[op_value][0]( cm, buff )


def get_instruction_payload(op_value, buff):
  return DALVIK_OPCODES_PAYLOAD[op_value][0]( buff )


class LinearSweepAlgorithm(object):
    """
        This class is used to disassemble a method. The algorithm used by this class is linear sweep.
    """
    def get_instructions(self, cm, size, insn, idx):
        """
            :param cm: a ClassManager object
            :type cm: :class:`ClassManager` object
            :param size: the total size of the buffer
            :type size: int
            :param insn: a raw buffer where are the instructions
            :type insn: string
            :param idx: a start address in the buffer
            :type idx: int

            :rtype: a generator of :class:`Instruction` objects
        """
        self.odex = cm.get_odex_format()

        max_idx = size * calcsize('=H')
        if max_idx > len(insn):
          max_idx = len(insn)

        # Get instructions
        while idx < max_idx:
          obj = None
          classic_instruction = True

          op_value = unpack('=B', bytes([insn[0]]))
          #print "%x %x" % (op_value, idx)

          #payload instructions or extented/optimized instructions
          if (op_value == 0x00 or op_value == 0xff) and ((idx + 2) < max_idx):
            op_value = unpack('=H', bytes([insn[idx:idx + 2]]))
            # payload instructions ?
            if op_value in DALVIK_OPCODES_PAYLOAD:
              try:
                obj = get_instruction_payload(op_value, insn[idx:])
                classic_instruction = False
              except struct.error:
                warning("error while decoding instruction ...")

            elif op_value in DALVIK_OPCODES_EXTENDED_WIDTH:
              try:
                obj = get_extented_instruction(cm, op_value, insn[idx:])
                classic_instruction = False
              except(struct.error, why):
                warning("error while decoding instruction ..." + why.__str__())

            # optimized instructions ?
            elif self.odex and (op_value in DALVIK_OPCODES_OPTIMIZED):
              obj = get_optimized_instruction(cm, op_value, insn[idx:])
              classic_instruction = False

          # classical instructions
          if classic_instruction:
            op_value = unpack('=B', bytes([insn[idx]]))
            obj = get_instruction(cm, op_value, insn[idx:], self.odex)

          # emit instruction
          yield obj
          idx = idx + obj.get_length()


class DCode(object):
    """
        This class represents the instructions of a method

        :param class_manager: the ClassManager
        :type class_manager: :class:`ClassManager` object
        :param offset: the offset of the buffer
        :type offset: int
        :param size: the total size of the buffer
        :type size: int
        :param buff: a raw buffer where are the instructions
        :type buff: string
    """
    def __init__(self, class_manager, offset, size, buff):
        self.CM = class_manager
        self.insn = buff
        self.offset = offset
        self.size = size

        self.notes = {}
        self.cached_instructions = []
        self.rcache = 0

        self.idx = 0

    def get_insn(self):
      """
          Get the insn buffer

          :rtype: string
      """
      return self.insn

    def set_insn(self, insn):
      """
          Set a new raw buffer to disassemble

          :param insn: the buffer
          :type insn: string
      """
      self.insn = insn
      self.size = len(self.insn)

    def set_idx(self, idx):
        """
            Set the start address of the buffer

            :param idx: the index
            :type idx: int
        """
        self.idx = idx

    def set_instructions(self, instructions):
      """
          Set the instructions

          :param instructions: the list of instructions
          :type instructions: a list of :class:`Instruction`
      """
      self.cached_instructions = instructions

    def get_instructions(self):
        """
            Get the instructions

            :rtype: a generator of each :class:`Instruction` (or a cached list of instructions if you have setup instructions)
        """
        # it is possible to a cache for instructions (avoid a new disasm)
        if self.cached_instructions:
          for i in self.cached_instructions:
            yield i

        else:
          if self.rcache >= 5:
            lsa = LinearSweepAlgorithm()
            for i in lsa.get_instructions(self.CM, self.size, self.insn, self.idx):
              self.cached_instructions.append(i)

            for i in self.cached_instructions:
              yield i
          else:
            self.rcache += 1
            if self.size >= 1000:
              self.rcache = 5

            lsa = LinearSweepAlgorithm()
            for i in lsa.get_instructions(self.CM, self.size, self.insn, self.idx):
                yield i

    def reload(self):
        pass

    def add_inote(self, msg, idx, off=None):
      """
          Add a message to a specific instruction by using (default) the index of the address if specified

          :param msg: the message
          :type msg: string
          :param idx: index of the instruction (the position in the list of the instruction)
          :type idx: int
          :param off: address of the instruction
          :type off: int
      """
      if off != None:
        idx = self.off_to_pos(off)

      if idx not in self.notes:
        self.notes[idx] = []

      self.notes[idx].append(msg)

    def get_instruction(self, idx, off=None):
        """
            Get a particular instruction by using (default) the index of the address if specified

            :param idx: index of the instruction (the position in the list of the instruction)
            :type idx: int
            :param off: address of the instruction
            :type off: int

            :rtype: an :class:`Instruction` object
        """
        if off != None:
          idx = self.off_to_pos(off)
        return [i for i in self.get_instructions()][idx]

    def off_to_pos(self, off):
        """
            Get the position of an instruction by using the address

            :param off: address of the instruction
            :type off: int

            :rtype: int
        """
        idx = 0
        nb = 0
        for i in self.get_instructions():
            if idx == off:
                return nb
            nb += 1
            idx += i.get_length()
        return -1

    def get_ins_off(self, off):
        """
            Get a particular instruction by using the address

            :param off: address of the instruction
            :type off: int

            :rtype: an :class:`Instruction` object
        """
        idx = 0
        for i in self.get_instructions():
            if idx == off:
                return i
            idx += i.get_length()
        return None

    def show(self):
        """
            Display this object
        """
        nb = 0
        idx = 0
        for i in self.get_instructions():
            print ("%-8d(%08x)" % (nb, idx))
            i.show(nb)
            print ("")

            idx += i.get_length()
            nb += 1

    def pretty_show(self, m_a):
        """
            Display (with a pretty print) this object

            :param m_a: :class:`MethodAnalysis` object
        """
        bytecode.PrettyShow(m_a, m_a.basic_blocks.gets(), self.notes)
        bytecode.PrettyShowEx(m_a.exceptions.gets())

    def get_raw(self):
        """
            Return the raw buffer of this object

            :rtype: string
        """
        return ''.join(i.get_raw() for i in self.get_instructions())

    def get_length(self):
      """
          Return the length of this object

          :rtype: int
      """
      return len(self.get_raw())


class TryItem(object):
    """
        This class represents the try_item format

        :param buff: a raw buffer where are the try_item format
        :type buff: string
        :param cm: the ClassManager
        :type cm: :class:`ClassManager` object
    """
    def __init__(self, buff, cm):
        self.offset = buff.get_idx()

        self.__CM = cm

        self.start_addr = unpack("=I", buff.read(4))[0]
        self.insn_count = unpack("=H", buff.read(2))[0]
        self.handler_off = unpack("=H", buff.read(2))[0]

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def get_start_addr(self):
        """
            Get the start address of the block of code covered by this entry. The address is a count of 16-bit code units to the start of the first covered instruction.

            :rtype: int
        """
        return self.start_addr

    def get_insn_count(self):
        """
            Get the number of 16-bit code units covered by this entry

            :rtype: int
        """
        return self.insn_count

    def get_handler_off(self):
        """
            Get the offset in bytes from the start of the associated :class:`EncodedCatchHandlerList` to the :class:`EncodedCatchHandler` for this entry.

            :rtype: int
        """
        return self.handler_off

    def get_raw(self):
        return pack("=I", self.start_addr) + pack("=H", self.insn_count) + pack("=H", self.handler_off)

    def get_length(self):
      return len(self.get_raw())

class DalvikCode(object):
    """
        This class represents the instructions of a method

        :param buff: a raw buffer where are the instructions
        :type buff: string
        :param cm: the ClassManager
        :type cm: :class:`ClassManager` object
    """
    def __init__(self, buff, cm):
        self.__CM = cm
        self.offset = buff.get_idx()

        self.int_padding = ""
        off = buff.get_idx()
        while off % 4 != 0:
            self.int_padding += '\00'
            off += 1
        buff.set_idx(off)

        self.__off = buff.get_idx()

        self.registers_size = unpack("=H", buff.read(2))[0]
        self.ins_size = unpack("=H", buff.read(2))[0]
        self.outs_size = unpack("=H", buff.read(2))[0]
        self.tries_size = unpack("=H", buff.read(2))[0]
        self.debug_info_off = unpack("=I", buff.read(4))[0]
        self.insns_size = unpack("=I", buff.read(4))[0]

        ushort = calcsize('=H')

        self.code = DCode(self.__CM, buff.get_idx(), self.insns_size, buff.read(self.insns_size * ushort))

        if (self.insns_size % 2 == 1):
            self.padding = unpack("=H", buff.read(2))[0]

        self.tries = []
        self.handlers = None
        if self.tries_size > 0:
            for i in range(0, self.tries_size):
                self.tries.append(TryItem(buff, self.__CM))

            self.handlers = EncodedCatchHandlerList(buff, self.__CM)

    def get_registers_size(self):
        """
            Get the number of registers used by this code

            :rtype: int
        """
        return self.registers_size

    def get_ins_size(self):
      """
          Get the number of words of incoming arguments to the method that this code is for

          :rtype: int
      """
      return self.ins_size

    def get_outs_size(self):
      """
          Get the number of words of outgoing argument space required by this code for method invocation

          :rtype: int
      """
      return self.outs_size

    def get_tries_size(self):
        """
            Get the number of :class:`TryItem` for this instance

            :rtype: int
        """
        return self.tries_size

    def get_debug_info_off(self):
      """
          Get the offset from the start of the file to the debug info (line numbers + local variable info) sequence for this code, or 0 if there simply is no information

          :rtype: int
      """
      return self.debug_info_off

    def get_insns_size(self):
      """
          Get the size of the instructions list, in 16-bit code units

          :rtype: int
      """
      return self.insns_size

    def get_handlers(self):
        """
            Get the bytes representing a list of lists of catch types and associated handler addresses.

            :rtype: :class:`EncodedCatchHandlerList`
        """
        return self.handlers

    def get_tries(self):
        """
            Get the array indicating where in the code exceptions are caught and how to handle them

            :rtype: a list of :class:`TryItem` objects
        """
        return self.tries

    def get_debug(self):
        """
            Return the associated debug object

            :rtype: :class:`DebugInfoItem`
        """
        return self.__CM.get_debug_off(self.debug_info_off)

    def get_bc(self):
        """
            Return the associated code object

            :rtype: :class:`DCode`
        """
        return self.code

    def set_idx(self, idx):
        self.code.set_idx(idx)

    def reload(self):
        self.code.reload()

    def get_length(self):
        return self.insns_size

    def _begin_show(self):
      debug("registers_size: %d" % self.registers_size)
      debug("ins_size: %d" % self.ins_size)
      debug("outs_size: %d" % self.outs_size)
      debug("tries_size: %d" % self.tries_size)
      debug("debug_info_off: %d" % self.debug_info_off)
      debug("insns_size: %d" % self.insns_size)

      bytecode._PrintBanner()

    def show(self):
        self._begin_show()
        self.code.show()
        self._end_show()

    def _end_show(self):
      bytecode._PrintBanner()

    def pretty_show(self, m_a):
        self._begin_show()
        self.code.pretty_show(m_a)
        self._end_show()

    def get_obj(self):
        return [self.code, self.tries, self.handlers]

    def get_raw(self):
        code_raw = self.code.get_raw()
        self.insns_size = (len(code_raw) / 2) + (len(code_raw) % 2)

        buff = self.int_padding
        buff += pack("=H", self.registers_size) + \
                pack("=H", self.ins_size) + \
                pack("=H", self.outs_size) + \
                pack("=H", self.tries_size) + \
                pack("=I", self.debug_info_off) + \
                pack("=I", self.insns_size) + \
                code_raw

       # if (self.insns_size % 2 == 1):
       #     buff += pack("=H", self.padding)

        if self.tries_size > 0:
            buff += ''.join(i.get_raw() for i in self.tries)
            buff += self.handlers.get_raw()

        return buff

    def add_inote(self, msg, idx, off=None):
        """
            Add a message to a specific instruction by using (default) the index of the address if specified

            :param msg: the message
            :type msg: string
            :param idx: index of the instruction (the position in the list of the instruction)
            :type idx: int
            :param off: address of the instruction
            :type off: int
        """
        if self.code:
            return self.code.add_inote(msg, idx, off)

    def get_instruction(self, idx, off=None):
        if self.code:
            return self.code.get_instruction(idx, off)

    def get_size(self):
      length = len(self.int_padding)

      length += len( pack("=H", self.registers_size) + \
                     pack("=H", self.ins_size) + \
                     pack("=H", self.outs_size) + \
                     pack("=H", self.tries_size) + \
                     pack("=I", self.debug_info_off) + \
                     pack("=I", self.insns_size) )
      length += self.code.get_length()

      if (self.insns_size % 2 == 1):
           length += len(pack("=H", self.padding))

      if self.tries_size > 0:
        for i in self.tries:
          length += i.get_length()

        length += self.handlers.get_length()

      return length

    def set_off(self, off):
        self.__off = off

    def get_off(self):
        return self.__off

class CodeItem(object):
    def __init__(self, size, buff, cm):
        self.__CM = cm

        self.offset = buff.get_idx()

        self.code = []
        self.__code_off = {}

        for i in range(0, size):
            x = DalvikCode( buff, cm )
            self.code.append( x )
            self.__code_off[ x.get_off() ] = x

    def set_off(self, off):
      self.offset = off

    def get_off(self):
      return self.offset

    def get_code(self, off):
        try:
            return self.__code_off[off]
        except KeyError:
            return None

    def reload(self):
        for i in self.code:
            i.reload()

    def show(self):
        print ("CODE_ITEM")
        for i in self.code:
            i.show()

    def get_obj(self):
        return [ i for i in self.code ]

    def get_raw(self):
        return ''.join(i.get_raw() for i in self.code)

    def get_length(self):
      length = 0
      for i in self.code:
        length += i.get_size()
      return length

class MapItem(object):
    def __init__(self, buff, cm):
        self.__CM = cm

        self.off = buff.get_idx()

        self.type = unpack("=H", buff.read(2))[0]
        self.unused = unpack("=H", buff.read(2))[0]
        self.size = unpack("=I", buff.read(4))[0]
        self.offset = unpack("=I", buff.read(4))[0]

        self.item = None

        buff.set_idx( self.offset )

        lazy_analysis = self.__CM.get_lazy_analysis()

        if lazy_analysis:
          self.next_lazy(buff, cm)
        else:
          self.next(buff, cm)

    def get_off(self):
      return self.off

    def get_offset(self):
      return self.offset

    def get_type(self):
        return self.type

    def get_size(self):
      return self.size

    def next(self, buff, cm):
        if TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_ID_ITEM":
            self.item = [ StringIdItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CODE_ITEM":
            self.item = CodeItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_ID_ITEM":
            self.item = TypeHIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_PROTO_ID_ITEM":
            self.item = ProtoHIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_FIELD_ID_ITEM":
            self.item = FieldHIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_METHOD_ID_ITEM":
            self.item = MethodHIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DEF_ITEM":
            self.item = ClassHDefItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_HEADER_ITEM":
            self.item = HeaderItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_ITEM":
            self.item = [ AnnotationItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_SET_ITEM":
            self.item = [ AnnotationSetItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATIONS_DIRECTORY_ITEM":
            self.item = [ AnnotationsDirectoryItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ANNOTATION_SET_REF_LIST":
            self.item = [ AnnotationSetRefList( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_LIST":
            self.item = [ TypeList( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_DATA_ITEM":
            self.item = [ StringDataItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_DEBUG_INFO_ITEM":
            self.item = DebugInfoItemEmpty( buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ENCODED_ARRAY_ITEM":
            self.item = [ EncodedArrayItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DATA_ITEM":
            self.item = [ ClassDataItem(buff, cm) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_MAP_LIST":
            pass # It's me I think !!!

        else:
            bytecode.Exit( "Map item %d @ 0x%x(%d) is unknown" % (self.type, buff.get_idx(), buff.get_idx()) )

    def next_lazy(self, buff, cm):
        if TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_ID_ITEM":
            self.item = [ StringIdItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CODE_ITEM":
            self.item = CodeItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_ID_ITEM":
            self.item = TypeIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_PROTO_ID_ITEM":
            self.item = ProtoIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_FIELD_ID_ITEM":
            self.item = FieldIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_METHOD_ID_ITEM":
            self.item = MethodIdItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DEF_ITEM":
            self.item = ClassDefItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_HEADER_ITEM":
            self.item = HeaderItem( self.size, buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_TYPE_LIST":
            self.item = [ TypeList( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_STRING_DATA_ITEM":
            self.item = [ StringDataItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_DEBUG_INFO_ITEM":
            self.item = DebugInfoItemEmpty( buff, cm )

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_ENCODED_ARRAY_ITEM":
            self.item = [ EncodedArrayItem( buff, cm ) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_CLASS_DATA_ITEM":
            self.item = [ ClassDataItem(buff, cm) for i in range(0, self.size) ]

        elif TYPE_MAP_ITEM[ self.type ] == "TYPE_MAP_LIST":
            pass # It's me I think !!!


    def reload(self):
        if self.item != None:
            if isinstance( self.item, list ):
                for i in self.item:
                    i.reload()
            else:
                self.item.reload()

    def show(self):
        bytecode._Print( "\tMAP_TYPE_ITEM", TYPE_MAP_ITEM[ self.type ])

        if self.item != None:
            if isinstance( self.item, list ):
                for i in self.item:
                    i.show()
            else:
                self.item.show()

    def pretty_show(self):
        bytecode._Print( "\tMAP_TYPE_ITEM", TYPE_MAP_ITEM[ self.type ])

        if self.item != None:
            if isinstance( self.item, list ):
                for i in self.item:
                    if isinstance(i, ClassDataItem):
                        i.pretty_show()
                    else:
                        i.show()
            else:
                self.item.show()

    def get_obj(self):
        return self.item

    def get_raw(self):
      if isinstance(self.item, list):
        self.offset = self.item[0].get_off()
      else:
        self.offset = self.item.get_off()

      return pack("=H", self.type) + pack("=H", self.unused) + pack("=I", self.size) + pack("=I", self.offset)

    def get_length(self):
        return calcsize( "=HHII" )

    def get_item(self):
        return self.item

    def set_item(self, item):
      self.item = item


class OffObj(object):
    def __init__(self, o):
        self.off = o


class ClassManager(object):
    """
       This class is used to access to all elements (strings, type, proto ...) of the dex format
    """
    def __init__(self, vm, config):
        self.vm = vm
        self.buff = vm

        self.decompiler_ob = None
        self.vmanalysis_ob = None
        self.gvmanalysis_ob = None

        self.__manage_item = {}
        self.__manage_item_off = []

        self.__strings_off = {}

        self.__obj_offset = {}
        self.__item_offset = {}

        self.__cached_proto = {}

        self.recode_ascii_string = config["RECODE_ASCII_STRING"]
        self.recode_ascii_string_meth = None
        if config["RECODE_ASCII_STRING_METH"]:
          self.recode_ascii_string_meth = config["RECODE_ASCII_STRING_METH"]

        self.lazy_analysis = config["LAZY_ANALYSIS"]

        self.hook_strings = {}

        self.engine = []
        self.engine.append("python")

        if self.vm != None:
            self.odex_format = self.vm.get_format_type() == "ODEX"

    def get_ascii_string(self, s):
        try:
            return s.decode("ascii")
        except UnicodeDecodeError:
            d = ""
            for i in s:
                if ord(i) < 128:
                    d += i
                else:
                    d += "%x" % ord(i)
            return d

    def get_odex_format(self):
        return self.odex_format

    def get_obj_by_offset(self, offset):
      return self.__obj_offset[ offset ]

    def get_item_by_offset(self, offset):
      return self.__item_offset[ offset ]

    def get_string_by_offset(self, offset):
      return self.__strings_off[ offset ]

    def get_lazy_analysis(self):
      return self.lazy_analysis

    def get_vmanalysis(self):
        return self.vmanalysis_ob

    def set_vmanalysis(self, vmanalysis):
        self.vmanalysis_ob = vmanalysis

    def get_gvmanalysis(self):
        return self.gvmanalysis_ob

    def set_gvmanalysis(self, gvmanalysis):
        self.gvmanalysis_ob = gvmanalysis

    def set_decompiler(self, decompiler):
        self.decompiler_ob = decompiler

    def get_engine(self):
        return self.engine[0]

    def get_all_engine(self):
        return self.engine

    def add_type_item(self, type_item, c_item, item):
        self.__manage_item[ type_item ] = item

        self.__obj_offset[ c_item.get_off() ] = c_item
        self.__item_offset[ c_item.get_offset() ] = item

        sdi = False
        if type_item == "TYPE_STRING_DATA_ITEM":
            sdi = True

        if item != None:
            if isinstance(item, list):
                for i in item:
                    goff = i.offset
                    self.__manage_item_off.append( goff )

                    self.__obj_offset[ i.get_off() ] = i

                    if sdi == True:
                      self.__strings_off[ goff ] = i
            else:
                self.__manage_item_off.append( c_item.get_offset() )

    def get_code(self, idx):
        try:
            return self.__manage_item[ "TYPE_CODE_ITEM" ].get_code( idx )
        except KeyError:
            return None

    def get_class_data_item(self, off):
        for i in self.__manage_item[ "TYPE_CLASS_DATA_ITEM" ]:
            if i.get_off() == off:
                return i

        bytecode.Exit( "unknown class data item @ 0x%x" % off )

    def get_encoded_array_item(self, off):
        for i in self.__manage_item["TYPE_ENCODED_ARRAY_ITEM" ]:
            if i.get_off() == off:
                return i

    def get_string(self, idx):
        if idx in self.hook_strings:
            return self.hook_strings[ idx ]

        try:
            off = self.__manage_item[ "TYPE_STRING_ID_ITEM" ][idx].get_string_data_off()
        except IndexError:
            bytecode.Warning( "unknown string item @ %d" % (idx) )
            return "AG:IS: invalid string"

        try:
            if self.recode_ascii_string:
                if self.recode_ascii_string_meth:
                  return self.recode_ascii_string_meth(self.__strings_off[off].get())
                return self.get_ascii_string(self.__strings_off[off].get())
            return self.__strings_off[off].get()
        except KeyError:
            bytecode.Warning( "unknown string item @ 0x%x(%d)" % (off,idx) )
            return "AG:IS: invalid string"

    def get_raw_string(self, idx):
        try:
            off = self.__manage_item[ "TYPE_STRING_ID_ITEM" ][idx].get_string_data_off()
        except IndexError:
            bytecode.Warning( "unknown string item @ %d" % (idx) )
            return "AG:IS: invalid string"

        try:
            return self.__strings_off[off].get()
        except KeyError:
            bytecode.Warning( "unknown string item @ 0x%x(%d)" % (off,idx) )
            return "AG:IS: invalid string"

    def get_type_list(self, off):
        if off == 0:
            return []

        for i in self.__manage_item[ "TYPE_TYPE_LIST" ]:
            if i.get_type_list_off() == off:
                return [type_.get_string() for type_ in i.get_list()]

    def get_type(self, idx):
        _type = self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( idx )
        if _type == -1:
            return "AG:ITI: invalid type"
        return self.get_string( _type )

    def get_type_ref(self, idx):
        return self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( idx )

    def get_proto(self, idx):
        try:
            proto = self.__cached_proto[ idx ]
        except KeyError:
            proto = self.__manage_item[ "TYPE_PROTO_ID_ITEM" ].get( idx )
            self.__cached_proto[ idx ] = proto

        return [ proto.get_parameters_off_value(), proto.get_return_type_idx_value() ]

    def get_field(self, idx):
        field = self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( idx )
        return [ field.get_class_name(), field.get_type(), field.get_name() ]

    def get_field_ref(self, idx):
        return self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( idx )

    def get_method(self, idx):
        method = self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( idx )
        return method.get_list()

    def get_method_ref(self, idx):
        return self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( idx )

    def set_hook_class_name(self, class_def, value):
        python_export = True
        _type = self.__manage_item[ "TYPE_TYPE_ID_ITEM" ].get( class_def.get_class_idx() )
        self.set_hook_string( _type, value )

        try:
            self.vm._delete_python_export_class( class_def )
        except AttributeError:
            python_export = False

        class_def.reload()

        # FIXME
        self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].reload()

        for i in class_def.get_methods():
          i.reload()

        for i in class_def.get_fields():
          i.reload()

        if python_export:
            self.vm._create_python_export_class( class_def )

    def set_hook_method_name(self, encoded_method, value):
        python_export = True

        method = self.__manage_item[ "TYPE_METHOD_ID_ITEM" ].get( encoded_method.get_method_idx() )
        self.set_hook_string( method.get_name_idx(), value )

        class_def = self.__manage_item[ "TYPE_CLASS_DEF_ITEM" ].get_class_idx( method.get_class_idx() )
        if class_def != None:
          try:
            name = "METHOD_" + bytecode.FormatNameToPython( encoded_method.get_name() )
          except AttributeError:
            name += "_" + bytecode.FormatDescriptorToPython(encoded_method.get_descriptor())

          debug("try deleting old name in python...")
          try:
            delattr(class_def, name)
            debug("success with regular name")
          except AttributeError:
            debug("WARNING: fail with regular name")
            #python_export = False

            try:
              name = "METHOD_" + bytecode.FormatNameToPython( encoded_method.get_name() + '_' + encoded_method.proto.replace(' ','').replace('(','').replace('[','').replace(')','').replace('/','_').replace(';','') )
            except AttributeError:
              name += "_" + bytecode.FormatDescriptorToPython(encoded_method.get_descriptor())

            try:
              delattr(class_def, name)
              debug("success with name containing prototype")
            except AttributeError:
              debug("WARNING: fail with name containing prototype")
              python_export = False

          if python_export:
            name = "METHOD_" + bytecode.FormatNameToPython(value)
            setattr(class_def, name, encoded_method)
            debug("new name in python: created: %s." % name)
          else:
            debug("skipping creating new name in python")

        method.reload()

    def set_hook_field_name(self, encoded_field, value):
        python_export = True

        field = self.__manage_item[ "TYPE_FIELD_ID_ITEM" ].get( encoded_field.get_field_idx() )
        self.set_hook_string( field.get_name_idx(), value )

        class_def = self.__manage_item[ "TYPE_CLASS_DEF_ITEM" ].get_class_idx( field.get_class_idx() )
        if class_def != None:
          try:
            name = "FIELD_" + bytecode.FormatNameToPython( encoded_field.get_name() )
          except AttributeError:
            name += "_" + bytecode.FormatDescriptorToPython( encoded_field.get_descriptor() )


          try:
            delattr( class_def, name )
          except AttributeError:
            python_export = False

          if python_export:
            name = "FIELD_" + bytecode.FormatNameToPython( value )
            setattr( class_def, name, encoded_field )

        field.reload()


    def set_hook_string(self, idx, value):
        self.hook_strings[ idx ] = value

    def get_next_offset_item(self, idx):
        for i in self.__manage_item_off:
            if i > idx:
                return i
        return idx

    def get_debug_off(self, off):
        self.buff.set_idx( off )

        return DebugInfoItem( self.buff, self )

class MapList(object):
    """
       This class can parse the "map_list" of the dex format
    """
    def __init__(self, cm, off, buff):
        self.CM = cm

        buff.set_idx( off )

        self.offset = off

        self.size = unpack("=I", buff.read( 4 ) )[0]

        self.map_item = []
        for i in range(0, self.size):
            idx = buff.get_idx()

            mi = MapItem( buff, self.CM )
            self.map_item.append( mi )

            buff.set_idx( idx + mi.get_length() )

            c_item = mi.get_item()
            if c_item == None:
              mi.set_item( self )
              c_item = mi.get_item()

            self.CM.add_type_item( TYPE_MAP_ITEM[ mi.get_type() ], mi, c_item )

        for i in self.map_item:
            i.reload()

    def reload(self):
      pass

    def get_off(self):
      return self.offset

    def set_off(self, off):
      self.offset = off

    def get_item_type(self, ttype):
        """
            Get a particular item type

            :param ttype: a string which represents the desired type

            :rtype: None or the item object
        """
        for i in self.map_item:
            if TYPE_MAP_ITEM[ i.get_type() ] == ttype:
                return i.get_item()
        return None

    def show(self):
        """
            Print the MapList object
        """
        bytecode._Print("MAP_LIST SIZE", self.size)
        for i in self.map_item:
            if i.item != self:
                i.show()

    def pretty_show(self):
        """
            Print with a pretty display the MapList object
        """
        bytecode._Print("MAP_LIST SIZE", self.size)
        for i in self.map_item:
            if i.item != self:
                i.pretty_show()

    def get_obj(self):
      return [ x.get_obj() for x in self.map_item ]

    def get_raw(self):
        return pack("=I", self.size) + ''.join(x.get_raw() for x in self.map_item)

    def get_class_manager(self):
        return self.CM

    def get_length(self):
      return len(self.get_raw())

class XREF(object):
    def __init__(self):
        self.items = []

    def add(self, x, y):
        self.items.append((x, y))

class DREF(object):
    def __init__(self):
        self.items = []

    def add(self, x, y):
        self.items.append((x, y))


class DalvikVMFormat(bytecode._Bytecode):
    """
        This class can parse a classes.dex file of an Android application (APK).

        :param buff: a string which represents the classes.dex file
        :param decompiler: associate a decompiler object to display the java source code
        :type buff: string
        :type decompiler: object

        :Example:
          DalvikVMFormat( read("classes.dex") )
    """
    def __init__(self, buff, decompiler=None, config=None, using_api=None):
        #to allow to pass apk object ==> we do not need to pass additionally target version
        if isinstance(buff, APK):
            self.api_version = buff.get_target_sdk_version()
            buff = buff.get_dex() #getting dex from APK file
        elif using_api:
            self.api_version = using_api
        else:
            self.api_version = CONF["DEFAULT_API"]
            
        #TODO: can using_api be added to config parameter?    
        super(DalvikVMFormat, self).__init__(buff)
        
        self.config = config
        if not self.config:
          self.config = {"RECODE_ASCII_STRING": CONF["RECODE_ASCII_STRING"],
                         "RECODE_ASCII_STRING_METH": CONF["RECODE_ASCII_STRING_METH"],
                         "LAZY_ANALYSIS": CONF["LAZY_ANALYSIS"]}

        self.CM = ClassManager(self, self.config)
        self.CM.set_decompiler(decompiler)

        self._preload(buff)
        self._load(buff)

    def _preload(self, buff):
        pass

    def _load(self, buff):
        self.__header = HeaderItem(0, self, ClassManager(None, self.config))

        if self.__header.map_off == 0:
            bytecode.Warning("no map list ...")
        else:
            self.map_list = MapList( self.CM, self.__header.map_off, self )

            self.classes = self.map_list.get_item_type( "TYPE_CLASS_DEF_ITEM" )
            self.methods = self.map_list.get_item_type( "TYPE_METHOD_ID_ITEM" )
            self.fields = self.map_list.get_item_type( "TYPE_FIELD_ID_ITEM" )
            self.codes = self.map_list.get_item_type( "TYPE_CODE_ITEM" )
            self.strings = self.map_list.get_item_type( "TYPE_STRING_DATA_ITEM" )
            self.debug = self.map_list.get_item_type( "TYPE_DEBUG_INFO_ITEM" )
            self.header = self.map_list.get_item_type( "TYPE_HEADER_ITEM" )

        self.classes_names = None
        self.__cache_methods = None
        self.__cached_methods_idx = None
        self.__cache_fields = None

    def get_api_version(self):
        '''
            This method returns api version that should be used for loading api
            specific resources.
            
            :rtype: int
        '''
        return self.api_version
    
    def get_classes_def_item(self):
        """
            This function returns the class def item

            :rtype: :class:`ClassDefItem` object
        """
        return self.classes

    def get_methods_id_item(self):
        """
            This function returns the method id item

            :rtype: :class:`MethodIdItem` object
        """
        return self.methods

    def get_fields_id_item(self):
        """
            This function returns the field id item

            :rtype: :class:`FieldIdItem` object
        """
        return self.fields

    def get_codes_item(self):
        """
            This function returns the code item

            :rtype: :class:`CodeItem` object
        """
        return self.codes

    def get_string_data_item(self):
        """
            This function returns the string data item

            :rtype: :class:`StringDataItem` object
        """
        return self.strings

    def get_debug_info_item(self):
        """
            This function returns the debug info item

            :rtype: :class:`DebugInfoItem` object
        """
        return self.debug

    def get_header_item(self):
        """
            This function returns the header item

            :rtype: :class:`HeaderItem` object
        """
        return self.header

    def get_class_manager(self):
        """
            This function returns a ClassManager object which allow you to get
            access to all index references (strings, methods, fields, ....)

            :rtype: :class:`ClassManager` object
        """
        return self.CM

    def show(self):
        """
          Show the all information in the object
        """
        self.map_list.show()

    def pretty_show(self):
        """
          Show (but pretty !) the all information in the object
        """
        self.map_list.pretty_show()

    def save(self):
      """
          Return the dex (with the modifications) into raw format (fix checksums)
          (beta: do not use !)

          :rtype: string
      """
      l = []
      h = {}
      s = {}
      h_r = {}

      idx = 0
      for i in self.map_list.get_obj():
        length = 0

        if isinstance(i, list):
          for j in i:
            if isinstance(j, AnnotationsDirectoryItem):
              if idx % 4 != 0:
                idx = idx + (4 - (idx % 4))

            l.append( j )

            c_length = j.get_length()
            if isinstance(j, StringDataItem):
                c_length += 1
            h[ j ] = idx + length
            h_r[ idx + length ] = j
            s[ idx + length ] = c_length

            length += c_length
            #debug("SAVE" + str(j) + " @ 0x%x" % (idx+length))

          debug("SAVE " + str(i[0]) + " @0x%x (%x)" % (idx, length))

        else:
          if isinstance(i, MapList):
            if idx % 4 != 0:
              idx = idx + (4 - (idx % 4))

          l.append( i )
          h[ i ] = idx
          h_r[ idx ] = i

          length = i.get_length()

          s[idx] = length

          debug("SAVE " + str(i) + " @0x%x (%x)" % (idx, length))

        idx += length

      self.header.file_size = idx

      for i in l:
        idx = h[ i ]
        i.set_off(idx)
        if isinstance(i,CodeItem):
            last_idx = idx
            for j in i.get_obj():
                j.set_off(last_idx)
                #j.set_debug_info_off(0)
                last_idx += j.get_size()

      last_idx = 0
      buff = ""
      for i in l:
        idx = h[ i ]

        if idx != last_idx:
          debug( "Adjust alignment @%x with 00 %x" % (idx, idx - last_idx) )
          buff += "\x00" * (idx - last_idx)

        buff += i.get_raw()
        if isinstance(i, StringDataItem):
            buff += "\x00"
        last_idx = idx + s[ idx ]

      debug("GLOBAL SIZE %d" % len(buff))

      return self.fix_checksums(buff)

    def fix_checksums(self, buff):
      """
          Fix a dex format buffer by setting all checksums

          :rtype: string
      """
      import zlib
      import hashlib

      signature = hashlib.sha1(buff[32:]).digest()

      buff = buff[:12] + signature + buff[32:]
      checksum = zlib.adler32(buff[12:])
      buff = buff[:8] + pack("=i", checksum) + buff[12:]

      debug("NEW SIGNATURE %s" % repr(signature))
      debug("NEW CHECKSUM %x" % checksum)

      return buff

    def get_cm_field(self, idx):
        """
          Get a specific field by using an index

          :param idx: index of the field
          :type idx: int
        """
        return self.CM.get_field(idx)

    def get_cm_method(self, idx):
        """
          Get a specific method by using an index

          :param idx: index of the method
          :type idx: int
        """
        return self.CM.get_method(idx)

    def get_cm_string(self, idx):
        """
          Get a specific string by using an index

          :param idx: index of the string
          :type idx: int
        """
        return self.CM.get_raw_string( idx )

    def get_cm_type(self, idx):
        """
          Get a specific type by using an index

          :param idx: index of the type
          :type idx: int
        """
        return self.CM.get_type( idx )

    def get_classes_names(self, update=False):
        """
            Return the names of classes

            :param update: True indicates to recompute the list.
                           Maybe needed after using a MyClass.set_name().
            :rtype: a list of string
        """
        if self.classes_names == None or update:
            self.classes_names = [ i.get_name() for i in self.classes.class_def ]
        return self.classes_names

    def get_classes(self):
        """
          Return all classes

          :rtype: a list of :class:`ClassDefItem` objects
        """
        return self.classes.class_def

    def get_class(self, name):
        """
          Return a specific class

            :param name: the name of the class

          :rtype: a :class:`ClassDefItem` object
        """
        for i in self.classes.class_def:
          if i.get_name() == name:
            return i
        return None

    def get_method(self, name):
        """
            Return a list all methods which corresponds to the regexp

            :param name: the name of the method (a python regexp)

            :rtype: a list with all :class:`EncodedMethod` objects
        """
        prog = re.compile(name)
        l = []
        for i in self.classes.class_def:
            for j in i.get_methods():
                if prog.match( j.get_name() ):
                    l.append( j )
        return l

    def get_field(self, name):
        """
            Return a list all fields which corresponds to the regexp

            :param name: the name of the field (a python regexp)

            :rtype: a list with all :class:`EncodedField` objects
        """
        prog = re.compile(name)
        l = []
        for i in self.classes.class_def:
            for j in i.get_fields():
                if prog.match( j.get_name() ):
                    l.append( j )
        return l

    def get_all_fields(self):
        """
            Return a list of field items

            :rtype: a list of :class:`FieldIdItem` objects
        """
        try:
            return self.fields.gets()
        except AttributeError:
            return []

    def get_fields(self):
        """
          Return all field objects

          :rtype: a list of :class:`EncodedField` objects
        """
        l = []
        for i in self.classes.class_def:
            for j in i.get_fields():
                l.append( j )
        return l


    def get_methods(self):
        """
          Return all method objects

          :rtype: a list of :class:`EncodedMethod` objects
        """
        l = []
        for i in self.classes.class_def:
            for j in i.get_methods():
                l.append( j )
        return l

    def get_len_methods(self):
        """
          Return the number of methods

          :rtype: int
        """
        return len( self.get_methods() )

    def get_method_by_idx(self, idx):
        """
          Return a specific method by using an index
          :param idx: the index of the method
          :type idx: int

          :rtype: None or an :class:`EncodedMethod` object
        """
        if self.__cached_methods_idx == None:
          self.__cached_methods_idx = {}
          for i in self.classes.class_def:
            for j in i.get_methods():
              self.__cached_methods_idx[ j.get_method_idx() ] = j

        try:
          return self.__cached_methods_idx[ idx ]
        except KeyError:
          return None

    def get_method_descriptor(self, class_name, method_name, descriptor):
        """
            Return the specific method

            :param class_name: the class name of the method
            :type class_name: string
            :param method_name: the name of the method
            :type method_name: string
            :param descriptor: the descriptor of the method
            :type descriptor: string

            :rtype: None or a :class:`EncodedMethod` object
        """
        key = class_name + method_name + descriptor

        if self.__cache_methods == None:
            self.__cache_methods = {}
            for i in self.classes.class_def:
                for j in i.get_methods():
                    self.__cache_methods[ j.get_class_name() + j.get_name() + j.get_descriptor() ] = j

        return self.__cache_methods.get(key)

    def get_methods_descriptor(self, class_name, method_name):
        """
            Return the specific methods of the class

            :param class_name: the class name of the method
            :type class_name: string
            :param method_name: the name of the method
            :type method_name: string

            :rtype: None or a :class:`EncodedMethod` object
        """
        l = []
        for i in self.classes.class_def:
          if i.get_name() == class_name:
            for j in i.get_methods():
                if j.get_name() == method_name:
                    l.append(j)

        return l

    def get_methods_class(self, class_name):
        """
            Return all methods of a specific class

            :param class_name: the class name
            :type class_name: string

            :rtype: a list with :class:`EncodedMethod` objects
        """
        l = []
        for i in self.classes.class_def:
            for j in i.get_methods():
                if class_name == j.get_class_name():
                    l.append( j )

        return l

    def get_fields_class(self, class_name):
        """
            Return all fields of a specific class

            :param class_name: the class name
            :type class_name: string

            :rtype: a list with :class:`EncodedField` objects
        """
        l = []
        for i in self.classes.class_def:
            for j in i.get_fields():
                if class_name == j.get_class_name():
                    l.append( j )

        return l

    def get_field_descriptor(self, class_name, field_name, descriptor):
        """
            Return the specific field

            :param class_name: the class name of the field
            :type class_name: string
            :param field_name: the name of the field
            :type field_name: string
            :param descriptor: the descriptor of the field
            :type descriptor: string

            :rtype: None or a :class:`EncodedField` object
        """

        key = class_name + field_name + descriptor

        if self.__cache_fields == None:
            self.__cache_fields = {}
            for i in self.classes.class_def:
                for j in i.get_fields():
                    self.__cache_fields[ j.get_class_name() + j.get_name() + j.get_descriptor() ] = j

        return self.__cache_fields.get(key)

    def get_strings(self):
        """
            Return all strings

            :rtype: a list with all strings used in the format (types, names ...)
        """
        return [i.get() for i in self.strings]

    def get_regex_strings(self, regular_expressions):
        """
            Return all target strings matched the regex

            :param regular_expressions: the python regex
            :type regular_expressions: string

            :rtype: a list of strings matching the regex expression
        """
        str_list = []
        if regular_expressions.count is None:
            return None
        for i in self.get_strings():
            if re.match(regular_expressions, i):
                str_list.append(i)
        return str_list

    def get_format_type(self):
        """
            Return the type

            :rtype: a string
        """
        return "DEX"

    def create_xref(self, python_export=True):
        """
            Create XREF for this object

            :param python_export (boolean): export xref in each method
        """
        gvm = self.CM.get_gvmanalysis()

        for _class in self.get_classes():
            key = _class.get_name()
            if key in gvm.nodes:
              _class.XREFfrom = XREF()
              for i in gvm.GI.successors(gvm.nodes[key].id):
                xref = gvm.nodes_id[i]
                xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor)
                if python_export == True:
                    name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \
                    bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \
                    bytecode.FormatDescriptorToPython(xref_meth.get_descriptor())
                    setattr(_class.XREFfrom, name, xref_meth)
                _class.XREFfrom.add(xref_meth, xref.edges[gvm.nodes[key]])

            for method in _class.get_methods():
                method.XREFfrom = XREF()
                method.XREFto = XREF()

                key = "%s %s %s" % (method.get_class_name(), method.get_name(), method.get_descriptor())

                if key in gvm.nodes:
                    for i in gvm.G.predecessors(gvm.nodes[key].id):
                        xref = gvm.nodes_id[i]
                        xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor)
                        if xref_meth != None:
                            name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \
                            bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \
                            bytecode.FormatDescriptorToPython(xref_meth.get_descriptor())

                            if python_export == True:
                                setattr(method.XREFfrom, name, xref_meth)
                            method.XREFfrom.add(xref_meth, xref.edges[gvm.nodes[key]])

                    for i in gvm.G.successors(gvm.nodes[key].id):
                        xref = gvm.nodes_id[i]
                        xref_meth = self.get_method_descriptor(xref.class_name, xref.method_name, xref.descriptor)
                        if xref_meth != None:
                            name = bytecode.FormatClassToPython(xref_meth.get_class_name()) + "__" + \
                            bytecode.FormatNameToPython(xref_meth.get_name()) + "__" + \
                            bytecode.FormatDescriptorToPython(xref_meth.get_descriptor())

                            if python_export == True:
                                setattr(method.XREFto, name, xref_meth)
                            method.XREFto.add(xref_meth, gvm.nodes[key].edges[xref])

    def create_dref(self, python_export=True):
        """
            Create DREF for this object

            :param python_export (boolean): export dref in each field
        """
        vmx = self.CM.get_vmanalysis()

        for _class in self.get_classes():
            for field in _class.get_fields():
                field.DREFr = DREF()
                field.DREFw = DREF()

                paths = vmx.tainted_variables.get_field( field.get_class_name(), field.get_name(), field.get_descriptor() )

                if paths != None:
                    access = {}
                    access["R"] = {}
                    access["W"] = {}

                    for path in paths.get_paths():
                        access_val, idx = path[0]
                        m_idx = path[1]

                        if access_val == 'R':
                            dref_meth = self.get_method_by_idx( m_idx )
                            name = bytecode.FormatClassToPython( dref_meth.get_class_name() ) + "__" + \
                            bytecode.FormatNameToPython( dref_meth.get_name() ) + "__" + \
                            bytecode.FormatDescriptorToPython( dref_meth.get_descriptor() )

                            if python_export == True:
                                setattr( field.DREFr, name, dref_meth )

                            try:
                                access["R"][ dref_meth ].append( idx )
                            except KeyError:
                                access["R"][ dref_meth ] = []
                                access["R"][ dref_meth ].append( idx )

                        else:
                            dref_meth = self.get_method_by_idx( m_idx )
                            name = bytecode.FormatClassToPython( dref_meth.get_class_name() ) + "__" + \
                            bytecode.FormatNameToPython( dref_meth.get_name() ) + "__" + \
                            bytecode.FormatDescriptorToPython( dref_meth.get_descriptor() )

                            if python_export == True:
                                setattr( field.DREFw, name, dref_meth )

                            try:
                                access["W"][ dref_meth ].append( idx )
                            except KeyError:
                                access["W"][ dref_meth ] = []
                                access["W"][ dref_meth ].append( idx )

                    for i in access["R"]:
                        field.DREFr.add( i, access["R"][i] )
                    for i in access["W"]:
                        field.DREFw.add( i, access["W"][i] )

    def create_python_export(self):
        """
            Export classes/methods/fields' names in the python namespace
        """
        for _class in self.get_classes():
          self._create_python_export_class(_class)

    def _delete_python_export_class(self, _class):
      self._create_python_export_class( _class, True)

    def _create_python_export_class(self, _class, delete=False):
        if _class != None:
            ### Class
            name = "CLASS_" + str(bytecode.FormatClassToPython( _class.get_name()))
            if delete:
              delattr( self, name )
              return
            else:
              setattr( self, name, _class )

            ### Methods
            m = {}
            for method in _class.get_methods():
                if method.get_name() not in m:
                    m[ method.get_name() ] = []
                m[ method.get_name() ].append( method )

            for i in m:
                if len(m[i]) == 1:
                    j = m[i][0]
                    name = "METHOD_" + str(bytecode.FormatNameToPython( j.get_name() ))
                    setattr( _class, name, j )
                else:
                    for j in m[i]:
                        name = "METHOD_" + str(bytecode.FormatNameToPython( j.get_name() )) + "_" + str(bytecode.FormatDescriptorToPython( j.get_descriptor() ))
                        setattr( _class, name, j )

            ### Fields
            f = {}
            for field in _class.get_fields():
                if field.get_name() not in f:
                    f[ field.get_name() ] = []
                f[ field.get_name() ].append( field )

            for i in f:
                if len(f[i]) == 1:
                    j = f[i][0]
                    name = "FIELD_" + str(bytecode.FormatNameToPython( j.get_name() ))
                    setattr( _class, name, j )
                else:
                    for j in f[i]:
                        name = "FIELD_" + str(bytecode.FormatNameToPython( j.get_name() )) + "_" + str(bytecode.FormatDescriptorToPython( j.get_descriptor() ))
                        setattr( _class, name, j )

    def get_BRANCH_DVM_OPCODES(self):
        return BRANCH_DVM_OPCODES

    def get_determineNext(self):
        return determineNext

    def get_determineException(self):
        return determineException

    def get_DVM_TOSTRING(self):
        return DVM_TOSTRING()

    def set_decompiler(self, decompiler):
        self.CM.set_decompiler(decompiler)

    def set_vmanalysis(self, vmanalysis):
        self.CM.set_vmanalysis(vmanalysis)

    def set_gvmanalysis(self, gvmanalysis):
        self.CM.set_gvmanalysis(gvmanalysis)

    def disassemble(self, offset, size):
      """
        Disassembles a given offset in the DEX file

        :param dex: the filename of the android dex file
        :type filename: string
        :param offset: offset to disassemble in the file (from the beginning of the file)
        :type offset: int
        :param size:
        :type size:
      """
      for i in DCode(self.CM, offset, size, self.get_buff()[offset:offset + size]).get_instructions():
        yield i

    def _get_class_hierarchy(self):
        ids = {}
        present = {}
        r_ids = {}
        to_add = {}
        els = []

        for current_class in self.get_classes():
            s_name = current_class.get_superclassname()[1:-1]
            c_name = current_class.get_name()[1:-1]

            if s_name not in ids:
                ids[s_name] = len(ids) + 1
                r_ids[ids[s_name]] = s_name

            if c_name not in ids:
                ids[c_name] = len(ids) + 1

            els.append([ids[c_name], ids[s_name], c_name])
            present[ids[c_name]] = True

        for i in els:
            if i[1] not in present:
                to_add[i[1]] = r_ids[i[1]]

        for i in to_add:
            els.append([i, 0, to_add[i]])

        treeMap = {}
        Root = bytecode.Node(0, "Root")
        treeMap[Root.id] = Root
        for element in els:
         nodeId, parentId, title = element
         if not nodeId in treeMap:
             treeMap[nodeId] = bytecode.Node(nodeId, title)
         else:
             treeMap[nodeId].id = nodeId
             treeMap[nodeId].title = title

         if not parentId in treeMap:
             treeMap[parentId] = bytecode.Node(0, '')
         treeMap[parentId].children.append(treeMap[nodeId])

        return Root

    def print_classes_hierarchy(self):
        def print_map(node, l, lvl=0):
         for n in node.children:
             if lvl == 0:
                l.append("%s" % (n.title))
             else:
                l.append("%s %s" % ('\t' * lvl, n.title))
             if len(n.children) > 0:
                 print_map(n, l, lvl + 1)

        l = []
        print_map(self._get_class_hierarchy(), l)
        return l

    def list_classes_hierarchy(self):
      def print_map(node, l):
        if node.title not in l:
          l[node.title] = []

        for n in node.children:
          if len(n.children) > 0:
            w = {}
            w[n.title] = []
            l[node.title].append(w)

            print_map(n, w)
          else:
            l[node.title].append(n.title)

      l = {}
      print_map(self._get_class_hierarchy(), l)

      return l

    def get_format(self):
      objs = self.map_list.get_obj()

      h = {}
      index = {}
      self._get_objs(h, index, objs)

      return h, index

    def _get_objs(self, h, index, objs):
      for i in objs:
        if isinstance(i, list):
          self._get_objs(h, index, i)
        else:
          try:
            if i != None:
              h[i] = {}
              index[i] = i.offset
          except AttributeError:
            pass

          try:
            if not isinstance(i, MapList):
              next_objs = i.get_obj()
              if isinstance(next_objs, list):
                self._get_objs(h[i], index, next_objs)
          except AttributeError:
            pass

    def colorize_operands(self, operands, colors):
      for operand in operands:
        if operand[0] == OPERAND_REGISTER:
          yield "%sv%d%s" % (colors["registers"], operand[1], colors["normal"])

        elif operand[0] == OPERAND_LITERAL:
          yield "%s%d%s" % (colors["literal"], operand[1], colors["normal"])

        elif operand[0] == OPERAND_RAW:
          yield "%s%s%s" % (colors["raw"], operand[1], colors["normal"])

        elif operand[0] == OPERAND_OFFSET:
          yield "%s%d%s" % (colors["offset"], operand[1], colors["normal"])

        elif operand[0] & OPERAND_KIND:
            if operand[0] == (OPERAND_KIND + KIND_STRING):
              yield "%s%s%s" % (colors["string"], operand[2], colors["normal"])
            elif operand[0] == (OPERAND_KIND + KIND_METH):
              yield "%s%s%s" % (colors["meth"], operand[2], colors["normal"])
            elif operand[0] == (OPERAND_KIND + KIND_FIELD):
              yield "%s%s%s" % (colors["field"], operand[2], colors["normal"])
            elif operand[0] == (OPERAND_KIND + KIND_TYPE):
              yield "%s%s%s" % (colors["type"], operand[2], colors["normal"])
            else:
              yield "%s" % repr(operands[2])
        else:
          yield "%s" % repr(operands[1])

    def get_operand_html(self, operand, registers_colors, colors, escape_fct, wrap_fct):
        if operand[0] == OPERAND_REGISTER:
            return "<FONT color=\"%s\">v%s</FONT>" % (registers_colors[operand[1]], operand[1])

        elif operand[0] == OPERAND_LITERAL:
            return "<FONT color=\"%s\">0x%x</FONT>" % (colors["literal"], operand[1])

        elif operand[0] == OPERAND_RAW:
            if len(operand[1]) > 32:
              wrapped = wrap_fct(operand[1], 32)
              wrapped_adjust = "<br/>" + "<br/>".join(escape_fct(repr(i)[1:-1]) for i in wrapped)
              return "<FONT color=\"%s\">%s</FONT>" % (colors["raw"], wrapped_adjust)

            return "<FONT color=\"%s\">%s</FONT>" % (colors["raw"], escape_fct(repr(operand[1])[1:-1]))

        elif operand[0] == OPERAND_OFFSET:
            return "<FONT FACE=\"Times-Italic\" color=\"%s\">0x%x</FONT>" % (colors["offset"], operand[1])

        elif operand[0] & OPERAND_KIND:
            if operand[0] == (OPERAND_KIND + KIND_STRING):
              if len(operand[2]) > 32:
                wrapped = wrap_fct(operand[2], 32)
                wrapped_adjust = "<br/>" + "<br/>".join(escape_fct(i) for i in wrapped)
                return "<FONT color=\"%s\">%s</FONT>" % (colors["string"], wrapped_adjust)

              return "<FONT color=\"%s\">%s</FONT>" % (colors["string"], escape_fct(operand[2]))
            elif operand[0] == (OPERAND_KIND + KIND_METH):
                return "<FONT color=\"%s\">%s</FONT>" % (colors["method"], escape_fct(operand[2]))
            elif operand[0] == (OPERAND_KIND + KIND_FIELD):
                return "<FONT color=\"%s\">%s</FONT>" % (colors["field"], escape_fct(operand[2]))
            elif operand[0] == (OPERAND_KIND + KIND_TYPE):
                return "<FONT color=\"%s\">%s</FONT>" % (colors["type"], escape_fct(operand[2]))

            return escape_fct(str(operand[2]))

        return escape_fct(str(operand[1]))


class OdexHeaderItem(object):
    """
        This class can parse the odex header

        :param buff: a Buff object string which represents the odex dependencies
    """
    def __init__(self, buff):
        buff.set_idx(8)

        self.dex_offset = unpack("=I", buff.read(4))[0]
        self.dex_length = unpack("=I", buff.read(4))[0]
        self.deps_offset = unpack("=I", buff.read(4))[0]
        self.deps_length = unpack("=I", buff.read(4))[0]
        self.aux_offset = unpack("=I", buff.read(4))[0]
        self.aux_length = unpack("=I", buff.read(4))[0]
        self.flags = unpack("=I", buff.read(4))[0]
        self.padding = unpack("=I", buff.read(4))[0]

    def show(self):
        print ("dex_offset:%x dex_length:%x deps_offset:%x deps_length:%x aux_offset:%x aux_length:%x flags:%x" % (self.dex_offset,
                                                                                                                  self.dex_length,
                                                                                                                  self.deps_offset,
                                                                                                                  self.deps_length,
                                                                                                                  self.aux_offset,
                                                                                                                  self.aux_length,
                                                                                                                  self.flags))

    def get_raw(self):
      return pack("=I", self.dex_offset) +    \
             pack("=I", self.dex_length) +    \
             pack("=I", self.deps_offset) +   \
             pack("=I", self.deps_length) +   \
             pack("=I", self.aux_offset) +    \
             pack("=I", self.aux_length) +    \
             pack("=I", self.flags) +         \
             pack("=I", self.padding)


class OdexDependencies(object):
    """
        This class can parse the odex dependencies

        :param buff: a Buff object string which represents the odex dependencies
    """
    def __init__(self, buff):
        self.modification_time = unpack("=I", buff.read(4))[0]
        self.crc = unpack("=I", buff.read(4))[0]
        self.dalvik_build = unpack("=I", buff.read(4))[0]
        self.dependency_count = unpack("=I", buff.read(4))[0]
        self.dependencies = []
        self.dependency_checksums = []

        for i in range(0, self.dependency_count):
            string_length = unpack("=I", buff.read(4))[0]
            name_dependency = buff.read(string_length)
            self.dependencies.append(name_dependency)
            self.dependency_checksums.append(buff.read(20))

    def get_dependencies(self):
        """
            Return the list of dependencies

            :rtype: a list of strings
        """
        return self.dependencies

    def get_raw(self):
      dependencies = ""

      for idx, value in enumerate(self.dependencies):
        dependencies += pack("=I", len(value)) + \
                        pack("=%ds" % len(value), value) + \
                        pack("=20s", self.dependency_checksums[idx])

      return pack("=I", self.modification_time) + \
             pack("=I", self.crc) +               \
             pack("=I", self.dalvik_build) +      \
             pack("=I", self.dependency_count) +  \
             dependencies


class DalvikOdexVMFormat(DalvikVMFormat):
    """
        This class can parse an odex file

        :param buff: a string which represents the odex file
        :param decompiler: associate a decompiler object to display the java source code
        :type buff: string
        :type decompiler: object

        :Example:
          DalvikOdexVMFormat( read("classes.odex") )
    """
    def _preload(self, buff):
        self.orig_buff = buff
        self.magic = buff[:8]
        if self.magic == ODEX_FILE_MAGIC_35 or self.magic == ODEX_FILE_MAGIC_36:
            self.odex_header = OdexHeaderItem(self)

            self.set_idx(self.odex_header.deps_offset)
            self.dependencies = OdexDependencies(self)

            self.padding = buff[self.odex_header.deps_offset + self.odex_header.deps_length:]

            self.set_idx(self.odex_header.dex_offset)
            self.set_buff(self.read(self.odex_header.dex_length))
            self.set_idx(0)

    def save(self):
      """
          Do not use !
      """
      dex_raw = super(DalvikOdexVMFormat, self).save()
      return self.magic + self.odex_header.get_raw() + dex_raw + self.dependencies.get_raw() + self.padding

    def get_buff(self):
      return self.magic + self.odex_header.get_raw() + super(DalvikOdexVMFormat, self).get_buff() + self.dependencies.get_raw() + self.padding

    def get_dependencies(self):
        """
            Return the odex dependencies object

            :rtype: an OdexDependencies object
        """
        return self.dependencies

    def get_format_type(self):
        """
            Return the type

            :rtype: a string
        """
        return "ODEX"


def get_params_info(nb, proto):
    i_buffer = "# Parameters:\n"

    ret = proto.split(')')
    params = ret[0][1:].split()
    if params:
        i_buffer += "# - local registers: v%d...v%d\n" % (0, nb - len(params) - 1)
        j = 0
        for i in range(nb - len(params), nb):
            i_buffer += "# - v%d:%s\n" % (i, get_type(params[j]))
            j += 1
    else:
        i_buffer += "# local registers: v%d...v%d\n" % (0, nb - 1)

    i_buffer += "#\n# - return:%s\n\n" % get_type(ret[1])

    return i_buffer


def get_bytecodes_method(dex_object, ana_object, method):
    mx = ana_object.get_method(method)
    return get_bytecodes_methodx(method, mx)


def get_bytecodes_methodx(method, mx):
    basic_blocks = mx.basic_blocks.gets()
    i_buffer = ""

    idx = 0
    nb = 0

    i_buffer += "# %s->%s%s [access_flags=%s]\n#\n" % (method.get_class_name(), method.get_name(), method.get_descriptor(), method.get_access_flags_string())
    if method.code != None:
        i_buffer += get_params_info(method.code.get_registers_size(), method.get_descriptor())

        for i in basic_blocks:
            bb_buffer = ""
            ins_buffer = ""

            bb_buffer += "%s : " % (i.name)

            instructions = i.get_instructions()
            for ins in instructions:
                ins_buffer += "\t%-8d(%08x) " % (nb, idx)
                ins_buffer += "%-20s %s" % (ins.get_name(), ins.get_output(idx))

                op_value = ins.get_op_value()
                if ins == instructions[-1] and i.childs != []:
                    # packed/sparse-switch
                    if (op_value == 0x2b or op_value == 0x2c) and len(i.childs) > 1:
                          values = i.get_special_ins(idx).get_values()
                          bb_buffer += "[ D:%s " % (i.childs[0][2].name)
                          bb_buffer += ' '.join("%d:%s" % (values[j], i.childs[j + 1][2].name) for j in range(0, len(i.childs) - 1)) + " ]"
                    else:
                        #if len(i.childs) == 2:
                        #    i_buffer += "%s[ %s%s " % (branch_false_color, i.childs[0][2].name, branch_true_color))
                        #    print_fct(' '.join("%s" % c[2].name for c in i.childs[1:]) + " ]%s" % normal_color)
                        #else:
                        bb_buffer += "[ " + ' '.join("%s" % c[2].name for c in i.childs) + " ]"

                idx += ins.get_length()
                nb += 1

                ins_buffer += "\n"

            if i.get_exception_analysis() != None:
              ins_buffer += "\t%s\n" % (i.exception_analysis.show_buff())

            i_buffer += bb_buffer + "\n" + ins_buffer + "\n"

    return i_buffer


def auto(filename, raw=None):
  """
      :param filename:
      :param raw:
      :type filename:
      :type raw:
  """
  data_raw = raw
  if raw == None:
    data_raw = read(filename)
    ret_type = is_android_raw(data_raw[:10])
    if ret_type == "DEX":
      return DalvikVMFormat(data_raw)
    elif ret_type == "ODEX":
      return DalvikOdexVMFormat(data_raw)

  return None

