/*
 *      Interactive disassembler (IDA).
 *      Copyright (c) 1990-98 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              E-mail: ig@estar.msk.su
 *                              FIDO:   2:5020/209
 *
 */

#ifndef _NETNODE_HPP
#define _NETNODE_HPP
#pragma pack(push, 1)           // IDA uses 1 byte alignments!

//
//      This file contains functions that provide the lowest level interface
//      to the ida database, namely Btree. To learn more about Btrees 
//      Balanced Trees: http://www.public.asu.edu/~peterjn/btree/
//
//      We don't use Btree directly.
//      Instead, we have another layer built on the top of Btree.
//      Here is a brief explanation of this layer.
//
//      There is a graph. The graph consists of nodes and links between them.
//      We call a node "netnode". Netnodes are numbered with 32-bit values.
//      Usually there is a trivial mapping of linear addresses used in
//      the program to netnodes. If we have additional information about
//      an address (a comment is attached to it, for example), this
//      information is stored in the corresponding netnode.
//      See nalt.hpp if you want to see how the kernel uses netnodes.
//      Also, some netnodes have no corresponding linear address. They are
//      used to store information not related to a particular address.
//
//      Each netnode _may_ have the following attributes:
//
//        - a name (max length of name is MAXNAMESIZE)
//          there is no limitation on characters used in names.
//
//        - a value: arbitary sized object, max size is MAXSPECSIZE
//
//        - altvals: a sparse array of 32-bit values.
//          indexes in this array may be 8-bit or 32-bit values
//
//        - supvals: an array of arbitrary sized objects. (size of each
//          object is limited by MAXSPECSIZE)
//          indexes in this array may be 8-bit or 32-bit values
//
//        - charvals: a sparse array of 8-bit values.
//          indexes in this array may be 8-bit or 32-bit values
//
//        - hashvals: a hash (an associative array)
//          indexes in this array are strings
//          values are arbitrary sized (max size is MAXSPECSIZE)
//
//      Initially a new netnode contains no information so no disk space
//      is used for it. As you add new information, the netnode grows.
//      All arrays behave in the same manner: initally
//        - all members of altvals/charvals array are zeroes
//        - all members of supvals/hashvals array are undefined.
//
//      About values returned by the netnode function:
//      the returned string values may be modified
//      freely. They are returned in static buffers.
//      The size of each buffer is MAXSPECSIZE+1. There are 10 buffers and
//      they are used in a round-robin manner.
//
//      There are high-level functions to store arbitrary sized objects (blobs)
//      in supvals.
//
//      You may use netnodes to store additional information about the program.
//      Limitations on the use of netnodes are the following:
//
//        - use netnodes only if you could not find a kernel service to
//          store your type of information
//
//         -Do not create netnodes with valid identifier names.
//          From the user supplied name, "my netnode name" IDA creates the 
//          internally used name, "$ my netnode name" so the user supplied
//          netnode name does not clash with other user defined names in 
//          the program. Although you will probably not destroy anything on 
//          accident, using already defined names for the names of your 
//          netnodes is still discouraged.
//
//        - you may create as many netnodes as you want (creation of unnamed
//          netnode doesn't increase the size of the database).
//          however, since each netnode has a number, creating too many netnodes
//          could lead to the exhauston of the netnode numbers (the numbering
//          starts at 0xFF000000)
//
//        - remember that netnodes are automatically saved to the disk
//          by the kernel.
//

//      Advanced info:
//      In fact a netnode may contain up to 256 arrays of arbitrary sized
//      objects. Each array his its 8-bit tag. Usually tags are represented
//      by characters constants. Altvals and supvals are simply 2 of
//      256 arrays, with tags 'A' and 'S' respectively.

//      Links between the netnodes are called netlinks. Each netlink has a type.
//      The ida kernel doesn't use the links.
//
//      The netlink type is represented as a 32-bit number and has a name.
//      The netlinks are used to build the graph.
//      Also, each particular netlink between
//      two netnodes may have arbitrary text attached to it.

//--------------------------------------------------------------------------

// The BTREE page size. This is not interesting for the end-users.

const int BTREE_PAGE_SIZE = 8192;  // don't use the default 2048 page size


// Maximum length of a netnode name

const int MAXNAMESIZE = 512;


// Maximum length of strings or objects stored in supval array element

