// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief  C++ API tsk module wrapper
//!\author Eduardo Aguiar
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <Python.h>
#include <mobius/tsk/diskimage.h>
#include <mobius/tsk/filesystem.h>
#include <mobius/tsk/entry.h>
#include <mobius/tsk/stream.h>
#include <mobius/tsk/exception.h>

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk module methods
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyMethodDef tsk_methods[] =
{
  {NULL, NULL, 0, NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: data structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
typedef struct
{
  PyObject_HEAD
  mobius::tsk::diskimage *obj;
} tsk_DiskImage_o;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: prototypes
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void tsk_DiskImage_tp_dealloc (tsk_DiskImage_o *);
static PyObject *tsk_DiskImage_tp_new (PyTypeObject *, PyObject *, PyObject *);
static PyObject *tsk_DiskImage_get_size (tsk_DiskImage_o *);
static PyObject *tsk_DiskImage_get_sector_size (tsk_DiskImage_o *);
static PyObject *tsk_DiskImage_get_type (tsk_DiskImage_o *);

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: getters and setters structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyGetSetDef tsk_DiskImage_getsetters[] =
{
  {
    (char *) "size",
    (getter) tsk_DiskImage_get_size,
    (setter) 0,
    (char *) "image size in bytes", NULL
  },
  {
    (char *) "sector_size",
    (getter) tsk_DiskImage_get_sector_size,
    (setter) 0,
    (char *) "sector size in bytes", NULL
  },
  {
    (char *) "type",
    (getter) tsk_DiskImage_get_type,
    (setter) 0,
    (char *) "image type", NULL
  },
  {NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: type structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyTypeObject tsk_DiskImage_t =
{
  PyObject_HEAD_INIT (0)
  0,                                                  // ob_size
  "tsk.DiskImage",                                    // tp_name
  sizeof (tsk_DiskImage_o),                           // tp_basicsize
  0,                                                  // tp_itemsize
  (destructor) tsk_DiskImage_tp_dealloc,              // tp_dealloc
  0,                                                  // tp_print
  0,                                                  // tp_getattr
  0,                                                  // tp_setattr
  0,                                                  // tp_compare
  0,                                                  // tp_repr
  0,                                                  // tp_as_number
  0,                                                  // tp_as_sequence
  0,                                                  // tp_as_mapping
  0,                                                  // tp_hash
  0,                                                  // tp_call
  0,                                                  // tp_str
  0,                                                  // tp_getattro
  0,                                                  // tp_setattro
  0,                                                  // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           // tp_flags
  "disk image",                                       // tp_doc
  0,                                                  // tp_traverse
  0,                                                  // tp_clear
  0,                                                  // tp_richcompare
  0,                                                  // tp_weaklistoffset
  0,                                                  // tp_iter
  0,                                                  // tp_iternext
  0,                                                  // tp_methods
  0,                                                  // tp_members
  tsk_DiskImage_getsetters,                           // tp_getset
  0,                                                  // tp_base
  0,                                                  // tp_dict
  0,                                                  // tp_descr_get
  0,                                                  // tp_descr_set
  0,                                                  // tp_dictoffset
  0,                                                  // tp_init
  0,                                                  // tp_alloc
  tsk_DiskImage_tp_new                                // tp_new
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: data structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
typedef struct
{
  PyObject_HEAD
  mobius::tsk::filesystem *obj;
} tsk_FileSystem_o;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: prototypes
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void tsk_FileSystem_tp_dealloc (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_tp_new (PyTypeObject *, PyObject *, PyObject *);
static PyObject *tsk_FileSystem_get_offset (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_inode_count (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_root_inode (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_first_inode (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_last_inode (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_root_entry (tsk_FileSystem_o *);
static PyObject *tsk_FileSystem_get_id (tsk_FileSystem_o *);

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: getters and setters structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyGetSetDef tsk_FileSystem_getsetters[] =
{
  {
    (char *) "offset",
    (getter) tsk_FileSystem_get_offset,
    (setter) 0,
    (char *) "offset of the filesystem", NULL
  },
  {
    (char *) "inode_count",
    (getter) tsk_FileSystem_get_inode_count,
    (setter) 0,
    (char *) "inode count", NULL
  },
  {
    (char *) "root_inode",
    (getter) tsk_FileSystem_get_root_inode,
    (setter) 0,
    (char *) "root entry inode number", NULL
  },
  {
    (char *) "first_inode",
    (getter) tsk_FileSystem_get_first_inode,
    (setter) 0,
    (char *) "first inode number", NULL
  },
  {
    (char *) "last_inode",
    (getter) tsk_FileSystem_get_last_inode,
    (setter) 0,
    (char *) "last inode number", NULL
  },
  {
    (char *) "root_entry",
    (getter) tsk_FileSystem_get_root_entry,
    (setter) 0,
    (char *) "root entry", NULL
  },
  {
    (char *) "id",
    (getter) tsk_FileSystem_get_id,
    (setter) 0,
    (char *) "filesystem ID", NULL
  },
  {NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: type structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyTypeObject tsk_FileSystem_t =
{
  PyObject_HEAD_INIT (0)
  0,                                                  // ob_size
  "tsk.FileSystem",                                   // tp_name
  sizeof (tsk_FileSystem_o),                          // tp_basicsize
  0,                                                  // tp_itemsize
  (destructor) tsk_FileSystem_tp_dealloc,             // tp_dealloc
  0,                                                  // tp_print
  0,                                                  // tp_getattr
  0,                                                  // tp_setattr
  0,                                                  // tp_compare
  0,                                                  // tp_repr
  0,                                                  // tp_as_number
  0,                                                  // tp_as_sequence
  0,                                                  // tp_as_mapping
  0,                                                  // tp_hash
  0,                                                  // tp_call
  0,                                                  // tp_str
  0,                                                  // tp_getattro
  0,                                                  // tp_setattro
  0,                                                  // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           // tp_flags
  "file system",                                      // tp_doc
  0,                                                  // tp_traverse
  0,                                                  // tp_clear
  0,                                                  // tp_richcompare
  0,                                                  // tp_weaklistoffset
  0,                                                  // tp_iter
  0,                                                  // tp_iternext
  0,                                                  // tp_methods
  0,                                                  // tp_members
  tsk_FileSystem_getsetters,                          // tp_getset
  0,                                                  // tp_base
  0,                                                  // tp_dict
  0,                                                  // tp_descr_get
  0,                                                  // tp_descr_set
  0,                                                  // tp_dictoffset
  0,                                                  // tp_init
  0,                                                  // tp_alloc
  tsk_FileSystem_tp_new                               // tp_new
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: data structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
typedef struct
{
  PyObject_HEAD
  mobius::tsk::entry *obj;
} tsk_Entry_o;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: prototypes
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void tsk_Entry_tp_dealloc (tsk_Entry_o *);
static PyObject *tsk_Entry_get_type (tsk_Entry_o *);
static PyObject *tsk_Entry_get_inode (tsk_Entry_o *);
static PyObject *tsk_Entry_get_size (tsk_Entry_o *);
static PyObject *tsk_Entry_get_name (tsk_Entry_o *);
static PyObject *tsk_Entry_get_short_name (tsk_Entry_o *);
static PyObject *tsk_Entry_get_is_deleted (tsk_Entry_o *);
static PyObject *tsk_Entry_get_is_reallocated (tsk_Entry_o *);
static PyObject *tsk_Entry_get_is_folder (tsk_Entry_o *);
static PyObject *tsk_Entry_get_mode (tsk_Entry_o *);
static PyObject *tsk_Entry_get_uid (tsk_Entry_o *);
static PyObject *tsk_Entry_get_gid (tsk_Entry_o *);
static PyObject *tsk_Entry_get_atime (tsk_Entry_o *);
static PyObject *tsk_Entry_get_mtime (tsk_Entry_o *);
static PyObject *tsk_Entry_get_ctime (tsk_Entry_o *);
static PyObject *tsk_Entry_get_crtime (tsk_Entry_o *);
static PyObject *tsk_Entry_get_dtime (tsk_Entry_o *);
static PyObject *tsk_Entry_get_streams (tsk_Entry_o *);
static PyObject *tsk_Entry_get_children (tsk_Entry_o *);
static PyObject *tsk_Entry_get_path (tsk_Entry_o *);
static int tsk_Entry_set_path (tsk_Entry_o *, PyObject *, void *);

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: getters and setters structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyGetSetDef tsk_Entry_getsetters[] =
{
  {
    (char *) "type",
    (getter) tsk_Entry_get_type,
    (setter) 0,
    (char *) "type", NULL
  },
  {
    (char *) "inode",
    (getter) tsk_Entry_get_inode,
    (setter) 0,
    (char *) "inode number", NULL
  },
  {
    (char *) "size",
    (getter) tsk_Entry_get_size,
    (setter) 0,
    (char *) "size in bytes", NULL
  },
  {
    (char *) "name",
    (getter) tsk_Entry_get_name,
    (setter) 0,
    (char *) "file name", NULL
  },
  {
    (char *) "short_name",
    (getter) tsk_Entry_get_short_name,
    (setter) 0,
    (char *) "file short name", NULL
  },
  {
    (char *) "is_deleted",
    (getter) tsk_Entry_get_is_deleted,
    (setter) 0,
    (char *) "check if entry is deleted", NULL
  },
  {
    (char *) "is_reallocated",
    (getter) tsk_Entry_get_is_reallocated,
    (setter) 0,
    (char *) "check if entry is reallocated", NULL
  },
  {
    (char *) "is_folder",
    (getter) tsk_Entry_get_is_folder,
    (setter) 0,
    (char *) "check if it is a folder", NULL
  },
  {
    (char *) "mode",
    (getter) tsk_Entry_get_mode,
    (setter) 0,
    (char *) "permission mode", NULL
  },
  {
    (char *) "uid",
    (getter) tsk_Entry_get_uid,
    (setter) 0,
    (char *) "user id", NULL
  },
  {
    (char *) "gid",
    (getter) tsk_Entry_get_gid,
    (setter) 0,
    (char *) "group id", NULL
  },
  {
    (char *) "atime",
    (getter) tsk_Entry_get_atime,
    (setter) 0,
    (char *) "last access time", NULL
  },
  {
    (char *) "mtime",
    (getter) tsk_Entry_get_mtime,
    (setter) 0,
    (char *) "last data modification time", NULL
  },
  {
    (char *) "ctime",
    (getter) tsk_Entry_get_ctime,
    (setter) 0,
    (char *) "last metadata modification time", NULL
  },
  {
    (char *) "crtime",
    (getter) tsk_Entry_get_crtime,
    (setter) 0,
    (char *) "creation time", NULL
  },
  {
    (char *) "dtime",
    (getter) tsk_Entry_get_dtime,
    (setter) 0,
    (char *) "deletion time", NULL
  },
  {
    (char *) "streams",
    (getter) tsk_Entry_get_streams,
    (setter) 0,
    (char *) "entry data streams", NULL
  },
  {
    (char *) "children",
    (getter) tsk_Entry_get_children,
    (setter) 0,
    (char *) "child entries", NULL
  },
  {
    (char *) "path",
    (getter) tsk_Entry_get_path,
    (setter) tsk_Entry_set_path,
    (char *) "full path", NULL
  },
  {NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: type structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyTypeObject tsk_Entry_t =
{
  PyObject_HEAD_INIT (0)
  0,                                                  // ob_size
  "tsk.Entry",                                        // tp_name
  sizeof (tsk_Entry_o),                               // tp_basicsize
  0,                                                  // tp_itemsize
  (destructor) tsk_Entry_tp_dealloc,                  // tp_dealloc
  0,                                                  // tp_print
  0,                                                  // tp_getattr
  0,                                                  // tp_setattr
  0,                                                  // tp_compare
  0,                                                  // tp_repr
  0,                                                  // tp_as_number
  0,                                                  // tp_as_sequence
  0,                                                  // tp_as_mapping
  0,                                                  // tp_hash
  0,                                                  // tp_call
  0,                                                  // tp_str
  0,                                                  // tp_getattro
  0,                                                  // tp_setattro
  0,                                                  // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           // tp_flags
  "file system entry",                                // tp_doc
  0,                                                  // tp_traverse
  0,                                                  // tp_clear
  0,                                                  // tp_richcompare
  0,                                                  // tp_weaklistoffset
  0,                                                  // tp_iter
  0,                                                  // tp_iternext
  0,                                                  // tp_methods
  0,                                                  // tp_members
  tsk_Entry_getsetters,                               // tp_getset
  0,                                                  // tp_base
  0,                                                  // tp_dict
  0,                                                  // tp_descr_get
  0,                                                  // tp_descr_set
  0,                                                  // tp_dictoffset
  0,                                                  // tp_init
  0,                                                  // tp_alloc
  0                                                   // tp_new
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: data structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
typedef struct
{
  PyObject_HEAD
  mobius::tsk::entry_list *obj;
} tsk_EntryList_o;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: prototypes
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void tsk_EntryList_tp_dealloc (tsk_EntryList_o *);
static int tsk_EntryList_tp_len (tsk_EntryList_o *);
static PyObject *tsk_EntryList_tp_getitem (tsk_EntryList_o *, long int);

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: sequence methods structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PySequenceMethods tsk_EntryList_seq_methods =
{
  (lenfunc) tsk_EntryList_tp_len,                     // sq_length
  0,                                                  // sq_concat
  0,                                                  // sq_repeat
  (ssizeargfunc) tsk_EntryList_tp_getitem,            // sq_item
  0,                                                  // sq_slice
  0,                                                  // sq_ass_item
  0,                                                  // sq_ass_slice
  0
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: type structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyTypeObject tsk_EntryList_t =
{
  PyObject_HEAD_INIT (0)
  0,                                                  // ob_size
  "tsk.EntryList",                                    // tp_name
  sizeof (tsk_EntryList_o),                           // tp_basicsize
  0,                                                  // tp_itemsize
  (destructor) tsk_EntryList_tp_dealloc,              // tp_dealloc
  0,                                                  // tp_print
  0,                                                  // tp_getattr
  0,                                                  // tp_setattr
  0,                                                  // tp_compare
  0,                                                  // tp_repr
  0,                                                  // tp_as_number
  &tsk_EntryList_seq_methods,                         // tp_as_sequence
  0,                                                  // tp_as_mapping
  0,                                                  // tp_hash
  0,                                                  // tp_call
  0,                                                  // tp_str
  0,                                                  // tp_getattro
  0,                                                  // tp_setattro
  0,                                                  // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           // tp_flags
  "file system entry list",                           // tp_doc
  0,                                                  // tp_traverse
  0,                                                  // tp_clear
  0,                                                  // tp_richcompare
  0,                                                  // tp_weaklistoffset
  0,                                                  // tp_iter
  0,                                                  // tp_iternext
  0,                                                  // tp_methods
  0,                                                  // tp_members
  0,                                                  // tp_getset
  0,                                                  // tp_base
  0,                                                  // tp_dict
  0,                                                  // tp_descr_get
  0,                                                  // tp_descr_set
  0,                                                  // tp_dictoffset
  0,                                                  // tp_init
  0,                                                  // tp_alloc
  0                                                   // tp_new
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: data structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
typedef struct
{
  PyObject_HEAD
  mobius::tsk::stream *obj;
} tsk_Stream_o;

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: prototypes
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void tsk_Stream_tp_dealloc (tsk_Stream_o *);
static PyObject *tsk_Stream_get_flags (tsk_Stream_o *);
static PyObject *tsk_Stream_get_type (tsk_Stream_o *);
static PyObject *tsk_Stream_get_id (tsk_Stream_o *);
static PyObject *tsk_Stream_get_idx (tsk_Stream_o *);
static PyObject *tsk_Stream_get_size (tsk_Stream_o *);
static PyObject *tsk_Stream_get_name (tsk_Stream_o *);
static PyObject *tsk_Stream_f_tell (tsk_Stream_o *, PyObject *);
static PyObject *tsk_Stream_f_seek (tsk_Stream_o *, PyObject *);
static PyObject *tsk_Stream_f_read (tsk_Stream_o *, PyObject *);

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: getters and setters structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyGetSetDef tsk_Stream_getsetters[] =
{
  {
    (char *) "flags",
    (getter) tsk_Stream_get_flags,
    (setter) 0,
    (char *) "flags", NULL
  },
  {
    (char *) "type",
    (getter) tsk_Stream_get_type,
    (setter) 0,
    (char *) "type", NULL
  },
  {
    (char *) "id",
    (getter) tsk_Stream_get_id,
    (setter) 0,
    (char *) "ID", NULL
  },
  {
    (char *) "idx",
    (getter) tsk_Stream_get_idx,
    (setter) 0,
    (char *) "stream index", NULL
  },
  {
    (char *) "size",
    (getter) tsk_Stream_get_size,
    (setter) 0,
    (char *) "size in bytes", NULL
  },
  {
    (char *) "name",
    (getter) tsk_Stream_get_name,
    (setter) 0,
    (char *) "file name", NULL
  },
  {NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: methods structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyMethodDef tsk_Stream_methods[] =
{
  {
    (char *) "tell",
    (PyCFunction) tsk_Stream_f_tell,
    METH_VARARGS,
    "get read position"
  },
  {
    (char *) "seek",
    (PyCFunction) tsk_Stream_f_seek,
    METH_VARARGS,
    "set read position"
  },
  {
    (char *) "read",
    (PyCFunction) tsk_Stream_f_read,
    METH_VARARGS,
    "read bytes from stream"
  },
  {NULL} // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: type structure
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyTypeObject tsk_Stream_t =
{
  PyObject_HEAD_INIT (0)
  0,                                                  // ob_size
  "tsk.Stream",                                       // tp_name
  sizeof (tsk_Stream_o),                              // tp_basicsize
  0,                                                  // tp_itemsize
  (destructor) tsk_Stream_tp_dealloc,                 // tp_dealloc
  0,                                                  // tp_print
  0,                                                  // tp_getattr
  0,                                                  // tp_setattr
  0,                                                  // tp_compare
  0,                                                  // tp_repr
  0,                                                  // tp_as_number
  0,                                                  // tp_as_sequence
  0,                                                  // tp_as_mapping
  0,                                                  // tp_hash
  0,                                                  // tp_call
  0,                                                  // tp_str
  0,                                                  // tp_getattro
  0,                                                  // tp_setattro
  0,                                                  // tp_as_buffer
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,           // tp_flags
  "data stream",                                      // tp_doc
  0,                                                  // tp_traverse
  0,                                                  // tp_clear
  0,                                                  // tp_richcompare
  0,                                                  // tp_weaklistoffset
  0,                                                  // tp_iter
  0,                                                  // tp_iternext
  tsk_Stream_methods,                                 // tp_methods
  0,                                                  // tp_members
  tsk_Stream_getsetters,                              // tp_getset
  0,                                                  // tp_base
  0,                                                  // tp_dict
  0,                                                  // tp_descr_get
  0,                                                  // tp_descr_set
  0,                                                  // tp_dictoffset
  0,                                                  // tp_init
  0,                                                  // tp_alloc
  0                                                   // tp_new
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: tp_new
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_DiskImage_tp_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
{
  const char *arg_path;

  if (!PyArg_ParseTuple (args, "s", &arg_path))
    return NULL;

  tsk_DiskImage_o *self = (tsk_DiskImage_o *) type->tp_alloc (type, 0);
  if (self != NULL)
    {
      try
        {
          self->obj = new mobius::tsk::diskimage (arg_path);
        }
      catch (const mobius::tsk::exception& e)
        {
          Py_DECREF (self);
          PyErr_SetString (PyExc_IOError, e.what ());
          self = NULL;
        }
    }

  return (PyObject *) self;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: tp_dealloc
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void
tsk_DiskImage_tp_dealloc (tsk_DiskImage_o *self)
{
  delete self->obj;
  self->ob_type->tp_free ((PyObject*) self);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: size getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_DiskImage_get_size (tsk_DiskImage_o *self)
{
  return PyInt_FromSize_t (self->obj->get_size ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: sector_size getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_DiskImage_get_sector_size (tsk_DiskImage_o *self)
{
  return PyInt_FromSize_t (self->obj->get_sector_size ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.DiskImage: type getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_DiskImage_get_type (tsk_DiskImage_o *self)
{
  return PyInt_FromLong (self->obj->get_type ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: tp_new
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_tp_new (PyTypeObject *type, PyObject *args, PyObject *kwds)
{
  PyObject *arg_o;
  size_t arg_offset;

  if (!PyArg_ParseTuple (args, "O!k", &tsk_DiskImage_t, &arg_o, &arg_offset))
    return NULL;

  tsk_FileSystem_o *self = (tsk_FileSystem_o *) type->tp_alloc (type, 0);
  if (self != NULL)
    {
      mobius::tsk::diskimage *image = ((tsk_DiskImage_o *) arg_o)->obj;
      try
        {
          self->obj = new mobius::tsk::filesystem (*image, arg_offset);
        }
      catch (const mobius::tsk::exception& e)
        {
          Py_DECREF (self);
          PyErr_SetString (PyExc_Exception, e.what ());
          self = NULL;
        }
    }

  return (PyObject *) self;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: tp_dealloc
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void
tsk_FileSystem_tp_dealloc (tsk_FileSystem_o *self)
{
  delete self->obj;
  self->ob_type->tp_free ((PyObject*) self);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: offset getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_offset (tsk_FileSystem_o *self)
{
  return PyInt_FromSize_t (self->obj->get_offset ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: inode_count getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_inode_count (tsk_FileSystem_o *self)
{
  return PyInt_FromSize_t (self->obj->get_inode_count ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: root_inode getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_root_inode (tsk_FileSystem_o *self)
{
  return PyInt_FromSize_t (self->obj->get_root_inode ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: first_inode getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_first_inode (tsk_FileSystem_o *self)
{
  return PyInt_FromSize_t (self->obj->get_first_inode ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: last_inode getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_last_inode (tsk_FileSystem_o *self)
{
  return PyInt_FromSize_t (self->obj->get_last_inode ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: root_entry getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_root_entry (tsk_FileSystem_o *self)
{
  tsk_Entry_o *ret = (tsk_Entry_o *) tsk_Entry_t.tp_alloc (&tsk_Entry_t, 0);
  if (ret != NULL)
    ret->obj = new mobius::tsk::entry (self->obj->get_root_entry ());

  return (PyObject *) ret;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.FileSystem: id getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_FileSystem_get_id (tsk_FileSystem_o *self)
{
  return PyString_FromString (self->obj->get_id ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: tp_dealloc
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void
tsk_Entry_tp_dealloc (tsk_Entry_o *self)
{
  delete self->obj;
  self->ob_type->tp_free ((PyObject*) self);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: type getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_type (tsk_Entry_o *self)
{
  return PyInt_FromLong (self->obj->get_type ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: inode getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_inode (tsk_Entry_o *self)
{
  return PyInt_FromSize_t (self->obj->get_inode ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: size getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_size (tsk_Entry_o *self)
{
  return PyInt_FromSize_t (self->obj->get_size ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: name getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_name (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_name ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: short_name getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_short_name (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_short_name ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: is_deleted getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_is_deleted (tsk_Entry_o *self)
{
  return PyBool_FromLong (self->obj->is_deleted ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: is_reallocated getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_is_reallocated (tsk_Entry_o *self)
{
  return PyBool_FromLong (self->obj->is_reallocated ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: is_folder getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_is_folder (tsk_Entry_o *self)
{
  return PyBool_FromLong (self->obj->is_folder ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: mode getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_mode (tsk_Entry_o *self)
{
  return PyInt_FromLong (self->obj->get_mode ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: uid getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_uid (tsk_Entry_o *self)
{
  return PyInt_FromLong (self->obj->get_uid ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: gid getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_gid (tsk_Entry_o *self)
{
  return PyInt_FromLong (self->obj->get_gid ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: atime getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_atime (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_atime ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: mtime getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_mtime (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_mtime ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: ctime getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_ctime (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_ctime ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: crtime getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_crtime (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_crtime ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: dtime getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_dtime (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_dtime ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: streams getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_streams (tsk_Entry_o *self)
{
  PyObject *ret = PyList_New (0);
  if (ret == NULL)
    return NULL;

  for (std::size_t i = 0; i < self->obj->get_stream_count (); i++)
    {
      mobius::tsk::stream stream = self->obj->get_stream_by_idx (i);
      tsk_Stream_o *item = (tsk_Stream_o *) tsk_Stream_t.tp_alloc (&tsk_Stream_t, 0);

      if (item == NULL)
        {
          Py_CLEAR (ret);
          return NULL;
        }

      item->obj = new mobius::tsk::stream (stream);
      PyList_Append (ret, (PyObject *) item);
    }

  return ret;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: children getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_children (tsk_Entry_o *self)
{
  tsk_EntryList_o *ret = (tsk_EntryList_o *) tsk_EntryList_t.tp_alloc (&tsk_EntryList_t, 0);
  if (ret != NULL)
    {
      mobius::tsk::entry_list entry_list = self->obj->get_children ();
      ret->obj = new mobius::tsk::entry_list (entry_list);
    }

  return (PyObject *) ret;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: path getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Entry_get_path (tsk_Entry_o *self)
{
  return PyString_FromString (self->obj->get_path ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Entry: path setter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static int
tsk_Entry_set_path (tsk_Entry_o *self, PyObject *value, void *closure)
{
  if (value == 0)
    {
      PyErr_SetString (PyExc_TypeError, "Cannot delete 'path' attribute");
      return -1;
    }

  if (!PyString_Check (value))
    {
      PyErr_SetString (PyExc_TypeError, "'path' attribute type must be a string");
      return -1;
    }

  self->obj->set_path (PyString_AsString (value));

  return 0;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: tp_dealloc
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void
tsk_EntryList_tp_dealloc (tsk_EntryList_o *self)
{
  delete self->obj;
  self->ob_type->tp_free ((PyObject*) self);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: tp_len
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static int
tsk_EntryList_tp_len (tsk_EntryList_o *self)
{
  return self->obj->get_length ();
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.EntryList: tp_getitem
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_EntryList_tp_getitem (tsk_EntryList_o *self, long int i)
{
  if (i < 0 || i >= self->obj->get_length ())
    {
      PyErr_SetString (PyExc_IndexError, "index out of range");
      return NULL;
    }

  tsk_Entry_o *ret = (tsk_Entry_o *) tsk_Entry_t.tp_alloc (&tsk_Entry_t, 0);
  if (ret != NULL)
    {
      try
        {
          ret->obj = new mobius::tsk::entry (self->obj->operator[](i));
        }
      catch (const mobius::tsk::exception& e)
        {
          Py_DECREF (ret);
          PyErr_SetString (PyExc_IndexError, e.what ());
          ret = NULL;
        }
    }

  return (PyObject *) ret;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: tp_dealloc
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static void
tsk_Stream_tp_dealloc (tsk_Stream_o *self)
{
  delete self->obj;
  self->ob_type->tp_free ((PyObject*) self);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: flags getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_flags (tsk_Stream_o *self)
{
  return PyInt_FromLong (self->obj->get_flags ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: type getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_type (tsk_Stream_o *self)
{
  return PyInt_FromLong (self->obj->get_type ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: id getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_id (tsk_Stream_o *self)
{
  return PyInt_FromSize_t (self->obj->get_id ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: idx getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_idx (tsk_Stream_o *self)
{
  return PyInt_FromSize_t (self->obj->get_idx ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: size getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_size (tsk_Stream_o *self)
{
  return PyInt_FromSize_t (self->obj->get_size ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: name getter
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_get_name (tsk_Stream_o *self)
{
  return PyString_FromString (self->obj->get_name ().c_str ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: tell
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_f_tell (tsk_Stream_o *self, PyObject *args)
{
  return PyInt_FromSize_t (self->obj->tell ());
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: seek
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_f_seek (tsk_Stream_o *self, PyObject *args)
{
  mobius::tsk::offset_t offset;
  int whence;

  if (!PyArg_ParseTuple (args, "LI", &offset, &whence))
    return NULL;

  self->obj->seek (offset, whence);

  Py_INCREF (Py_None);
  return Py_None;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk.Stream: read
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyObject *
tsk_Stream_f_read (tsk_Stream_o *self, PyObject *args)
{
  mobius::tsk::offset_t size = self->obj->get_size ();
  mobius::tsk::offset_t offset = self->obj->tell ();
  mobius::tsk::offset_t bytes;

  // parse arguments
  PyObject *obj = nullptr;
  if (!PyArg_ParseTuple (args, "|O", &obj))
    return NULL;

  if (obj == nullptr || obj == Py_None)
    bytes = size - offset;

  else if (PyInt_Check (obj))
    bytes = PyInt_AsUnsignedLongLongMask (obj);
  
  else
    {
      PyErr_SetString (PyExc_TypeError, "invalid type for size argument");
      return NULL;
    }

  // if size == 0, return an empty string
  if (!bytes)
    return PyString_FromString ("");

  // call stream.read
  char *buffer = new char[bytes];
  PyObject *ret;

  try
    {
      mobius::tsk::offset_t count = self->obj->read (buffer, bytes);
      ret = PyString_FromStringAndSize (buffer, count);
    }
  catch (const mobius::tsk::exception& e)
    {
      PyErr_SetString (PyExc_IOError, e.what ());
      ret = NULL;
    }

  delete [] buffer;

  return ret;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief tsk module initialisation function
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
PyMODINIT_FUNC
inittsk ()
{
  if (PyType_Ready (&tsk_DiskImage_t) < 0) return;
  if (PyType_Ready (&tsk_FileSystem_t) < 0) return;
  if (PyType_Ready (&tsk_Entry_t) < 0) return;
  if (PyType_Ready (&tsk_EntryList_t) < 0) return;
  if (PyType_Ready (&tsk_Stream_t) < 0) return;

  PyObject* m = Py_InitModule3 ("tsk", tsk_methods, "Mobius Forensic Toolkit API wrapper");
  if (m == NULL)
    return;

  Py_INCREF (&tsk_DiskImage_t);
  PyModule_AddObject (m, "DiskImage", (PyObject *) &tsk_DiskImage_t);
  Py_INCREF (&tsk_FileSystem_t);
  PyModule_AddObject (m, "FileSystem", (PyObject *) &tsk_FileSystem_t);
  Py_INCREF (&tsk_Entry_t);
  PyModule_AddObject (m, "Entry", (PyObject *) &tsk_Entry_t);
  Py_INCREF (&tsk_EntryList_t);
  PyModule_AddObject (m, "EntryList", (PyObject *) &tsk_EntryList_t);
  Py_INCREF (&tsk_Stream_t);
  PyModule_AddObject (m, "Stream", (PyObject *) &tsk_Stream_t);
}
