"""Functions that deal with cross-references (xrefs).

There are 2 groups of xrefs: CODE and DATA references. All xrefs are kept in the bTree except the ordinary execution flow to the next instruction. The ordinary execution flow to the next instruction is kept in flags (see bytes.hpp)
The source address of an xref must be an item head (is_head) or a structure member id. Even if an xref is generated by an element in the middle of the item, the item head address must be used. There are some exceptions to the rule but they are not worth mentioning here.
Xrefs are automatically sorted by addresses. However, the flow to the next instruction is always at the beginning of the list.
Xrefs are usually created by the processor module, as a reaction to the ev_emu_insn event. Plugins may create xrefs too but please note that upon a reanalysis of an item, all its xrefs, except the ones marked with XREF_USER, are deleted by the kernel. 
    """
from __future__ import annotations
from sys import version_info as _swig_python_version_info
if __package__ or '.' in __name__:
    from . import _ida_xref
else:
    import _ida_xref
try:
    import builtins as __builtin__
except ImportError:
    import __builtin__


def _swig_repr(self):
    try:
        strthis = 'proxy of ' + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ''
    return '<%s.%s; %s >' % (self.__class__.__module__, self.__class__.
        __name__, strthis)


def _swig_setattr_nondynamic_instance_variable(set):

    def set_instance_attr(self, name, value):
        if name == 'this':
            set(self, name, value)
        elif name == 'thisown':
            self.this.own(value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name),
            property):
            set(self, name, value)
        else:
            raise AttributeError('You cannot add instance attributes to %s' %
                self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):

    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError('You cannot add class attributes to %s' % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""

    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


import weakref
SWIG_PYTHON_LEGACY_BOOL = _ida_xref.SWIG_PYTHON_LEGACY_BOOL
from typing import Tuple, List, Union
import ida_idaapi


def create_switch_xrefs(ea, si):
    """This function creates xrefs from the indirect jump.

Usually there is no need to call this function directly because the kernel
will call it for switch tables

Note: Custom switch information are not supported yet.

:param ea: address of the 'indirect jump' instruction
:param si: switch information

:returns: Boolean"""
    return _ida_xref.create_switch_xrefs(ea, si)


class cases_and_targets_t(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v),
        doc='The membership flag')
    __repr__ = _swig_repr
    cases: 'casevec_t' = property(_ida_xref.cases_and_targets_t_cases_get,
        _ida_xref.cases_and_targets_t_cases_set)
    targets: 'eavec_t' = property(_ida_xref.cases_and_targets_t_targets_get,
        _ida_xref.cases_and_targets_t_targets_set)

    def __init__(self):
        _ida_xref.cases_and_targets_t_swiginit(self, _ida_xref.
            new_cases_and_targets_t())
    __swig_destroy__ = _ida_xref.delete_cases_and_targets_t


_ida_xref.cases_and_targets_t_swigregister(cases_and_targets_t)


def calc_switch_cases(ea, si):
    """Get information about a switch's cases.

The returned information can be used as follows:

    for idx in range(len(results.cases)):
        cur_case = results.cases[idx]
        for cidx in range(len(cur_case)):
            print("case: %d" % cur_case[cidx])
        print("  goto 0x%x" % results.targets[idx])

:param ea: address of the 'indirect jump' instruction
:param si: switch information

:returns: a structure with 2 members: 'cases', and 'targets'."""
    return _ida_xref.calc_switch_cases(ea, si)


def create_switch_table(ea, si):
    """Create switch table from the switch information

:param ea: address of the 'indirect jump' instruction
:param si: switch information

:returns: Boolean"""
    return _ida_xref.create_switch_table(ea, si)


fl_U = _ida_xref.fl_U
"""unknown - for compatibility with old versions. Should not be used anymore. 
          """
fl_CF = _ida_xref.fl_CF
"""Call Far This xref creates a function at the referenced location 
          """
fl_CN = _ida_xref.fl_CN
"""Call Near This xref creates a function at the referenced location 
          """