const int MAXSPECSIZE = 1024;


// A number to represent bad netnode reference

const ulong BADNODE = 0xFFFFFFFFL;


// Tags internally used in netnodes. You should not use them
// for your tagged alt/sup/char/hash arrays.

const char atag = 'A';                  // Array of altvals
const char stag = 'S';                  // Array of supvals
const char htag = 'H';                  // Array of hashvals
const char vtag = 'V';                  // Value of netnode
const char ntag = 'N';                  // Name of netnode
const char ltag = 'L';                  // Links between netnodes

//      Helper functions. They should not be called directly!

class netnode;
idaman bool  ida_export netnode_check       (netnode *, const char *name,int namlen,bool create);
idaman void  ida_export netnode_kill        (netnode *);
idaman int   ida_export netnode_start       (netnode *);
idaman int   ida_export netnode_next        (netnode *);
idaman char *ida_export netnode_name        (ulong num);
idaman bool  ida_export netnode_rename      (ulong num, const char *newname,int namlen);
idaman char *ida_export netnode_value       (ulong num);
idaman int   ida_export netnode_set         (ulong num, const void *value,int length);
idaman int   ida_export netnode_delvalue    (ulong num);
idaman ulong ida_export netnode_altval      (ulong num, ulong alt,char tag);
idaman uchar ida_export netnode_charval     (ulong num, ulong alt,char tag);
idaman ulong ida_export netnode_altval_idx8 (ulong num, uchar alt,char tag);
idaman uchar ida_export netnode_charval_idx8(ulong num, uchar alt,char tag);
idaman char *ida_export netnode_supval      (ulong num, ulong alt,char tag);
idaman int   ida_export netnode_supset      (ulong num, ulong alt,const void *value,int length,char tag);
idaman int   ida_export netnode_supdel      (ulong num, ulong alt,char tag);
idaman ulong ida_export netnode_sup1st      (ulong num, char tag);
idaman ulong ida_export netnode_supnxt      (ulong num, ulong cur,char tag);
idaman ulong ida_export netnode_suplast     (ulong num, char tag);
idaman ulong ida_export netnode_supprev     (ulong num, ulong cur,char tag);
idaman char *ida_export netnode_supval_idx8 (ulong num, uchar alt,char tag);
idaman int   ida_export netnode_supset_idx8 (ulong num, uchar alt,const void *value,int length,char tag);
idaman int   ida_export netnode_supdel_idx8 (ulong num, uchar alt,char tag);
idaman ulong ida_export netnode_sup1st_idx8 (ulong num, char tag);
idaman ulong ida_export netnode_supnxt_idx8 (ulong num, uchar alt,char tag);
idaman ulong ida_export netnode_suplast_idx8(ulong num, char tag);
idaman ulong ida_export netnode_supprev_idx8(ulong num, uchar alt,char tag);
idaman int   ida_export netnode_supdel_any  (ulong num, char tag);
idaman char *ida_export netnode_hashval     (ulong num, const char *idx,char tag);
idaman ulong ida_export netnode_hashval_long(ulong num, const char *idx,char tag);
idaman int   ida_export netnode_hashset     (ulong num, const char *idx,const void *value,int length,char tag);
idaman int   ida_export netnode_hashdel     (ulong num, const char *idx,char tag);
idaman char *ida_export netnode_hash1st     (ulong num, char tag);
idaman char *ida_export netnode_hashnxt     (ulong num, const char *idx,char tag);
idaman char *ida_export netnode_hashlast    (ulong num, char tag);
idaman char *ida_export netnode_hashprev    (ulong num, const char *idx,char tag);
idaman ulong ida_export netnode_blobsize    (ulong num, ulong start,char tag);
idaman void *ida_export netnode_getblob     (ulong num, void *buf, ulong *bufsize, ulong start, char tag);
idaman int   ida_export netnode_setblob     (ulong num, const void *buf, ulong size, ulong start, char tag);
idaman int   ida_export netnode_delblob     (ulong num, ulong start,char tag);
idaman int   ida_export netnode_inited      (void);
idaman int   ida_export netnode_last_length (void);
idaman ulong ida_export netnode_copy        (ulong num, ulong count, ulong target, bool move);
idaman ulong ida_export netnode_altshift    (ulong num, ulong from, ulong to, ulong size, char tag);
idaman ulong ida_export netnode_charshift   (ulong num, ulong from, ulong to, ulong size, char tag);
idaman ulong ida_export netnode_supshift    (ulong num, ulong from, ulong to, ulong size, char tag);
idaman int   ida_export exist(const netnode &n);

