Index: trunk/python2/SConstruct
===================================================================
--- trunk/python2/SConstruct	(revision 196)
+++ trunk/python2/SConstruct	(revision 196)
@@ -0,0 +1,38 @@
+import os, os.path, pdb
+from functools import partial
+import utils
+import config
+import class_parser
+
+def build_python_bindings(target, source, env, initialization=''):
+    """ A command to generate python bindings """
+    module_name = os.path.splitext(os.path.basename(target[0].name))[0]
+    utils.warn("Generating automatic python bindings for module %s" % module_name)
+
+    p = class_parser.HeaderParser(module_name, verbose=config.V)
+    p.module.init_string = initialization
+    p.parse_filenames([s.get_abspath() for s in source])
+
+    fd = open(target[0].get_abspath(), 'w')
+    p.write(fd)
+    fd.close()
+
+
+
+nenv = utils.ExtendedEnvironment()
+
+BOUND_FILES = Split("""
+    ../include/regfi.h
+    regfi/pyregfi.h
+    """)
+
+nenv.config = config
+nenv.Append(CFLAGS = "-I../include/ -Iinclude")
+nenv.Append(LIBPATH="../lib")
+nenv.Append(LINKFLAGS="")
+nenv.Command('regfi/pyregfi.c', BOUND_FILES, partial(build_python_bindings,
+                                                     initialization='pyregfi_init();'))
+nenv.Depends('regfi/pyregfi.c', 'class_parser.py')
+
+nenv.PythonModule("pyregfi", ['regfi/pyregfi.c', 'regfi/regfi.c', 'regfi/class.c', 'regfi/error.c'],
+                  LIBS=['regfi', 'talloc'])
Index: trunk/python2/class_parser.py
===================================================================
--- trunk/python2/class_parser.py	(revision 196)
+++ trunk/python2/class_parser.py	(revision 196)
@@ -0,0 +1,2971 @@
+import sys, os, re, pdb, StringIO
+ 
+DEBUG = 0
+
+def log(msg):
+    if DEBUG>0:
+        sys.stderr.write(msg+"\n")
+
+def escape_for_string(string):
+    result = string
+    result = result.encode("string-escape")
+    result = result.replace('"',r'\"')
+
+    return result
+
+class Module:
+    def __init__(self, name):
+        self.name = name
+        self.constants = set()
+        self.classes = {}
+        self.headers = '#include <Python.h>\n'
+        self.files = []
+
+    def __str__(self):
+        result = "Module %s\n" % (self.name)
+        l = self.classes.values()
+        l.sort()
+        for attr in l:
+            if attr.is_active():
+                result += "    %s\n" % attr
+
+        l = list(self.constants)
+        l.sort()
+        result += 'Constants:\n'
+        for attr, type in l:
+            result += " %s\n" % attr
+
+        return result
+
+    init_string = ''
+    def initialization(self):
+        result = self.init_string + """
+talloc_set_log_fn((void *)printf);
+//talloc_enable_leak_report();
+"""
+        for cls in self.classes.values():
+            if cls.is_active():
+                result += cls.initialise()
+
+        return result
+
+    def add_constant(self, constant, type="numeric"):
+        """ This will be called to add #define constant macros """
+        self.constants.add((constant, type))
+
+    def add_class(self, cls, handler):
+        self.classes[cls.class_name] = cls
+
+        ## Make a wrapper in the type dispatcher so we can handle
+        ## passing this class from/to python
+        type_dispatcher[cls.class_name] = handler
+
+    def private_functions(self):
+        """ Emits hard coded private functions for doing various things """
+        return """
+/* The following is a static array mapping CLASS() pointers to their
+python wrappers. This is used to allow the correct wrapper to be
+chosen depending on the object type found - regardless of the
+prototype.
+
+This is basically a safer way for us to cast the correct python type
+depending on context rather than assuming a type based on the .h
+definition. For example consider the function
+
+AFFObject Resolver.open(uri, mode)
+
+The .h file implies that an AFFObject object is returned, but this is
+not true as most of the time an object of a derived class will be
+returned. In C we cast the returned value to the correct type. In the
+python wrapper we just instantiate the correct python object wrapper
+at runtime depending on the actual returned type. We use this lookup
+table to do so.
+*/
+static int TOTAL_CLASSES=0;
+
+/* This is a global reference to this module so classes can call each
+   other.
+*/
+static PyObject *g_module = NULL;
+
+static struct python_wrapper_map_t {
+       Object class_ref;
+       PyTypeObject *python_type;
+} python_wrappers[%s];
+
+/** This is a generic wrapper type */
+typedef struct {
+  PyObject_HEAD
+  void *base;
+  void *ctx;
+} Gen_wrapper;
+
+/* Create the relevant wrapper from the item based on the lookup
+table.
+*/
+Gen_wrapper *new_class_wrapper(Object item) {
+   int i;
+   Gen_wrapper *result;
+   Object cls;
+
+   /* Hack to get the current null_context */
+   void* null_context;
+   int* tmp = talloc(NULL, int);
+   null_context = talloc_parent(tmp);
+   talloc_free(tmp);
+
+   // Return None for a NULL pointer
+   if(!item) {
+     Py_INCREF(Py_None);
+     return (Gen_wrapper *)Py_None;
+   };
+
+   // Search for subclasses
+   for(cls=(Object)item->__class__; cls != cls->__super__; cls=cls->__super__) {
+     for(i=0; i<TOTAL_CLASSES; i++) {
+       if(python_wrappers[i].class_ref == cls) {
+         PyErr_Clear();
+
+         result = (Gen_wrapper *)_PyObject_New(python_wrappers[i].python_type);
+         result->ctx = talloc_asprintf(NULL, "new_class_wrapper %%s@%%p", NAMEOF(item), item);
+         result->base = (void *)item;
+
+         /* If its owned by the null_context it means that the function does
+            not want to own the memory - we therefore steal it so it gets freed
+            with the python object. */
+         if(talloc_parent(result->base) == null_context)
+                  talloc_steal(result->ctx, result->base);
+
+         return result;
+       };
+     };
+   };
+
+  PyErr_Format(PyExc_RuntimeError, "Unable to find a wrapper for object %%s", NAMEOF(item));
+  return NULL;
+};
+
+static PyObject *resolve_exception(char **error_buff) {
+  enum _error_type *type = aff4_get_current_error(error_buff);
+  switch(*type) {
+case EProgrammingError:
+    return PyExc_SystemError;
+case EKeyError:
+    return PyExc_KeyError;
+case ERuntimeError:
+    return PyExc_RuntimeError;
+case EWarning:
+    return PyExc_AssertionError;
+default:
+    return PyExc_RuntimeError;
+};
+};
+
+static int type_check(PyObject *obj, PyTypeObject *type) {
+   PyTypeObject *tmp;
+
+   // Recurse through the inheritance tree and check if the types are expected
+   if(obj)
+     for(tmp = obj->ob_type; tmp && tmp != &PyBaseObject_Type; tmp = tmp->tp_base) {
+       if(tmp == type) return 1;
+     };
+
+  return 0;
+};
+
+static int check_error() {
+   if(!CheckError(EZero)) {
+         char *buffer;
+         PyObject *exception = resolve_exception(&buffer);
+
+         PyErr_Format(exception, "%%s", buffer);
+         ClearError();
+         return 1;
+   };
+  return 0;
+};
+
+#define CHECK_ERROR if(check_error()) goto error;
+
+""" % (len(self.classes)+1)
+
+    def initialise_class(self, class_name, out, done = None):
+        if done and class_name in done: return
+
+        done.add(class_name)
+
+        cls = self.classes[class_name]
+        """ Write out class initialisation code into the main init function. """
+        if cls.is_active():
+            base_class = self.classes.get(cls.base_class_name)
+
+            if base_class and base_class.is_active():
+                ## We have a base class - ensure it gets written out
+                ## first:
+                self.initialise_class(cls.base_class_name, out, done)
+
+                ## Now assign ourselves as derived from them
+                out.write(" %s_Type.tp_base = &%s_Type;" % (
+                        cls.class_name, cls.base_class_name))
+            
+            out.write("""
+ %(name)s_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&%(name)s_Type) < 0)
+     return;
+
+ Py_INCREF((PyObject *)&%(name)s_Type);
+ PyModule_AddObject(m, "%(name)s", (PyObject *)&%(name)s_Type);
+""" % {'name': cls.class_name})
+
+    def write(self, out):
+        ## Prepare all classes
+        for cls in self.classes.values():
+            cls.prepare()
+
+        out.write("""
+/**********************************************************************
+     Autogenerated module %s
+
+This module was autogenerated from the following files:
+""" % self.name)
+        for file in self.files:
+            out.write("%s\n" % file)
+
+        out.write("\nThis module implements the following classes:\n")
+        out.write(self.__str__())
+        out.write("""***********************************************************************/
+""")
+        out.write(self.headers)
+        out.write(self.private_functions())
+
+        for cls in self.classes.values():
+            if cls.is_active():
+                out.write("/******************** %s ***********************/" % cls.class_name)
+                cls.struct(out)
+                cls.prototypes(out)
+
+        out.write("/*****************************************************\n             Implementation\n******************************************************/\n\n")
+        for cls in self.classes.values():
+            if cls.is_active():
+                cls.PyMethodDef(out)
+                cls.code(out)
+                cls.PyTypeObject(out)
+
+        ## Write the module initializer
+        out.write("""
+static PyMethodDef %(module)s_methods[] = {
+     {NULL}  /* Sentinel */
+};
+
+PyMODINIT_FUNC init%(module)s(void) {
+   /* Make sure threads are enabled */
+   PyEval_InitThreads();
+
+   /* create module */
+   PyObject *m = Py_InitModule3("%(module)s", %(module)s_methods,
+                                   "%(module)s module.");
+   PyObject *d = PyModule_GetDict(m);
+   PyObject *tmp;
+
+   g_module = m;
+""" % {'module': self.name})
+
+        ## The trick is to initialise the classes in order of their
+        ## inheritance. The following code will order initializations
+        ## according to their inheritance tree
+        done = set()
+        for class_name in self.classes.keys():
+            self.initialise_class(class_name, out, done)
+
+        ## Add the constants in here
+        for constant, type in self.constants:
+            if type == 'integer':
+                out.write(""" tmp = PyLong_FromUnsignedLongLong((int64_t)%s); \n""" % constant)
+            elif type == 'string':
+                out.write(" tmp = PyString_FromString((char *)%s); \n" % constant)
+            else:
+                out.write(" // I dont know how to convert %s type %s\n" % (constant, type))
+                continue
+
+            out.write("""
+ PyDict_SetItemString(d, "%s", tmp);
+ Py_DECREF(tmp);\n""" % (constant))
+
+        out.write(self.initialization())
+        out.write("}\n\n")
+
+class Type:
+    interface = None
+    buildstr = 'O'
+    sense = 'IN'
+    error_value = "return 0;"
+    active = True
+
+    def __init__(self, name, type):
+        self.name = name
+        self.type = type
+        self.attributes = set()
+
+    def comment(self):
+        return "%s %s " % (self.type, self.name)
+
+    def python_name(self):
+        return self.name
+
+    def python_proxy_post_call(self):
+        """ This is called after a proxy call """
+        return ''
+
+    def returned_python_definition(self, *arg, **kw):
+        return self.definition(*arg, **kw)
+
+    def definition(self, default=None, **kw):
+        if default:
+            return "%s %s=%s;\n" % (self.type, self.name, default)
+        else:
+            return "%s __attribute__((unused)) %s;\n" % (self.type, self.name)
+
+    def byref(self):
+        return "&%s" % self.name
+
+    def call_arg(self):
+        return self.name
+
+    def pre_call(self, method):
+        return ''
+
+    def assign(self, call, method, target=None):
+        return "Py_BEGIN_ALLOW_THREADS\n%s = %s;\nPy_END_ALLOW_THREADS\n" % (target or self.name, call)
+
+    def post_call(self, method):
+        if "DESTRUCTOR" in self.attributes:
+            return "talloc_free(self->ctx); self->base = NULL;\n"
+
+        return ''
+
+    def from_python_object(self, source, destination, method, **kw):
+        return ''
+
+    def return_value(self, value):
+        return "return %s;" % value
+
+    def __str__(self):
+        if self.name == 'func_return':
+            return self.type
+        if 'void' in self.type:
+            return ''
+
+        result = "%s : %s" % (self.type, self.name)
+
+        return result
+
+class String(Type):
+    interface = 'string'
+    buildstr = 's'
+    error_value = "return NULL;"
+
+    def __init__(self, name, type):
+        Type.__init__(self, name, type)
+        self.length = "strlen(%s)" % name
+
+    def byref(self):
+        return "&%s" % self.name
+
+    def to_python_object(self, name=None, result='py_result',**kw):
+        name = name or self.name
+
+        result = """PyErr_Clear();
+   if(!%(name)s) { PyErr_Format(PyExc_RuntimeError, "%(name)s is NULL"); goto error; };
+   %(result)s = PyString_FromStringAndSize((char *)%(name)s, %(length)s);\nif(!%(result)s) goto error;
+""" % dict(name=name, result=result,length=self.length)
+
+        if "BORROWED" not in self.attributes and 'BORROWED' not in kw:
+            result += "talloc_unlink(NULL, %s);\n" % name
+
+        return result
+
+    def from_python_object(self, source, destination, method, context='NULL'):
+        method.error_set = True
+        return """
+{
+  char *buff; Py_ssize_t length;
+
+  PyErr_Clear();
+  if(-1==PyString_AsStringAndSize(%(source)s, &buff, &length))
+     goto error;
+
+  %(destination)s = talloc_size(%(context)s, length + 1);
+  memcpy(%(destination)s, buff, length);
+  %(destination)s[length]=0;
+};
+""" % dict(source = source, destination = destination, context =context)
+
+class ZString(String):
+    interface = 'null_terminated_string'
+
+class BorrowedString(String):
+    def to_python_object(self, name=None, result='py_result', **kw):
+        name = name or self.name
+        return "PyErr_Clear();\n" +\
+            "%s = PyString_FromStringAndSize((char *)%(name)s, %(length)s);\n" % dict(
+            name=name, length=self.length, result=result)
+
+class Char_and_Length(Type):
+    interface = 'char_and_length'
+    buildstr = 's#'
+    error_value = "return NULL;"
+
+    def __init__(self, data, data_type, length, length_type):
+        Type.__init__(self, data, data_type)
+
+        self.name = data
+        self.data_type=data_type
+        self.length = length
+        self.length_type = length_type
+
+    def comment(self):
+        return "%s %s, %s %s" % (self.data_type, self.name,
+                                 self.length_type, self.length)
+
+    def definition(self, default = '""', **kw):
+        return "char *%s=%s; Py_ssize_t %s=strlen(%s);\n" % (
+            self.name, default,
+            self.length, default)
+
+    def byref(self):
+        return "&%s, &%s" % (self.name, self.length)
+
+    def call_arg(self):
+        return "(%s)%s, (%s)%s" % (self.data_type, self.name, self.length_type,
+                                   self.length)
+
+    def to_python_object(self, name=None, result='py_result', **kw):
+        return "PyErr_Clear();\n"\
+            "%s = PyString_FromStringAndSize(%s, %s);\nif(!%s) goto error;" % (
+            result, self.name, self.length, result);
+
+class Integer(Type):
+    interface = 'integer'
+    buildstr = 'K'
+
+    def __init__(self, name,type):
+        Type.__init__(self,name,type)
+        self.type = 'uint64_t'
+        self.original_type = type
+
+    def definition(self, default = 0, **kw):
+        return Type.definition(self, default)
+
+    def to_python_object(self, name=None, result='py_result', **kw):
+        name = name or self.name
+        return "PyErr_Clear();\n%s = PyLong_FromLongLong(%s);\n" % (result, name)
+
+    def from_python_object(self, source, destination, method, **kw):
+        return "PyErr_Clear();\n"\
+            "%(destination)s = PyLong_AsUnsignedLong(%(source)s);\n" % dict(
+            source = source, destination= destination)
+
+    def comment(self):
+        return "%s %s " % (self.original_type, self.name)
+
+class Integer32(Integer):
+    buildstr = 'I'
+
+    def __init__(self, name,type):
+        Type.__init__(self,name,type)
+        self.type = 'unsigned int '
+        self.original_type = type
+
+    def to_python_object(self, name=None, result='py_result', **kw):
+        name = name or self.name
+        return "PyErr_Clear();\n%s = PyLong_FromLong(%s);\n" % (result, name)
+
+class Integer64(Integer):
+    buildstr = 'K'
+    type = 'unsigned int'
+
+class Char(Integer):
+    buildstr = "s"
+    interface = 'small_integer'
+
+    def to_python_object(self, name = None, result = 'py_result', **kw):
+        ## We really want to return a string here
+        return """{ char *str_%(name)s = &%(name)s;
+    PyErr_Clear();
+    %(result)s = PyString_FromStringAndSize(str_%(name)s, 1);
+if(!%(result)s) goto error;
+};
+""" % dict(result=result, name = name or self.name)
+
+    def definition(self, default = '"\\x0"', **kw):
+        ## Shut up unused warnings
+        return "char %s __attribute__((unused))=0;\nchar *str_%s __attribute__((unused)) = %s;\n" % (
+            self.name,self.name, default)
+
+    def byref(self):
+        return "&str_%s" % self.name
+
+    def pre_call(self, method):
+        method.error_set = True
+        return """
+if(strlen(str_%(name)s)!=1) {
+  PyErr_Format(PyExc_RuntimeError,
+          "You must only provide a single character for arg %(name)r");
+  goto error;
+};
+
+%(name)s = str_%(name)s[0];
+""" % dict(name = self.name)
+
+class StringOut(String):
+    sense = 'OUT'
+
+class IntegerOut(Integer):
+    sense = 'OUT_DONE'
+    buildstr = ''
+
+    def python_name(self):
+        return None
+
+    def byref(self):
+        return ''
+
+    def call_arg(self):
+        return "&%s" % self.name
+
+class Integer32Out(Integer32):
+    sense = 'OUT_DONE'
+    buildstr = ''
+
+    def python_name(self):
+        return None
+
+    def byref(self):
+        return ''
+
+    def call_arg(self):
+        return "&%s" % self.name
+
+class Char_and_Length_OUT(Char_and_Length):
+    sense = 'OUT_DONE'
+    buildstr = 'l'
+
+    def definition(self, default = 0, **kw):
+        return "char *%s=NULL; Py_ssize_t %s=%s;\n" % (
+            self.name,
+            self.length, default) + "PyObject *tmp_%s;\n" % self.name
+
+    def python_name(self):
+        return self.length
+
+    def byref(self):
+        return "&%s" % self.length
+
+    def pre_call(self, method):
+        return """PyErr_Clear();
+tmp_%s = PyString_FromStringAndSize(NULL, %s);
+if(!tmp_%s) goto error;
+PyString_AsStringAndSize(tmp_%s, &%s, (Py_ssize_t *)&%s);
+""" % (self.name, self.length, self.name, self.name, self.name, self.length)
+
+    def to_python_object(self, name=None, result='py_result', sense='in', **kw):
+        name = name or self.name
+        if 'results' in kw:
+            kw['results'].pop(0)
+
+        if sense=='proxied':
+            return "py_%s = PyLong_FromLong(%s);\n" % (self.name, self.length)
+
+        return  """if(func_return > %(length)s) {
+  func_return = 0;
+};
+
+_PyString_Resize(&tmp_%(name)s, func_return); \n%(result)s = tmp_%(name)s;\n""" % \
+            dict(name= name, result= result, length=self.length)
+
+
+    def python_proxy_post_call(self, result='py_result'):
+        return """
+{
+    char *tmp_buff; int tmp_len;
+    if(-1==PyString_AsStringAndSize(%(result)s, &tmp_buff, &tmp_len)) goto error;
+
+    memcpy(%(name)s,tmp_buff, tmp_len);
+    Py_DECREF(%(result)s);
+    %(result)s = PyLong_FromLong(tmp_len);
+};
+""" % dict(result = result, name=self.name)
+
+class TDB_DATA_P(Char_and_Length_OUT):
+    bare_type = "TDB_DATA"
+
+    def __init__(self, name, type):
+        Type.__init__(self, name, type)
+
+    def definition(self, default=None, **kw):
+        return Type.definition(self)
+
+    def byref(self):
+        return "%s.dptr, &%s.dsize" % (self.name, self.name)
+
+    def pre_call(self, method):
+        return ''
+
+    def call_arg(self):
+        return Type.call_arg(self)
+
+    def to_python_object(self, name=None,result='py_result', **kw):
+        name = name or self.name
+        return "PyErr_Clear();"\
+            "%s = PyString_FromStringAndSize((char *)%s->dptr, %s->dsize);"\
+            "\ntalloc_free(%s);" % (result,
+                                    name, name, name)
+
+    def from_python_object(self, source, destination, method, **kw):
+        method.error_set = True
+        return """
+%(destination)s = talloc(self, %(bare_type)s);
+{ Py_ssize_t tmp; char *buf;
+
+  PyErr_Clear();
+  if(-1==PyString_AsStringAndSize(%(source)s, &buf, &tmp)) {
+  goto error;
+};
+
+  // Take a copy of the python string
+  %(destination)s->dptr = talloc_memdup(%(destination)s, buf, tmp);
+  %(destination)s->dsize = tmp;
+}
+// We no longer need the python object
+Py_DECREF(%(source)s);
+""" % dict(source = source, destination = destination, 
+           bare_type = self.bare_type)
+
+class TDB_DATA(TDB_DATA_P):
+    def to_python_object(self, name = None, result='py_result', **kw):
+        name = name or self.name
+
+        return "PyErr_Clear();\n"\
+            "%s = PyString_FromStringAndSize((char *)%s.dptr, %s.dsize);\n" % (
+            result,
+            name, name)
+
+class Void(Type):
+    buildstr = ''
+    error_value = "return;"
+    original_type = ''
+
+    def __init__(self, *args):
+        Type.__init__(self, None, 'void *')
+
+    def definition(self, default = None, **kw):
+        return ''
+
+    def to_python_object(self, name=None, result = 'py_result', **kw):
+        return "Py_INCREF(Py_None); py_result = Py_None;\n"
+
+    def call_arg(self):
+        return "NULL"
+
+    def byref(self):
+        return None
+
+    def assign(self, call, method, target=None):
+        ## We dont assign the result to anything
+        return "Py_BEGIN_ALLOW_THREADS\n%s;\nPy_END_ALLOW_THREADS\n" % call
+
+    def return_value(self, value):
+        return "return;"
+
+class StringArray(String):
+    interface = 'array'
+    buildstr = 'O'
+
+    def definition(self, default = '""', **kw):
+        return "char **%s=NULL; PyObject *py_%s=NULL;\n" % (
+            self.name, self.name)
+
+    def byref(self):
+        return "&py_%s" % (self.name)
+
+    def from_python_object(self, source, destination, method, context='NULL'):
+        method.error_set = True
+        return """{
+Py_ssize_t i,size=0;
+
+if(%(source)s) {
+   if(!PySequence_Check(%(source)s)) {
+     PyErr_Format(PyExc_ValueError, "%(destination)s must be a sequence");
+     goto error;
+   };
+
+   size = PySequence_Size(%(source)s);
+};
+
+%(destination)s = talloc_zero_array(NULL, char *, size + 1);
+
+for(i=0; i<size;i++) {
+ PyObject *tmp = PySequence_GetItem(%(source)s, i);
+ if(!tmp) goto error;
+ %(destination)s[i] = PyString_AsString(tmp);
+ if(!%(destination)s[i]) {
+   Py_DECREF(tmp);
+   goto error;
+ };
+ Py_DECREF(tmp);
+};
+
+};""" % dict(source = source, destination = destination, context = context)
+
+    def pre_call(self, method):
+        return self.from_python_object("py_%s" % self.name, self.name, method)
+
+    def error_condition(self):
+        return """if(%s) talloc_free(%s);\n""" % (self.name, self.name)
+
+class Wrapper(Type):
+    """ This class represents a wrapped C type """
+    sense = 'IN'
+    error_value = "return NULL;"
+
+    def from_python_object(self, source, destination, method, **kw):
+        return """
+/* First check that the returned value is in fact a Wrapper */
+if(!type_check(%(source)s, &%(type)s_Type)) {
+  PyErr_Format(PyExc_RuntimeError, "function must return an %(type)s instance");
+  goto error;
+};
+
+%(destination)s = ((Gen_wrapper *)%(source)s)->base;
+""" % dict(source = source, destination = destination, type = self.type)
+
+    def to_python_object(self, **kw):
+        return ''
+
+    def returned_python_definition(self, default = 'NULL', sense='in', **kw):
+        return "%s %s;\n" % (self.type, self.name)
+
+    def definition(self, default = 'NULL', sense='in', **kw):
+        result = "Gen_wrapper *%s __attribute__((unused)) = %s;\n" % (self.name, default)
+        if sense == 'in' and not 'OUT' in self.attributes:
+            result += " %s __attribute__((unused)) call_%s;\n" % (self.type, self.name)
+
+        return result
+
+    def call_arg(self):
+        return "call_%s" % self.name
+
+    def pre_call(self, method):
+        if 'OUT' in self.attributes or self.sense == 'OUT':
+            return ''
+
+        return """
+if(!%(name)s || (PyObject *)%(name)s==Py_None) {
+   call_%(name)s = NULL;
+} else if(!type_check((PyObject *)%(name)s,&%(type)s_Type)) {
+     PyErr_Format(PyExc_RuntimeError, "%(name)s must be derived from type %(type)s");
+     goto error;
+} else {
+   call_%(name)s = %(name)s->base;
+};\n""" % self.__dict__
+
+    def assign(self, call, method, target=None):
+        method.error_set = True;
+        args = dict(name = target or self.name, call = call, type = self.type)
+
+        result = """{
+       Object returned_object;
+
+       ClearError();
+
+       Py_BEGIN_ALLOW_THREADS
+       returned_object = (Object)%(call)s;
+       Py_END_ALLOW_THREADS
+
+       CHECK_ERROR;
+""" % args
+
+        ## Is NULL an acceptable return type? In some python code NULL
+        ## can be returned (e.g. in iterators) but usually it should
+        ## be converted to None.
+        if "NULL_OK" in self.attributes:
+            result += """if(returned_object == NULL) {
+     %(name)s = NULL; """ % args
+        else:
+            result += """
+       // A NULL return without errors means we return None
+       if(!returned_object) {
+         %(name)s = (Gen_wrapper *)Py_None;
+         Py_INCREF(Py_None);
+""" % args
+
+        result += """
+       } else {
+         //printf("%%s: Wrapping %%s@%%p\\n", __FUNCTION__, NAMEOF(returned_object), returned_object);
+         %(name)s = new_class_wrapper(returned_object);
+         if(!%(name)s) goto error;
+""" % args
+
+        if "BORROWED" in self.attributes:
+            result += "           talloc_reference(%(name)s->ctx, %(name)s->base);\n" % args
+
+        result += """       };
+    }
+"""
+        return result
+
+    def to_python_object(self, name=None, result = 'py_result', sense='in', **kw):
+        name = name or self.name
+        args = dict(result=result,
+                    name = name)
+
+        if sense=='proxied':
+            return "%(result)s = (PyObject *)new_class_wrapper((Object)%(name)s);\n" % args
+
+        return "%(result)s = (PyObject *)%(name)s;\n" % args
+
+class PointerWrapper(Wrapper):
+    """ A pointer to a wrapped class """
+    def __init__(self, name, type):
+        type = type.split()[0]
+        Wrapper.__init__(self,name, type)
+
+    def definition(self, default = 'NULL', sense='in', **kw):
+        result = "Gen_wrapper *%s = %s;" % (self.name, default)
+        if sense == 'in' and not 'OUT' in self.attributes:
+            result += " %s *call_%s;\n" % (self.type, self.name)
+
+        return result
+
+    def pre_call(self, method):
+        if 'OUT' in self.attributes or self.sense == 'OUT':
+            return ''
+
+        return """
+if(!%(name)s || (PyObject *)%(name)s==Py_None) {
+   call_%(name)s = NULL;
+} else if(!type_check((PyObject *)%(name)s,&%(type)s_Type)) {
+     PyErr_Format(PyExc_RuntimeError, "%(name)s must be derived from type %(type)s");
+     goto error;
+} else {
+   call_%(name)s = (%(type)s *)&%(name)s->base;
+};\n""" % self.__dict__
+
+class StructWrapper(Wrapper):
+    """ A wrapper for struct classes """
+    def assign(self, call, method, target = None):
+        args = dict(name = target or self.name, call = call, type = self.type)
+        result = """
+PyErr_Clear();
+%(name)s = (Gen_wrapper *)PyObject_New(py%(type)s, &%(type)s_Type);
+%(name)s->ctx = talloc_size(NULL, 1);
+%(name)s->base = %(call)s;
+""" % args
+
+        if "NULL_OK" in self.attributes:
+            result += "if(!%(name)s->base) { Py_DECREF(%(name)s); return NULL; };" % args
+
+        result += """
+// A NULL object gets translated to a None
+ if(!%(name)s->base) {
+   Py_DECREF(%(name)s);
+   Py_INCREF(Py_None);
+   %(name)s = (Gen_wrapper *)Py_None;
+ } else {
+""" % args
+
+        if "FOREIGN" in self.attributes:
+            result += '// Not taking references to foreign memory\n'
+        elif "BORROWED" in self.attributes:
+            result += "talloc_reference(%(name)s->ctx, %(name)s->base);\n" % args
+        else:
+            result += "talloc_steal(%(name)s->ctx, %(name)s->base);\n" % args
+
+        result += "}\n"
+
+        return result
+
+    def byref(self):
+        return "&%s" % self.name
+
+    def definition(self, default = 'NULL', sense='in', **kw):
+        result = "Gen_wrapper *%s = %s;" % (self.name, default)
+        if sense == 'in' and not 'OUT' in self.attributes:
+            result += " %s *call_%s;\n" % (self.type, self.name)
+
+        return result;
+
+class PointerStructWrapper(StructWrapper):
+    def __init__(self, name, type):
+        type = type.split()[0]
+        Wrapper.__init__(self,name, type)
+
+class Timeval(Type):
+    """ handle struct timeval values """
+    interface = 'numeric'
+    buildstr = 'f'
+
+    def definition(self, default = None, **kw):
+        return "float %(name)s_flt; struct timeval %(name)s;\n" % self.__dict__
+
+    def byref(self):
+        return "&%s_flt" % self.name
+
+    def pre_call(self, method):
+        return "%(name)s.tv_sec = (int)%(name)s_flt; %(name)s.tv_usec = (%(name)s_flt - %(name)s.tv_sec) * 1e6;\n" % self.__dict__
+
+    def to_python_object(self, name=None, result = 'py_result', **kw):
+        name = name or self.name
+        return """%(name)s_flt = (double)(%(name)s.tv_sec) + %(name)s.tv_usec;
+%(result)s = PyFloat_FromDouble(%(name)s_flt);
+""" % dict(name = name, result=result)
+
+class PyObject(Type):
+    """ Accept an opaque python object """
+    interface = 'opaque'
+    buildstr = 'O'
+    def definition(self, default = 'NULL', **kw):
+        self.default = default
+        return 'PyObject *%(name)s = %(default)s;\n' % self.__dict__
+
+    def byref(self):
+        return "&%s" % self.name
+
+type_dispatcher = {
+    "IN char *": String,
+    "IN unsigned char *": String,
+    "unsigned char *": String,
+    "char *": String,
+    "ZString": ZString,
+
+    "OUT char *": StringOut,
+    "OUT unsigned char *": StringOut,
+    "unsigned int": Integer,
+    'int': Integer,
+    'OUT uint64_t *': IntegerOut,
+    'OUT uint32_t *': Integer32Out,
+    'char': Char,
+    'void': Void,
+    'void *': Void,
+
+    'TDB_DATA *': TDB_DATA_P,
+    'TDB_DATA': TDB_DATA,
+    'uint64_t': Integer,
+    'uint32_t': Integer32,
+    'time_t': Integer32,
+    'uint16_t': Integer,
+    'uint8_t': Integer,
+    'int64_t': Integer,
+    'ssize_t': Integer,
+    'size_t': Integer,
+    'unsigned long int': Integer,
+    'struct timeval': Timeval,
+    'char **': StringArray,
+
+    'PyObject *': PyObject,
+    }
+
+method_attributes = ['BORROWED', 'DESTRUCTOR','IGNORE']
+
+def dispatch(name, type):
+    if not type: return Void()
+
+    m = re.match("struct ([a-zA-Z0-9]+)_t *", type)
+    if m:
+        type = m.group(1)
+
+    type_components = type.split()
+    attributes = set()
+
+    if type_components[0] in method_attributes:
+        attributes.add(type_components.pop(0))
+
+    type = " ".join(type_components)
+    result = type_dispatcher[type](name, type)
+
+    result.attributes = attributes
+
+    return result
+
+class ResultException:
+    value = 0
+    exception = "PyExc_IOError"
+
+    def __init__(self, check, exception, message):
+        self.check = check
+        self.exception = exception
+        self.message = message
+
+    def write(self, out):
+        out.write("\n//Handle exceptions\n")
+        out.write("if(%s) {\n    PyErr_Format(PyExc_%s, %s);\n  goto error; \n};\n\n" % (
+                self.check, self.exception, self.message))
+
+class Method:
+    default_re = re.compile("DEFAULT\(([A-Z_a-z0-9]+)\) =(.+)")
+    exception_re = re.compile("RAISES\(([^,]+),\s*([^\)]+)\) =(.+)")
+    typedefed_re = re.compile(r"struct (.+)_t \*")
+
+    def __init__(self, class_name, base_class_name, method_name, args, return_type,
+                 myclass = None):
+        self.name = method_name
+        ## myclass needs to be a class generator
+        if not isinstance(myclass, ClassGenerator): raise RuntimeError("myclass must be a class generator")
+
+        self.myclass = myclass
+        self.docstring = ''
+        self.defaults = {}
+        self.exception = None
+        self.error_set = False
+        self.class_name = class_name
+        self.base_class_name = base_class_name
+        self.args = []
+        self.definition_class_name = class_name
+        for type,name in args:
+            self.add_arg(type, name)
+
+        try:
+            self.return_type = dispatch('func_return', return_type)
+            self.return_type.attributes.add("OUT")
+            self.return_type.original_type = return_type
+        except KeyError:
+            ## Is it a wrapped type?
+            if return_type:
+                log("Unable to handle return type %s.%s %s" % (self.class_name, self.name, return_type))
+                #pdb.set_trace()
+            self.return_type = Void()
+
+    def clone(self, new_class_name):
+        self.find_optional_vars()
+
+        result = self.__class__(new_class_name, self.base_class_name, self.name,
+                                [], 'void *',
+                                myclass = self.myclass)
+        result.args = self.args
+        result.return_type = self.return_type
+        result.definition_class_name = self.definition_class_name
+        result.defaults = self.defaults
+        result.exception = self.exception
+
+        return result
+
+    def find_optional_vars(self):
+        for line in self.docstring.splitlines():
+            m =self.default_re.search(line)
+            if m:
+                name = m.group(1)
+                value = m.group(2)
+                log("Setting default value for %s of %s" % (m.group(1),
+                                                            m.group(2)))
+                self.defaults[name] = value
+
+            m =self.exception_re.search(line)
+            if m:
+                self.exception = ResultException(m.group(1), m.group(2), m.group(3))
+
+    def write_local_vars(self, out):
+        self.find_optional_vars()
+
+        ## We do it in two passes - first mandatory then optional
+        kwlist = """static char *kwlist[] = {"""
+        ## Mandatory
+        for type in self.args:
+            python_name = type.python_name()
+            if python_name and python_name not in self.defaults:
+                kwlist += '"%s",' % python_name
+
+        for type in self.args:
+            python_name = type.python_name()
+            if python_name and python_name in self.defaults:
+                kwlist += '"%s",' % python_name
+
+        kwlist += ' NULL};\n'
+
+        for type in self.args:
+            python_name = type.python_name()
+            try:
+                out.write(type.definition(default = self.defaults[python_name]))
+            except KeyError:
+                out.write(type.definition())
+
+        ## Make up the format string for the parse args in two pases
+        parse_line = ''
+        for type in self.args:
+            python_name = type.python_name()
+            if type.buildstr and python_name not in self.defaults:
+                parse_line += type.buildstr
+
+        parse_line += '|'
+        for type in self.args:
+            python_name = type.python_name()
+            if type.buildstr and python_name in self.defaults:
+                parse_line += type.buildstr
+
+        if parse_line != '|':
+            ## Now parse the args from python objects
+            out.write(kwlist)
+            out.write("\nif(!PyArg_ParseTupleAndKeywords(args, kwds, \"%s\", kwlist, " % parse_line)
+            tmp = []
+            for type in self.args:
+                ref = type.byref()
+                if ref:
+                    tmp.append(ref)
+
+            out.write(",".join(tmp))
+            self.error_set = True
+            out.write("))\n goto error;\n\n")
+
+    def error_condition(self):
+        result = ""
+        if "DESTRUCTOR" in self.return_type.attributes:
+            result += "talloc_free(self->ctx); self->base = NULL;\n"
+
+        return result +"return NULL;\n";
+
+    def write_definition(self, out):
+        args = dict(method = self.name, class_name = self.class_name)
+        out.write("\n/********************************************************\nAutogenerated wrapper for function:\n")
+        out.write(self.comment())
+        out.write("********************************************************/\n")
+
+        self._prototype(out)
+        out.write("""{
+       PyObject *returned_result, *py_result;
+""" % args)
+
+        out.write(self.return_type.definition())
+
+        self.write_local_vars( out);
+
+        out.write("""// Make sure that we have something valid to wrap
+if(!self->base) return PyErr_Format(PyExc_RuntimeError, "%(class_name)s object no longer valid");
+""" % args)
+
+        ## Precall preparations
+        out.write("// Precall preparations\n")
+        out.write(self.return_type.pre_call(self))
+        for type in self.args:
+            out.write(type.pre_call(self))
+
+        out.write("""// Check the function is implemented
+  {  void *method = ((%(def_class_name)s)self->base)->%(method)s;
+     if(!method || (void *)unimplemented == (void *)method) {
+         PyErr_Format(PyExc_RuntimeError, "%(class_name)s.%(method)s is not implemented");
+         goto error;
+     };
+  };
+""" % dict(def_class_name = self.definition_class_name, method=self.name,
+           class_name = self.class_name))
+
+        out.write("\n// Make the call\n ClearError();")
+        call = "((%s)self->base)->%s(((%s)self->base)" % (self.definition_class_name, self.name, self.definition_class_name)
+        tmp = ''
+        for type in self.args:
+            tmp += ", " + type.call_arg()
+
+        call += "%s)" % tmp
+
+        ## Now call the wrapped function
+        out.write(self.return_type.assign(call, self))
+        if self.exception:
+            self.exception.write(out)
+
+        self.error_set = True
+
+        out.write("\n// Postcall preparations\n")
+        ## Postcall preparations
+        out.write(self.return_type.post_call(self))
+        for type in self.args:
+            out.write(type.post_call(self))
+
+        ## Now assemble the results
+        results = [self.return_type.to_python_object()]
+        for type in self.args:
+            if type.sense == 'OUT_DONE':
+                results.append(type.to_python_object(results = results))
+
+        ## If all the results are returned by reference we dont need
+        ## to prepend the void return value at all.
+        if isinstance(self.return_type, Void) and len(results)>1:
+            results.pop(0)
+
+        out.write("\n// prepare results\n")
+        ## Make a tuple of results and pass them back
+        if len(results)>1:
+            out.write("returned_result = PyList_New(0);\n")
+            for result in results:
+                out.write(result)
+                out.write("PyList_Append(returned_result, py_result); Py_DECREF(py_result);\n");
+            out.write("return returned_result;\n")
+        else:
+            out.write(results[0])
+            ## This useless code removes compiler warnings
+            out.write("returned_result = py_result;\nreturn returned_result;\n");
+
+        ## Write the error part of the function
+        if self.error_set:
+            out.write("\n// error conditions:\n")
+            out.write("error:\n    " + self.error_condition());
+
+        out.write("\n};\n\n")
+
+    def add_arg(self, type, name):
+        try:
+            t = type_dispatcher[type](name, type)
+        except KeyError:
+            ## Sometimes types must be typedefed in advance
+            try:
+                m = self.typedefed_re.match(type)
+                type = m.group(1)
+                log( "Trying %s for %s" % (type, m.group(0)))
+                t = type_dispatcher[type](name, type)
+            except (KeyError, AttributeError):
+                log( "Unable to handle type %s.%s %s" % (self.class_name, self.name, type))
+                return
+
+        ## Here we collapse char * + int type interfaces into a
+        ## coherent string like interface.
+        try:
+            previous = self.args[-1]
+            if t.interface == 'integer' and \
+                    previous.interface == 'string':
+
+                ## We make a distinction between IN variables and OUT
+                ## variables
+                if previous.sense == 'OUT':
+                    cls = Char_and_Length_OUT
+                else:
+                    cls = Char_and_Length
+
+
+                cls = cls(
+                    previous.name,
+                    previous.type,
+                    name, type)
+
+                self.args[-1] = cls
+
+                return
+        except IndexError:
+            pass
+
+        self.args.append(t)
+
+    def comment(self):
+        result = self.return_type.original_type+" "+self.class_name+"."+self.name+"("
+        args = []
+        for type in self.args:
+            args.append( type.comment())
+
+        result += ",".join(args) + ");\n"
+
+        return result
+
+    def prototype(self, out):
+        self._prototype(out)
+        out.write(";\n")
+
+    def _prototype(self, out):
+        out.write("""static PyObject *py%(class_name)s_%(method)s(py%(class_name)s *self, PyObject *args, PyObject *kwds) """ % dict(method = self.name, class_name = self.class_name))
+
+    def __str__(self):
+        result = "def %s %s(%s):" % (
+            self.return_type,
+            self.name, ' , '.join([a.__str__() for a in self.args]))
+        return result
+
+    def PyMethodDef(self, out):
+        docstring = self.comment() + "\n\n" + self.docstring
+        out.write('     {"%s",(PyCFunction)py%s_%s, METH_VARARGS|METH_KEYWORDS, "%s"},\n' % (
+                self.name,
+                self.class_name,
+                self.name, escape_for_string(docstring)))
+
+class IteratorMethod(Method):
+    """ A Method which implements an iterator """
+    def __init__(self, *args, **kw):
+        Method.__init__(self, *args, **kw)
+
+        ## Tell the return type that a NULL python return is ok
+        self.return_type.attributes.add("NULL_OK")
+
+    def _prototype(self, out):
+        out.write("""static PyObject *py%(class_name)s_%(method)s(py%(class_name)s *self)""" % dict(method = self.name, class_name = self.class_name))
+
+    def __str__(self):
+        result = "Iterator returning %s." % (
+            self.return_type)
+        return result
+
+    def PyMethodDef(self, out):
+        ## This method should not go in the method table as its linked
+        ## in directly
+        pass
+
+class SelfIteratorMethod(IteratorMethod):
+    def write_definition(self, out):
+        args = dict(method = self.name, class_name = self.class_name)
+        out.write("\n/********************************************************\nAutogenerated wrapper for function:\n")
+        out.write(self.comment())
+        out.write("********************************************************/\n")
+
+        self._prototype(out)
+        out.write("""{
+          ((%(class_name)s)self->base)->%(method)s((%(class_name)s)self->base);
+          return PyObject_SelfIter((PyObject *)self);
+};
+""" % args)
+
+class ConstructorMethod(Method):
+    ## Python constructors are a bit different than regular methods
+    def _prototype(self, out):
+        out.write("""
+static int py%(class_name)s_init(py%(class_name)s *self, PyObject *args, PyObject *kwds)
+""" % dict(method = self.name, class_name = self.class_name))
+
+    def write_destructor(self, out):
+        ## We make sure that we unlink exactly the reference we need
+        ## (the object will persist if it has some other
+        ## references). Note that if we just used talloc_free here it
+        ## will remove some random reference which may not actually be
+        ## the reference we own (which is NULL).
+        free = """
+    if(self->base) {
+        //printf("Unlinking %s@%p\\n", NAMEOF(self->base), self->base);
+        talloc_free(self->ctx);
+        self->base=NULL;
+    };
+"""
+        out.write("""static void
+%(class_name)s_dealloc(py%(class_name)s *self) {
+%(free)s
+ PyObject_Del(self);
+};\n
+""" % dict(class_name = self.class_name, free=free))
+
+    def error_condition(self):
+        return "return -1;";
+
+    def write_definition(self, out):
+        self._prototype(out)
+        out.write("""{\n""")
+        self.write_local_vars(out)
+
+        ## Precall preparations
+        for type in self.args:
+            out.write(type.pre_call(self))
+
+        ## Now call the wrapped function
+        out.write("\nself->ctx = talloc_strdup(NULL, \"%s\");" % self.class_name)
+        out.write("\n ClearError();\nPy_BEGIN_ALLOW_THREADS\nself->base = CONSTRUCT(%s, %s, %s, self->ctx" % (
+                self.class_name,
+                self.definition_class_name,
+                self.name))
+        tmp = ''
+        for type in self.args:
+            tmp += ", " + type.call_arg()
+
+        self.error_set = True
+        out.write("""%s);\nPy_END_ALLOW_THREADS\n
+       if(!CheckError(EZero)) {
+         char *buffer;
+         PyObject *exception = resolve_exception(&buffer);
+
+         PyErr_Format(exception,
+                    "%%s", buffer);
+         ClearError();
+         goto error;
+  } else if(!self->base) {
+    PyErr_Format(PyExc_IOError, "Unable to construct class %s");
+    goto error;
+  };
+""" % (tmp, self.class_name))
+
+        out.write("  return 0;\n");
+
+        ## Write the error part of the function
+        if self.error_set:
+            out.write("error:\n    " + self.error_condition());
+
+        out.write("\n};\n\n")
+
+class GetattrMethod(Method):
+    def __init__(self, class_name, base_class_name, myclass):
+        self.base_class_name = base_class_name
+        self._attributes = []
+        self.error_set = True
+        self.return_type = Void()
+        self.myclass = myclass
+        self.rename_class_name(class_name)
+
+    def add_attribute(self, attr):
+        if attr.name:
+            self._attributes.append([self.class_name, attr])
+
+    def rename_class_name(self, new_name):
+        """ This allows us to rename the class_name at a later stage.
+        Required for late initialization of Structs whose name is not
+        know until much later on.
+        """
+        self.class_name = new_name
+        self.name = "py%s_getattr" % new_name
+        for x in self._attributes:
+            x[0] = new_name
+
+    def get_attributes(self):
+        for class_name, attr in self._attributes:
+            try:
+                if not self.myclass.module.classes[attr.type].active:
+                    continue
+            except KeyError: pass
+
+            yield class_name, attr
+
+    def __str__(self):
+        result = ""
+        for class_name, attr in self.get_attributes():
+            result += "    %s\n" % attr.__str__()
+
+        return result
+
+
+    def clone(self, class_name):
+        result = self.__class__(class_name, self.base_class_name, self.myclass)
+        result._attributes = self._attributes[:]
+
+        return result
+
+    def prototype(self, out):
+        if self.name:
+            out.write("""
+static PyObject *%(name)s(py%(class_name)s *self, PyObject *name);
+""" % self.__dict__)
+
+    def built_ins(self, out):
+        """ check for some built in attributes we need to support """
+        out.write("""  if(!strcmp(name, "__members__")) {
+     PyObject *result = PyList_New(0);
+     PyObject *tmp;
+     PyMethodDef *i;
+
+     if(!result) goto error;
+""")
+        ## Add attributes
+        for class_name, attr in self.get_attributes():
+            out.write(""" tmp = PyString_FromString("%(name)s");
+    PyList_Append(result, tmp); Py_DECREF(tmp);
+""" % dict(name = attr.name))
+
+        ## Add methods
+        out.write("""
+
+    for(i=%s_methods; i->ml_name; i++) {
+     tmp = PyString_FromString(i->ml_name);
+    PyList_Append(result, tmp); Py_DECREF(tmp);
+    }; """ % self.class_name)
+
+        out.write("""
+     return result; 
+   }\n""")
+
+    def write_definition(self, out):
+        if not self.name: return
+        out.write("""
+static PyObject *py%(class_name)s_getattr(py%(class_name)s *self, PyObject *pyname) {
+  char *name;
+  // Try to hand it off to the python native handler first
+  PyObject *result = PyObject_GenericGetAttr((PyObject*)self, pyname);
+
+  if(result) return result;
+
+  PyErr_Clear();
+  // No - nothing interesting was found by python
+  name = PyString_AsString(pyname);
+
+  if(!self->base) return PyErr_Format(PyExc_RuntimeError, "Wrapped object (%(class_name)s.%(name)s) no longer valid");
+  if(!name) return NULL;
+""" % self.__dict__)
+
+        self.built_ins(out)
+
+        for class_name, attr in self.get_attributes():
+            ## what we want to assign
+            if self.base_class_name:
+                call = "(((%s)self->base)->%s)" % (class_name, attr.name)
+            else:
+                call = "(self->base->%s)" % (attr.name)
+
+            out.write("""
+if(!strcmp(name, "%(name)s")) {
+    PyObject *py_result;
+    %(python_def)s
+
+    %(python_assign)s
+    %(python_obj)s
+    return py_result;
+};""" % dict(name = attr.name, python_obj = attr.to_python_object(),
+             python_assign = attr.assign(call, self),
+             python_def = attr.definition(sense='out')))
+
+        out.write("""
+
+  return PyObject_GenericGetAttr((PyObject *)self, pyname);
+""" % self.__dict__)
+
+        ## Write the error part of the function
+        if self.error_set:
+            out.write("error:\n" + self.error_condition());
+
+        out.write("}\n\n")
+
+class ProxiedGetattr(GetattrMethod):
+    def built_ins(self,out):
+        out.write("""  if(!strcmp(name, "__members__")) {
+     PyObject *result;
+     PyObject *tmp;
+     PyMethodDef *i;
+
+     PyErr_Clear();
+     // Get the list of members from our proxied object
+     result  = PyObject_GetAttrString(self->base->proxied, name);
+     if(!result) goto error;
+""")
+        ## Add attributes
+        for class_name, attr in self.get_attributes():
+            out.write(""" tmp = PyString_FromString("%(name)s");
+    PyList_Append(result, tmp); Py_DECREF(tmp);
+""" % dict(name = attr.name))
+
+        ## Add methods
+        out.write("""
+
+    for(i=%s_methods; i->ml_name; i++) {
+     tmp = PyString_FromString(i->ml_name);
+    PyList_Append(result, tmp); Py_DECREF(tmp);
+    }; """ % self.class_name)
+
+        out.write("""
+     return result;
+   }\n""")
+
+        out.write(""" /** Just try to get the attribute from our proxied object */  {
+   PyObject *result = PyObject_GetAttrString(self->base->proxied, name);
+   if(result) return result;
+}; """)
+
+class ProxiedMethod(Method):
+    def __init__(self, method, myclass):
+        self.name = method.name
+        self.method = method
+        self.myclass = myclass
+        self.class_name = method.class_name
+        self.base_class_name = method.base_class_name
+        self.args = method.args
+        self.definition_class_name = method.definition_class_name
+        self.return_type = method.return_type
+        self.docstring = "Proxy for %s" % self.name
+        self.defaults = {}
+        self.exception = None
+        self.error_set = False
+
+    def get_name(self):
+        return "py%(class_name)s_%(name)s" % dict(class_name =self.myclass.class_name,
+                                                  name = self.name)
+
+    def _prototype(self, out):
+        out.write("""
+static %(return_type)s %(name)s(%(definition_class_name)s self""" % dict(
+                return_type = self.return_type.original_type,
+                class_name = self.myclass.class_name,
+                method = self.name,
+                name = self.get_name(),
+                definition_class_name = self.definition_class_name))
+
+        for arg in self.args:
+            out.write(", %s" % (arg.comment()))
+
+        out.write(")")
+
+    def prototype(self, out):
+        self._prototype(out)
+        out.write(";\n")
+
+    def write_definition(self, out):
+        self._prototype(out)
+        self._write_definition(out)
+
+    def _write_definition(self, out):
+        ## We need to grab the GIL before we do anything
+        out.write("""{
+      //Grab the GIL so we can do python stuff
+      PyGILState_STATE gstate;
+      gstate = PyGILState_Ensure();
+      """)
+
+        out.write("{\nPyObject *py_result=NULL;\n")
+        out.write('PyObject *method_name = PyString_FromString("%s");\n' % self.name)
+        out.write(self.return_type.returned_python_definition())
+
+        for arg in self.args:
+            out.write("PyObject *py_%s=NULL;\n" % arg.name)
+
+        out.write("\n//Obtain python objects for all the args:\n")
+        for arg in self.args:
+            out.write(arg.to_python_object(result = "py_%s" % arg.name,
+                                           sense='proxied', BORROWED=True))
+
+        out.write('if(!((%s)self)->proxied) {\n RaiseError(ERuntimeError, "No proxied object in %s"); goto error;\n};\n' % (self.myclass.class_name, self.myclass.class_name))
+
+        out.write("\n//Now call the method\n")
+        out.write("""PyErr_Clear();
+py_result = PyObject_CallMethodObjArgs(((%s)self)->proxied,method_name,""" % self.myclass.class_name)
+        for arg in self.args:
+            out.write("py_%s," % arg.name)
+
+        ## Sentinal
+        self.error_set = True
+        out.write("""NULL);
+
+/** Check for python errors */
+if(PyErr_Occurred()) {
+   PyObject *exception_t, *exception, *tb;
+   PyObject *str;
+   char *str_c;
+   char *error_str;
+   enum _error_type *error_type = aff4_get_current_error(&error_str);
+
+   // Fetch the exception state and convert it to a string:
+   PyErr_Fetch(&exception_t, &exception, &tb);
+
+   str = PyObject_Repr(exception);
+   str_c = PyString_AsString(str);
+
+   if(str_c) {
+      strncpy(error_str, str_c, BUFF_SIZE-1);
+      error_str[BUFF_SIZE-1]=0;
+      *error_type = ERuntimeError;
+   };
+   Py_DECREF(str);
+   goto error;
+};
+
+""");
+
+        for arg in self.args:
+            out.write(arg.python_proxy_post_call())
+
+        ## Now convert the python value back to a value
+        out.write(self.return_type.from_python_object('py_result',self.return_type.name, self, context = "self"))
+
+        out.write("if(py_result) { Py_DECREF(py_result);};\nPy_DECREF(method_name);\n\n");
+        out.write("PyGILState_Release(gstate);\n")
+
+        ## Decref all our python objects:
+        for arg in self.args:
+            out.write("if(py_%s) { Py_DECREF(py_%s);};\n" %( arg.name, arg.name))
+
+        out.write(self.return_type.return_value('func_return'))
+        if self.error_set:
+            out.write("\nerror:\n")
+            out.write("if(py_result) { Py_DECREF(py_result);};\nPy_DECREF(method_name);\n\n");
+            ## Decref all our python objects:
+            for arg in self.args:
+                out.write("if(py_%s) { Py_DECREF(py_%s);};\n" % (arg.name, arg.name))
+
+            out.write("PyGILState_Release(gstate);\n %s;\n" % self.error_condition())
+
+        out.write("   };\n};\n")
+
+    def error_condition(self):
+        return self.return_type.error_value
+
+class StructConstructor(ConstructorMethod):
+    """ A constructor for struct wrappers - basically just allocate
+    memory for the struct.
+    """
+    def write_definition(self, out):
+        out.write("""static int py%(class_name)s_init(py%(class_name)s *self, PyObject *args, PyObject *kwds) {\n""" % dict(method = self.name, class_name = self.class_name))
+        out.write("\nself->ctx = talloc_strdup(NULL, \"%s\");" % self.class_name)
+        out.write("\nself->base = talloc(self->ctx, %s);\n" % self.class_name)
+        out.write("  return 0;\n};\n\n")
+
+    def write_destructor(self, out):
+        out.write("""static void
+%(class_name)s_dealloc(py%(class_name)s *self) {
+   talloc_free(self->ctx);
+};\n
+""" % dict(class_name = self.class_name))
+
+class ProxyConstructor(ConstructorMethod):
+    def write_destructor(self, out):
+        out.write("""static void
+%(class_name)s_dealloc(py%(class_name)s *self) {
+    if(self->base) {
+        // Release the proxied object
+        //Py_DECREF(self->base->proxied);
+        talloc_free(self->ctx);
+        self->base = NULL;
+    };
+};\n
+
+static int %(class_name)s_destructor(void *this) {
+  py%(class_name)s *self = (py%(class_name)s *)this;
+  Py_DECREF(self->base->proxied);
+  return 0;
+};
+""" % dict(class_name = self.class_name))
+
+    def initialise_attributes(self, out):
+        attributes = self.myclass.module.classes[self.base_class_name].attributes.get_attributes()
+        for definition_class_name, attribute in attributes:
+            out.write("""
+{
+  // Converting from %(attribute_name)s
+  PyErr_Clear();
+  PyObject *py_result = PyObject_GetAttrString(self->base->proxied, "%(name)s");
+
+  if(py_result) {
+       %(type)s tmp;
+       %(from_python_object)s;
+       ((%(definition_class_name)s)self->base)->%(name)s = tmp;
+       Py_DECREF(py_result);
+  };
+  PyErr_Clear();
+};""" % dict(definition = attribute.definition(), name=attribute.name,
+             attribute_name = attribute.__class__.__name__,
+             type = attribute.type,
+             definition_class_name = definition_class_name,
+             from_python_object = attribute.from_python_object(
+                        'py_result',"tmp", method=self,
+                        context = 'self->base')))
+
+
+    def write_constructor_proxy(self, out):
+        ## Get the base_class constructor
+        self.base_cons_method = ProxiedMethod(self.myclass.module.classes[self.base_class_name].constructor, self.myclass)
+
+        self.base_cons_method._prototype(out)
+        out.write("{\nPyObject *py_result;\n")
+        out.write('PyObject *method_name;')
+        out.write("%(class_name)s this = (%(class_name)s)self;\n" % self.__dict__)
+        out.write("PyGILState_STATE gstate;\ngstate = PyGILState_Ensure();\n")
+        out.write('method_name = PyString_FromString("__class__");\n')
+        for arg in self.base_cons_method.args:
+            out.write("PyObject *py_%s;\n" % arg.name)
+
+        out.write("\n//Obtain python objects for all the args:\n")
+        for arg in self.base_cons_method.args:
+            out.write(arg.to_python_object(result = "py_%s" % arg.name,
+                                           sense = 'proxied',
+                                           BORROWED=True))
+
+        out.write('if(!((%s)self)->proxied) {\n RaiseError(ERuntimeError, "No proxied object in %s"); goto error;\n};\n' % (self.myclass.class_name, self.myclass.class_name))
+
+        out.write("""
+// Enlarge the object size to accomodate the extended class
+self = talloc_realloc_size(self, self, sizeof(struct %(base_class_name)s_t));
+""" % self.__dict__)
+        out.write("\n//Now call the method\n")
+        out.write("PyErr_Clear();\npy_result = PyObject_CallMethodObjArgs(((%s)self)->proxied,method_name," % self.myclass.class_name)
+
+        call = ''
+        for arg in self.base_cons_method.args:
+            call += "py_%s," % arg.name
+
+        ## Sentinal
+        self.error_set = True
+        call += """NULL"""
+
+        out.write(call + ");\n");
+        out.write("""
+if(!py_result && PyCallable_Check(this->proxied)) {
+   PyErr_Clear();
+   py_result = PyObject_CallFunctionObjArgs(((%(name)s)self)->proxied, %(call)s);
+};
+
+/** Check for python errors */
+if(PyErr_Occurred()) {
+   PyObject *exception_t, *exception, *tb;
+   PyObject *str;
+   char *str_c;
+   char *error_str;
+   enum _error_type *error_type = aff4_get_current_error(&error_str);
+
+   // Fetch the exception state and convert it to a string:
+   PyErr_Fetch(&exception_t, &exception, &tb);
+
+   str = PyObject_Repr(exception);
+   str_c = PyString_AsString(str);
+
+   if(str_c) {
+      strncpy(error_str, str_c, BUFF_SIZE-1);
+      error_str[BUFF_SIZE-1]=0;
+      *error_type = ERuntimeError;
+   };
+   Py_DECREF(str);
+   goto error;
+};
+
+// Take over the proxied object now
+this->proxied = py_result;
+""" % dict(name=self.myclass.class_name, call = call));
+
+        ## Now we try to populate the C struct slots with proxies of
+        ## the python objects
+        for class_name, attr in self.myclass.module.classes[\
+            self.base_class_name].attributes.get_attributes():
+            out.write("""
+// Converting %(name)s from proxy:
+{
+   PyObject *py_result = PyObject_GetAttrString(this->proxied, "%(name)s");
+   if(py_result) {
+""" % dict(name = attr.name))
+            out.write("{ %s " % attr.definition())
+            out.write(attr.from_python_object("py_result",
+                                              "((%s)self)->%s" % (class_name, attr.name),
+                                              self))
+            out.write("}\nPy_DECREF(py_result);\n};\n};\n")
+
+        out.write("PyGILState_Release(gstate);\n")
+        out.write("\n\nreturn self;\n")
+        if self.error_set:
+            out.write("error:\n PyGILState_Release(gstate);\ntalloc_free(self); return NULL;\n")
+
+        out.write("};\n\n")
+
+    def write_definition(self, out):
+        self.write_constructor_proxy(out)
+        out.write("""static int py%(class_name)s_init(py%(class_name)s *self, PyObject *args, PyObject *kwds) {
+      PyGILState_STATE gstate = PyGILState_Ensure();
+""" % dict(method = self.name, class_name = self.class_name))
+
+        self.write_local_vars(out)
+
+        ## Precall preparations
+        for type in self.args:
+            out.write(type.pre_call(self))
+
+        ## Make up the call
+        self.call = "talloc_memdup(NULL, &__%(class_name)s, sizeof(__%(class_name)s));\n" % self.__dict__
+
+        ## Now call the wrapped function
+        out.write("""
+ self->base = %(call)s
+
+// Take over a copy of the proxied object
+ self->base->proxied = proxied;
+
+ /* We take a reference to the proxied object, and the proxied base
+ class takes a reference. This way we (the python object) and the
+ proxied C class can be freed independantly and only when both are
+ freed the proxied object is freed.  */
+
+ //Py_INCREF(proxied);
+ Py_INCREF(proxied);
+ talloc_set_destructor((void*)self->base, %(class_name)s_destructor);
+""" % self.__dict__)
+
+        ## Install the handler for the constructor. FIXME - implement
+        ## shortcut bypassing here so if the proxied class is itself a
+        ## python binding to a C class and it does not override
+        ## anything, we call directly into the original C class method
+        ## instead of converting to python, and back.
+        out.write("((%(definition_class_name)s)self->base)->%(name)s = %(func)s;\n" % dict(
+                definition_class_name = self.base_cons_method.definition_class_name,
+                name = self.base_cons_method.name,
+                func = self.base_cons_method.get_name()))
+
+        ## Now iterate over all our methods and install handlers:
+        for method in self.myclass.methods:
+            out.write("""
+   if(1 || PyDict_GetItemString(proxied->ob_type->tp_dict, "%(name)s")) {
+     ((%(definition_class_name)s)self->base)->%(name)s = py%(class_name)s_%(name)s;
+   };
+""" % dict(definition_class_name = method.definition_class_name,
+           name = method.name,
+           class_name = self.myclass.class_name))
+
+        ## Now fill in all attributes from the proxied object. Since
+        ## the C struct attribute access is just memory access its
+        ## difficult to trap it and refill attributes dynamically from
+        ## the python object. Therefore for now we just read all
+        ## attributes initially and populate the C struct with them.
+        self.initialise_attributes(out)
+
+        out.write("\n   PyGILState_Release(gstate);\n  return 0;\n");
+
+        ## Write the error part of the function
+        if self.error_set:
+            out.write("error:\n  PyGILState_Release(gstate);\n  " + self.error_condition());
+
+        out.write("\n};\n\n")
+
+class EmptyConstructor(ConstructorMethod):
+    def write_definition(self, out):
+        out.write("""static int py%(class_name)s_init(py%(class_name)s *self, PyObject *args, PyObject *kwds) {\n""" % dict(method = self.name, class_name = self.class_name))
+        out.write("""return 0;};\n\n""")
+
+class ClassGenerator:
+    docstring = ''
+    def __init__(self, class_name, base_class_name, module):
+        self.class_name = class_name
+        self.methods = []
+        self.module = module
+        self.constructor = EmptyConstructor(class_name, base_class_name,
+                                             "Con", [], '', myclass = self)
+
+        self.base_class_name = base_class_name
+        self.attributes = GetattrMethod(self.class_name, self.base_class_name, self)
+        self.modifier = set()
+        self.active = True
+        self.iterator = None
+
+    def prepare(self):
+        """ This method is called just before we need to write the
+        output and allows us to do any last minute fixups.
+        """
+        pass
+
+    def __str__(self):
+        result = "#%s\n" % self.docstring
+
+        result += "Class %s(%s):\n" % (self.class_name, self.base_class_name)
+        result += " Constructor:%s\n" % self.constructor
+        result += " Attributes:\n%s\n" % self.attributes
+        result += " Methods:\n"
+        for a in self.methods:
+            result += "    %s\n" % a.__str__()
+
+        return result
+
+    def is_active(self):
+        """ Returns true if this class is active and should be generated """
+        if not self.active or self.modifier and \
+                ('PRIVATE' in self.modifier or 'ABSTRACT' in self.modifier):
+            log("%s is not active %s" % (self.class_name, self.modifier))
+            return False
+
+        return True
+
+    def clone(self, new_class_name):
+        """ Creates a clone of this class - usefull when implementing
+        class extensions
+        """
+        result = ClassGenerator(new_class_name, self.class_name, self.module)
+        result.constructor = self.constructor.clone(new_class_name)
+        result.methods = [ x.clone(new_class_name) for x in self.methods ]
+        result.attributes = self.attributes.clone(new_class_name)
+
+        return result
+
+    def add_attribute(self, attr_name, attr_type, modifier):
+        try:
+            if not self.module.classes[attr_type].is_active(): return
+        except KeyError: pass
+
+        try:
+            ## All attribute references are always borrowed - that
+            ## means we dont want to free them after accessing them
+            type_class = dispatch(attr_name, "BORROWED "+attr_type)
+        except KeyError:
+            log("Unknown attribute type %s for  %s.%s" % (attr_type,
+                                                          self.class_name,
+                                                          attr_name))
+            return
+
+        type_class.attributes.add(modifier)
+        self.attributes.add_attribute(type_class)
+
+    def add_constructor(self, method_name, args, return_type, docstring):
+        if method_name.startswith("Con"):
+            self.constructor = ConstructorMethod(self.class_name, self.base_class_name,
+                                                 method_name, args, return_type,
+                                                 myclass = self)
+            self.constructor.docstring = docstring
+
+    def struct(self,out):
+        out.write("""\ntypedef struct {
+  PyObject_HEAD
+  %(class_name)s base;
+  void *ctx;
+} py%(class_name)s;\n
+""" % dict(class_name=self.class_name))
+
+    def code(self, out):
+        if not self.constructor:
+            raise RuntimeError("No constructor found for class %s" % self.class_name)
+
+        self.constructor.write_destructor(out)
+        self.constructor.write_definition(out)
+        if self.attributes:
+            self.attributes.write_definition(out)
+
+        for m in self.methods:
+            m.write_definition(out)
+
+    def initialise(self):
+        return "python_wrappers[TOTAL_CLASSES].class_ref = (Object)&__%s;\n" \
+            "python_wrappers[TOTAL_CLASSES++].python_type = &%s_Type;\n" % (
+            self.class_name, self.class_name)
+
+    def PyMethodDef(self, out):
+        out.write("static PyMethodDef %s_methods[] = {\n" % self.class_name)
+        for method in self.methods:
+            method.PyMethodDef(out)
+
+        out.write("     {NULL}  /* Sentinel */\n};\n")
+
+    def prototypes(self, out):
+        """ Write prototype suitable for .h file """
+        out.write("""staticforward PyTypeObject %s_Type;\n""" % self.class_name)
+        self.constructor.prototype(out)
+
+        if self.attributes:
+            self.attributes.prototype(out)
+        for method in self.methods:
+            method.prototype(out)
+
+    def numeric_protocol_int(self):
+        pass
+
+    def numeric_protocol_nonzero(self):
+        return """
+static int
+%(class_name)s_nonzero(py%(class_name)s *v)
+{
+        return v->base != 0;
+};
+""" % self.__dict__
+
+    def numeric_protocol(self, out):
+        args = {'class':self.class_name}
+        for type, func in [ ('nonzero', self.numeric_protocol_nonzero),
+                            ('int', self.numeric_protocol_int) ]:
+            definition = func()
+            if definition:
+                out.write(definition)
+                args[type] = "%s_%s" % (self.class_name,type)
+            else:
+                args[type] = '0'
+
+        out.write("""
+static PyNumberMethods %(class)s_as_number = {
+        (binaryfunc)    0,       /*nb_add*/
+        (binaryfunc)    0,       /*nb_subtract*/
+        (binaryfunc)    0,       /*nb_multiply*/
+                        0,       /*nb_divide*/
+                        0,       /*nb_remainder*/
+                        0,       /*nb_divmod*/
+                        0,       /*nb_power*/
+        (unaryfunc)     0,       /*nb_negative*/
+        (unaryfunc)     0,       /*tp_positive*/
+        (unaryfunc)     0,       /*tp_absolute*/
+        (inquiry)       %(nonzero)s,   /*tp_nonzero*/
+        (unaryfunc)     0,       /*nb_invert*/
+                        0,       /*nb_lshift*/
+        (binaryfunc)    0,       /*nb_rshift*/
+                        0,       /*nb_and*/
+                        0,       /*nb_xor*/
+                        0,       /*nb_or*/
+                        0,       /*nb_coerce*/
+         (unaryfunc)    %(int)s,       /*nb_int*/
+                        0,       /*nb_long*/
+                        0,       /*nb_float*/
+                        0,       /*nb_oct*/
+                        0,       /*nb_hex*/
+        0,                              /* nb_inplace_add */
+        0,                              /* nb_inplace_subtract */
+        0,                              /* nb_inplace_multiply */
+        0,                              /* nb_inplace_divide */
+        0,                              /* nb_inplace_remainder */
+        0,                              /* nb_inplace_power */
+        0,                              /* nb_inplace_lshift */
+        0,                              /* nb_inplace_rshift */
+        0,                              /* nb_inplace_and */
+        0,                              /* nb_inplace_xor */
+        0,                              /* nb_inplace_or */
+        0,                              /* nb_floor_divide */
+        0,                              /* nb_true_divide */
+        0,                              /* nb_inplace_floor_divide */
+        0,                              /* nb_inplace_true_divide */
+        0,                              /* nb_index */
+};
+"""  % args)
+        return "&%(class)s_as_number" % args
+
+    def PyTypeObject(self, out):
+        args = {'class':self.class_name, 'module': self.module.name, 
+                'iterator': 0,
+                'iternext': 0,
+                'tp_str': 0,
+                'getattr_func': 0,
+                'docstring': "%s: %s" % (self.class_name, 
+                                         escape_for_string(self.docstring))}
+
+        if self.attributes:
+            args['getattr_func'] = self.attributes.name
+
+        args['numeric_protocol'] = self.numeric_protocol(out)
+        if "ITERATOR" in self.modifier:
+            args['iterator'] = "PyObject_SelfIter"
+            args['iternext'] = "py%s_iternext" % self.class_name
+
+        if "SELF_ITER" in self.modifier:
+            args['iterator'] = 'py%s___iter__' % self.class_name
+
+        if "TP_STR" in self.modifier:
+            args['tp_str'] = 'py%s___str__' % self.class_name
+
+        out.write("""
+static PyTypeObject %(class)s_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /* ob_size */
+    "%(module)s.%(class)s",               /* tp_name */
+    sizeof(py%(class)s),            /* tp_basicsize */
+    0,                         /* tp_itemsize */
+    (destructor)%(class)s_dealloc,/* tp_dealloc */
+    0,                         /* tp_print */
+    0,                         /* tp_getattr */
+    0,                         /* tp_setattr */
+    0,                         /* tp_compare */
+    0,                         /* tp_repr */
+    %(numeric_protocol)s,      /* tp_as_number */
+    0,                         /* tp_as_sequence */
+    0,                         /* tp_as_mapping */
+    0,                         /* tp_hash */
+    0,                         /* tp_call */
+    (reprfunc)%(tp_str)s,      /* tp_str */
+    (getattrofunc)%(getattr_func)s,                         /* tp_getattro */
+    0,                         /* tp_setattro */
+    0,                         /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /* tp_flags */
+    "%(docstring)s",     /* tp_doc */
+    0,	                       /* tp_traverse */
+    0,                         /* tp_clear */
+    0,                         /* tp_richcompare */
+    0,                         /* tp_weaklistoffset */
+    (getiterfunc)%(iterator)s,              /* tp_iter */
+    (iternextfunc)%(iternext)s,/* tp_iternext */
+    %(class)s_methods,         /* 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 */
+    (initproc)py%(class)s_init,      /* tp_init */
+    0,                         /* tp_alloc */
+    0,                         /* tp_new */
+};
+""" % args )
+
+class StructGenerator(ClassGenerator):
+    """ A wrapper generator for structs """
+    def __init__(self, class_name, module):
+        self.class_name = class_name
+        self.methods = []
+        self.module = module
+        self.base_class_name = None
+        self.active = False
+        self.modifier = set()
+        self.constructor = None
+        self.attributes = GetattrMethod(self.class_name, self.base_class_name, self)
+
+    def prepare(self):
+        ## This is needed for late stage initialization - sometimes
+        ## our class_name is not know until now.
+        if not self.constructor:
+            self.constructor = StructConstructor(self.class_name, self.base_class_name,
+                                                 'Con', [], "void", myclass = self)
+
+            self.attributes.rename_class_name(self.class_name)
+            for x in self.attributes._attributes:
+                x[1].attributes.add('FOREIGN')
+
+    def __str__(self):
+        result = "#%s\n" % self.docstring
+
+        result += "Struct %s:\n" % (self.class_name)
+        result += "%s\n" % self.attributes
+
+        return result
+
+    def struct(self, out):
+        out.write("""\ntypedef struct {
+  PyObject_HEAD
+  %(class_name)s *base;
+  void *ctx;
+} py%(class_name)s;\n
+""" % dict(class_name=self.class_name))
+
+    def initialise(self):
+        return ''
+
+class ProxyClassGenerator(ClassGenerator):
+    def __init__(self, class_name, base_class_name, module, *args, **kwargs):
+        ClassGenerator.__init__(self, class_name, base_class_name, module, *args, **kwargs)
+        self.constructor = ProxyConstructor(self.class_name,
+                                            self.base_class_name, '__init__',
+                                            [('PyObject *', 'proxied')],
+                                            'void', myclass = self)
+        self.module = module
+        self.attributes = ProxiedGetattr(self.class_name, self.base_class_name, self)
+
+
+    def initialise(self):
+        return "INIT_CLASS(%(class_name)s);\n" % self.__dict__ + ClassGenerator.initialise(self)
+
+    def struct(self, out):
+        out.write("""
+// The proxied type is an extension of the wrapped type with a pointer
+// to the proxied PyObject.
+CLASS(%(class_name)s, %(base_class_name)s)
+   uint32_t magic;
+   PyObject *proxied;
+END_CLASS
+
+VIRTUAL(%(class_name)s, %(base_class_name)s) {
+} END_VIRTUAL
+
+typedef struct {
+  PyObject_HEAD
+  %(class_name)s base;
+  void *ctx;
+} py%(class_name)s;\n
+""" % self.__dict__)
+
+    def PyMethodDef(self, out):
+        out.write("static PyMethodDef %s_methods[] = {\n" % self.class_name)
+        ## For now no methods
+        out.write("     {NULL}  /* Sentinel */\n};\n")
+
+class parser:
+    class_re = re.compile(r"^([A-Z]+)?\s*CLASS\(([A-Z_a-z0-9]+)\s*,\s*([A-Z_a-z0-9]+)\)")
+    method_re = re.compile(r"^\s*([0-9A-Z_a-z ]+\s+\*?)METHOD\(([A-Z_a-z0-9]+),\s*([A-Z_a-z0-9]+),?")
+    enum_start_re = re.compile(r'enum ([0-9A-Z_a-z]+) {')
+    enum_re = re.compile(r'([0-9A-Z_a-z]+) = [^,]+,')
+    enum_end_re = re.compile('}')
+    arg_re = re.compile(r"\s*([0-9A-Z a-z_]+\s+\*?)([0-9A-Za-z_]+),?")
+    constant_re = re.compile(r"#define\s+([A-Z_0-9]+)\s+[^\s]+")
+    struct_re = re.compile(r"([A-Z]+)?\s+(typedef )?struct\s+([A-Z_a-z0-9]+)\s+{")
+    proxy_class_re = re.compile(r"^([A-Z]+)?\s*PROXY_CLASS\(([A-Za-z0-9]+)\)")
+    end_class_re = re.compile("END_CLASS")
+    attribute_re = re.compile(r"^\s*([0-9A-Z_a-z ]+\s+\*?)\s*([A-Z_a-z]+)\s*;")
+    comment_re = re.compile(r"^\s*//")
+    comment_start_re = re.compile(r"/\*+")
+    comment_end_re = re.compile(r"\*+/")
+    blank_line_re = re.compile("\s+")
+    typedef_re = re.compile("typedef ([A-Za-z_0-9]+) +([A-Za-z_0-9]+) *;")
+    bind_re = re.compile("BIND\(([a-zA-Z_0-9]+)\);")
+    current_class = None
+
+    def __init__(self, module, verbosity=0):
+        self.module = module
+        self.current_comment = ''
+        self.verbosity = verbosity
+        self.state = 'DEFAULT'
+
+        ## this is a list of objects which are to be bound
+        self.to_bind = []
+
+        global DEBUG
+
+        DEBUG = verbosity
+
+        io = StringIO.StringIO("""
+// Base object
+CLASS(Object, Obj)
+END_CLASS
+""")
+        self.parse_fd(io, '')
+
+    def add_class(self, class_name, base_class_name, class_type, handler, docstring, modifier):
+        try:
+            self.current_class = self.module.classes[base_class_name].clone(class_name)
+        except (KeyError, AttributeError):
+            log("Base class %s is not defined !!!!" % base_class_name)
+            self.current_class = class_type(class_name, base_class_name, self.module)
+
+        ## Now add the new class to the module object
+        self.current_class.docstring = docstring
+        self.current_class.modifier = modifier
+        self.module.add_class(self.current_class, handler)
+
+    def parse_filenames(self, filenames):
+        ## Be quiet for the first pass as many problems will be
+        ## resolved on the second pass anyway.
+        global DEBUG
+        DEBUG = 0
+        for f in filenames:
+            self._parse(f)
+
+        DEBUG = self.verbosity
+        log("Second pass: Consolidating definitions")
+        for f in filenames:
+            self._parse(f)
+
+    def _parse(self, filename):
+        fd = open(filename)
+        self.parse_fd(fd, filename)
+        fd.close()
+
+        if filename not in self.module.files:
+              self.module.headers += '#include "%s"\n' % filename
+              self.module.files.append(filename)
+
+    def parse_fd(self, fd, filename):
+        self.current_class = None
+        self.current_comment = ''
+
+        while 1:
+            line = fd.readline()
+            if not line: break
+
+            ## Handle binds
+            m= self.bind_re.search(line)
+            if m:
+                print "Will bind %s" % m.group(1)
+                self.to_bind.append(m.group(1))
+                continue
+
+            ## Handle enums
+            if self.state == 'DEFAULT':
+                m = self.enum_start_re.search(line)
+                if m:
+                    self.state = 'enum'
+                    type_dispatcher[m.group(1)] = type_dispatcher['int']
+                    continue
+
+            elif self.state == 'enum':
+                m = self.enum_re.search(line)
+                if m:
+                    self.module.add_constant(m.group(1), 'integer')
+
+                if '}' in line:
+                    self.state = 'DEFAULT'
+                    continue
+
+            ## Handle c++ style comments //
+            m = self.comment_re.match(line)
+            if m:
+                self.current_comment = line[m.end():]
+                while 1:
+                    line = fd.readline()
+
+                    m = self.comment_re.match(line)
+                    if not m:
+                        break
+
+                    self.current_comment += line[m.end():]
+
+            ## Multiline C style comments
+            m = self.comment_start_re.search(line)
+            if m:
+                line = line[m.end():]
+                while 1:
+                    m = self.comment_end_re.search(line)
+                    if m:
+                        self.current_comment += line[:m.start()]
+                        line = fd.readline()
+                        break
+                    else:
+                        self.current_comment += line
+
+                    line = fd.readline()
+                    if not line: break
+
+            ## Handle simple typdefs (as if typedef uint64_t my_fancy_type;)
+            m = self.typedef_re.search(line)
+            if m:
+                ## We basically add a new type as a copy of the old
+                ## type
+                old, new = m.group(1), m.group(2)
+                if old in type_dispatcher:
+                    type_dispatcher[new] = type_dispatcher[old]
+
+            ## Handle constant #define
+            m = self.constant_re.search(line)
+            if m:
+                ## We need to determine if it is a string or integer
+                if re.search('"', line):
+                    ## Its a string
+                    self.module.add_constant(m.group(1), 'string')
+                else:
+                    self.module.add_constant(m.group(1), 'integer')
+
+            ## Wrap structs
+            m = self.struct_re.search(line)
+            if m:
+                modifier = m.group(1)
+                class_name = m.group(3)
+                base_class_name = None
+                ## Structs may be refered to as a pointer or absolute
+                ## - its the same thing ultimatley.
+
+                ## We only wrap structures which are explicitely bound
+                if (modifier and 'BOUND' in modifier) or \
+                        class_name in self.to_bind:
+                    self.add_class(class_name, base_class_name, StructGenerator, StructWrapper,
+                                   self.current_comment, modifier)
+                    type_dispatcher["%s *" % class_name] = PointerStructWrapper
+
+                continue
+
+            m = self.class_re.search(line)
+            if m:
+                ## We need to make a new class now... We basically
+                ## need to build on top of previously declared base
+                ## classes - so we try to find base classes, clone
+                ## them if possible:
+                modifier = m.group(1)
+                class_name = m.group(2)
+                base_class_name = m.group(3)
+                self.add_class(class_name, base_class_name, ClassGenerator, Wrapper,
+                               self.current_comment, modifier)
+                type_dispatcher["%s *" % class_name] = PointerWrapper
+
+                continue
+
+            ## Make a proxy class for python callbacks
+            m = self.proxy_class_re.search(line)
+            if m:
+                modifier = m.group(1)
+                base_class_name = m.group(2)
+                class_name = "Proxied%s" % base_class_name
+                try:
+                    proxied_class = self.module.classes[base_class_name]
+                except KeyError:
+                    raise RuntimeError("Need to create a proxy for %s but it has not been defined (yet). You must place the PROXIED_CLASS() instruction after the class definition" % base_class_name)
+                self.current_class = ProxyClassGenerator(class_name,
+                                                         base_class_name, self.module)
+                #self.current_class.constructor.args += proxied_class.constructor.args
+                self.current_class.docstring = self.current_comment
+
+                ## Create proxies for all these methods
+                for method in proxied_class.methods:
+                    self.current_class.methods.append(ProxiedMethod(method, self.current_class))
+
+                self.module.add_class(self.current_class, Wrapper)
+
+                ## Make sure that further lines are not interpreted as part of this class.
+                self.current_class = None
+
+            m = self.method_re.search(line)
+            if self.current_class and m:
+                args = []
+                method_name = m.group(3)
+                return_type = m.group(1).strip()
+                ## Ignore private methods
+                if return_type.startswith("PRIVATE"): continue
+
+                ## Now parse the args
+                offset = m.end()
+                while 1:
+                    m = self.arg_re.match(line[offset:])
+                    if not m:
+                        ## Allow multiline definitions if there is \\
+                        ## at the end of the line
+                        if line.strip().endswith("\\"):
+                            line = fd.readline()
+                            offset = 0
+                            if line:
+                                continue
+
+                        break
+
+                    offset += m.end()
+                    args.append([m.group(1).strip(), m.group(2).strip()])
+
+                if return_type == self.current_class.class_name and \
+                        method_name.startswith("Con"):
+                    self.current_class.add_constructor(method_name, args, return_type,
+                                                       self.current_comment)
+                else:
+                    self.current_class.add_method(method_name, args, return_type,
+                                                  self.current_comment)
+
+            m = self.attribute_re.search(line)
+            if self.current_class and m:
+                type = m.group(1)
+                name = m.group(2)
+                self.current_class.add_attribute(name, type)
+
+            m = self.end_class_re.search(line)
+            if m:
+                ## Just clear the current class context
+                self.current_class = None
+
+            ## If this is a shadow file we do not include it from the
+            ## main module. A shadow file is a way for us to redefine
+            ## other C constructs which will be imported from an
+            ## external header file so we can bind them slightly
+            ## differently.
+            if "this is a shadow file" in self.current_comment \
+                    and filename not in self.module.files:
+                self.module.files.append(filename)
+
+            ## We only care about comment immediately above methods
+            ## etc as we take them to be documentation. If we get here
+            ## the comment is not above anything we care about - so we
+            ## clear it:
+            self.current_comment = ''
+
+    def write(self, out):
+        self.module.write(out)
+
+
+import lexer
+
+class EnumConstructor(ConstructorMethod):
+    def write_destructor(self, out):
+        out.write("""static void
+%(class_name)s_dealloc(py%(class_name)s *self) {
+ Py_DECREF(self->value);
+ PyObject_Del(self);
+};\n
+""" % dict(class_name = self.class_name))
+    def write_definition(self, out):
+        self.myclass.modifier.add("TP_STR")
+        self._prototype(out)
+        out.write("""{
+static char *kwlist[] = {"value", NULL};
+
+if(!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &self->value))
+ goto error;
+
+Py_INCREF(self->value);
+
+  return 0;
+error:
+    return -1;
+};
+
+static PyObject *py%(class_name)s___str__(py%(class_name)s *self) {
+  PyObject *result = PyDict_GetItem(%(class_name)s_rev_lookup, self->value);
+
+  if(result) {
+     Py_INCREF(result);
+ } else {
+     result = PyObject_Str(self->value);
+ };
+
+ return result;
+};
+
+""" % self.__dict__)
+
+class Enum(StructGenerator):
+    def __init__(self, name, module):
+        StructGenerator.__init__(self, name, module)
+        self.values = []
+        self.name = name
+        self.attributes = None
+        self.active = True
+
+    def prepare(self):
+        self.constructor = EnumConstructor(self.class_name, self.base_class_name,
+                                           'Con', [], "void", myclass = self)
+        StructGenerator.prepare(self)
+
+    def __str__(self):
+        result = "Enum %s:\n" % (self.name)
+        for attr in self.values:
+            result += "    %s\n" % attr.__str__()
+
+        return result
+
+    def struct(self,out):
+        out.write("""\ntypedef struct {
+  PyObject_HEAD
+  PyObject *value;
+} py%(class_name)s;\n
+
+
+static PyObject *%(class_name)s_Dict_lookup;
+static PyObject *%(class_name)s_rev_lookup;
+""" % dict(class_name=self.class_name))
+
+    def PyMethodDef(self, out):
+        out.write("static PyMethodDef %s_methods[] = {\n" % self.class_name)
+        out.write("     {NULL}  /* Sentinel */\n};\n")
+
+    def numeric_protocol_nonzero(self):
+        pass
+
+    def numeric_protocol_int(self):
+        return """
+static PyObject *%(class_name)s_int(py%(class_name)s *self) {
+    Py_INCREF(self->value);
+    return self->value;
+};
+""" % self.__dict__
+
+    def initialise(self):
+        result = """
+%(class_name)s_Dict_lookup = PyDict_New();
+%(class_name)s_rev_lookup = PyDict_New();
+""" % self.__dict__
+
+        if self.values:
+            result += "{ PyObject *tmp, *tmp2;\n"
+            for attr in self.values:
+                result += ''' tmp = PyLong_FromLong(%(value)s);
+  tmp2 = PyString_FromString("%(value)s");
+  PyDict_SetItem(%(class_name)s_Dict_lookup, tmp2, tmp);
+  PyDict_SetItem(%(class_name)s_rev_lookup, tmp, tmp2);
+  Py_DECREF(tmp);
+  Py_DECREF(tmp2);
+
+''' % dict(value = attr, class_name=self.class_name)
+            result += "};\n"
+
+        return result
+
+class EnumType(Integer):
+    buildstr = 'i'
+
+    def __init__(self, name, type):
+        Integer.__init__(self, name, type)
+        self.type = type
+
+    def to_python_object(self, name=None, result='py_result', **kw):
+        name = name or self.name
+        return """PyErr_Clear();
+%s = PyObject_CallMethod(g_module, "%s", "K", (uint64_t)%s);
+""" % (result, self.type, name)
+
+    def pre_call(self, method):
+        method.error_set = True
+        return """
+// Check if the integer passed is actually a valid member of the enum
+// Enum value of 0 is always allowed
+if(%(name)s) { PyObject *py_%(name)s = PyLong_FromLong(%(name)s);
+  PyObject *tmp = PyDict_GetItem(%(type)s_rev_lookup, py_%(name)s);
+
+  Py_DECREF(py_%(name)s);
+  if(!tmp) {
+    PyErr_Format(PyExc_RuntimeError, "value %%lu is not valid for Enum %(type)s of arg '%(name)s'", (unsigned long)%(name)s);
+    goto error;
+  };
+  Py_DECREF(tmp);
+};
+""" % self.__dict__
+
+class HeaderParser(lexer.SelfFeederMixIn):
+    tokens = [
+        [ 'INITIAL', r'#define\s+', 'PUSH_STATE', 'DEFINE' ],
+        [ 'DEFINE', r'([A-Za-z_0-9]+)\s+[^\n]+', 'DEFINE,POP_STATE', None ],
+        [ 'DEFINE', r'\n', 'POP_STATE', None],
+
+        ## Recognize ansi c comments
+        [ '.', r'/\*(.)', 'PUSH_STATE', 'COMMENT' ],
+        [ 'COMMENT', r'(.+?)\*/\s+', 'COMMENT_END,POP_STATE', None],
+        [ 'COMMENT', r'(.+)', 'COMMENT', None],
+
+        ## And c++ comments
+        [ '.', r'//([^\n]+)', 'COMMENT', None],
+
+        ## An empty line clears the current comment
+        [ '.', r'\r?\n\r?\n', 'CLEAR_COMMENT', None],
+
+        ## Ignore whitespace
+        [ '.', r'\s+', 'SPACE', None ],
+        [ '.', r'\\\n', 'SPACE', None ],
+
+        ## Recognize CLASS() definitions
+        [ 'INITIAL', r"^([A-Z]+)?\s*CLASS\(([A-Z_a-z0-9]+)\s*,\s*([A-Z_a-z0-9]+)\)",
+                     'PUSH_STATE,CLASS_START', 'CLASS'],
+
+        [ 'CLASS', r"^\s*(FOREIGN|ABSTRACT|PRIVATE)?([0-9A-Z_a-z ]+( |\*))METHOD\(([A-Z_a-z0-9]+),\s*([A-Z_a-z0-9]+),?",
+                     "PUSH_STATE,METHOD_START", "METHOD"],
+        [ 'METHOD', r"\s*([0-9A-Z a-z_]+\s+\*?\*?)([0-9A-Za-z_]+),?", "METHOD_ARG", None ],
+        [ 'METHOD', r'\);', 'POP_STATE,METHOD_END', None],
+
+        [ 'CLASS', r"^\s*(FOREIGN|ABSTRACT)?([0-9A-Z_a-z ]+\s+\*?)\s*([A-Z_a-z0-9]+)\s*;",
+                   'CLASS_ATTRIBUTE', None],
+        [ 'CLASS', "END_CLASS", 'END_CLASS,POP_STATE', None],
+
+        ## Recognize struct definitions (With name)
+        [ 'INITIAL', "([A-Z_a-z0-9 ]+)?struct\s+([A-Z_a-z0-9]+)\s+{",
+                     'PUSH_STATE,STRUCT_START', 'STRUCT'],
+
+        ## Without name (using typedef)
+        [ 'INITIAL', "typedef\s+struct\s+{",
+                     'PUSH_STATE,TYPEDEF_STRUCT_START', 'STRUCT'],
+
+        [ 'STRUCT', r"^\s*([0-9A-Z_a-z ]+\s+\*?)\s*([A-Z_a-z0-9]+)\s*;",
+                     'STRUCT_ATTRIBUTE', None],
+
+        [ 'STRUCT', r"^\s*([0-9A-Z_a-z ]+)\*\s+([A-Z_a-z0-9]+)\s*;",
+                     'STRUCT_ATTRIBUTE_PTR', None],
+
+        ## Struct ended with typedef
+        [ 'STRUCT', '}\s+([0-9A-Za-z_]+);', 'POP_STATE,TYPEDEF_STRUCT_END', None],
+        [ 'STRUCT', '}', 'POP_STATE,STRUCT_END', None],
+
+        ## Handle recursive struct or union definition (At the moment
+        ## we cant handle them at all)
+        [ '(RECURSIVE_)?STRUCT', '(struct|union)\s+([_A-Za-z0-9]+)?\s*{', 'PUSH_STATE', 'RECURSIVE_STRUCT'],
+        [ 'RECURSIVE_STRUCT', '}\s+[0-9A-Za-z]+', 'POP_STATE', None],
+
+        ## Process enums (2 forms - named and typedefed)
+        [ 'INITIAL', r'enum\s+([0-9A-Za-z_]+)\s+{', 'PUSH_STATE,ENUM_START', 'ENUM' ],
+        ## Unnamed
+        [ 'INITIAL', r'typedef\s+enum\s+{', 'PUSH_STATE,TYPEDEF_ENUM_START', 'ENUM' ],
+        [ 'ENUM', r'([0-9A-Za-z_]+)\s+=[^\n]+', 'ENUM_VALUE', None],
+
+        ## Typedefed ending
+        [ 'ENUM', r'}\s+([0-9A-Za-z_]+);', 'POP_STATE,TYPEDEFED_ENUM_END', None],
+        [ 'ENUM', r'}', 'POP_STATE,ENUM_END', None],
+
+        [ 'INITIAL', r'BIND_STRUCT\(([0-9A-Za-z_ \*]+)\)', 'BIND_STRUCT', None],
+
+        ## A simple typedef of one type for another type:
+        [ 'INITIAL', r"typedef ([A-Za-z_0-9]+) +([^;]+);", 'SIMPLE_TYPEDEF', None],
+
+        ## Handle proxied directives
+        [ 'INITIAL', r"PROXY_CLASS\(([A-Za-z0-9]+)\);", 'PROXY_CLASS', None],
+
+        ]
+
+    def __init__(self, name, verbose = 1):
+        self.module = Module(name)
+        lexer.SelfFeederMixIn.__init__(self, verbose = 0)
+
+        io = StringIO.StringIO("""
+// Base object
+CLASS(Object, Obj)
+END_CLASS
+""")
+        self.parse_fd(io)
+
+    current_comment = ''
+    def COMMENT(self, t, m):
+        self.current_comment += m.group(1) + "\n"
+
+    def COMMENT_END(self, t, m):
+        self.current_comment += m.group(1)
+
+    def CLEAR_COMMENT(self, t, m):
+        self.current_comment = ''
+
+    def DEFINE(self, t, m):
+        line = m.group(0)
+        line = line.split('/*')[0]
+        if '"' in line:
+            type = 'string'
+        else:
+            type = 'integer'
+
+        name = m.group(1).strip()
+        if len(name)>3 and name[0]!='_' and name==name.upper():
+            self.module.add_constant(name, type)
+
+    current_class = None
+    def CLASS_START(self, t, m):
+        class_name = m.group(2).strip()
+        base_class_name = m.group(3).strip()
+
+        try:
+            self.current_class = self.module.classes[base_class_name].clone(class_name)
+        except (KeyError, AttributeError):
+            log("Base class %s is not defined !!!!" % base_class_name)
+            self.current_class = ClassGenerator(class_name, base_class_name, self.module)
+
+        self.current_class.docstring = self.current_comment
+        self.current_class.modifier.add(m.group(1))
+        self.module.add_class(self.current_class, Wrapper)
+        type_dispatcher["%s *" % class_name] = PointerWrapper
+
+    current_method = None
+    def METHOD_START(self, t, m):
+        return_type = m.group(2).strip()
+        method_name = m.group(5).strip()
+        modifier = m.group(1) or ''
+
+        if 'PRIVATE' in modifier: return
+
+        ## Is it a regular method or a constructor?
+        self.current_method = Method
+        if return_type == self.current_class.class_name and \
+                method_name.startswith("Con"):
+            self.current_method = ConstructorMethod
+        elif method_name == 'iternext':
+            self.current_method = IteratorMethod
+            self.current_class.modifier.add("ITERATOR")
+        elif method_name == '__iter__':
+            self.current_method = SelfIteratorMethod
+            self.current_class.modifier.add("SELF_ITER")
+        elif method_name == '__str__':
+            self.current_class.modifier.add("TP_STR")
+
+        self.current_method = self.current_method(self.current_class.class_name,
+                                                  self.current_class.base_class_name,
+                                                  method_name, [], return_type,
+                                                  myclass = self.current_class)
+        self.current_method.docstring = self.current_comment
+        self.current_method.modifier = modifier
+
+    def METHOD_ARG(self, t, m):
+        name = m.group(2).strip()
+        type = m.group(1).strip()
+        if self.current_method:
+            self.current_method.add_arg(type, name)
+
+    def METHOD_END(self, t, m):
+        if not self.current_method: return
+
+        if isinstance(self.current_method, ConstructorMethod):
+            self.current_class.constructor = self.current_method
+        else:
+            found = False
+            for i in range(len(self.current_class.methods)):
+                ## Try to replace existing methods with this new method
+                method = self.current_class.methods[i]
+                if method.name == self.current_method.name:
+                    self.current_class.methods[i] = self.current_method
+                    self.current_method = None
+                    return
+
+            ## Method does not exist, just add to the end
+            self.current_class.methods.append(self.current_method)
+
+        self.current_method = None
+
+    def CLASS_ATTRIBUTE(self, t, m):
+        modifier = m.group(1) or ''
+        type = m.group(2).strip()
+        name = m.group(3).strip()
+        self.current_class.add_attribute(name, type, modifier)
+
+    def END_CLASS(self, t, m):
+        self.current_class = None
+
+    current_struct = None
+    def STRUCT_START(self, t, m):
+        self.current_struct = StructGenerator(m.group(2).strip(), self.module)
+        self.current_struct.docstring = self.current_comment
+        self.current_struct.modifier.add(m.group(1))
+
+    def TYPEDEF_STRUCT_START(self, t, m):
+        self.current_struct = StructGenerator(None, self.module)
+        self.current_struct.docstring = self.current_comment
+
+    def STRUCT_ATTRIBUTE(self, t, m):
+        name = m.group(2).strip()
+        type = m.group(1).strip()
+        self.current_struct.add_attribute(name, type, '')
+
+    def STRUCT_ATTRIBUTE_PTR(self, t, m):
+        type = "%s *" % m.group(1).strip()
+        name = m.group(2).strip()
+        self.current_struct.add_attribute(name, type, '')
+
+    def STRUCT_END(self, t, m):
+        self.module.add_class(self.current_struct, StructWrapper)
+        type_dispatcher["%s *" % self.current_struct.class_name] = PointerStructWrapper
+        self.current_struct = None
+
+    def TYPEDEF_STRUCT_END(self, t, m):
+        self.current_struct.class_name = m.group(1).strip()
+
+        self.STRUCT_END(t, m)
+
+    current_enum = None
+    def ENUM_START(self, t, m):
+        self.current_enum = Enum(m.group(1).strip(), self.module)
+
+    def TYPEDEF_ENUM_START(self, t, m):
+        self.current_enum = Enum(None, self.module)
+
+    def ENUM_VALUE(self, t, m):
+        self.current_enum.values.append(m.group(1).strip())
+
+    def ENUM_END(self, t, m):
+        self.module.classes[self.current_enum.name] = self.current_enum
+
+        ## For now we just treat enums as an integer, and also add
+        ## them to the constant table. In future it would be nice to
+        ## have them as a proper python object so we can override
+        ## __str__ and __int__.
+        for attr in self.current_enum.values:
+            self.module.add_constant(attr, 'integer')
+
+        #type_dispatcher[self.current_enum.name] = Integer
+        type_dispatcher[self.current_enum.name] = EnumType
+        self.current_enum = None
+
+    def TYPEDEFED_ENUM_END(self, t, m):
+        self.current_enum.name = self.current_enum.class_name = m.group(1)
+        self.ENUM_END(t, m)
+
+    def BIND_STRUCT(self, t, m):
+        self.module.classes[m.group(1)].active = True
+
+    def SIMPLE_TYPEDEF(self, t, m):
+        ## We basically add a new type as a copy of the old
+        ## type
+        old, new = m.group(1).strip(), m.group(2).strip()
+        if old in type_dispatcher:
+            type_dispatcher[new] = type_dispatcher[old]
+
+    def PROXY_CLASS(self, t, m):
+        base_class_name = m.group(1).strip()
+        class_name = "Proxied%s" % base_class_name
+        try:
+            proxied_class = self.module.classes[base_class_name]
+        except KeyError:
+            raise RuntimeError("Need to create a proxy for %s but it has not been defined (yet). You must place the PROXIED_CLASS() instruction after the class definition" % base_class_name)
+        current_class = ProxyClassGenerator(class_name,
+                                            base_class_name, self.module)
+        #self.current_class.constructor.args += proxied_class.constructor.args
+        current_class.docstring = self.current_comment
+
+        ## Create proxies for all these methods
+        for method in proxied_class.methods:
+            current_class.methods.append(ProxiedMethod(method, current_class))
+
+        self.module.add_class(current_class, Wrapper)
+
+    def parse_filenames(self, filenames):
+        for f in filenames:
+            self._parse(f)
+
+        ## Second pass
+        for f in filenames:
+            self._parse(f)
+
+    def _parse(self, filename):
+        fd = open(filename)
+        self.parse_fd(fd)
+        fd.close()
+
+        if filename not in self.module.files:
+              self.module.headers += '#include "%s"\n' % filename
+              self.module.files.append(filename)
+
+    def write(self, out):
+        self.module.write(out)
+
+
+if __name__ == '__main__':
+    p = HeaderParser('pyaff4', verbose = 1)
+    for arg in sys.argv[1:]:
+        p.parse_fd(open(arg))
+
+    log("second parse")
+    for arg in sys.argv[1:]:
+        p.parse_fd(open(arg))
+
+    pdb.set_trace()
+    p.write(sys.stdout)
+
+#    p = parser(Module("pyaff4"))
+#    for arg in sys.argv[1:]:
+#        p.parse(arg)
+#        log("second parse")
+#        p.parse(arg)
+
+#    p.write(sys.stdout)
+
Index: trunk/python2/config.py
===================================================================
--- trunk/python2/config.py	(revision 196)
+++ trunk/python2/config.py	(revision 196)
@@ -0,0 +1,2 @@
+MINGW_XCOMPILE = False
+V = True
Index: trunk/python2/include/aff4_errors.h
===================================================================
--- trunk/python2/include/aff4_errors.h	(revision 196)
+++ trunk/python2/include/aff4_errors.h	(revision 196)
@@ -0,0 +1,67 @@
+/*
+** aff4_errors.h
+** 
+** Made by mic
+** Login   <mic@laptop>
+** 
+** Started on  Sat Mar  6 20:54:25 2010 mic
+** Last update Sat Mar  6 20:54:25 2010 mic
+*/
+
+#ifndef   	AFF4_ERRORS_H_
+# define   	AFF4_ERRORS_H_
+
+// Some helpful little things
+#define ERROR_BUFFER_SIZE 1024
+
+/** This is used for error reporting. This is similar to the way
+    python does it, i.e. we set the error flag and return NULL.
+*/
+enum _error_type {
+  EZero,EGeneric,EOverflow,EWarning,
+  EUnderflow,EIOError, ENoMemory, EInvalidParameter, ERuntimeError, EKeyError,
+
+  // Reserved for impossible conditions
+  EProgrammingError
+};
+
+void *raise_errors(enum _error_type t, char *string,  ...);
+
+/** We only set the error state if its not already set */
+#define RaiseError(t, message, ...)                                     \
+  if(*aff4_get_current_error(NULL) == EZero) {                          \
+    raise_errors(t, "%s: (%s:%d) " message, __FUNCTION__, __FILE__, __LINE__, ## __VA_ARGS__); \
+  };
+
+#define LogWarnings(format, ...)		\
+  do {						\
+    RaiseError(EWarning, format, ## __VA_ARGS__);	\
+    PrintError();				\
+  } while(0);
+  
+#define ClearError()				\
+  do {*aff4_get_current_error(NULL) = EZero;} while(0);
+
+#define PrintError()				\
+  do {char *error_str; if(*aff4_get_current_error(&error_str)) fprintf(stdout, "%s", error_str); fflush(stdout); ClearError(); }while(0);
+
+#define CheckError(error)			\
+  (*aff4_get_current_error(NULL) == error)
+
+/** The current error state is returned by this function.
+
+    This is done in a thread safe manner.
+ */
+enum _error_type *aff4_get_current_error(char **error_str);
+
+
+// These macros are used when we need to do something which might
+// change the error state on the error path of a function.
+#define PUSH_ERROR_STATE { enum _error_type *tmp_error_p = aff4_get_current_error(NULL); enum _error_type tmp_error = *tmp_error_p; enum _error_type exception __attribute__((unused));
+
+#define POP_ERROR_STATE *tmp_error_p = tmp_error;};
+
+
+void error_init();
+
+#endif 	    /* !AFF4_ERRORS_H_ */
Index: trunk/python2/include/class.h
===================================================================
--- trunk/python2/include/class.h	(revision 196)
+++ trunk/python2/include/class.h	(revision 196)
@@ -0,0 +1,447 @@
+/***************************************************
+  Classes and objects in C
+
+  This file makes it easy to implement classes and objects in C. To
+  define a class we need to perform three steps:
+
+  Define the class prototype. This is suitable to go in a .h file for
+  general use by other code.
+
+  Note all classes extend Object.
+
+  Example::
+
+CLASS(Foo, Object)
+    int x;
+    int y;
+
+    //This declares a method of a class Foo, called Con returning a
+    //Foo object. In other words it is a constructor.
+    Foo METHOD(Foo, Con, int x, int y);
+    int METHOD(Foo, add);
+
+END_CLASS
+
+Now we need to define some functions for the constructor and
+methods. Note that the constuctor is using ALLOCATE_CLASS to allocate
+space for the class structures. Callers may call with self==NULL to
+force allocation of a new class. Note that we do not call the
+constructor of our superclass implicitly here. (Calling the sperclass
+constructor is optional, but ALLOCATE_CLASS is not.).
+
+Foo Foo_Con(Foo self,int x,int y) {
+  self->x = x;
+  self->y = y;
+
+  return self;
+};
+
+int Foo_add(Foo this) {
+  return (this->x + this->y);
+};
+
+Now we need to define the Virtual function table - These are those
+functions and attributes which are defined in this class (over its
+superclass). Basically these are all those things in the class
+definition above, with real function names binding them. (Note that by
+convention we preceed the name of the method with the name of the
+class):
+
+VIRTUAL(Foo,Object)
+   VMETHOD(Con) = Foo_Con;
+   VMETHOD(add) = Foo_add;
+END_VIRTUAL
+
+We can use inheritance too:
+
+CLASS(Bar, Foo)
+   Bar METHOD(Bar, Con, char *something)
+END_CLASS
+
+Here Bar extends Foo and defines a new constructor with a different prototype:
+
+VIRTUAL(Bar,Foo)
+   VMETHOD(Con) = Bar_Con
+END_VIRTUAL
+
+If there is a function which expects a Foo, we will need to over ride
+the Foo constructor in the Bar, so the function will not see the
+difference between the Foo and Bar:
+
+CLASS(Bar,Foo)
+  int bar_attr;
+END_CLASS
+
+Foo Bar_Con(Foo self, int x, int y) {
+...
+}
+
+VIRTUAL(Bar, Foo)
+  VMETHOD(super.Con) = Bar_Con
+END_VIRTUAL
+
+Note that in this case we are over riding the Con method defined in
+Foo while creating derived Bar classes. The notation in the VIRTUAL
+table is to use super.Con, because Foo's Con method (the one we are
+over riding), can be located by using super.Con inside a Bar object.
+
+Imagine now that in Bar_Con we wish to use methods and attributes
+defined in Bar. Since Bar_Con over rides Bar's base class (Foo) it
+must have the prototype described above. Since self is of type Foo its
+impossible to use self->bar_attr (There is no bar_attr in Foo - its in
+Bar).
+
+In this case, we need to make a type cast to convice C that self is
+actually a Bar not a Foo:
+
+Foo Bar_Con(Foo self, int x, int y) {
+   Bar this = (Bar)self;
+
+   this->bar_attr=1
+};
+
+This allows us to access bars attributes.
+
+This is a general oddity with C style classes, which C++ and Java
+hide. In C we must always know which class defines which method and
+attribute and reference the right class's method. So for example if we
+want to call a Bar's add method:
+
+Bar a;
+
+a->super.add()
+
+because add is defined in Bar's super class (Foo). Constract this with
+C++ or Java which hide where methods are defined and simply make all
+methods appear like they were defined inside the derived class. This
+takes a while to get used to but the compiler will ensure that the
+references are correct - otherwise things will generally not compile
+properly.
+
+This difference can be used for good and bad. It is possible in C to
+call the base class's version of the method at any time (despite the
+fact it was over ridden). 
+
+For example:
+
+CLASS(Derived, Foo)
+      int METHOD(Derived, add);
+END_CLASS
+
+VIRTUAL(Derived, Foo)
+   VMETHOD(add) = Derived_add
+END_VIRTUAL
+
+If d is a Derived object, we can call Foo's version like this:
+d->super.add()
+
+But Derived's version is accessed by:
+d->add()
+
+Sometimes a derived class may want to over ride the base class's
+methods as well, in this case the VIRTUAL section should over ride
+super.add as well.
+
+*/
+/******************************************************
+# Copyright 2004: Commonwealth of Australia.
+#
+# Developed by the Computer Network Vulnerability Team,
+# Information Security Group.
+# Department of Defence.
+#
+# Michael Cohen <scudette@users.sourceforge.net>
+#
+# ******************************************************
+#  Version: FLAG  $Version: 0.87-pre1 Date: Thu Jun 12 00:48:38 EST 2008$
+# ******************************************************
+#
+# * This program is free software; you can redistribute it and/or
+# * modify it under the terms of the GNU General Public License
+# * as published by the Free Software Foundation; either version 2
+# * of the License, or (at your option) any later version.
+# *
+# * This program is distributed in the hope that it will be useful,
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# * GNU General Public License for more details.
+# *
+# * You should have received a copy of the GNU General Public License
+# * along with this program; if not, write to the Free Software
+# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+# ******************************************************/
+#ifndef __CLASS_H__
+#define __CLASS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef min
+#undef min
+#endif
+#define min(X, Y)  ((X) < (Y) ? (X) : (Y))
+
+#ifdef max
+#undef max
+#endif
+#define max(X, Y)  ((X) > (Y) ? (X) : (Y))
+
+
+#include "talloc.h"
+
+#define CLASS(class,super_class)                                 \
+  typedef struct class ## _t *class;                             \
+  int class ## _init(Object self);                               \
+  extern struct class ## _t __ ## class;                         \
+  struct class ## _t { struct super_class ## _t super;		 \
+  class   __class__;                                             \
+  super_class  __super__;
+
+
+#define METHOD(cls, name, ... )		\
+  (* name)(cls self, ## __VA_ARGS__ )
+
+  // Class methods are attached to the class but are not called with
+  // an instance. This is similar to the python class method or java
+  // static methods.
+#define CLASS_METHOD(name, ... )                \
+  (*name)(__VA_ARGS__)
+
+/***************************************************
+   This is a convenience macro which may be used if x if really large
+
+***************************************************/
+#define CALL(x, method, ... )			\
+  (x)->method((x), ## __VA_ARGS__)
+
+#define END_CLASS };
+
+/***************************************************
+   This is used to set the classes up for use:
+
+   class_init = checks the class template (__class) to see if it has
+   been allocated. otherwise allocates it in the global context.
+
+   class_Alloc = Allocates new memory for an instance of the
+   class. This is a recursive function calling each super class in
+   turn and setting the currently over ridden defaults. So for eample
+   suppose this class (foo) derives from bar, we first fill the
+   template with bars methods, and attributes. Then we over write
+   those with foos methods and attributes.
+
+**********************************************************/
+#define VIRTUAL(class,superclass)				\
+  struct class ## _t __ ## class;                                       \
+                                                                        \
+  int class ## _init(Object this) {                                    \
+  class self = (class)this;                                             \
+  if(self->__super__) return 1;                                         \
+  superclass ##_init(this);                                             \
+  this->__class__ = (Object)&__ ## class;                               \
+  self->__class__ = (class)&__ ## class;                               \
+  this->__super__ = (Object)&__ ## superclass;                          \
+  self->__super__ = (superclass)&__ ## superclass;                      \
+  this->__size = sizeof(struct class ## _t);                            \
+  this->__name__ = #class;
+
+#define SET_DOCSTRING(string)			\
+  ((Object)self)->__doc__ = string
+
+#define END_VIRTUAL return 1; };
+
+#define VMETHOD(method)				\
+  (self)->method
+
+#define VMETHOD_BASE(base, method)		\
+  (((base)self)->method)
+
+#define CLASS_ATTR(self, base, method)		\
+  (((base)self)->method)
+
+#define VATTR(attribute)			\
+  (self)->attribute
+
+#define NAMEOF(obj)				\
+  ((Object)obj)->__name__
+
+#define SIZEOF(obj)                             \
+  ((Object)obj)->__size
+
+#define DOCSTRING(obj)				\
+  ((Object)obj)->__doc__
+
+#define INIT_CLASS(class)                       \
+  class ## _init((Object)&__ ## class)
+
+/*************************************************************
+   This MACRO is used to construct a new Class using a constructor.
+
+    This is done to try and hide the bare (unbound) method names in
+    order to prevent name space pollution. (Bare methods may be
+    defined as static within the implementation file). This macro
+    ensures that class structures are initialised properly before
+    calling their constructors.
+
+   We require the following args:
+    class - the type of class to make
+    virt_class - The class where the method was defined
+    constructors - The constructor method to use
+    context - a talloc context to use.
+
+
+    Note that the class and virt_class do not have to be the same if
+    the method was not defined in the current class. For example
+    suppose Foo extends Bar, but method is defined in Bar but
+    inherited in Foo:
+
+    CONSTRUCT(Foo, Bar, super.method, context)
+
+    virt_class is Bar because thats where method was defined.
+*************************************************************/
+
+// The following only initialises the class if the __super__ element
+// is NULL. This is fast as it wont call the initaliser unnecessaily
+#define CONSTRUCT(class, virt_class, constructor, context, ... )        \
+  (class)( __## class.__super__ == NULL ?                               \
+           class ## _init((Object)&__ ## class) : 0,                    \
+           __## virt_class.__super__ == NULL ?                          \
+           virt_class ## _init((Object)&__ ## virt_class): 0,           \
+             ((virt_class)(&__ ## class))->constructor(                 \
+                       (virt_class)_talloc_memdup(context, &__ ## class, sizeof(struct class ## _t),  __location__ "(" #class ")"), \
+				   ## __VA_ARGS__) )
+
+/** This variant is useful when all we have is a class reference
+    (GETCLASS(Foo)) or &__Foo
+*/
+#define CONSTRUCT_FROM_REFERENCE(class, constructor, context, ... )	\
+  ( (class)->constructor(						\
+                       (void *)_talloc_memdup(context, ((Object)class), ((Object)class)->__size,  __location__ "(" #class "." #constructor ")"), \
+		      ## __VA_ARGS__) )
+
+/** Finds the size of the class in x */
+#define CLASS_SIZE(class)			\
+  ((Object)class)->__size
+
+typedef struct Object_t *Object;
+
+struct Object_t {
+  //A reference to a class instance - this is useful to be able to
+  //tell which class an object really belongs to:
+  Object __class__;
+
+  //And its super class:
+  Object __super__;
+
+  char *__name__;
+
+  /** Objects may have a doc string associated with them. */
+  char *__doc__;
+
+  //How large the class is:
+  int __size;
+};
+
+#define SUPER(base, imp, method, ...)            \
+  ((base)&__ ## imp)->method((base)self, ## __VA_ARGS__)
+
+#define GETCLASS(class)				\
+  (Object)&__ ## class
+
+// Returns true if the obj belongs to the class
+#define ISINSTANCE(obj,class)			\
+  (((Object)obj)->__class__ == GETCLASS(class))
+
+// This is a string comparison version of ISINSTANCE which works
+// across different shared objects.
+#define ISNAMEINSTANCE(obj, class)		\
+  (obj && !strcmp(class, NAMEOF(obj)))
+
+// We need to ensure that class was properly initialised:
+#define ISSUBCLASS(obj,class)			\
+  issubclass((Object)obj, (Object)&__ ## class)
+
+#define CLASSOF(obj)				\
+  ((Object)obj)->__class__
+
+inline void Object_init(Object);
+
+extern struct Object_t __Object;
+
+int issubclass(Object obj, Object class);
+
+extern void unimplemented(Object self);
+
+#define UNIMPLEMENTED(class, method)             \
+  ((class)self)->method = (void *)unimplemented;
+
+#define ZSTRING_NO_NULL(str) str , (strlen(str))
+#define ZSTRING(str) str , (strlen(str)+1)
+
+  // These dont do anything but are useful to indicate when a function
+  // parameter is used purely to return a value. They are now used to
+  // assist the python binding generator in generating the right sort
+  // of code
+#define OUT
+#define IN
+
+  // This modifier before a class means that the class is abstract and
+  // does not have an implementation - we do not generate bindings for
+  // that class then.
+#define ABSTRACT
+
+  // This modifier indicates that the following pointer is pointing to
+  // a borrowed reference - callers must not free the memory after use.
+#define BORROWED
+
+  // This tells the autobinder to generated bindings to this struct
+#define BOUND
+
+  // This tells the autobinder to ignore this class as it should be
+  // private to the implementation - external callers should not
+  // access this.
+#define PRIVATE
+
+  // This attribute of a method means that this method is a
+  // desctructor - the object is no longer valid after this method is
+  // run
+#define DESTRUCTOR
+
+  // including this after an argument definition will cause the
+  // autogenerator to assign default values to that parameter and make
+  // it optional
+#define DEFAULT(x)
+
+  // This explicitely denote that the type is a null terminated char
+  // ptr as opposed to a pointer to char and length.
+#define ZString char *
+
+  /* The following is a direction for the autogenerator to proxy the
+     given class. This is done in the following way:
+
+1) a new python type is created called Proxy_class_name() with a
+constructor which takes a surrogate object.
+
+2) The proxy class contains a member "base" of the type of the proxied
+C class.
+
+3) The returned python object may be passed to any C functions which
+expect the proxied class, and internal C calls will be converted to
+python method calls on the proxied object.
+  */
+#define PROXY_CLASS(name)
+
+  /* This signals the autogenerator to bind the named struct */
+#define BIND_STRUCT(name)
+
+  // This means that the memory owned by this pointer is managed
+  // externally (not using talloc). It is dangerous to use this
+  // keyword too much because we are unable to manage its memory
+  // appropriately and it can be free'd from under us.
+#define FOREIGN
+
+#endif
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif
Index: trunk/python2/inspect.py
===================================================================
--- trunk/python2/inspect.py	(revision 196)
+++ trunk/python2/inspect.py	(revision 196)
@@ -0,0 +1,278 @@
+#!/usr/bin/python
+""" Module to inspect the contents of an AFF4 volume """
+import sys, pdb, os
+import re, cmd, readline
+import optparse
+import pyaff4
+import shlex
+import fnmatch, time
+import subprocess
+import readline
+
+time.sleep(1)
+
+## Set more sane completer delimiters
+readline.set_completer_delims(' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?')
+
+## Configure colors
+colors = {}
+colors['cyan']   = '\033[96m'
+colors['purple'] = '\033[95m'
+colors['blue']   = '\033[94m'
+colors['green']  = '\033[92m'
+colors['yellow'] = '\033[93m'
+colors['red']    = '\033[91m'
+colors['end']    = '\033[0m'
+
+#If the output is not a terminal, remove the colors
+if not sys.stdout.isatty():
+   for key, value in colors.iteritems():
+      colors[key] = ''
+
+parser = optparse.OptionParser()
+(options, args) = parser.parse_args()
+
+## Load the specified args as volumes
+oracle = pyaff4.Resolver()
+VOLUMES = []
+STREAMS = {}
+
+for arg in args:
+    volume = pyaff4.RDFURN()
+    volume.set(arg)
+    if oracle.load(volume):
+        VOLUMES.append(volume)
+        urn = pyaff4.RDFURN()
+        iter = oracle.get_iter(volume, pyaff4.AFF4_CONTAINS)
+        while oracle.iter_next(iter, urn):
+           print urn.value
+           if not urn: break
+
+           ## We store is as a simplified path
+           path = "/%s%s" % (urn.parser.netloc, urn.parser.query)
+           STREAMS[path] = urn
+
+class Inspector(cmd.Cmd):
+    prompt = "/:>"
+    intro = "Inspecting the volumes %s. Type 'help' for help." % args
+    CWD = "/"
+
+    def cmdloop(self, *args):
+        while 1:
+            try:
+                if not cmd.Cmd.cmdloop(self, *args):
+                    break
+            except KeyboardInterrupt,e:
+                print "Type %sexit%s to exit, %shelp%s for help" % (
+                    colors['yellow'],
+                    colors['end'],
+                    colors['cyan'],
+                    colors['end'])
+
+    def do_EOF(self, args):
+        """ Exit this program """
+        print "%sGoodbye%s" % (colors['yellow'],
+                               colors['end'])
+        return True
+
+    def do_cd(self, line):
+        """ Change directory """
+        args = shlex.split(line)
+        if not args[0].startswith("/"):
+            args[0] = self.CWD + args[0]
+
+        try:
+            potential_cd = os.path.normpath(args[0])
+            if not potential_cd.endswith('/'):
+                potential_cd += "/"
+
+            for s in STREAMS:
+                if s.startswith(potential_cd):
+                    self.CWD = potential_cd
+                    self.prompt = "%s:>" % self.CWD
+                    return
+
+            raise IOError("No such directory %s" % potential_cd)
+        except IndexError:
+            print "CWD: %s" % self.CWD
+
+    def complete_cd(self, *args):
+        return self.complete_stream(*args)
+
+    def do_help(self, line):
+        """ Provide help for commands """
+        args = shlex.split(line)
+        if not args:
+            ## List all commands
+            for k in dir(self):
+                if k.startswith("do_"):
+                    method = getattr(self, k)
+                    print "%s%s%s: %s" % (colors['red'],
+                                          k[3:],
+                                          colors['end'],
+                                          method.__doc__)
+            return
+
+        for arg in args:
+            try:
+                method = getattr(self, "do_%s" % arg)
+            except AttributeError:
+                print "%sError:%s Command %s%s%s not found" % (colors['red'],
+                                                               colors['end'],
+                                                               colors['yellow'],
+                                                               arg,
+                                                               colors['end'])
+
+            print "%s: %s" % (arg, method.__doc__)
+
+    def do_ls(self, line):
+        """ List streams matching a glob expression """
+        globs = shlex.split(line)
+        if not globs: globs=[self.CWD]
+
+        result = []
+
+        for s in STREAMS:
+            for g in globs:
+                if fnmatch.fnmatch(s, g + "*"):
+                    if s.startswith(self.CWD):
+                        s = s[len(self.CWD):]
+
+                    path = s.split("/")[0]
+                    if path == s:
+                        decoration = colors['blue']
+                    else:
+                        decoration = colors['end']
+
+                    if path not in result:
+                        print "%s%s%s" % (decoration, path, colors['end'])
+                        result.append(path)
+
+    def do_less(self, line):
+        """ Read the streams specified and pipe them through the pager """
+        globs = shlex.split(line)
+        for s in STREAMS:
+            for g in globs:
+                if not g.startswith("/"):
+                    g = self.CWD + g
+
+                g = os.path.normpath(g)
+                if fnmatch.fnmatch(s, g):
+                    ## Try to open the stream
+                    try:
+                        fd = oracle.open(STREAMS[s], 'r')
+                    except IOError, e:
+                        raise
+
+                    pager = os.environ.get("PAGER","less")
+                    pipe=os.popen(pager,"w")
+
+                    while 1:
+                        data = fd.read(1024 * 1024)
+                        if not data: break
+
+                        pipe.write(data)
+
+                    pipe.close()
+
+    def do_cp(self, line):
+        """ Copy a stream from a source to a destination. """
+        globs = shlex.split(line)
+        src = globs[0]
+        dest = globs[1]
+        if(len(globs) > 2):
+           print "usage: cp src dest"
+           return
+
+        if not src.startswith("/"):
+           src = self.CWD + src
+
+        src = os.path.normpath(src)
+        src_urn = pyaff4.RDFURN()
+        src_urn.set("aff4:/" + src)
+        ## Try to open the stream
+        try:
+           fd = oracle.open(src_urn, 'r')
+        except IOError, e:
+           raise
+
+        dest_fd = open(dest, "w")
+        while 1:
+           data = fd.read(1024 * 1024)
+           if not data: break
+
+           dest_fd.write(data)
+
+        dest_fd.close()
+
+    def complete_cp(self, *args):
+       return self.complete_stream(*args)
+
+    def complete_less(self, *args):
+        return self.complete_stream(*args)
+
+    def _display_attribute(self, iter):
+       while 1:
+          obj = oracle.alloc_from_iter(iter)
+          if not obj: break
+
+          print "    -> type (%s) " % (obj.dataType)
+          print "    -> data (%s) " % (obj.serialise(iter.urn))
+
+
+    def do_resolve(self, line):
+       globs = shlex.split(line)
+       attribute = pyaff4.XSDString()
+       subject = pyaff4.RDFURN()
+       iter = pyaff4.RESOLVER_ITER()
+
+       subject.set(globs[0])
+       try:
+          attribute.set(globs[1])
+          print attribute.value
+          self._display_attribute(iter)
+
+       except IndexError:
+          ## Just display all the attributes
+          while oracle.attributes_iter(subject, attribute, iter):
+             print attribute.value
+             self._display_attribute(iter)
+
+    def complete_stream(self, text, line, begidx, endidx):
+        if not text.startswith("/"):
+            text = self.CWD + text
+
+        if not text:
+            completions = STREAMS.keys()
+
+        completions = [ text + f[len(text):].split("/")[0]
+                        for f in STREAMS.keys()
+                        if f.startswith(text)
+                        ]
+
+        return completions
+
+    def do_pwd(self, line):
+        print "CWD: %s" % self.CWD
+
+    def do_exit(self, *args):
+        """ Exits the program """
+        return self.do_EOF(*args)
+
+    def emptyline(self):
+        return
+
+    def onecmd(self, line):
+        try:
+            return cmd.Cmd.onecmd(self, line)
+        except Exception,e:
+            print "%sError:%s %s%s%s %s" % (colors['red'],
+                                            colors['end'],
+                                            colors['yellow'],
+                                            e.__class__.__name__,
+                                            colors['end'],
+                                            e)
+
+        return None
+
+Inspector().cmdloop()
Index: trunk/python2/lexer.py
===================================================================
--- trunk/python2/lexer.py	(revision 196)
+++ trunk/python2/lexer.py	(revision 196)
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+# ******************************************************
+# Michael Cohen <scudette@users.sourceforge.net>
+#
+# ******************************************************
+#  Version: FLAG $Version: 0.87-pre1 Date: Thu Jun 12 00:48:38 EST 2008$
+# ******************************************************
+#
+# * This program is free software; you can redistribute it and/or
+# * modify it under the terms of the GNU General Public License
+# * as published by the Free Software Foundation; either version 2
+# * of the License, or (at your option) any later version.
+# *
+# * This program is distributed in the hope that it will be useful,
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# * GNU General Public License for more details.
+# *
+# * You should have received a copy of the GNU General Public License
+# * along with this program; if not, write to the Free Software
+# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+# ******************************************************
+""" A simple feed lexer.
+"""
+
+import re,sys
+
+class Lexer:
+    """ A generic feed lexer """
+    ## The following is a description of the states we have and the
+    ## way we move through them: format is an array of
+    ## [ state_re, re, token/action, next state ]
+    tokens = []
+    state = "INITIAL"
+    buffer = ''
+    error = 0
+    verbose = 0
+    state_stack = []
+    processed = 0
+    processed_buffer = ''
+    saved_state = None
+    flags = 0
+    
+    def __init__(self, verbose=0, fd=None):
+        if not self.verbose:
+            self.verbose = verbose
+
+        if len(self.tokens[0])==4:
+            for row in self.tokens:
+                row.append(re.compile(row[0], re.DOTALL))
+                row.append(re.compile(row[1], re.DOTALL | re.M | re.S | self.flags ))
+                
+        self.fd = fd
+
+    def save_state(self, t=None, m=None):
+        """ Returns a dict which represents the current state of the lexer.
+
+        When provided to restore_state, the lexer is guaranteed to be
+        in the same state as when the save_state was called.
+
+        Note that derived classes may need to extend this.
+        """
+        ## Cant save our state if we have errors. We need to guarantee
+        ## that we rewind to a good part of the file.
+        if self.error: return
+        try:
+            end = m.end()
+        except: end = 0
+        
+        self.saved_state = dict(state_stack = self.state_stack[:],
+                                processed = self.processed - end,
+                                processed_buffer = self.processed_buffer,
+                                readptr = self.fd.tell() - len(self.buffer) - end,
+                                state = self.state,
+                                objects = self.objects[:],
+                                error = self.error,
+                                )
+
+        if self.verbose>1:
+            print "Saving state %s" % self.processed
+
+    def restore_state(self):
+        state = self.saved_state
+        if not state: return
+        
+        self.state_stack = state['state_stack']
+        self.processed = state['processed']
+        self.processed_buffer = state['processed_buffer']
+        self.buffer = ''
+        self.fd.seek(state['readptr'])
+        self.state = state['state']
+        self.objects = state['objects']
+        self.error = state['error']
+        if self.verbose>1:
+            print "Restoring state to offset %s" % self.processed
+
+    def next_token(self, end = True):
+        ## Now try to match any of the regexes in order:
+        current_state = self.state
+        for state_re, re_str, token, next, state, regex in self.tokens:
+            ## Does the rule apply for us now?
+            if state.match(current_state):
+                if self.verbose > 2:
+                    print "%s: Trying to match %r with %r" % (self.state, self.buffer[:10], re_str)
+                m = regex.match(self.buffer)
+                if m:
+                    if self.verbose > 3:
+                        print "%s matched %s" % (re_str, m.group(0).encode("utf8"))
+                    ## The match consumes the data off the buffer (the
+                    ## handler can put it back if it likes)
+                    self.processed_buffer += self.buffer[:m.end()]
+                    self.buffer = self.buffer[m.end():]
+                    self.processed += m.end()
+
+                    ## Try to iterate over all the callbacks specified:
+                    for t in token.split(','):
+                        try:
+                            if self.verbose > 0:
+                                print "0x%X: Calling %s %r" % (self.processed, t, m.group(0))
+                            cb = getattr(self, t, self.default_handler)
+                        except AttributeError:
+                            continue
+
+                        ## Is there a callback to handle this action?
+                        next_state = cb(t, m)
+                        if next_state == "CONTINUE":
+                            continue
+                        
+                        elif next_state:
+                            next = next_state
+                            self.state = next
+
+                    
+                    if next:
+                        self.state = next
+                
+                    return token
+
+        ## Check that we are making progress - if we are too full, we
+        ## assume we are stuck:
+        if end and len(self.buffer)>0 or len(self.buffer)>1024:
+            self.processed_buffer += self.buffer[:1]
+            self.buffer = self.buffer[1:]
+            self.ERROR("Lexer Stuck, discarding 1 byte (%r) - state %s" % (self.buffer[:10], self.state))
+            return "ERROR"
+
+        ## No token were found
+        return None
+    
+    def feed(self, data):
+        self.buffer += data
+
+    def empty(self):
+        return not len(self.buffer)
+
+    def default_handler(self, token, match):
+        if self.verbose > 2:
+            print "Default handler: %s with %r" % (token,match.group(0))
+
+    def ERROR(self, message = None, weight =1):
+        if self.verbose > 0 and message:
+            print "Error(%s): %s" % (weight,message)
+
+        self.error += weight
+
+    def PUSH_STATE(self, token = None, match = None):
+        if self.verbose > 1:
+            print "Storing state %s" % self.state
+        self.state_stack.append(self.state)
+
+    def POP_STATE(self, token = None, match = None):
+        try:
+            state = self.state_stack.pop()
+            if self.verbose > 1:
+                print "Returned state to %s" % state
+                
+            return state
+        except IndexError:
+            print "Tried to pop the state but failed - possible recursion error"
+            return None
+
+    def close(self):
+        """ Just a conveniece function to force us to parse all the data """
+        while self.next_token(): pass
+
+class SelfFeederMixIn(Lexer):
+    """ This mixin is used to make a lexer which feeds itself one
+    sector at the time.
+
+    Note that self.fd must be the fd we read from.
+    """
+    def parse_fd(self, fd):
+        self.feed(fd.read())
+        while self.next_token(): pass
+
Index: trunk/python2/regfi/class.c
===================================================================
--- trunk/python2/regfi/class.c	(revision 196)
+++ trunk/python2/regfi/class.c	(revision 196)
@@ -0,0 +1,63 @@
+/******************************************************
+# Copyright 2004: Commonwealth of Australia.
+#
+# Developed by the Computer Network Vulnerability Team,
+# Information Security Group.
+# Department of Defence.
+#
+# Michael Cohen <scudette@users.sourceforge.net>
+#
+# ******************************************************
+#  Version: FLAG  $Version: 0.87-pre1 Date: Thu Jun 12 00:48:38 EST 2008$
+# ******************************************************
+#
+# * This program is free software; you can redistribute it and/or
+# * modify it under the terms of the GNU General Public License
+# * as published by the Free Software Foundation; either version 2
+# * of the License, or (at your option) any later version.
+# *
+# * This program is distributed in the hope that it will be useful,
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# * GNU General Public License for more details.
+# *
+# * You should have received a copy of the GNU General Public License
+# * along with this program; if not, write to the Free Software
+# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+# ******************************************************/
+#include "class.h"
+
+#define BUFF_SIZE 1024
+
+// Noone should instantiate Object directly. this should be already
+// allocated therefore:
+
+inline void Object_init(Object this) {
+  this->__class__ = &__Object;
+  this->__super__ = NULL;
+};
+
+struct Object_t __Object = {
+  .__class__ = &__Object,
+  .__super__ = &__Object,
+  .__size = sizeof(struct Object_t),
+  .__name__ = "Object"
+};
+
+int issubclass(Object obj, Object class) {
+  obj = obj->__class__;
+  while(1) {
+    if(obj == class->__class__)
+      return 1;
+
+    obj=obj->__super__;
+
+    if(obj == &__Object || obj==NULL) 
+      return 0;
+  };
+};
+
+void unimplemented(Object self) {
+  printf("%s contains unimplemented functions.. is it an abstract class?\n", NAMEOF(self));
+  abort();
+};
Index: trunk/python2/regfi/error.c
===================================================================
--- trunk/python2/regfi/error.c	(revision 196)
+++ trunk/python2/regfi/error.c	(revision 196)
@@ -0,0 +1,84 @@
+/*
+** error.c
+** 
+** Made by (mic)
+** Login   <mic@laptop>
+** 
+** Started on  Mon Mar 15 20:45:09 2010 mic
+** Last update Sun May 12 01:17:25 2002 Speed Blue
+*/
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <talloc.h>
+#include "aff4_errors.h"
+
+/** These slots carry the TLS error keys */
+static pthread_key_t error_str_slot;
+static pthread_key_t error_value_slot;
+
+void error_dest(void *slot) {
+  if(slot) talloc_free(slot);
+};
+
+void *raise_errors(enum _error_type t, char *reason, ...) {
+  char *error_buffer;
+  // This has to succeed:
+  enum _error_type *type = aff4_get_current_error(&error_buffer);
+
+  if(reason) {
+    va_list ap;
+    va_start(ap, reason);
+
+    vsnprintf(error_buffer, ERROR_BUFFER_SIZE-1, reason,ap);
+    error_buffer[ERROR_BUFFER_SIZE-1]=0;
+    va_end(ap);
+  };
+
+  //update the error type
+  *type = t;
+
+  return NULL;
+};
+
+static int error_subsystem_initialised=0;
+
+enum _error_type *aff4_get_current_error(char **error_buffer) {
+  enum _error_type *type;
+
+  if(!error_subsystem_initialised) error_init();
+
+  type = pthread_getspecific(error_value_slot);
+
+  // This is optional
+  if(error_buffer) {
+    *error_buffer = pthread_getspecific(error_str_slot);
+
+  // If TLS buffers are not set we need to create them
+    if(!*error_buffer) {
+      *error_buffer =talloc_size(NULL, ERROR_BUFFER_SIZE);
+      pthread_setspecific(error_str_slot, *error_buffer);
+    };
+  };
+
+  if(!type) {
+    type = talloc(NULL, enum _error_type);
+    pthread_setspecific(error_value_slot, type);
+  };
+
+  return type;
+};
+
+/** Initialise the error subsystem */
+void error_init() {
+  error_subsystem_initialised = 1;
+
+  // We create the error buffer slots
+  if(pthread_key_create(&error_str_slot, error_dest) ||
+     pthread_key_create(&error_value_slot, error_dest)) {
+    printf("Unable to set up TLS variables\n");
+    abort();
+  };
+};
Index: trunk/python2/regfi/pyregfi.h
===================================================================
--- trunk/python2/regfi/pyregfi.h	(revision 196)
+++ trunk/python2/regfi/pyregfi.h	(revision 196)
@@ -0,0 +1,121 @@
+/*
+** regfi.h
+** 
+** Made by mic
+** Login   <mic@laptop>
+** 
+** Started on  Fri Apr 30 02:06:43 2010 mic
+** Last update Fri Apr 30 02:06:43 2010 mic
+*/
+
+#ifndef   	PYREGFI_H_
+# define   	PYREGFI_H_
+#include "class.h"
+#include "aff4_errors.h"
+#include "regfi.h"
+
+/** Forward declerations */
+struct RegistryFile_t;
+struct ValueIterator_t;
+
+BIND_STRUCT(REGFI_NK_REC);
+BIND_STRUCT(REGFI_VK_REC);
+BIND_STRUCT(REGFI_DATA);
+
+/** This is the base class for data objects */
+CLASS(RawData, Object)
+    REGFI_DATA *data;
+    REGFI_VK_REC *rec;
+
+    RawData METHOD(RawData, Con, REGFI_DATA *data,REGFI_VK_REC *record);
+
+    /** Return the raw buffer as a string. By default we only return
+        this much data - specify a required length to return more.
+
+        DEFAULT(len) = 4096;
+    */
+    int METHOD(RawData, get_value, OUT char *buffer, int len);
+END_CLASS
+
+CLASS(DataString, RawData)
+     BORROWED char *METHOD(DataString, get_value);
+END_CLASS
+
+CLASS(DWORDData, RawData)
+     uint64_t METHOD(DWORDData, get_value);
+END_CLASS
+
+/** This is an iterator for reading keys from the registry */
+CLASS(KeyIterator, Object)
+     PRIVATE REGFI_ITERATOR *iter;
+     PRIVATE const REGFI_NK_REC *next_item;
+
+     KeyIterator METHOD(KeyIterator, Con, struct RegistryFile_t *file, char **path,
+                        REGFI_ENCODING encoding);
+
+     struct ValueIterator_t *METHOD(KeyIterator, list_values);
+
+     void METHOD(KeyIterator, __iter__);
+     REGFI_NK_REC *METHOD(KeyIterator, iternext);
+END_CLASS
+
+/** This is an iterator for reading values from the registry */
+CLASS(ValueIterator, Object)
+    PRIVATE REGFI_ITERATOR *iter;
+    PRIVATE const REGFI_VK_REC *next_item;
+
+    ValueIterator METHOD(ValueIterator, Con, KeyIterator key);
+
+    void METHOD(ValueIterator, __iter__);
+    RawData METHOD(ValueIterator, iternext);
+END_CLASS
+
+CLASS(RegistryFile, Object)
+  REGFI_FILE *reg;
+  int fd;
+
+  RegistryFile METHOD(RegistryFile, Con, char *filename);
+
+  /* Get an iterator for a specific path in the register if path is
+     specified.
+
+     DEFAULT(path) == NULL;
+     DEFAULT(encoding) = REGFI_ENCODING_ASCII;
+  */
+  KeyIterator METHOD(RegistryFile, get_key, char **path, REGFI_ENCODING encoding);
+
+  /** Set the verbosity level of messages generated by the library for the 
+ *  current thread.
+ *
+ * @param mask   An integer representing the types of messages desired.
+ *               Acceptable values are created through bitwise ORs of 
+ *               REGFI_LOG_* values.  For instance, if only errors and
+ *               informational messages were desired (but not warnings),
+ *               then one would specify: REGFI_LOG_ERROR|REGFI_LOG_INFO
+ *               By default the message mask is: REGFI_LOG_ERROR|REGFI_LOG_WARN.
+ *
+ * @return       true on success and false on failure.  Failure occurs if 
+ *               underlying pthread functions fail.  errno is set in this case.
+ *
+ * Message masks are set in a thread-specific way.  If one were to set a message
+ * mask in one thread and then spawn a new thread, then the new thread will have
+ * it's message mask reset to the default.  This function may be called at any 
+ * time and will take effect immediately for the current thread.
+ *
+ * @note When a non-zero message mask is set, messages will
+ *       accumulate in memory without limit if they are not fetched using
+ *       @ref regfi_get_log_str and subsequently freed by the caller.  It is
+ *       recommended that messsages be fetched after each regfi API call in
+ *       order to provide the most context.
+ *
+ * @ingroup regfiBase
+ */
+  int METHOD(RegistryFile, set_log_mask, uint16_t mask);
+
+  
+END_CLASS
+
+
+void pyregfi_init();
+
+#endif 	    /* !PYREGFI_H_ */
Index: trunk/python2/regfi/regfi.c
===================================================================
--- trunk/python2/regfi/regfi.c	(revision 196)
+++ trunk/python2/regfi/regfi.c	(revision 196)
@@ -0,0 +1,257 @@
+/*
+** regfi.c
+** 
+** Made by (mic)
+** Login   <mic@laptop>
+** 
+** Started on  Fri Apr 30 02:06:28 2010 mic
+** Last update Sun May 12 01:17:25 2002 Speed Blue
+*/
+
+#include "pyregfi.h"
+
+static int RegistryFile_dest(void *self) {
+  RegistryFile this = (RegistryFile)self;
+
+  regfi_free(this->reg);
+  close(this->fd);
+
+  return 0;
+};
+
+static RegistryFile RegistryFile_Con(RegistryFile self, char *filename) {
+  self->fd = open(filename, O_RDONLY);
+  if(self->fd < 0) {
+    RaiseError(EIOError, "Unable to open %s", filename);
+    goto error;
+  };
+
+  self->reg = regfi_alloc(self->fd);
+
+  if(!self->reg) {
+    RaiseError(ERuntimeError, "REGFI Error: %s", regfi_log_get_str());
+    goto error;
+  };
+
+  talloc_set_destructor((void *)self, RegistryFile_dest);
+  return self;
+
+ error:
+  talloc_free(self);
+  return NULL;
+};
+
+static KeyIterator RegistryFile_get_key(RegistryFile self, char **path, REGFI_ENCODING encoding) {
+  return CONSTRUCT(KeyIterator, KeyIterator, Con, NULL, self, path, encoding);
+};
+
+
+VIRTUAL(RegistryFile, Object) {
+  VMETHOD(Con) = RegistryFile_Con;
+  VMETHOD(get_key) = RegistryFile_get_key;
+} END_VIRTUAL
+
+static int KeyIterator_dest(void *self) {
+  KeyIterator this = (KeyIterator)self;
+
+  regfi_iterator_free(this->iter);
+  if(this->next_item) {
+    regfi_free_record(this->next_item);
+  };
+
+  return 0;
+};
+
+static KeyIterator KeyIterator_Con(KeyIterator self, RegistryFile file, char **path,
+                             REGFI_ENCODING encoding) {
+  self->iter = regfi_iterator_new(file->reg, encoding);
+
+  if(!self->iter) {
+    RaiseError(ERuntimeError, "Error: %s", regfi_log_get_str());
+    goto error;
+  };
+
+  talloc_set_destructor((void*)self, KeyIterator_dest);
+
+  // Traverse to the path
+  if(path[0]) {
+    if(!regfi_iterator_walk_path(self->iter, (const char **)path)) {
+      RaiseError(ERuntimeError, "Unable to walk down key path");
+      goto error;
+    };
+  };
+
+  // Get the first key in the list
+  self->next_item = regfi_iterator_first_subkey(self->iter);
+
+  return self;
+ error:
+  return NULL;
+};
+
+static void KeyIterator__iter__(KeyIterator self) {
+  if(self->next_item) {
+    regfi_free_record(self->next_item);
+  };
+
+  self->next_item = regfi_iterator_first_subkey(self->iter);
+};
+
+static REGFI_NK_REC *KeyIterator_next(KeyIterator self) {
+  const REGFI_NK_REC * result;
+
+  if(!self->next_item) return NULL;
+
+  result = self->next_item;
+
+  self->next_item = regfi_iterator_next_subkey(self->iter);
+
+  return result;
+};
+
+static ValueIterator KeyIterator_list_values(KeyIterator self) {
+  return CONSTRUCT(ValueIterator, ValueIterator, Con, NULL, self);
+};
+
+VIRTUAL(KeyIterator, Object) {
+  VMETHOD(Con) = KeyIterator_Con;
+  VMETHOD(iternext) = KeyIterator_next;
+  VMETHOD(__iter__) = KeyIterator__iter__;
+  VMETHOD(list_values) = KeyIterator_list_values;
+} END_VIRTUAL
+
+static int ValueIterator_dest(void *self) {
+  ValueIterator this = (ValueIterator)self;
+
+  if(this->next_item) regfi_free_record(this->next_item);
+
+  return 0;
+};
+
+static ValueIterator ValueIterator_Con(ValueIterator self, KeyIterator key) {
+  // Take a copy of the iterator
+  self->iter = key->iter;
+  talloc_reference(self, self->iter);
+
+  self->next_item = regfi_iterator_first_value(self->iter);
+
+  talloc_set_destructor((void *)self, ValueIterator_dest);
+
+  return self;
+};
+
+static void ValueIterator__iter__(ValueIterator self) {
+  if(self->next_item) regfi_free_record(self->next_item);
+
+  self->next_item = regfi_iterator_first_value(self->iter);
+};
+
+static RawData ValueIterator_iternext(ValueIterator self) {
+  RawData result;
+  REGFI_DATA *data;
+  REGFI_VK_REC *rec = (REGFI_VK_REC *)self->next_item;
+
+  if(!rec) return NULL;
+
+  data = (REGFI_DATA *)regfi_iterator_fetch_data(self->iter, rec);
+  if(!data) {
+    RaiseError(ERuntimeError, "Unable to fetch data: %s", regfi_log_get_str());
+    goto error;
+  };
+
+  switch(self->next_item->type) {
+  case REG_EXPAND_SZ:
+  case REG_SZ:
+    result = (RawData)CONSTRUCT(DataString, RawData, Con, NULL, data, rec);
+    break;
+
+  case REG_DWORD:
+    result = (RawData)CONSTRUCT(DWORDData, RawData, Con, NULL, data, rec);
+    break;
+
+  case REG_BINARY:
+  default:
+    result = (RawData)CONSTRUCT(RawData, RawData, Con, NULL, data, rec);
+    break;
+  };
+
+
+  /*  if(self->next_item) {
+    regfi_free_record(self->next_item);
+  };
+  */
+
+  self->next_item = regfi_iterator_next_value(self->iter);
+
+  return result;
+ error:
+  talloc_free(self);
+  return NULL;
+};
+
+VIRTUAL(ValueIterator, Object) {
+  VMETHOD(Con) = ValueIterator_Con;
+  VMETHOD(__iter__) = ValueIterator__iter__;
+  VMETHOD(iternext) = ValueIterator_iternext;
+} END_VIRTUAL
+
+static int RawData_dest(void *self) {
+  RawData this = (RawData)self;
+
+  if(this->data) {
+    regfi_free_record(this->data);
+  };
+
+  if(this->rec) {
+    regfi_free_record(this->rec);
+  };
+
+  return 0;
+};
+
+static RawData RawData_Con(RawData self, REGFI_DATA *data, REGFI_VK_REC *record) {
+  self->rec = record;
+  self->data = data;
+
+  talloc_set_destructor((void *)self, RawData_dest);
+
+  return self;
+};
+
+static int RawData_get_value(RawData self, char *buff, int len) {
+  int available_to_read = min(len, self->data->interpreted_size);
+
+  memcpy(buff, self->data->raw, available_to_read);
+
+  return available_to_read;
+};
+
+VIRTUAL(RawData, Object) {
+  VMETHOD(Con) = RawData_Con;
+  VMETHOD(get_value) = RawData_get_value;
+} END_VIRTUAL
+
+static char *DataString_get_value(DataString self) {
+  RawData this = (RawData)self;
+
+  return this->data->interpreted.string;
+};
+
+VIRTUAL(DataString, RawData) {
+  VMETHOD(get_value) = DataString_get_value;
+} END_VIRTUAL
+
+static uint64_t DWORDData_get_value(DWORDData self) {
+  RawData this = (RawData)self;
+
+  return this->data->interpreted.dword;
+};
+
+VIRTUAL(DWORDData, RawData) {
+  VMETHOD(get_value) = DWORDData_get_value;
+} END_VIRTUAL
+
+void pyregfi_init() {
+  INIT_CLASS(RegistryFile);
+
+};
Index: trunk/python2/utils.py
===================================================================
--- trunk/python2/utils.py	(revision 196)
+++ trunk/python2/utils.py	(revision 196)
@@ -0,0 +1,513 @@
+import os, sys, re, pdb
+import distutils.sysconfig as sysconfig
+import distutils.util
+import platform
+import SCons.SConf as SConf
+import config
+
+# taken from scons wiki
+def CheckPKGConfig(context, version):
+    context.Message( 'Checking for pkg-config version > %s... ' % version)
+    ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
+    context.Result( ret )
+    return ret
+
+def CheckFramework(context, name):
+    ret = 0
+    if (platform.system().lower() == 'darwin'):
+        context.Message( '\nLooking for framework %s... ' % name )
+        lastFRAMEWORKS = context.env['FRAMEWORKS']
+        context.env.Append(FRAMEWORKS = [name])
+        ret = context.TryLink("""
+              int main(int argc, char **argv) {
+                return 0;
+              }
+              """, '.c')
+        if not ret:
+            context.env.Replace(FRAMEWORKS = lastFRAMEWORKS
+)
+
+    return ret
+
+def CheckFink(context):
+    context.Message( 'Looking for fink... ')
+    prog = context.env.WhereIs('fink')
+    if prog:
+        ret = 1
+        prefix = prog.rsplit(os.sep, 2)[0]
+        context.env.Append(LIBPATH = [prefix + os.sep +'lib'],
+                           CPPPATH = [prefix + os.sep +'include'])
+        context.Message( 'Adding fink lib and include path')
+    else:
+        ret = 0
+        
+    context.Result(ret)    
+    return int(ret)
+
+def CheckMacports(context):
+    context.Message( 'Looking for macports... ')
+    prog = context.env.WhereIs('port')
+    if prog:
+        ret = 1
+        prefix = prog.rsplit(os.sep, 2)[0]
+        context.env.Append(LIBPATH = [prefix + os.sep + 'lib'],
+                           CPPPATH = [prefix + os.sep + 'include'])
+        context.Message( 'Adding port lib and include path')
+    else:
+        ret = 0
+        
+    context.Result(ret)    
+    return int(ret)
+
+# TODO: We should use the scons one instead
+def CheckLib(context, name):
+    context.Message( 'Looking for lib %s... ' % name )
+    lastLIBS = context.env['LIBS']
+    context.env.Append(LIBS = [name])
+    ret = context.TryLink("""
+              int main(int argc, char **argv) {
+                return 0;
+              }
+              """,'.c')
+    if not ret:
+        context.env.Replace(LIBS = lastLIBS)
+
+    return ret
+
+def ConfigPKG(context, name):
+    context.Message( '\nUsing pkg-config for %s... ' % name )
+    ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+    context.Result(  ret )
+    if ret:
+        context.env.ParseConfig('pkg-config --cflags --libs \'%s\'' % name)
+    return int(ret)
+
+def CheckPKG(context, name):
+    context.Message( 'Checking for %s... ' % name )
+    if platform.system().lower() == 'windows':
+        return 0 
+    ret = 1
+    if not CheckFramework(context, name):
+        if not ConfigPKG(context, name.lower()):
+            ret = CheckLib(context, name) 
+
+    context.Result(ret)
+    return int(ret)
+
+
+## Configure colors for pretty builds
+colors = {}
+colors['cyan']   = '\033[96m'
+colors['purple'] = '\033[95m'
+colors['blue']   = '\033[94m'
+colors['green']  = '\033[92m'
+colors['yellow'] = '\033[93m'
+colors['red']    = '\033[91m'
+colors['end']    = '\033[0m'
+
+#If the output is not a terminal, remove the colors
+if not sys.stdout.isatty():
+   for key, value in colors.iteritems():
+      colors[key] = ''
+
+def error(msg):
+   print "%s%s%s" % (colors['red'], msg, colors['end'])
+   sys.exit(1)
+
+def warn(msg):
+   print "%s%s%s" % (colors['yellow'], msg, colors['end'])
+
+compile_source_message = '%sCompiling %s==> %s$SOURCE%s' % \
+   (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+
+compile_shared_source_message = '%sCompiling shared %s==> %s$SOURCE%s' % \
+   (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+
+compile_python_source_message = '%sCompiling python module %s==> %s$SOURCE%s' % \
+   (colors['blue'], colors['purple'], colors['yellow'], colors['end'])
+
+link_program_message = '%sLinking Program %s==> %s$TARGET%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+link_library_message = '%sLinking Static Library %s==> %s$TARGET%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+ranlib_library_message = '%sRanlib Library %s==> %s$TARGET%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+link_shared_library_message = '%sLinking Shared Library %s==> %s$TARGET%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+link_python_module_message = '%sLinking Native Python module %s==> %s${TARGET}%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+java_library_message = '%sCreating Java Archive %s==> %s$TARGET%s' % \
+   (colors['red'], colors['purple'], colors['yellow'], colors['end'])
+
+def install_colors(args):
+    """ Installs colors into an environment """
+    args.update(dict( CXXCOMSTR = compile_source_message,
+                      CCCOMSTR = compile_source_message,
+                      SHCCCOMSTR = compile_shared_source_message,
+                      SHCXXCOMSTR = compile_shared_source_message,
+                      ARCOMSTR = link_library_message,
+                      RANLIBCOMSTR = ranlib_library_message,
+                      SHLINKCOMSTR = link_shared_library_message,
+                      LINKCOMSTR = link_program_message,
+                      JARCOMSTR = java_library_message,
+                      JAVACCOMSTR = compile_source_message,))
+
+import optparse
+
+### This workaround is because scons does not provide access to the
+### parser, and by setting Help() we are unable to generate the option
+### listing from AddOption
+my_parser = optparse.OptionParser()
+
+import SCons.Script.Main as Main
+import SCons.Script as Script
+
+def add_option(arg, option, *args, **kwargs):
+    opt = "--%s" % option
+    Main.AddOption(opt, *args, **kwargs)
+    my_parser.add_option(opt, *args, **kwargs)
+
+    arg[option] = Main.GetOption(option)
+
+def generate_help(vars, env):
+    Script.Help("AFF4 build system configuration.\n\nFollowing are compile time options:\n")
+    Script.Help(my_parser.format_help())
+    Script.Help("\nThe following variables can be used on the command line:\n")
+    Script.Help(vars.GenerateHelpText(env))
+
+HEADERS = {}
+
+def check_size(conf, types):
+    global _DEFAULTS
+
+    for t in types:
+        name = "SIZEOF_" + t.replace(" ","_").upper()
+        HEADERS[name] = conf.CheckTypeSize(
+            t, size = _DEFAULTS[t][0])
+
+def check_type(conf, types):
+    header = None
+    for t in types:
+        if ':' in t:
+            t, header = t.split(':')
+        define = "HAVE_" + t.upper().replace(".","_")
+
+        result = 0
+        if conf.CheckType(t, includes="#include <%s>\n" % header):
+            result = 1
+
+        HEADERS[define] = result
+
+def check_build(conf, message, define, prog):
+    """ Build and links prog and adds define if that succeeds """
+    context = SConf.CheckContext(conf)
+    context.Message("Checking for %s ..." % message)
+    if context.TryLink(prog, ".c"):
+        HEADERS[define] = 1
+        context.Message("yes\n")
+    else:
+        context.Message("no\n")
+
+def check(type, conf, headers, extra_include =''):
+    for header in headers:
+        if ":" in header:
+            define, header = header.split(':')
+        else:
+            if "/" in header:
+                tmp = header.split("/")[-1]
+            else:
+                tmp = header
+
+            define = "HAVE_" + tmp.upper().replace(".","_")
+
+        global HEADERS
+        result = 0
+        if type == 'header':
+            #pdb.set_trace()
+            if conf.CheckCHeader(header): result = 1
+            HEADERS[define] = result
+        elif type == 'func':
+            if conf.CheckFunc(header, header=extra_include): result = 1
+            HEADERS[define] = result
+        elif type == 'lib':
+            if conf.CheckLib(header): result =1
+            HEADERS[define] = result
+
+## Build the config.h file
+def config_h_build(target, source, env):
+    config_h_defines = env.Dictionary()
+    config_h_defines.update(env.config.__dict__)
+    warn("Generating %s" % (target[0].path))
+
+    for a_target, a_source in zip(target, source):
+        config_h = file(str(a_target), "w")
+        config_h_in = file(str(a_source), "r")
+        config_h.write(config_h_in.read() % config_h_defines)
+        config_h_in.close()
+
+    keys = HEADERS.keys()
+    keys.sort()
+
+    for k in keys:
+        if HEADERS[k]:
+            config_h.write("#define %s %s\n" % (k,HEADERS[k]))
+        else:
+            config_h.write("/** %s unset */\n" % k)
+
+    config_h.close()
+
+import SCons.Environment
+
+class ExtendedEnvironment(SCons.Environment.Environment):
+    """ Implementation from Richard Levitte email to
+    org.tigris.scons.dev dated Jan 26, 2006 7:05:10 am."""
+    python_cppflags = distutils.util.split_quoted(
+        "-I"+sysconfig.get_python_inc())
+
+    def PythonModule(self, libname, lib_objs=[], **kwargs):
+        """ This builds a python module which is almost a library but
+        is sometimes named differently.
+
+        We have two modes - a cross compile mode where we do our best
+        to guess the flags. In the native mode we can get the required
+        flags directly from distutils.
+        """
+        if config.MINGW_XCOMPILE:
+            shlib_suffix = ".pyd"
+            cppflags = "-I%s" % config.XCOMPILE_PYTHON_PATH
+            shlink_flags = ['']
+
+        else:
+            platform = self.subst('$PLATFORM')
+            shlib_pre_action = None
+            shlib_suffix = distutils.util.split_quoted(
+                sysconfig.get_config_var('SO'))
+            shlib_post_action = None
+            cppflags = distutils.util.split_quoted(
+                "-I"+sysconfig.get_python_inc())
+            shlink_flags = str(self['LINKFLAGS']).split()
+
+        install_dest = distutils.util.split_quoted(
+            os.path.join(
+                sysconfig.get_config_var('BINLIBDEST'),os.path.dirname(libname)))
+
+        flags = distutils.util.split_quoted(
+            sysconfig.get_config_var('LDSHARED'))
+
+        ## For some stupid reason they include the compiler in LDSHARED
+        shlink_flags.extend([x for x in flags if 'gcc' not in x])
+
+        shlink_flags.append(sysconfig.get_config_var('LOCALMODLIBS'))
+
+        ## TODO cross compile mode
+        kwargs['LIBPREFIX'] = ''
+        kwargs['CPPFLAGS'] = cppflags
+        kwargs['SHLIBSUFFIX'] = shlib_suffix
+        kwargs['SHLINKFLAGS'] = shlink_flags
+
+        if not self.config.V:
+            kwargs['SHCCCOMSTR'] = compile_python_source_message
+            kwargs['SHLINKCOMSTR'] = link_python_module_message
+
+        lib = self.SharedLibrary(libname,lib_objs,
+                                 **kwargs)
+
+        ## Install it to the right spot
+        self.Install(install_dest, lib)
+        self.Alias('install', install_dest)
+
+        return lib
+
+    def VersionedSharedLibrary(self, libname, libversion, lib_objs=[]):
+        """ This creates a version library similar to libtool.
+
+        We name the library with the appropriate soname.
+        """
+        platform = self.subst('$PLATFORM')
+        shlib_pre_action = None
+        shlib_suffix = self.subst('$SHLIBSUFFIX')
+        shlib_post_action = None
+        shlink_flags = SCons.Util.CLVar(self.subst('$SHLINKFLAGS'))
+
+        if platform == 'posix':
+            shlib_post_action = [ 'rm -f $TARGET', 'ln -s ${SOURCE.file} $TARGET' ]
+            shlib_post_action_output_re = [ '%s\\.[0-9\\.]*$' % re.escape(shlib_suffix), shlib_suffix ]
+            shlib_suffix += '.' + libversion
+            shlink_flags += [ '-Wl,-Bsymbolic', '-Wl,-soname=${LIBPREFIX}%s%s' % (
+                    libname, shlib_suffix) ]
+        elif platform == 'aix':
+            shlib_pre_action = [ "nm -Pg $SOURCES > ${TARGET}.tmp1", "grep ' [BDT] ' < ${TARGET}.tmp1 > ${TARGET}.tmp2", "cut -f1 -d' ' < ${TARGET}.tmp2 > ${TARGET}", "rm -f ${TARGET}.tmp[12]" ]
+            shlib_pre_action_output_re = [ '$', '.exp' ]
+            shlib_post_action = [ 'rm -f $TARGET', 'ln -s $SOURCE $TARGET' ]
+            shlib_post_action_output_re = [ '%s\\.[0-9\\.]*' % re.escape(shlib_suffix), shlib_suffix ]
+            shlib_suffix += '.' + libversion
+            shlink_flags += ['-G', '-bE:${TARGET}.exp', '-bM:SRE']
+        elif platform == 'cygwin':
+            shlink_flags += [ '-Wl,-Bsymbolic', '-Wl,--out-implib,${TARGET.base}.a' ]
+        elif platform == 'darwin':
+            shlib_suffix = '.' + libversion + shlib_suffix
+            shlink_flags += [ '-dynamiclib', '-current-version %s' % libversion ]
+
+        lib = self.SharedLibrary(libname,lib_objs,
+                                 SHLIBSUFFIX=shlib_suffix,
+                                 SHLINKFLAGS=shlink_flags)
+
+        if shlib_pre_action:
+            shlib_pre_action_output = re.sub(shlib_pre_action_output_re[0], shlib_pre_action_output_re[1], str(lib[0]))
+            self.Command(shlib_pre_action_output, [ lib_objs ], shlib_pre_action)
+            self.Depends(lib, shlib_pre_action_output)
+
+        if shlib_post_action:
+            shlib_post_action_output = re.sub(shlib_post_action_output_re[0], shlib_post_action_output_re[1], str(lib[0]))
+            self.Command(shlib_post_action_output, lib, shlib_post_action)
+
+        return lib
+
+    def InstallVersionedSharedLibrary(self, destination, lib):
+        platform = self.subst('$PLATFORM')
+        shlib_suffix = self.subst('$SHLIBSUFFIX')
+        shlib_install_pre_action = None
+        shlib_install_post_action = None
+
+        if platform == 'posix':
+            shlib_post_action = [ 'rm -f $TARGET', 'ln -s ${SOURCE.file} $TARGET' ]
+            shlib_post_action_output_re = [ '%s\\.[0-9\\.]*$' % re.escape(shlib_suffix), shlib_suffix ]
+            shlib_install_post_action = shlib_post_action
+            shlib_install_post_action_output_re = shlib_post_action_output_re
+
+        ilib = self.Install(destination,lib)
+
+        if shlib_install_pre_action:
+            shlib_install_pre_action_output = re.sub(shlib_install_pre_action_output_re[0], shlib_install_pre_action_output_re[1], str(ilib[0]))
+            self.Command(shlib_install_pre_action_output, ilib, shlib_install_pre_action)
+            self.Depends(shlib_install_pre_action_output, ilib)
+
+        if shlib_install_post_action:
+            shlib_install_post_action_output = re.sub(shlib_install_post_action_output_re[0], shlib_install_post_action_output_re[1], str(ilib[0]))
+            self.Command(shlib_install_post_action_output, ilib, shlib_install_post_action)
+
+
+import subprocess
+
+def pkg_config(pkg, type):
+    try:
+        result = subprocess.Popen(["%s-config" % pkg, "--%s" % type],
+                                  stdout=subprocess.PIPE).communicate()[0]
+    except:
+        error("Unable to run %s-config - do you have the dev package installed?" % pkg)
+
+    return result.strip()
+
+
+# Sensible default for common types on common platforms.
+_DEFAULTS = {
+    'char': [1,],
+    'short' : [2,],
+    'int' : [4, 2],
+    'long' : [4, 8],
+    'long long' : [8, 4],
+    # Normally, there is no need to check unsigned types, because they are
+    # guaranteed to be of the same size than their signed counterpart.
+    'unsigned char': [1,],
+    'unsigned short' : [2,],
+    'unsigned int' : [4, 2],
+    'unsigned long' : [4, 8],
+    'unsigned long long' : [8, 4],
+    'float' : [4,],
+    'double' : [8,],
+    'long double' : [12,],
+    'size_t' : [4,],
+}
+
+def CheckTypeSize(context, type, includes = None, language = 'C', size = None):
+    """This check can be used to get the size of a given type, or to check whether
+    the type is of expected size.
+
+    Arguments:
+        - type : str
+            the type to check
+        - includes : sequence
+            list of headers to include in the test code before testing the type
+        - language : str
+            'C' or 'C++'
+        - size : int
+            if given, will test wether the type has the given number of bytes.
+            If not given, will test against a list of sizes (all sizes between
+            0 and 16 bytes are tested).
+
+        Returns:
+                status : int
+                        0 if the check failed, or the found size of the type if the check succeeded."""
+    minsz = 0
+    maxsz = 16
+
+    if includes:
+        src = "\n".join([r"#include <%s>\n" % i for i in includes])
+    else:
+        src = ""
+
+    if language == 'C':
+        ext = '.c'
+    elif language == 'C++':
+        ext = '.cpp'
+    else:
+        raise NotImplementedError("%s is not a recognized language" % language)
+
+    # test code taken from autoconf: this is a pretty clever hack to find that
+    # a type is of a given size using only compilation. This speeds things up
+    # quite a bit compared to straightforward code using TryRun
+    src += r"""
+typedef %s scons_check_type;
+
+int main()
+{
+    static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) <= %d)];
+    test_array[0] = 0;
+
+    return 0;
+}
+"""
+
+    if size:
+        # Only check if the given size is the right one
+        context.Message('Checking %s is %d bytes... ' % (type, size))
+        st = context.TryCompile(src % (type, size), ext)
+        context.Result(st)
+
+        if st:
+            return size
+        else:
+            return 0
+    else:
+        # Only check if the given size is the right one
+        context.Message('Checking size of %s ... ' % type)
+
+        # Try sensible defaults first
+        try:
+            szrange = _DEFAULTS[type]
+        except KeyError:
+            szrange = []
+        szrange.extend(xrange(minsz, maxsz))
+        st = 0
+
+        # Actual test
+        for sz in szrange:
+            st = context.TryCompile(src % (type, sz), ext)
+            if st:
+                break
+
+        if st:
+            context.Result('%d' % sz)
+            return sz
+        else:
+            context.Result('Failed !')
+            return 0
+
+#For example, to check wether long is 4 bytes on your platform, you can do:
+#config.CheckTypeSize('long', size = 4).
+## Now check the sizes