fl_JF = _ida_xref.fl_JF
"""Jump Far.
"""
fl_JN = _ida_xref.fl_JN
"""Jump Near.
"""
fl_USobsolete = _ida_xref.fl_USobsolete
"""User specified (obsolete)
"""
fl_F = _ida_xref.fl_F
"""Ordinary flow: used to specify execution flow to the next instruction. 
          """
dr_U = _ida_xref.dr_U
"""Unknown - for compatibility with old versions. Should not be used anymore. 
          """
dr_O = _ida_xref.dr_O
"""Offset The reference uses 'offset' of data rather than its value OR The reference appeared because the "OFFSET" flag of instruction is set. The meaning of this type is IDP dependent. 
          """
dr_W = _ida_xref.dr_W
"""Write access.
"""
dr_R = _ida_xref.dr_R
"""Read access.
"""
dr_T = _ida_xref.dr_T
"""Text (for forced operands only) Name of data is used in manual operand 
          """
dr_I = _ida_xref.dr_I
"""Informational (a derived java class references its base class informationally) 
          """
dr_S = _ida_xref.dr_S
"""Reference to enum member (symbolic constant)
"""
XREF_USER = _ida_xref.XREF_USER
"""User specified xref. This xref will not be deleted by IDA. This bit should be combined with the existing xref types (cref_t & dref_t) Cannot be used for fl_F xrefs 
        """
XREF_TAIL = _ida_xref.XREF_TAIL
"""Reference to tail byte in extrn symbols.
"""
XREF_BASE = _ida_xref.XREF_BASE
"""Reference to the base part of an offset.
"""
XREF_MASK = _ida_xref.XREF_MASK
"""Mask to get xref type.
"""
XREF_PASTEND = _ida_xref.XREF_PASTEND
"""Reference is past item. This bit may be passed to add_dref() functions but it won't be saved in the database. It will prevent the destruction of eventual alignment directives. 
        """


def xrefchar(xrtype: 'char') ->'char':
    """Get character describing the xref type. 
        
:param xrtype: combination of Cross-Reference type flags and a cref_t of dref_t value"""
    return _ida_xref.xrefchar(xrtype)


def add_cref(frm: ida_idaapi.ea_t, to: ida_idaapi.ea_t, type: 'cref_t') ->bool:
    """Create a code cross-reference. 
        
:param to: linear address of referenced instruction
:param type: cross-reference type
:returns: success"""
    return _ida_xref.add_cref(frm, to, type)


def del_cref(frm: ida_idaapi.ea_t, to: ida_idaapi.ea_t, expand: bool) ->bool:
    """Delete a code cross-reference. 
        
:param to: linear address of referenced instruction
:param expand: policy to delete the referenced instruction
* 1: plan to delete the referenced instruction if it has no more references.
* 0: don't delete the referenced instruction even if no more cross-references point to it
:returns: true: if the referenced instruction will be deleted"""
    return _ida_xref.del_cref(frm, to, expand)


def add_dref(frm: ida_idaapi.ea_t, to: ida_idaapi.ea_t, type: 'dref_t') ->bool:
    """Create a data cross-reference. 
        
:param to: linear address of referenced data
:param type: cross-reference type
:returns: success (may fail if user-defined xref exists from->to)"""
    return _ida_xref.add_dref(frm, to, type)


def del_dref(frm: ida_idaapi.ea_t, to: ida_idaapi.ea_t) ->None:
    """Delete a data cross-reference. 
        
:param to: linear address of referenced data"""
    return _ida_xref.del_dref(frm, to)