//--------------------------------------------------------------------------
//      N E T N O D E
//--------------------------------------------------------------------------

// Definition of netnode class.
// Note that the size of the 'netnode' class is 4 bytes and it can be
// freely casted to 'ulong' and back. This makes it easy to store
// information about the program location in the netnodes.

class netnode
{
  friend class netlink;
  friend class string;
  friend bool  ida_export netnode_check(netnode *, const char *name,int namlen, bool create);
  friend void  ida_export netnode_kill (netnode *);
  friend int   ida_export netnode_start(netnode *);
  friend int   ida_export netnode_next (netnode *);
  friend ulong ida_export netnode_altshift (ulong num, ulong from, ulong to, ulong size, char tag);
  friend ulong ida_export netnode_charshift(ulong num, ulong from, ulong to, ulong size, char tag);
  friend ulong ida_export netnode_supshift (ulong num, ulong from, ulong to, ulong size, char tag);
public:

//--------------------------------------------------------------------------
// Contructors, conversions and assigments

// Empty constructor

  netnode(void)                 {}


// Constructor to create a netnode to access information about the
// specified linear address

  netnode(ulong num)            { netnodenumber = num; }


// Conversion from netnode to linear address

  operator ulong() const        { return netnodenumber; }


// Construct an instance of netnode class to access the specified netnode
//      name      - name of netnode
//      namlen    - length of the name. may be omitted, in this
//                  case the length will be calcuated with strlen()
//      do_create - 1: create the netnode if it doesn't exist yet.
//                  0: don't create the netnode, set netnumber to BADNODE if
//                     it doesn't exist

  netnode(const char *name,int namlen=0,bool do_create=false)
  {
    netnode_check(this, name, namlen, do_create);
  }


//--------------------------------------------------------------------------
// Check for existence of a netnode.
// Create and delete netnodes.
//

// Does the specified netnode exist?
// This function returns 1 only if there is some information attached to the
// netnode. In the case of unnamed netnode without any information it will
// return 0.

  friend int ida_export exist(const netnode &n);


// Create a named netnode
//      name   - name of netnode to create
//      namlen - length of the name. If not specified, it will be
//               calculated using strlen()
// returns: 1 - ok, the node is created
//          0 - the node already exists. you may use the netnode class to
//              access it.

  bool create(const char *name,int namlen=0)            // 1 - Ok,
                                                        // 0 - already exists
                                                        // but accessed
       { return netnode_check(this, name, namlen, true); }


// Create unnamed netnode
// returns: 1 - ok
//          0 - should not happen, indicates internal error

  int create(void)            { return create((char *)0); }


// Delete a netnode with all information attached to it

  void kill(void)  { netnode_kill(this); }


//--------------------------------------------------------------------------
// Netnode names.


// Get name of netnode
// Name of netnode    - a name (max length of name is MAXNAMESIZE)
//                      there is no limitation on characters used in names.
// returns: NULL - netnode is unnamed

  char *name(void) const                        // Get name of netnode
                                                // NULL - no name
        { return netnode_name(*this); }


// Rename a netnode
//      newname - new name of netnode. NULL or "" means to delete name
//      namlen  - length of new name. If not specified, it will be
//                calculated using strlen()
// returns: 1 - ok
//          0 - failed, newname is already used

  bool rename(const char *newname,int namlen=0) // Rename to "" to kill the name
        { return netnode_rename(*this, newname, namlen); }


//--------------------------------------------------------------------------
// Value of netnode


// Get value of netnode
// Value of netnode  - a value: arbitary sized object, max size is MAXSPECSIZE
// returns: NULL - the netnode has no value

  char *value(void) const
        { return netnode_value(*this); }


// Set value of netnode
//      value  - pointer to value
//      length - length of value. If not specified, it will be calculated
//               using strlen()

  int set(const void *value,int length=0) // returns 1-ok
        { return netnode_set(*this, value, length); }


// Delete value of netnode
// returns: 1 - ok
//          0 - failed, netnode is bad or other error

  int delvalue(void)
        { return netnode_delvalue(*this); }

// Value of netnode as a long number:

  int   set_long(ulong x) { return set(&x,sizeof(x)); }
  bool  value_exists(void) { return value() != NULL; }
  ulong long_value(void)  { char *p = value(); return (p==NULL)?BADNODE:*(ulong*)p; }


//--------------------------------------------------------------------------
// Arrays of altvals
// Arrays of altvals    - altvals: a sparse array of 32-bit values.           
//                        indexes in this array may be 8-bit or 32-bit values 


// Get altval element of the specified array
//      alt - index into array of altvals
//      tag - tag of array. may be omitted
// returns: value of altval element. Unexistent altval members are returned
//          as zeroes

  ulong altval(ulong alt,char tag=atag) const// Get alternative value
        { return netnode_altval(*this, alt, tag); }


// Set value of altval array
//      alt   - index into array of altvals
//      value - new value of altval element
//      tag   - tag of array
// returns: 1 - ok
//          0 - failed, normally sohuld not occur

  int altset(ulong alt,ulong value,char tag=atag){ return supset(alt,&value,sizeof(value),tag); }


// Delete element of altval array
//      alt   - index into array of altvals
//      tag   - tag of array
// returns: 1 - ok
//          0 - failed, element doesn't exist

  int altdel(ulong alt,char tag=atag)           { return supdel(alt,tag); }


// Get first existing element of altval array
//      tag   - tag of array
// returns: index of first existing element of altval array
//          BADNODE if altval array is empty

  ulong alt1st(char tag=atag) const             { return sup1st(tag); }


// Get next existing element of altval array
//      cur   - current index
//      tag   - tag of array
// returns: index of the next exitsing element of altval array
//          BADNODE if no more altval array elements exist

  ulong altnxt(ulong cur,char tag=atag) const   { return supnxt(cur,tag); }


// Get last element of altval array
//      tag   - tag of array
// returns: index of last existing element of altval array
//          BADNODE if altval array is empty

  ulong altlast(char tag=atag) const            { return suplast(tag); }


// Get previous existing element of altval array
//      cur   - current index
//      tag   - tag of array
// returns: index of the previous exitsing element of altval array
//          BADNODE if no more altval array elements exist

  ulong altprev(ulong cur,char tag=atag) const  { return supprev(cur,tag); }

// Shift the altval array elements
// Moves the array elements at (from..from+size) to (to..to+size)
// Returns: number of shifted elements

  ulong altshift(ulong from, ulong to, ulong size, char tag=atag)
    { return netnode_altshift(*this, from, to, size, tag); }


// The following functions behave in the same manner as the functions
// described above. The only difference is that the array value is 8-bits.
//      index - 32 bits
//      value - 8  bits


  uchar charval(ulong alt,char tag) const
        { return netnode_charval(*this, alt, tag); }
  int charset(ulong alt,uchar val,char tag)     { return supset(alt,&val,sizeof(val),tag); }
  int chardel(ulong alt,char tag)               { return supdel(alt,tag); }
  ulong char1st(char tag) const                 { return sup1st(tag); }
  ulong charnxt(ulong cur,char tag) const       { return supnxt(cur,tag); }
  ulong charlast(char tag) const                { return suplast(tag); }
  ulong charprev(ulong cur,char tag) const      { return supprev(cur,tag); }
  ulong charshift(ulong from,ulong to, ulong size, char tag)
    { return netnode_charshift(*this, from, to, size, tag); }


// Another set of functions to work with altvals.
// The only difference is that the array index is 8-bits
// and therefore the array may contain up to 256 elements only.
//      index - 8  bits
//      value - 32 bits

  ulong altval_idx8(uchar alt,char tag) const
        { return netnode_altval_idx8(*this, alt, tag); }
  int altset_idx8(uchar alt,ulong val,char tag) { return supset_idx8(alt,&val,sizeof(val),tag); }
  int altdel_idx8(uchar alt,char tag)           { return supdel_idx8(alt,tag); }
  ulong alt1st_idx8(char tag) const             { return sup1st_idx8(tag); }
  ulong altnxt_idx8(uchar cur,char tag) const   { return supnxt_idx8(cur,tag); }
  ulong altlast_idx8(char tag) const            { return suplast_idx8(tag); }
  ulong altprev_idx8(uchar cur,char tag) const  { return supprev_idx8(cur,tag); }


// Another set of functions to work with altvals.
//      index - 8 bits
//      value - 8 bits


  uchar charval_idx8(uchar alt,char tag) const
        { return netnode_charval_idx8(*this, alt, tag); }
  int charset_idx8(uchar alt,uchar val,char tag){ return supset_idx8(alt,&val,sizeof(val),tag); }
  int chardel_idx8(uchar alt,char tag)          { return supdel_idx8(alt,tag); }
  ulong char1st_idx8(char tag) const            { return sup1st_idx8(tag); }
  ulong charnxt_idx8(uchar cur,char tag) const  { return supnxt_idx8(cur,tag); }
  ulong charlast_idx8(char tag) const           { return suplast_idx8(tag); }
  ulong charprev_idx8(uchar cur,char tag) const { return supprev_idx8(cur,tag); }


// Delete all elements of altval array
// This function may be applied to 32-bit and 8-bit altval arrays.
// This function deletes the whole altval array.
// returns: 1 - ok, 0 - some error

  int altdel(void)              { return supdel_any(atag); }


// Delete all elements of the specified altval array
// This function may be applied to 32-bit and 8-bit altval arrays.
// This function deletes the whole altval array.
//      tag   - tag of array
// returns: 1 - ok, 0 - some error

  int altdel_any(char tag)      { return supdel_any(tag); }


//--------------------------------------------------------------------------
// Arrays of supvals

// Arrays of supvals    - supvals: an array of arbitrary sized objects. (size of
//                        each object is limited by MAXSPECSIZE)
//                        indexes in this array may be 8-bit or 32-bit values
// Get value of the specified supval array element
//      alt   - index into array of supvals
//      tag   - tag of array. Default: stag
// returns: NULL - element doesn't exist

  char *supval(ulong alt,char tag=stag) const
        { return netnode_supval(*this, alt, tag); }


// Set value of supval array element
//      alt   - index into array of supvals
//      value - pointer to supval value
//      length- length of 'value'. If not specified, the length is calculated
//              using strlen()+1.
//      tag   - tag of array
// returns: 1 - ok, 0 - error, should not occur

  int supset(ulong alt,const void *value,int length=0,char tag=stag)
        { return netnode_supset(*this, alt, value, length, tag); }


// Delete supval element
//      alt   - index into array of supvals
//      tag   - tag of array
// returns: 1 - ok, 0 - error, should not occur

  int supdel(ulong alt,char tag=stag)
        { return netnode_supdel(*this, alt, tag); }


// Get first existing element of supval array
//      tag   - tag of array
// returns: index of first existing element of supval array
//          BADNODE if supval array is empty

  ulong sup1st(char tag=stag) const
        { return netnode_sup1st(*this, tag); }


// Get next existing element of supval array
//      cur   - current index
//      tag   - tag of array
// returns: index of the next existing element of supval array
//          BADNODE if no more supval array elements exist

  ulong supnxt(ulong cur,char tag=stag) const
        { return netnode_supnxt(*this, cur, tag); }


// Get last existing element of supval array
//      tag   - tag of array
// returns: index of last existing element of supval array
//          BADNODE if supval array is empty

  ulong suplast(char tag=stag) const
        { return netnode_suplast(*this, tag); }


// Get previous existing element of supval array
//      cur   - current index
//      tag   - tag of array
// returns: index of the previous exitsing element of supval array
//          BADNODE if no more supval array elements exist

  ulong supprev(ulong cur,char tag=stag) const
        { return netnode_supprev(*this, cur, tag); }


// Shift the supval array elements
// Moves the array elements at (from..from+size) to (to..to+size)
// Returns: number of shifted elements

  ulong supshift(ulong from, ulong to, ulong size, char tag=stag)
    { return netnode_supshift(*this, from, to, size, tag); }


// The following functions behave in the same manner as the functions
// described above. The only difference is that the array index is 8-bits
// and therefore the array may contains up to 256 elements only.