class xrefblk_t(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v),
        doc='The membership flag')
    __repr__ = _swig_repr
    frm: ida_idaapi.ea_t = property(_ida_xref.xrefblk_t_frm_get, _ida_xref.
        xrefblk_t_frm_set)
    to: ida_idaapi.ea_t = property(_ida_xref.xrefblk_t_to_get, _ida_xref.
        xrefblk_t_to_set)
    """the referenced address - filled by first_from(), next_from()
"""
    iscode: bool = property(_ida_xref.xrefblk_t_iscode_get, _ida_xref.
        xrefblk_t_iscode_set)
    """is code reference (cref_t)? otherwise it is a data reference (dref_t) 
        """
    type: 'uchar' = property(_ida_xref.xrefblk_t_type_get, _ida_xref.
        xrefblk_t_type_set)
    """type of the last returned reference (cref_t & dref_t)
"""
    user: bool = property(_ida_xref.xrefblk_t_user_get, _ida_xref.
        xrefblk_t_user_set)
    """is user defined xref? otherwise defined by ida
"""
    _flags: 'uchar' = property(_ida_xref.xrefblk_t__flags_get, _ida_xref.
        xrefblk_t__flags_set)

    def first_from(self, _from: ida_idaapi.ea_t, flags: int=0) ->bool:
        return _ida_xref.xrefblk_t_first_from(self, _from, flags)

    def first_to(self, _to: ida_idaapi.ea_t, flags: int=0) ->bool:
        return _ida_xref.xrefblk_t_first_to(self, _to, flags)

    def next_from(self, *args) ->bool:
        return _ida_xref.xrefblk_t_next_from(self, *args)

    def next_to(self, *args) ->bool:
        return _ida_xref.xrefblk_t_next_to(self, *args)

    def crefs_to(self, ea):
        """
        Provide an iterator on code references to ea including flow references
        """
        ref = get_first_cref_to(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_cref_to(ea, ref)

    def fcrefs_to(self, ea):
        """
        Provide an iterator on code references to ea
        """
        ref = get_first_fcref_to(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_fcref_to(ea, ref)

    def crefs_from(self, ea):
        """
        Provide an iterator on code references from ea including flow references
        """
        ref = get_first_cref_from(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_cref_from(ea, ref)

    def fcrefs_from(self, ea):
        """
        Provide an iterator on code references from ea
        """
        ref = get_first_fcref_from(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_fcref_from(ea, ref)

    def drefs_to(self, ea):
        """
        Provide an iterator on data references to ea
        """
        ref = get_first_dref_to(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_dref_to(ea, ref)

    def drefs_from(self, ea):
        """
        Provide an iterator on data references from ea
        """
        ref = get_first_dref_from(ea)
        while ref != ida_idaapi.BADADDR:
            yield ref
            ref = get_next_dref_from(ea, ref)

    def refs_from(self, ea, flag):
        """
        Provide an iterator on from reference represented by flag
        """

        def _copy_xref():
            """ Make a private copy of the xref class to preserve its contents """


            class _xref(object):
                pass
            xr = _xref()
            for attr in ['frm', 'to', 'iscode', 'type', 'user']:
                setattr(xr, attr, getattr(self, attr))
            return xr
        if self.first_from(ea, flag):
            yield _copy_xref()
            while self.next_from():
                yield _copy_xref()

    def refs_to(self, ea, flag):
        """
        Provide an iterator on to reference represented by flag
        """

        def _copy_xref():
            """ Make a private copy of the xref class to preserve its contents """


            class _xref(object):
                pass
            xr = _xref()
            for attr in ['frm', 'to', 'iscode', 'type', 'user']:
                setattr(xr, attr, getattr(self, attr))
            return xr
        if self.first_to(ea, flag):
            yield _copy_xref()
            while self.next_to():
                yield _copy_xref()

    def __init__(self):
        _ida_xref.xrefblk_t_swiginit(self, _ida_xref.new_xrefblk_t())
    __swig_destroy__ = _ida_xref.delete_xrefblk_t


_ida_xref.xrefblk_t_swigregister(xrefblk_t)
XREF_FLOW = _ida_xref.XREF_FLOW
"""return all references, including ordinary flow xrefs
"""
XREF_NOFLOW = _ida_xref.XREF_NOFLOW
"""skip ordinary flow xrefs (code xrefs to the next insn) 
        """
XREF_DATA = _ida_xref.XREF_DATA
"""return only data references (dr_...)
"""
XREF_CODE = _ida_xref.XREF_CODE
"""return only code references (fl_...)
"""
XREF_EA = _ida_xref.XREF_EA
"""return only program addresses
"""
XREF_TID = _ida_xref.XREF_TID
"""return only type ids. XREF_EA and XREF_TID are exclusive, only one of them can be specified 
        """


def get_first_dref_from(frm: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    """Get first data referenced from the specified address. 
        
:returns: linear address of first (lowest) data referenced from the specified address. Return BADADDR if the specified instruction/data doesn't reference to anything."""
    return _ida_xref.get_first_dref_from(frm)


def get_next_dref_from(frm: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    """Get next data referenced from the specified address. 
        
:param current: linear address of current referenced data. This value is returned by get_first_dref_from() or previous call to get_next_dref_from() functions.
:returns: linear address of next data or BADADDR."""
    return _ida_xref.get_next_dref_from(frm, current)


def get_first_dref_to(to: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    """Get address of instruction/data referencing to the specified data. 
        
:param to: linear address of referencing instruction or data
:returns: BADADDR if nobody refers to the specified data."""
    return _ida_xref.get_first_dref_to(to)


def get_next_dref_to(to: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    """Get address of instruction/data referencing to the specified data 
        
:param to: linear address of referencing instruction or data
:param current: current linear address. This value is returned by get_first_dref_to() or previous call to get_next_dref_to() functions.
:returns: BADADDR if nobody refers to the specified data."""
    return _ida_xref.get_next_dref_to(to, current)


def get_first_cref_from(frm: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    """Get first instruction referenced from the specified instruction. If the specified instruction passes execution to the next instruction then the next instruction is returned. Otherwise the lowest referenced address is returned (remember that xrefs are kept sorted!). 
        
:returns: first referenced address. If the specified instruction doesn't reference to other instructions then returns BADADDR."""
    return _ida_xref.get_first_cref_from(frm)


def get_next_cref_from(frm: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    """Get next instruction referenced from the specified instruction. 
        
:param current: linear address of current referenced instruction This value is returned by get_first_cref_from() or previous call to get_next_cref_from() functions.
:returns: next referenced address or BADADDR."""
    return _ida_xref.get_next_cref_from(frm, current)


def get_first_cref_to(to: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    """Get first instruction referencing to the specified instruction. If the specified instruction may be executed immediately after its previous instruction then the previous instruction is returned. Otherwise the lowest referencing address is returned. (remember that xrefs are kept sorted!). 
        
:param to: linear address of referenced instruction
:returns: linear address of the first referencing instruction or BADADDR."""
    return _ida_xref.get_first_cref_to(to)


def get_next_cref_to(to: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    """Get next instruction referencing to the specified instruction. 
        
:param to: linear address of referenced instruction
:param current: linear address of current referenced instruction This value is returned by get_first_cref_to() or previous call to get_next_cref_to() functions.
:returns: linear address of the next referencing instruction or BADADDR."""
    return _ida_xref.get_next_cref_to(to, current)


def get_first_fcref_from(frm: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    return _ida_xref.get_first_fcref_from(frm)


def get_next_fcref_from(frm: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    return _ida_xref.get_next_fcref_from(frm, current)


def get_first_fcref_to(to: ida_idaapi.ea_t) ->ida_idaapi.ea_t:
    return _ida_xref.get_first_fcref_to(to)


def get_next_fcref_to(to: ida_idaapi.ea_t, current: ida_idaapi.ea_t
    ) ->ida_idaapi.ea_t:
    return _ida_xref.get_next_fcref_to(to, current)


def has_external_refs(pfn: 'func_t *', ea: ida_idaapi.ea_t) ->bool:
    """Does 'ea' have references from outside of 'pfn'?
"""
    return _ida_xref.has_external_refs(pfn, ea)


def has_jump_or_flow_xref(ea: ida_idaapi.ea_t) ->bool:
    """Are there jump or flow references to EA?
"""
    return _ida_xref.has_jump_or_flow_xref(ea)


def delete_switch_table(jump_ea: ida_idaapi.ea_t, si: 'switch_info_t') ->None:
    return _ida_xref.delete_switch_table(jump_ea, si)


XREF_ALL = _ida_xref.XREF_ALL
XREF_FAR = _ida_xref.XREF_FAR


class casevec_t(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v),
        doc='The membership flag')
    __repr__ = _swig_repr

    def __init__(self, *args):
        _ida_xref.casevec_t_swiginit(self, _ida_xref.new_casevec_t(*args))
    __swig_destroy__ = _ida_xref.delete_casevec_t

    def push_back(self, *args) ->'qvector< long long > &':
        return _ida_xref.casevec_t_push_back(self, *args)

    def pop_back(self) ->None:
        return _ida_xref.casevec_t_pop_back(self)

    def size(self) ->'size_t':
        return _ida_xref.casevec_t_size(self)

    def empty(self) ->bool:
        return _ida_xref.casevec_t_empty(self)

    def at(self, _idx: 'size_t') ->'qvector< long long > const &':
        return _ida_xref.casevec_t_at(self, _idx)

    def qclear(self) ->None:
        return _ida_xref.casevec_t_qclear(self)

    def clear(self) ->None:
        return _ida_xref.casevec_t_clear(self)

    def resize(self, *args) ->None:
        return _ida_xref.casevec_t_resize(self, *args)

    def grow(self, *args) ->None:
        return _ida_xref.casevec_t_grow(self, *args)

    def capacity(self) ->'size_t':
        return _ida_xref.casevec_t_capacity(self)

    def reserve(self, cnt: 'size_t') ->None:
        return _ida_xref.casevec_t_reserve(self, cnt)

    def truncate(self) ->None:
        return _ida_xref.casevec_t_truncate(self)

    def swap(self, r: 'casevec_t') ->None:
        return _ida_xref.casevec_t_swap(self, r)

    def extract(self) ->'qvector< long long > *':
        return _ida_xref.casevec_t_extract(self)

    def inject(self, s: 'qvector< long long > *', len: 'size_t') ->None:
        return _ida_xref.casevec_t_inject(self, s, len)

    def __eq__(self, r: 'casevec_t') ->bool:
        return _ida_xref.casevec_t___eq__(self, r)

    def __ne__(self, r: 'casevec_t') ->bool:
        return _ida_xref.casevec_t___ne__(self, r)

    def begin(self, *args) ->'qvector< qvector< long long > >::const_iterator':
        return _ida_xref.casevec_t_begin(self, *args)

    def end(self, *args) ->'qvector< qvector< long long > >::const_iterator':
        return _ida_xref.casevec_t_end(self, *args)

    def insert(self, it: 'qvector< qvector< long long > >::iterator', x:
        'qvector< long long > const &'
        ) ->'qvector< qvector< long long > >::iterator':
        return _ida_xref.casevec_t_insert(self, it, x)

    def erase(self, *args) ->'qvector< qvector< long long > >::iterator':
        return _ida_xref.casevec_t_erase(self, *args)

    def find(self, *args) ->'qvector< qvector< long long > >::const_iterator':
        return _ida_xref.casevec_t_find(self, *args)

    def has(self, x: 'qvector< long long > const &') ->bool:
        return _ida_xref.casevec_t_has(self, x)

    def add_unique(self, x: 'qvector< long long > const &') ->bool:
        return _ida_xref.casevec_t_add_unique(self, x)

    def _del(self, x: 'qvector< long long > const &') ->bool:
        return _ida_xref.casevec_t__del(self, x)

    def __len__(self) ->'size_t':
        return _ida_xref.casevec_t___len__(self)

    def __getitem__(self, i: 'size_t') ->'qvector< long long > const &':
        return _ida_xref.casevec_t___getitem__(self, i)

    def __setitem__(self, i: 'size_t', v: 'qvector< long long > const &'
        ) ->None:
        return _ida_xref.casevec_t___setitem__(self, i, v)

    def append(self, x: 'qvector< long long > const &') ->None:
        return _ida_xref.casevec_t_append(self, x)

    def extend(self, x: 'casevec_t') ->None:
        return _ida_xref.casevec_t_extend(self, x)
    front = ida_idaapi._qvector_front
    back = ida_idaapi._qvector_back
    __iter__ = ida_idaapi._bounded_getitem_iterator


_ida_xref.casevec_t_swigregister(casevec_t)
import ida_idaapi
ida_idaapi._listify_types(casevec_t)
XREF_ALL = XREF_FLOW
XREF_FAR = XREF_NOFLOW