  char *       supval_idx8(uchar alt,char tag) const          { return netnode_supval_idx8(*this, alt, tag); }
  int          supset_idx8(uchar alt,const void *value,int length,char tag) { return netnode_supset_idx8(*this, alt, value, length, tag); }
  int          supdel_idx8(uchar alt,char tag)                { return netnode_supdel_idx8(*this, alt, tag); }
  ulong        sup1st_idx8(char tag) const                    { return netnode_sup1st_idx8(*this, tag); }
  ulong        supnxt_idx8(uchar alt,char tag) const          { return netnode_supnxt_idx8(*this, alt, tag); }
  ulong        suplast_idx8(char tag) const                   { return netnode_suplast_idx8(*this, tag); }
  ulong        supprev_idx8(uchar alt,char tag) const         { return netnode_supprev_idx8(*this, alt, tag); }


// Delete all elements of supval array
// This function may be applied to 32-bit and 8-bit supval arrays.
// This function deletes the whole supval array.
// returns: 1 - ok, 0 - some error

  int   supdel(void)            { return supdel_any(stag); }


// Delete all elements of the specified supval array
// This function may be applied to 32-bit and 8-bit supval arrays.
// This function deletes the whole supval array.
// returns: 1 - ok, 0 - some error

  int supdel_any(char tag)
        { return netnode_supdel_any(*this, tag); }


// Returns the length of the last item returned by supval/hashval/hashnext
  static int last_length(void)
        { return netnode_last_length(); }

//--------------------------------------------------------------------------
// Hashes (associative arrays indexed by strings)
// Array of hashvals    - hashvals: a hash (an associative array)
//                        indexes in this array are strings
//                        values are arbitrary sized (max size is MAXSPECSIZE)
//                        Hashes are associative arrays indexed by strings

// Get value of the specified hash element
//      idx   - index into hash
//      tag   - tag of hash. Default: htag
// returns: NULL - element doesn't exist or idx is NULL

  char *hashval(const char *idx,char tag=htag) const
        { return netnode_hashval(*this, idx, tag); }


// Get value of the specified hash element
//      idx   - index into hash
//      tag   - tag of hash. Default: htag
// returns: value of hash element (it should be set using hashset(ulong))
//          0 if the element does not exist

  ulong hashval_long(const char *idx,char tag=htag) const
        { return netnode_hashval_long(*this, idx, tag); }


// Set value of hash element
//      idx   - index into hash
//      value - pointer to value
//      length- length of 'value'. If not specified, the length is calculated
//              using strlen()+1.
//      tag   - tag of hash. Default: htag
// returns: 1 - ok, 0 - error, should not occur

  int hashset(const char *idx,const void *value,int length=0,char tag=htag)
        { return netnode_hashset(*this, idx, value, length, tag); }


// Set value of hash element to long value
//      idx   - index into hash
//      value - new value of hash element
//      tag   - tag of hash. Default: htag
// returns: 1 - ok, 0 - error, should not occur

  int hashset(const char *idx,ulong value,char tag=htag)
        { return hashset(idx, &value, sizeof(value), tag); }


// Delete hash element
//      idx   - index into hash
//      tag   - tag of hash. Default: htag
// returns: 1 - ok, 0 - error, should not occur

  int hashdel(const char *idx,char tag=htag)
        { return netnode_hashdel(*this, idx, tag); }


// Get first existing element of hash
//      tag   - tag of hash. Default: htag
// returns: index of first existing element of hash
//          NULL if hash is empty
// note: elements of hash are kept sorted in lexical order

  char *hash1st(char tag=htag) const
        { return netnode_hash1st(*this, tag); }


// Get next existing element of hash
//      idx   - current index into hash
//      tag   - tag of hash. Default: htag
// returns: index of the next existing element of hash
//          NULL if no more hash elements exist
// note: elements of hash are kept sorted in lexical order

  char *hashnxt(const char *idx,char tag=htag) const
        { return netnode_hashnxt(*this, idx, tag); }


// Get last existing element of hash
//      tag   - tag of hash. Default: htag
// returns: index of last existing element of hash
//          NULL if hash is empty
// note: elements of hash are kept sorted in lexical order

  char *hashlast(char tag=htag) const
        { return netnode_hashlast(*this, tag); }


// Get previous existing element of supval array
//      idx   - current index into hash
//      tag   - tag of hash. Default: htag
// returns: index of the previous existing element of hash
//          NULL if no more hash elements exist
// note: elements of hash are kept sorted in lexical order

  char *hashprev(const char *idx,char tag=htag) const
        { return netnode_hashprev(*this, idx, tag); }


// Delete all elements of hash
// This function deletes the whole hash
//      tag   - tag of hash. Default: htag
// returns: 1 - ok, 0 - some error

  int hashdel_any(char tag=htag) { return supdel_any(tag); }


//--------------------------------------------------------------------------
// Blobs - virtually unlimited size binary objects
// Blobs are stored in several supval array elements.


// Get size of blob
//      start - index of the first supval element used to store blob
//      tag   - tag of supval array
// returns: number of bytes required to store a blob

  ulong blobsize(ulong start,char tag) // get size of blob
        { return netnode_blobsize(*this, start, tag); }


// Get blob from a netnode
//      buf     - buffer to read into. if NULL, the buffer will be
//                allocated using qalloc()
//      bufsize - in:  size of 'buf' in bytes (if buf == NULL then meaningless)
//                out: if buf == NULL then size of blob otherwise is not changed
//                bufsize may be NULL
//      start   - index of the first supval element used to store blob
//      tag     - tag of supval array
// returns: NULL - blob doesn't exist
//          otherwise returns pointer to blob

  void *getblob(void *buf,     // buffer to receive (may be NULL, will be allocated)
                ulong *bufsize,// in: buffer size, out: blob size
                ulong start,   // start index of blob
                char tag)      // tag of blob
                               // returns NULL - no blob
        { return netnode_getblob(*this, buf, bufsize, start, tag); }


// Store a blob in a netnode
//      buf     - pointer to blob to save
//      size    - size of blob in bytes
//      start   - index of the first supval element used to store blob
//      tag     - tag of supval array
// returns: 1 - ok, 0 - error

  int setblob(const void *buf, // blob to save
              ulong size,      // its size
              ulong start,     // starting index
              char tag)        // tag of blob
                               // returns 1 - ok
        { return netnode_setblob(*this, buf, size, start, tag); }

// Delete a blob
//      start - index of the first supval element used to store blob
//      tag   - tag of supval array
// returns: number of deleted supvals

  int delblob(ulong start,char tag)
        { return netnode_delblob(*this, start, tag); }

//--------------------------------------------------------------------------
// Links between nodes


// Create a link between two nodes.
//      to       - target netnode
//      linktype - type of link to create
//      linkspec - arbitrary text stored in the link
// returns: 1 - ok

  int   link(netnode to,netlink linktype,const char *linkspec); // Link netnodes


// Delete a link between two nodes
//      to       - target netnode
//      linktype - type of link to create

  void  unlink(netnode to,netlink linktype);    // UnLink netnodes


// Get text accoiated with the link
//      to       - target netnode
//      linktype - type of link to create
// returns: NULL - the link doesn't exist

  char *linkspec(netnode to,netlink linktype) const;
                                                // Get link specification
                                                // NULL - no link


//--------------------------------------------------------------------------
// Enumerate all netnodes


// Get first netnode in the graph
// Sets netnodenumber to the lowest existing number.
// returns: 1 - ok, 0 - graph is empty

  int start(void)
        { return netnode_start(this); }


// Get next netnode in the graph
// Sets netnodenumber to the next existing number
// returns: 1 - ok, 0 - no more netnodes

  int next(void)
        { return netnode_next(this); }



//--------------------------------------------------------------------------
// Move and copy netnodes

// target - the target netnode
// count - how many netnodes to copy
// returns: number of copied/moved keys, BADNODE-failure, not enough memory

  ulong copyto(netnode target, ulong count=1) { return netnode_copy(netnodenumber, count, target.netnodenumber, false); }
  ulong moveto(netnode target, ulong count=1) { return netnode_copy(netnodenumber, count, target.netnodenumber, true); }

//--------------------------------------------------------------------------
// Netnode comparisons

  int operator==(netnode &n) const { return netnodenumber == n.netnodenumber; }
  int operator!=(netnode &n) const { return netnodenumber != n.netnodenumber; }
  int operator==(ulong x) const { return netnodenumber == x; }
  int operator!=(ulong x) const { return netnodenumber != x; }


//--------------------------------------------------------------------------
//
//      The following netnode definitions are for the kernel only.
//
//      Functions for global base manipulating
//

  static int  createbase(const char *fname,ulong iniNumber=0); // Create base
                                        // iniNumber - internal numeration start value
  static int  checkbase(const char *fname);     // Returns 2-file error,1-run repair,0-Ok
  static void set_close_flag(int closeflag);    // Set "closed" flag of database
  static ulong reserve_nodes(ulong n);  // Reserve 'n' node numbers. Returns first reserved number
  static void validate(const char *badbase,const char *newbase,void (*cb)(ulong));
  static void compress(const char *oldbase,const char *newbase,void (*cb)(ulong));

  static int  inited(void) { return netnode_inited(); }
  static void init(const char *file,ulong cachesize,int can_modify);
  static void flush(void);
  static void term(void);
  static void killbase(ulong iniNumber=0);      // Clean up ALL base
  static int  getdrive(void);                   // Get current drive
  static int  getgraph(void)                    // Get current graph
                                                // (for compatibility:
               { return atag; }                 //   always returns 'A'
  static int  registerbase(const char *filename,int cachesize,int writeFlag=1);
                                                // Register aux base file
                                                // 0 - too many bases
                                                // else - drive number
  static int  setbase(int drive,int graph=atag);        // Set current base
                                                // Base -- got from setbasefile
                                                // 'graph' parameter is not used.
                                                // (must be equal to atag)
                                                // (for compatibility)

//--------------------------------------------------------------------------
// Private definitions

private:

// Number of netnode. Usually this is linear address the netnode keeps
// information about.

  ulong netnodenumber;                  // Reference number for the node



  bool check(const char *oldname,int namlen=0) // Check and access node type
        { return netnode_check(this, oldname, namlen, false); }
//  int check(ulong name)                 // Check and access node type
//        { netnodenumber = name; return exist(*this); }

  string qsupval(ulong ea, char tag) const;
  void qsupset(ulong ea, const string &x, char tag);

};


//--------------------------------------------------------------------------
//      N E T L I N K
//--------------------------------------------------------------------------

class netlink {
  friend class netnode;
  friend void select(const netlink *n);
  ulong linknumber;
  int check(const char *oldname);       // Check and access link type
public:

// Empty constructor

  netlink(void)         {}


// Main constructor.
//      name      - name of netlink type
//      do_create - 1: create the netlink if it doesn't exist yet.
//                  0: don't create the netlink, set linknumber to 0 if
//                     it doesn't exist

  netlink(const char *name,int do_create=0) {
        if ( do_create ) create(name);
        else check(name);
  }


// Does a netlink exist?

  friend int exist(const netlink &L)   { return L.linknumber != 0; }


// Create a netlink
//      name - name of new netlink type
// returns: 1 - ok, 0 - netlink type already exists

  int create(const char *name);


// Get name of netlink type
// returns NULL - bad netlink type

  char *name(void);


// Rename a netlink type
//      name - new name of netlink type
// returns: 1 - ok, 0 - netlink type already exists

  int rename(const char *newname);


// Get first netlink type in the graph
// returns: 1 - ok, 0 - the graph doesn't contains netlinks

  int start(void);


// Get next netlink type in the graph
// returns: 1 - ok, 0 - no more netlinks

  int next(void);


// Get first netlink type used to link a netnode to other netnodes
//      from - source netnode
// returns: BADNODE - the netnode is not linked to other netnodes
//          otherwise returns a netnode linked to the source netnode using
//          the current netlink.

  netnode firstlink(netnode from) const; // Get first netnode linked with given linktype


// Get next netlink type used to link a netnode to other netnodes
//      from    - source netnode
//      current - current netnode
// returns: BADNODE - the netnode is not linked to no more netnodes
//          otherwise returns the next netnode linked to the source netnode
//          using the current netlink.

  netnode nextlink(netnode from,netnode current) const; // Get next netnode linked with given linktype


// Netlink comparisons

  int operator==(netlink &n) const { return linknumber == n.linknumber; }
  int operator!=(netlink &n) const { return linknumber != n.linknumber; }
};

//-----------------------------------------------------------------------

// The following netlinks and netnodes are created by the kernel:

extern netlink PartOf;               // name: "part of"
extern netlink IsA;                  // name: "is a"
extern netlink InstanceOf;           // name: "instance of"


// The rootnode is used by the kernel, don't use it!

idaman netnode ida_export_data RootNode;             // name: "Root Node"


// Error message handler. Should display the message and exit

extern void (idaapi *netErrorHandler)(const char *message);       // error handler.

#pragma pack(pop)
#endif // _NETNODE_HPP
