Initial revision
authorMatthias Clasen <matthiasc@src.gnome.org>
Mon, 9 May 2005 14:24:46 +0000 (14:24 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Mon, 9 May 2005 14:24:46 +0000 (14:24 +0000)
31 files changed:
README [new file with mode: 0644]
TODO [new file with mode: 0644]
gidl.dtd [new file with mode: 0644]
metadata-format.txt [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/compiler.c [new file with mode: 0644]
src/generate.c [new file with mode: 0644]
src/gidlmodule.c [new file with mode: 0644]
src/gidlmodule.h [new file with mode: 0644]
src/gidlnode.c [new file with mode: 0644]
src/gidlnode.h [new file with mode: 0644]
src/gidlparser.c [new file with mode: 0644]
src/gidlparser.h [new file with mode: 0644]
src/ginfo.c [new file with mode: 0644]
src/girepository.c [new file with mode: 0644]
src/girepository.h [new file with mode: 0644]
src/gmetadata.c [new file with mode: 0644]
src/gmetadata.h [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/array.test [new file with mode: 0644]
tests/boxed.test [new file with mode: 0644]
tests/enum.test [new file with mode: 0644]
tests/errors.test [new file with mode: 0644]
tests/function.test [new file with mode: 0644]
tests/gobject.test [new file with mode: 0644]
tests/interface.test [new file with mode: 0644]
tests/object.test [new file with mode: 0644]
tests/object.test1 [new file with mode: 0644]
tests/roundtrips.sh [new file with mode: 0755]
tests/xref1.test [new file with mode: 0644]
tests/xref2.test [new file with mode: 0644]

diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1f07049
--- /dev/null
+++ b/README
@@ -0,0 +1,18 @@
+This is a very first prototype of an introspection framework for GObject. 
+
+The metadata format is described in metadata-format.txt, the XML IDL format 
+follows the DTD in gidl.dtd. Look at the files in tests/ for IDL examples. 
+
+The code in src/ currently produces three things:
+- g-idl-compile, a metadata compiler. It converts one or more IDL files 
+  into one or more metadata blobs. It can either emit the raw metadata 
+  blob (--raw) or C code (--code). 
+- libirepository, the repository API. 
+- g-idl-generate, an IDL generator, using the repository API. It generates
+  IDL files from binary metadata which can be in a shared object, or a raw
+  metadata blob (--raw). 
+
+There are a number of IDL test files in test/, and a script to do
+roundtrip tests (IDL -> binary -> IDL).
+The introspection framework needs a lot more work, see TODO. 
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..8556a0f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,30 @@
+XML format
+----------
+- Document the format
+- Write a tool to create XML from annotated headers
+- Add attributes to connect signals to their default handlers
+  and wrappers to their vfuncs
+
+Binary format
+-------------
+- Add hashes to lookup interfaces and functions in interfaces
+- Write a validator
+
+Compiler
+--------
+- Cleanup, maybe turn the nodes in to objects to avoid the horrific 
+  type switches
+- Add thorough error checking
+
+Repository
+----------
+- Reconsider the current clunky API, maybe an iterator approach is better
+- Add thorough error checking
+- Use hashes 
+- Implement g_function_info_invoke()
+- Maybe allow populating repositories at runtime
+
+General
+-------
+- More tests
+- Check how the format scales to something of GTK+ size
diff --git a/gidl.dtd b/gidl.dtd
new file mode 100644 (file)
index 0000000..26bd3f0
--- /dev/null
+++ b/gidl.dtd
@@ -0,0 +1,132 @@
+<!ELEMENT api (namespace+) >
+
+<!ATTLIST api version CDATA #REQUIRED >
+
+<!ELEMENT namespace (function|callback|object|interface|enum|flags|boxed|struct|constant|errordomain)* >
+<!ATTLIST namespace name CDATA #REQUIRED >
+
+<!ELEMENT function (return-type,parameters?) >
+<!ATTLIST function name CDATA #REQUIRED
+                   cname CDATA #REQUIRED
+                   deprecated (0|1) #IMPLIED >
+<!ELEMENT parameters (parameter+) >
+<!ELEMENT return-type EMPTY >                   
+<!ATTLIST return-type type CDATA #REQUIRED
+                      null-ok (0|1) #IMPLIED
+                      transfer (full|shallow|none) #IMPLIED >
+
+
+<!ELEMENT parameter EMPTY >
+<!ATTLIST parameter type CDATA #REQUIRED
+                    name CDATA #REQUIRED
+                    direction (in|out|inout) #IMPLIED
+                    retval (0|1) #IMPLIED
+                   dipper (0|1) #IMPLIED
+                   optional (0|1) #IMPLIED
+                    null-ok (0|1) #IMPLIED
+                    transfer (full|shallow|none) #IMPLIED >
+                                
+<!ELEMENT callback (return-type,parameters?) >
+<!ATTLIST callback name CDATA #REQUIRED
+                   cname CDATA #IMPLIED
+                   deprecated (0|1) #IMPLIED >
+
+<!ELEMENT object (implements|field|signal|method|property|vfunc|constructor|constant)* >
+<!ATTLIST object name CDATA #IMPLIED
+                 cname CDATA #REQUIRED
+                 parent CDATA #REQUIRED
+                 get-type CDATA #IMPLIED
+                 deprecated (0|1) #IMPLIED >
+
+<!ELEMENT implements (interface+) >
+
+<!ELEMENT method (return-type,parameters?) >
+<!ATTLIST method name CDATA #REQUIRED
+                 cname CDATA #REQUIRED
+                 deprecated (0|1) #IMPLIED 
+                 type (setter|getter) #IMPLIED >
+
+<!ELEMENT constructor (parameters?) >
+<!ATTLIST constructor name CDATA #REQUIRED
+                      cname CDATA #REQUIRED
+                      deprecated (0|1) #IMPLIED >
+
+<!ELEMENT interface ((requires|signal|method|property|vfunc|constant)*) >
+<!ATTLIST interface name CDATA #REQUIRED
+                    cname CDATA #REQUIRED
+                    get-type CDATA #IMPLIED
+                    deprecated (0|1) #IMPLIED >
+
+<!ELEMENT requires ((interface|object)*) >
+
+<!ELEMENT property EMPTY >
+<!ATTLIST property name CDATA #REQUIRED
+                   cname CDATA #REQUIRED
+                   type CDATA #REQUIRED
+                   readable (0|1) #IMPLIED
+                   writable (0|1) #IMPLIED
+                   construct (0|1) #IMPLIED
+                   construct-only (0|1) #IMPLIED >
+
+<!ELEMENT signal (return-type,parameters) >
+<!ATTLIST signal name CDATA #REQUIRED 
+                 cname CDATA #REQUIRED
+                 when (FIRST|LAST|CLEANUP) #REQUIRED
+                 no-recurse (0|1) #IMPLIED
+                 detailed (0|1) #IMPLIED
+                 action (0|1) #IMPLIED
+                 no-hooks (0|1) #IMPLIED 
+                 has-class-closure (0|1) #IMPLIED > 
+
+<!ELEMENT vfunc (return-type,parameters?) >
+<!ATTLIST vfunc name CDATA #REQUIRED 
+                cname CDATA #REQUIRED
+                must-chain-up (0|1) #IMPLIED
+                override (always|never|maybe) #IMPLIED
+                is-class-closure (0|1) #IMPLIED > 
+
+<!ELEMENT field EMPTY >
+<!ATTLIST field cname CDATA #REQUIRED 
+                type CDATA #REQUIRED
+                bits CDATA #IMPLIED >
+
+<!ELEMENT enum (member+) >
+<!ATTLIST enum name CDATA #REQUIRED 
+               cname CDATA #REQUIRED
+               get-type CDATA #IMPLIED
+               deprecated (0|1) #IMPLIED >
+
+
+<!ELEMENT flags (member+) >
+<!ATTLIST flags name CDATA #REQUIRED 
+                cname CDATA #REQUIRED
+                get-type CDATA #IMPLIED
+                deprecated (0|1) #IMPLIED >
+
+<!ELEMENT member EMPTY >
+<!ATTLIST member name CDATA #REQUIRED
+                 cname CDATA #REQUIRED
+                 value CDATA #IMPLIED
+                 deprecated (0|1) #IMPLIED >
+
+<!ELEMENT boxed ((field|method)*) >
+<!ATTLIST boxed name CDATA #REQUIRED 
+                cname CDATA #REQUIRED
+                get-type CDATA #IMPLIED
+                deprecated (0|1) #IMPLIED >
+
+<!ELEMENT struct ((field|method)*) >
+<!ATTLIST struct name CDATA #REQUIRED 
+                 cname CDATA #REQUIRED
+                 deprecated (0|1) #IMPLIED >
+
+<!ELEMENT constant EMPTY >
+<!ATTLIST constant name CDATA #REQUIRED 
+                   type CDATA #REQUIRED
+                   value CDATA #REQUIRED
+                   deprecated (0|1) #IMPLIED >
+
+<!ELEMENT errordomain EMPTY >
+<!ATTLIST errordomain name CDATA #REQUIRED 
+                      get-quark CDATA #REQUIRED
+                      codes CDATA #REQUIRED >
diff --git a/metadata-format.txt b/metadata-format.txt
new file mode 100644 (file)
index 0000000..d9b7fd7
--- /dev/null
@@ -0,0 +1,995 @@
+GObject binary metadata for introspection
+-----------------------------------------
+
+Version 0.3
+
+Changes since 0.2:
+- make inline types 4 bytes after all, remove header->types and allow
+  types to appear anywhere
+- allow error domains in the directory
+
+Changes since 0.1:
+
+- drop comments about _GOBJ_METADATA
+- drop string pool, strings can appear anywhere
+- use 'blob' as collective name for the various blob types
+- rename 'type' field in blobs to 'blob_type'
+- rename 'type_name' and 'type_init' fields to 'gtype_name', 'gtype_init'
+- shrink directory entries to 12 bytes 
+- merge struct and boxed blobs
+- split interface blobs into enum, object and interface blobs
+- add an 'unregistered' flag to struct and enum blobs
+- add a 'wraps_vfunc' flag to function blobs and link them to 
+  the vfuncs they wrap
+- restrict value blobs to only occur inside enums and flags again
+- add constant blobs, allow them toplevel, in interfaces and in objects
+- rename 'receiver_owns_value' and 'receiver_owns_container' to
+  'transfer_ownership' and 'transfer_container_ownership'
+- add a 'struct_offset' field to virtual function and field blobs
+- add 'dipper' and 'optional' flags to arg blobs
+- add a 'true_stops_emit' flag to signal blobs
+- add variable blob sizes to header
+- store offsets to signature blobs instead of including them directly
+- change the type offset to be measured in words rather than bytes
+
+
+Metadata
+--------
+
+The format of GObject metadata is strongly influenced by the Mozilla XPCOM 
+format. 
+
+Some of the differences to XPCOM include:
+- Type information is stored not quite as compactly (XPCOM stores it inline 
+  in function descriptions in variable-sized blobs of 1 to n bytes. We store 
+  16 bits of type information for each parameter, which is enough to encode 
+  simple types inline. Complex (e.g. recursive) types are stored out of line 
+  in a separate list of types.
+- String and complex type data is stored outside of interface blobs, references 
+  are stored as offsets relative to the start of the metadata. One possibility
+  is to store the strings and types in a pools at the end of the metadata.
+
+Overview
+--------
+
+The metadata has the following general format.
+
+metadata ::= header, directory, blobs, annotations
+
+directory ::= list of entries
+
+entry ::= blob type, name, namespace, offset
+
+blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain
+
+annotations ::= list of annotations, sorted by offset 
+
+annotation ::= offset, key, value
+
+
+Details
+-------
+
+We describe the fragments that make up the metadata in the form of C structs 
+(although some fall short of being valid C structs since they contain multiple
+flexible arrays).
+
+Header (70 bytes)
+
+struct Header 
+{
+  gchar[16] magic;
+  guint8    major_version;
+  guint8    minor_version;
+  guint16   reserved;
+
+  guint16   n_entries;
+  guint16   n_local_entries;
+  guint32   directory;
+  guint32   annotations;
+
+  guint32   size;
+  guint32   namespace;
+  
+  guint16   entry_blob_size;        /* 12 */
+  guint16   function_blob_size;     /* 16 */
+  guint16   callback_blob_size;     /* 12 */
+  guint16   signal_blob_size;       /* 12 */
+  guint16   vfunc_blob_size;        /* 16 */
+  guint16   arg_blob_size;          /* 12 */
+  guint16   property_blob_size;     /* 12 */
+  guint16   field_blob_size;        /* 12 */  
+  guint16   value_blob_size;        /* 16 */
+  guint16   constant_blob_size;     /* 20 */
+  guint16   error_domain_blob_size; /* 16 */
+  guint16   annotation_blob_size;   /* 12 */
+
+  guint16   signature_blob_size;    /*  4 */
+  guint16   enum_blob_size;         /* 20 */
+  guint16   struct_blob_size;       /* 20 */
+  guint16   object_blob_size;       /* 32 */
+  guint16   interface_blob_size;    /* 28 */
+}
+
+magic:    The string "GOBJ\nMETADATA\r\n\032". This was inspired by XPCOM, 
+          which in turn borrowed from PNG.
+
+major_version, 
+minor_version: 
+          The version of the metadata format. Minor version changes indicate 
+          compatible changes and should still allow the metadata to be parsed 
+          by a parser designed for the same major_version.
+      
+n_entries: 
+          The number of entries in the directory. 
+
+n_local_entries:
+         The number of entries referring to blobs in this metadata. The
+         local entries must occur before the unresolved entries.
+
+directory: 
+          Offset of the directory in the metadata. 
+          FIXME: need to specify if and how the directory is sorted
+
+annotations: 
+          Offset of the list of annotations in the metadata.
+
+size:     The size of the metadata.
+
+namespace:
+          Offset of the namespace string in the metadata. 
+
+entry_blob_size:
+function_blob_size:
+callback_blob_size:
+signal_blob_size:
+vfunc_blob_size:
+arg_blob_size:
+property_blob_size:
+field_blob_size:
+value_blob_size:
+annotation_blob_size:
+constant_blob_size:
+          The sizes of fixed-size blobs. Recording this information here
+          allows to write parser which continue to work if the format is
+          extended by adding new fields to the end of the fixed-size blobs.
+
+signature_blob_size: 
+enum_blob_size:
+struct_blob_size:
+interface_blob_size:
+          For variable-size blobs, the size of the struct up to the first
+          flexible array member. Recording this information here allows to 
+          write parser which continue to work if the format is extended by 
+          adding new fields before the first flexible array member in 
+          variable-size blobs.
+
+Directory entry (12 bytes)
+
+struct DirectoryEntry 
+{
+  guint16 blob_type;
+
+  guint   is_local : 1;
+  guint   reserved :15;
+
+  guint32 name;
+  guint32 offset;
+}
+
+blob_type:
+          The type of blob this entry points to:
+          1 function
+          2 callback
+          3 struct
+          4 boxed
+          5 enum
+          6 flags
+          7 object
+          8 interface
+          9 constant
+        10 errordomain
+
+is_local: Wether this entry refers to a blob in this metadata.
+
+name:     The name of the entry.
+
+offset:   If is_local is set, this is the offset of the blob in the metadata.
+          Otherwise, it is the offset of the namespace in which the blob has
+          to be looked up by name.
+
+
+All blobs pointed to by a directory entry start with the same layout for 
+the first 8 bytes (the reserved flags may be used by some interface types)
+
+struct InterfacePrefix 
+{
+  guint16 blob_type; 
+  guint   deprecated : 1;
+  guint   reserved   :15;
+  guint32 name;
+}
+
+blob_type: 
+          An integer specifying the type of the blob, see DirectoryEntry 
+          for details.
+
+deprecated: 
+          Wether the blob is deprecated.
+
+name:     The name of the blob.
+
+
+The SignatureBlob is shared between Functions, 
+Callbacks, Signals and VirtualFunctions.
+
+SignatureBlob (8 + 12 * n_arguments bytes)
+
+struct SignatureBlob 
+{
+  SimpleTypeBlob    return_type;
+
+  guint             may_return_null              : 1;
+  guint             caller_owns_return_value     : 1;
+  guint             caller_owns_return_container : 1;
+  guint             reserved                     :13;
+
+  guint16           n_arguments;
+
+  ArgBlob[]         arguments;
+}
+
+return_type:
+          Describes the type of the return value. See details below.
+
+may_return_null:
+          Only relevant for pointer types. Indicates whether the caller
+          must expect NULL as a return value.
+
+caller_owns_return_value:
+          If set, the caller is responsible for freeing the return value
+          if it is no longer needed.
+
+caller_owns_return_container:
+          This flag is only relevant if the return type is a container type.
+          If the flag is set, the caller is resonsible for freeing the 
+          container, but not its contents.
+                     
+n_arguments:
+          The number of arguments that this function expects, also the length 
+          of the array of ArgBlobs.
+
+arguments: 
+          An array of ArgBlob for the arguments of the function.
+
+
+FunctionBlob (16 bytes)
+
+struct FunctionBlob 
+{
+  guint16 blob_type;  /* 1 */
+
+  guint   deprecated     : 1;
+  guint   is_setter      : 1; 
+  guint   is_getter      : 1;
+  guint   is_constructor : 1;
+  guint   wraps_vfunc    : 1;
+  guint   reserved       : 1;
+  guint   index          :10;
+
+  guint32 name;
+  guint32 c_name;
+  guint32 signature;
+}
+
+c_name:   The symbol which can be used to obtain the function pointer with 
+          dlsym().
+
+deprecated
+          The function is deprecated.
+
+is_setter
+          The function is a setter for a property. Language bindings may 
+          prefer to not bind individual setters and rely on the generic 
+          g_object_set().
+
+is_getter
+          The function is a getter for a property. Language bindings may 
+          prefer to not bind individual getters and rely on the generic 
+          g_object_get().
+
+is_constructor
+          The function acts as a constructor for the object it is contained 
+          in. 
+
+wraps_vfunc: 
+          The function is a simple wrapper for a virtual function.
+
+index:    Index of the property that this function is a setter or getter of 
+          in the array of properties of the containing interface, or index
+          of the virtual function that this function wraps.
+
+signature: 
+          Offset of the SignatureBlob describing the parameter types and the 
+          return value type.
+
+
+CallbackBlob (12 bytes)
+
+struct CallbackBlob 
+{
+  guint16 blob_type;  /* 2 */
+
+  guint   deprecated : 1;
+  guint   reserved   :15;
+
+  guint32 name;
+  guint32 signature;
+}
+
+signature: 
+          Offset of the SignatureBlob describing the parameter types and the 
+          return value type.
+
+
+ArgBlob (12 bytes)
+
+struct ArgBlob 
+{
+  guint32 name;
+
+  guint          in                           : 1;
+  guint          out                          : 1;
+  guint          dipper                       : 1;
+  guint          null_ok                      : 1;
+  guint          optional                     : 1;
+  guint          transfer_ownership           : 1;
+  guint          transfer_container_ownership : 1;
+  guint          is_return_value              : 1;
+  guint          reserved                     :24:
+
+  SimpleTypeBlob arg_type;
+}
+
+name:     A suggested name for the parameter. 
+
+in:       The parameter is an input to the function
+
+out:      The parameter is used to return an output of the function. 
+          Parameters can be both in and out. Out parameters implicitly 
+          add another level of indirection to the parameter type. Ie if 
+          the type is uint32 in an out parameter, the function actually 
+          takes an uint32*.
+
+dipper:   The parameter is a pointer to a struct or object that will 
+          receive an output of the function. 
+
+null_ok:  Only meaningful for types which are passed as pointers.
+          For an in parameter, indicates if it is ok to pass NULL in, for 
+          an out parameter, wether it may return NULL. Note that NULL is a 
+          valid GList and GSList value, thus null_ok will normally be set for 
+          parameters of these types.
+
+optional:          
+          For an out parameter, indicates that NULL may be passed in
+          if the value is not needed.
+
+transfer_ownership:
+          For an in parameter, indicates that the function takes over 
+          ownership of the parameter value. For an out parameter, it 
+          indicates that the caller is responsible for freeing the return 
+          value.
+
+transfer_container_ownership:
+          For container types, indicates that the ownership of the container, 
+          but not of its contents is transferred. This is typically the case 
+          for out parameters returning lists of statically allocated things.
+
+is_return_value:
+          The parameter should be considered the return value of the function. 
+          Only out parameters can be marked as return value, and there can be 
+          at most one per function call. If an out parameter is marked as 
+          return value, the actual return value of the function should be 
+          either void or a boolean indicating the success of the call.
+  
+arg_type:
+          Describes the type of the parameter. See details below.
+
+
+Types are specified by two bytes. If the high bytes are zero, the low byte 
+describes a basic type, otherwise the 32bit number is an offset which points 
+to a TypeBlob. 
+
+
+SimpleTypeBlob (4 bytes)
+
+union SimpleTypeBlob 
+{
+  struct 
+  {
+    guint  reserved   :24;      /* 0 */
+    guint  is_pointer : 1;
+    guint  reserved   : 2;
+    guint  tag        : 5;
+  };
+  guint32 offset;
+}
+
+is_pointer: 
+          indicates wether the type is passed by reference. 
+
+tag:      specifies what kind of type is described, as follows:
+          0  void
+          1  boolean (booleans are passed as ints)
+          2  int8
+          3  uint8
+          4  int16
+          5  uint16
+          6  int32
+          7  uint32
+          8  int64
+          9  uint64
+         10  float
+         11  double
+         12  string  (these are zero-terminated char* and assumed to be 
+                      in UTF-8, for other data, use uint8[])
+         13 GString 
+
+         For string and GString, is_pointer will always be set.
+
+offset:  Offset relative to header->types that points to a TypeBlob. 
+         Unlike other offsets, this is in words (ie 32bit units) rather
+         than bytes.
+
+
+TypeBlob (4 or more bytes)
+
+union TypeBlob
+{
+  ArrayTypeBlob        array_type;
+  InterfaceTypeBlob    interface_type;
+  ParameterTypeBlob    parameter_type;  
+  ErrorTypeBlob        error_type;  
+}
+
+
+ArrayTypeBlob (4 bytes)
+
+Arrays have a tag value of 20. They are passed by reference, thus is_pointer 
+is always 1.
+
+struct ArrayTypeBlob 
+{
+  guint          is_pointer      :1; /* 1 */
+  guint          reserved        :2;
+  guint          tag             :5; /* 20 */
+  guint          zero_terminated :1;
+  guint          has_length      :1;
+  guint          length          :6;  
+
+  SimpleTypeBlob type;
+}
+
+zero_terminated: 
+          Indicates that the array must be terminated by a suitable NULL 
+          value. 
+
+has_length: 
+          Indicates that length points to a parameter specifying the length 
+          of the array. If both has_length and zero_terminated are set, the 
+          convention is to pass -1 for the length if the array is 
+          zero-terminated. 
+          FIXME: what does this mean for types of field and properties ?
+
+length:   The index of the parameter which is used to pass the length of the 
+          array. The parameter must be an integer type and have the same 
+          direction as this one. 
+
+type:     The type of the array elements.
+
+
+InterfaceTypeBlob (4 bytes)
+
+struct InterfaceTypeBlob 
+{
+  guint   is_pointer :1; 
+  guint   reserved   :2;
+  guint   tag        :5; /* 21 */
+  guint8  reserved;
+
+  guint16 interface;
+}
+
+Types which are described by an entry in the metadata have a tag value of 21. 
+If the interface is an enum of flags type, is_pointer is 0, otherwise it is 1.
+
+interface: 
+          Index of the directory entry for the interface.
+    
+
+ParameterTypeBlob (4 + n * 4 bytes)
+
+GLists have a tag value of 22, GSLists have a tag value of 23, GHashTables have a
+tag value of 24. They are passed by reference, thus is_pointer is always 1.
+
+struct ParameterTypeBlob 
+{
+  guint          is_pointer :1; /* 1 */
+  guint          reserved   :2;
+  guint          tag        :5; /* 22, 23 or 24 */
+  guint          reserved   :8;
+
+  guint16        n_types;
+
+  SimpleTypeBlob type[];
+}
+
+n_types:  The number of parameter types to follow.
+
+type:     Describes the type of the list elements.
+
+
+ErrorTypeBlob (4 + 2 * n_domains bytes)
+
+struct ErrorTypeBlob
+{
+  guint           is_pointer :1; /* 1 */
+  guint           reserved   :2;
+  guint           tag        :5; /* 25 */
+  
+  guint8          reserved;
+
+  guint16         n_domains;
+
+  guint16         domains[];
+}
+
+n_domains:
+          The number of domains to follow
+
+domains:  Indices of the directory entries for the error domains
+
+
+ErrorDomainBlob (16 bytes)
+
+struct ErrorDomainBlob
+{
+  guint16        blob_type;  /* 10 */
+
+  guint          deprecated     : 1;
+  guint          reserved       :15; 
+
+  guint32        name;
+
+  guint32        get_quark;
+  guint16        error_codes;
+}
+
+get_quark:
+          The symbol name of the function which must be called to obtain the 
+          GQuark for the error domain.
+
+error_codes:
+          Index of the InterfaceBlob describing the enumeration which lists
+          the possible error codes.
+
+
+PropertyBlob (12 bytes)
+
+struct PropertyBlob
+{
+  guint32        name;
+
+  guint          deprecated     : 1;
+  guint          readable       : 1;
+  guint          writable       : 1;
+  guint          construct      : 1;
+  guint          construct_only : 1;
+  guint          reserved       :27
+
+  SimpleTypeBlob type;
+}
+
+name:     The name of the property. 
+
+readable:
+writable: 
+construct: 
+construct_only: 
+          The ParamFlags used when registering the property.
+
+type:     Describes the type of the property.
+
+
+SignalBlob (12 bytes)
+
+struct SignalBlob 
+{
+  guint32 name;
+
+  guint   deprecated        : 1;
+  guint   run_first         : 1;
+  guint   run_last          : 1;
+  guint   run_cleanup       : 1;
+  guint   no_recurse        : 1;
+  guint   detailed          : 1;
+  guint   action            : 1;
+  guint   no_hooks          : 1;
+  guint   has_class_closure : 1;
+  guint   true_stops_emit   : 1;
+  guint   reserved          : 5;
+
+  guint16 class_closure;
+  guint32 signature; 
+}
+
+name:     The name of the signal.
+
+run_first:
+run_last:
+run_cleanup:
+no_recurse:
+detailed:
+action:
+no_hooks: The flags used when registering the signal.
+
+has_class_closure: 
+          Set if the signal has a class closure.
+
+true_stops_emit:
+          Wether the signal has true-stops-emit semantics          
+
+class_closure: 
+          The index of the class closure in the list of virtual functions
+          of the interface on which the signal is defined.
+
+signature: 
+          Offset of the SignatureBlob describing the parameter types and the 
+          return value type.
+
+
+VirtualFunctionBlob (16 bytes)
+
+struct VirtualFunctionBlob 
+{
+  guint32 name;
+
+  guint   must_chain_up           : 1;
+  guint   must_be_implemented     : 1;
+  guint   must_not_be_implemented : 1;
+  guint   is_class_closure        : 1;
+  guint   reserved                :12;
+
+  guint16 signal;
+  guint16 struct_offset;
+  guint16 reserved;  
+  guint32 signature;
+}
+
+name:     The name of the virtual function.
+
+must_chain_up:
+          If set, every implementation of this virtual function must
+          chain up to the implementation of the parent class. 
+
+must_be_implemented:
+          If set, every derived class must override this virtual function.
+
+must_not_be_implemented:
+          If set, derived class must not override this virtual function.
+
+is_class_closure:
+          Set if this virtual function is the class closure of a signal.
+
+signal: 
+          The index of the signal in the list of signals of the interface 
+          to which this virtual function belongs.
+
+struct_offset:
+          The offset of the function pointer in the class struct.
+
+signature: 
+          Offset of the SignatureBlob describing the parameter types and the 
+          return value type.
+
+
+FieldBlob (12 bytes)
+
+struct FieldBlob 
+{
+  guint32        name;
+
+  guint          readable : 1; 
+  guint          writable : 1;
+  guint          reserved : 6;
+  guint8         bits;
+  
+  guint16        struct_offset;      
+       
+  SimpleTypeBlob type;
+}
+
+name:     The name of the field.
+
+readable:
+writable: How the field may be accessed.
+
+bits:     If this field is part of a bitfield, the number of bits which it
+          uses, otherwise 0.
+
+struct_offset:
+          The offset of the field in the struct.
+
+type:     The type of the field.
+
+
+ValueBlob (16 bytes)
+
+Values commonly occur in enums and flags, but we also allow them to occur
+in interfaces or freestanding, to describe constants.
+
+struct ValueBlob
+{
+  guint   deprecated : 1;
+  guint   reserved   :31;
+  guint32 name;
+
+  guint32 short_name;
+  guint32 value;
+}
+
+short_name: 
+          A short name for the value;
+
+value:    The numerical value;
+
+
+GTypeBlob (8 bytes)
+
+struct GTypeBlob 
+{
+  guint32 gtype_name;
+  guint32 gtype_init;
+}
+
+gtype_name: 
+          The name under which the interface is registered with GType.
+
+gtype_init:
+          The symbol name of the get_type() function which registers the type.
+
+
+StructBlob (20 + 8 * n_fields + x * n_functions)
+
+struct StructBlob 
+{
+  guint16      blob_type; /* 3: struct, 4: boxed */
+  guint        deprecated   : 1;
+  guint        unregistered : 1;
+  guint        reserved     :14;
+  guint32      name;
+
+  GTypeBlob    gtype;
+
+  guint16      n_fields;
+  guint16      n_functions;
+
+  FieldBlob    fields[];   
+  FunctionBlob functions[];  
+}
+
+unregistered: 
+          If this is set, the type is not registered with GType.
+
+gtype:    For types which are registered with GType, contains the 
+          information about the GType. Otherwise unused.
+
+n_fields: 
+n_functions: 
+          The lengths of the arrays.
+
+fields:   An array of n_fields FieldBlobs. 
+
+functions:
+          An array of n_functions FunctionBlobs. The described functions 
+          should be considered as methods of the struct. 
+
+
+EnumBlob (20 + 16 * n_values)
+
+struct EnumBlob
+{
+  guint16   blob_type;  /* 5: enum, 6: flags */
+  guint     deprecated   : 1; 
+  guint     unregistered : 1;
+  guint     reserved     :14;
+  guint32   name; 
+
+  GTypeBlob gtype;
+
+  guint16   n_values;
+  guint16   reserved;
+
+  ValueBlob values[];    
+}
+
+unregistered: 
+          If this is set, the type is not registered with GType.
+
+gtype:    For types which are registered with GType, contains the 
+          information about the GType. Otherwise unused.
+
+n_values:
+          The lengths of the values arrays.
+
+values:   Describes the enum values. 
+
+
+ObjectBlob (32 + x bytes)
+
+struct ObjectBlob
+{
+  guint16 blob_type;  /* 7 */
+  guint   deprecated   : 1; 
+  guint   reserved     :15;
+  guint32 name; 
+
+  GTypeBlob gtype;
+
+  guint16 parent;
+
+  guint16 n_interfaces;
+  guint16 n_fields;
+  guint16 n_properties;
+  guint16 n_methods;
+  guint16 n_signals;
+  guint16 n_virtual_functions;
+  guint16 n_constants;
+
+  guint16 interfaces[];
+  FieldBlob           fields[];
+  PropertyBlob        properties[];
+  FunctionBlob        methods[];
+  SignalBlob          signals[];
+  VirtualFunctionBlob virtual_functions[];
+  ConstantBlob        constants[];
+} 
+
+gtype:    Contains the information about the GType.
+
+parent:   The directory index of the parent interface. This is only set for 
+          objects.
+
+n_interfaces:
+n_fields: 
+n_properties:
+n_methods:
+n_signals:
+n_virtual_functions:
+n_constants:
+          The lengths of the arrays.
+
+Up to 16bits of padding may be inserted between the arrays to ensure that they
+start on a 32bit boundary.
+
+interfaces:
+          An array of indices of directory entries for the implemented 
+          interfaces.
+
+fields:   Describes the fields. 
+
+functions: 
+          Describes the methods, constructors, setters and getters. 
+
+properties:
+          Describes the properties. 
+
+signals:  Describes the signals. 
+
+virtual_functions:
+          Describes the virtual functions. 
+
+constants:
+          Describes the constants.
+
+
+InterfaceBlob (28 + x bytes)
+
+struct InterfaceBlob
+{
+  guint16 blob_type;  /* 8 */
+  guint   deprecated   : 1; 
+  guint   reserved     :15;
+  guint32 name; 
+
+  GTypeBlob gtype;
+
+  guint16 n_prerequisites;
+  guint16 n_properties;
+  guint16 n_methods;
+  guint16 n_signals;
+  guint16 n_virtual_functions;
+  guint16 n_constants;  
+
+  guint16 prerequisites[];
+  PropertyBlob        properties[];
+  FunctionBlob        methods[];
+  SignalBlob          signals[];
+  VirtualFunctionBlob virtual_functions[];
+  ConstantBlob        constants[];
+} 
+
+n_prerequisites:
+n_properties:
+n_methods:
+n_signals:
+n_virtual_functions:
+n_constants:
+          The lengths of the arrays.
+
+Up to 16bits of padding may be inserted between the arrays to ensure that they
+start on a 32bit boundary.
+
+prerequisites:
+          An array of indices of directory entries for required interfaces.
+
+functions: 
+          Describes the methods, constructors, setters and getters. 
+
+properties:
+          Describes the properties. 
+
+signals:  Describes the signals. 
+
+virtual_functions:
+          Describes the virtual functions. 
+
+constants:
+          Describes the constants.
+
+
+ConstantBlob (20 bytes)
+
+struct ConstantBlob
+{
+  guint16        blob_type;  /* 9 */
+  guint          deprecated   : 1; 
+  guint          reserved     :15;
+  guint32        name; 
+
+  SimpleTypeBlob type;
+  guint32        size;
+  guint32        offset;
+}
+
+type:     The type of the value. In most cases this should be a numeric
+          type or string.
+
+size:     The size of the value in bytes.
+
+offset:   The offset of the value in the metadata.
+
+
+AnnotationBlob (12 bytes)
+
+struct AnnotationBlob
+{ 
+  guint32 offset;
+  guint32 name;
+  guint32 value;
+}
+
+offset:   The offset of the interface to which this annotation refers. 
+          Annotations are kept sorted by offset, so that the annotations 
+          of an interface can be found by a binary search.
+
+name:     The name of the annotation, a string.
+
+value:    The value of the annotation (also a string)
+
+
+
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..fe96a1f
--- /dev/null
@@ -0,0 +1,38 @@
+AR=ar
+CC=gcc -g
+CFLAGS=`pkg-config --cflags glib-2.0 gobject-2.0`
+LIBS=`pkg-config --libs glib-2.0 gobject-2.0`
+
+LIBIREPOSITORY_OBJS =  \
+       girepository.o  \
+       gmetadata.o     \
+       ginfo.o
+
+COMPILER_OBJS =        \
+       gidlparser.o    \
+       gidlmodule.o    \
+       gidlnode.o      \
+       gmetadata.o     \
+       compiler.o      
+
+GENERATE_OBJS = generate.o
+
+all: libirepository.so g-idl-generate g-idl-compiler
+
+libirepository.so: $(LIBIREPOSITORY_OBJS)
+       $(CC) -shared -o $@ $(LIBIREPOSITORY_OBJS) $(LIBS)
+
+libirepository.a: $(LIBIREPOSITORY_OBJS)
+        $(AR) csr $@ $(LIBIREPOSITORY_OBJS) 
+
+g-idl-generate: $(GENERATE_OBJS) libirepository.a
+       $(CC) -o $@ $(GENERATE_OBJS) $(LIBS) -ldl libirepository.a
+
+g-idl-compiler: $(COMPILER_OBJS) 
+       $(CC)   -o $@ $(COMPILER_OBJS) $(LIBS) -ldl 
+
+.c.o:
+       $(CC) -c $< $(CFLAGS)
+
+clean:
+       rm -rf *.o *~ *.a *.so g-idl-generate g-idl-compiler
diff --git a/src/compiler.c b/src/compiler.c
new file mode 100644 (file)
index 0000000..c985d05
--- /dev/null
@@ -0,0 +1,214 @@
+/* GObject introspection: Metadata compiler
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gidlparser.h"
+
+gboolean raw = FALSE;
+gboolean no_init = FALSE;
+gchar **input = NULL;
+gchar *output = NULL;
+gchar *mname = NULL;
+
+static gchar *
+format_output (guchar *metadata,
+              gsize   len)
+{
+  GString *result;
+  gint i;
+
+  result = g_string_sized_new (6 * len);
+
+  g_string_append_printf (result, "const unsigned char _G_METADATA[] = \n{");
+
+  for (i = 0; i < len; i++)
+    {
+      if (i > 0)
+       g_string_append (result, ", ");
+
+      if (i % 10 == 0)
+       g_string_append (result, "\n\t");
+      
+      g_string_append_printf (result, "0x%.2x", metadata[i]);      
+    }
+
+  g_string_append_printf (result, "\n};\n\n");
+
+  if (!no_init)
+    {
+      g_string_append_printf (result,
+                             "void\n"
+                             "register_metadata (void) __attribute__((constructor))\n"
+                             "{\n"
+                             "\tg_irepository_register (NULL, _G_METADATA);\n"
+                             "}\n\n");
+
+      g_string_append_printf (result,
+                             "void\n"
+                             "unregister_metadata (void) __attribute__((destructor))\n"
+                             "{\n"
+                             "\tg_irepository_unregister (NULL, _G_METADATA);\n"
+                             "}\n");
+    }
+
+  return g_string_free (result, FALSE);
+}
+
+static void
+write_out_metadata (gchar *prefix,
+                   gchar *metadata,
+                   gsize  len)
+{
+  FILE *file;
+
+  if (output == NULL)
+    file = stdout;
+  else
+    {
+      gchar *filename;
+
+      if (prefix)
+       filename = g_strdup_printf ("%s-%s", prefix, output);  
+      else
+       filename = g_strdup (output);
+      file = g_fopen (filename, "w");
+
+      if (file == NULL)
+       {
+         g_fprintf (stderr, "failed to open '%s': %s\n",
+                    filename, g_strerror (errno));
+         g_free (filename);
+
+         return;
+       }
+
+      g_free (filename);
+    }
+
+  if (raw)
+    fwrite (metadata, 1, len, file);
+  else
+    {
+      gchar *code;
+
+      code = format_output (metadata, len);
+      fputs (code, file);
+      g_free (code);
+    }
+
+  if (output != NULL)
+    fclose (file);    
+}
+
+static GOptionEntry options[] = 
+{
+  { "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "emit raw metadata", NULL },
+  { "code", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &raw, "emit C code", NULL },
+  { "no-init", 0, 0, G_OPTION_ARG_NONE, &no_init, "do not create _init() function", NULL },
+  { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" }, 
+  { "module", 'm', 0, G_OPTION_ARG_STRING, &mname, "module to compile", "NAME" }, 
+  { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
+  { NULL, }
+};
+
+int
+main (int argc, char ** argv)
+{
+  GOptionContext *context;
+  GError *error = NULL;
+  GList *m, *modules; 
+  gint i;
+
+  g_metadata_check_sanity ();
+
+  context = g_option_context_new ("");
+  g_option_context_add_main_entries (context, options, NULL);
+  g_option_context_parse (context, &argc, &argv, &error);
+
+  if (!input) 
+    { 
+      g_fprintf (stderr, "no input files\n"); 
+
+      return 1;
+    }
+
+  modules = NULL;
+  for (i = 0; input[i]; i++)
+    {
+      GList *mods;
+      mods = g_idl_parse_file (input[i], &error);
+      
+      if (mods == NULL) 
+       {
+         g_fprintf (stderr, "error parsing file %s: %s\n", 
+                    input[i], error->message);
+      
+         return 1;
+       }
+
+      modules = g_list_concat (modules, mods);
+    }
+
+  for (m = modules; m; m = m->next)
+    {
+      GIdlModule *module = m->data;
+      gchar *prefix;
+      guchar *metadata;
+      gsize len;
+
+      if (mname && strcmp (mname, module->name) != 0)
+       continue;
+
+      g_idl_module_build_metadata (module, modules, &metadata, &len);
+      if (metadata == NULL)
+       {
+         g_error ("failed to build metadata for module '%s'\n", module->name);
+
+         continue;
+       }
+
+      if (!mname && (m->next || m->prev) && output)
+       prefix = module->name;
+      else
+       prefix = NULL;
+
+      write_out_metadata (prefix, metadata, len);
+      g_free (metadata);
+      metadata = NULL;
+
+      /* when writing to stdout, stop after the first module */
+      if (m->next && !output && !mname)
+       {
+         g_warning ("%d modules omitted\n", g_list_length (modules) - 1);
+
+         break;
+       }
+    }
+             
+  return 0; 
+}
diff --git a/src/generate.c b/src/generate.c
new file mode 100644 (file)
index 0000000..7d86365
--- /dev/null
@@ -0,0 +1,999 @@
+/* GObject introspection: IDL generator
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <errno.h>
+#include <dlfcn.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+
+#include "girepository.h"
+
+gboolean raw = FALSE;
+gchar **input = NULL;
+gchar *output = NULL;
+
+static void
+write_type_info (GITypeInfo *info, 
+                FILE       *file)
+{
+  gint tag;
+  gint i;
+  GITypeInfo *type;
+  
+  const gchar* basic[] = {
+    "void", 
+    "gboolean", 
+    "gint8", 
+    "guint8", 
+    "gint16", 
+    "guint16", 
+    "gint32", 
+    "guint32", 
+    "gint64", 
+    "guint64", 
+    "gfloat", 
+    "gdouble", 
+    "gchar", 
+    "GString", 
+    "gint", 
+    "guint", 
+    "glong", 
+    "gulong"
+  };
+
+  tag = g_type_info_get_tag (info);
+
+  if (tag < 20)
+    g_print ("%s%s", basic[tag], g_type_info_is_pointer (info) ? "*" : "");
+  else if (tag == 20)
+    {
+      gint length;
+
+      type = g_type_info_get_param_type (info, 0);
+      write_type_info (type, file);
+      g_print ("["); 
+
+      length = g_type_info_get_array_length (info);
+      
+      if (length >= 0)
+       g_print ("length=%d", length);
+      
+      if (g_type_info_is_zero_terminated (info))
+       g_print ("%szero-terminated=1", length >= 0 ? "," : "");
+      
+     g_print ("]"); 
+      g_base_info_unref ((GIBaseInfo *)type);
+    }
+  else if (tag == 21)
+    {
+      GIBaseInfo *iface = g_type_info_get_interface (info);
+      g_print ("%s%s", 
+              g_base_info_get_name (iface), 
+              g_type_info_is_pointer (info) ? "*" : "");
+      g_base_info_unref (iface);
+    }
+  else if (tag == 22)
+    {
+      type = g_type_info_get_param_type (info, 0);
+      g_print ("GList<");
+      write_type_info (type, file);
+      g_print (">"); 
+      g_base_info_unref ((GIBaseInfo *)type);
+    }
+  else if (tag == 23)
+    {
+      type = g_type_info_get_param_type (info, 0);
+      g_print ("GSList<");
+      write_type_info (type, file);
+      g_print (">"); 
+      g_base_info_unref ((GIBaseInfo *)type);
+    }
+  else if (tag == 24)
+    {
+      type = g_type_info_get_param_type (info, 0);
+      g_print ("GHashTable<");
+      write_type_info (type, file);
+      g_base_info_unref ((GIBaseInfo *)type);
+      type = g_type_info_get_param_type (info, 1);
+      g_print(",");
+      write_type_info (type, file);
+      g_print (">"); 
+      g_base_info_unref ((GIBaseInfo *)type);
+    }
+  else if (tag == 25) 
+    {
+      g_print ("GError<");
+      for (i = 0; i < g_type_info_get_n_error_domains (info); i++)
+       {
+         GIErrorDomainInfo *ed = g_type_info_get_error_domain (info, i);
+         g_print ("%s%s", i ? "," : "", g_base_info_get_name ((GIBaseInfo *)ed));
+         g_base_info_unref ((GIBaseInfo *)ed);
+       }
+      g_print (">");
+    }
+}
+
+static void
+write_field_info (GIFieldInfo *info,
+                 FILE        *file)
+{
+  const gchar *name;
+  GIFieldInfoFlags flags;
+  gint size;
+  gint offset;
+  GITypeInfo *type;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  flags = g_field_info_get_flags (info);
+  size = g_field_info_get_size (info);
+  offset = g_field_info_get_offset (info);
+
+  g_print ("      <field cname=\"%s\" readable=\"%s\" writable=\"%s\" ",
+          name, 
+          flags & GI_FIELD_IS_READABLE ? "1" : "0", 
+          flags & GI_FIELD_IS_WRITABLE ? "1" : "0");
+  if (size)
+    g_print ("bits=\"%d\" ", size);
+  g_print ("offset=\"%d\" ", offset);
+
+  g_print ("type=\"");
+
+  type = g_field_info_get_type (info);
+  write_type_info (type, file);
+  g_base_info_unref ((GIBaseInfo *)type);
+
+  g_print ("\" />\n");
+}
+
+static void 
+write_callable_info (GICallableInfo *info,
+                    FILE           *file,
+                    gint            indent)
+{
+  GITypeInfo *type;
+  gint i;
+
+  g_fprintf (file, "%*s  <return-type type=\"", indent, "");
+  
+  type = g_callable_info_get_return_type (info);
+  write_type_info (type, file);
+  g_base_info_unref ((GIBaseInfo *)type);
+
+  g_fprintf (file, "\"/>\n");
+       
+  if (g_callable_info_get_n_args (info) > 0)
+    {
+      g_fprintf (file, "%*s  <parameters>\n", indent, "");
+      for (i = 0; i < g_callable_info_get_n_args (info); i++)
+       {
+         GIArgInfo *arg = g_callable_info_get_arg (info, i);
+               
+         g_fprintf (file, "%*s    <parameter name=\"%s\" type=\"",
+                    indent, "", g_base_info_get_name ((GIBaseInfo *) arg));
+               
+         type = g_arg_info_get_type (arg);
+         write_type_info (type, file);
+         g_base_info_unref ((GIBaseInfo *)type);
+         g_fprintf (file, "\"");
+
+         g_fprintf (file, " direction=\"");
+         switch (g_arg_info_get_direction (arg))
+           {
+           case GI_DIRECTION_IN:
+             g_fprintf (file, "in");
+             break;
+           case GI_DIRECTION_OUT:
+             g_fprintf (file, "out");
+             break;
+           case GI_DIRECTION_INOUT:
+             g_fprintf (file, "inout");
+             break;
+           }
+         g_fprintf (file, "\"");
+
+         if (g_arg_info_may_be_null (arg))
+           g_fprintf (file, " null-ok=\"1\"");
+         
+         if (g_arg_info_is_dipper (arg))
+           g_fprintf (file, " dipper=\"1\"");
+         
+         if (g_arg_info_is_return_value (arg))
+           g_fprintf (file, " retval=\"1\"");
+         
+         if (g_arg_info_is_optional (arg))
+           g_fprintf (file, " optional=\"1\"");
+         
+         g_fprintf (file, "/>\n");
+                
+         g_base_info_unref ((GIBaseInfo *)arg);
+       }
+           
+      g_fprintf (file, "%*s  </parameters>\n", indent, "");
+    }
+}
+
+static void
+write_function_info (GIFunctionInfo *info,
+                    FILE           *file,
+                    gint            indent)
+{
+  GIFunctionInfoFlags flags;
+  const gchar *tag;
+  const gchar *name;
+  const gchar *cname;
+  gboolean deprecated;
+
+  flags = g_function_info_get_flags (info);
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  cname = g_function_info_get_symbol (info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
+    tag = "constructor";
+  else if (flags & GI_FUNCTION_IS_METHOD)
+    tag = "method";
+  else
+    tag = "function";
+       
+  g_fprintf (file, "%*s<%s name=\"%s\" cname=\"%s\"", 
+            indent, "", tag, name, cname);
+       
+  if (flags & GI_FUNCTION_IS_SETTER)
+    g_fprintf (file, " type=\"setter\"");
+  else if (flags & GI_FUNCTION_IS_GETTER)
+    g_fprintf (file, " type=\"getter\"");
+         
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+  write_callable_info ((GICallableInfo*)info, file, indent);
+  g_fprintf (file, "%*s</%s>\n", indent, "", tag);
+}
+
+static void
+write_callback_info (GICallbackInfo *info,
+                    FILE           *file,
+                    gint            indent)
+{
+  GIFunctionInfoFlags flags;
+  const gchar *name;
+  gboolean deprecated;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_fprintf (file, "%*s<callback name=\"%s\"", indent, "", name);
+       
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+  write_callable_info ((GICallableInfo*)info, file, indent);
+  g_fprintf (file, "%*s</callback>\n", indent, "");
+}
+
+static void
+write_struct_info (GIStructInfo *info,
+                  FILE         *file)
+{
+  const gchar *name;
+  const gchar *type_name;
+  const gchar *type_init;
+  gboolean deprecated;
+  gint i;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
+    {
+      type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+      type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+           
+      g_fprintf (file, "    <boxed name=\"%s\" cname=\"%s\" get-type=\"%s\"", name, type_name, type_init);
+    }
+  else
+    g_fprintf (file, "    <struct name=\"%s\" cname=\"%s\"", name);
+         
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+
+  for (i = 0; i < g_struct_info_get_n_fields (info); i++)
+    {
+      GIFieldInfo *field = g_struct_info_get_field (info, i);
+      write_field_info (field, file);
+      g_base_info_unref ((GIBaseInfo *)field);
+    }
+
+  for (i = 0; i < g_struct_info_get_n_methods (info); i++)
+    {
+      GIFunctionInfo *function = g_struct_info_get_method (info, i);
+      write_function_info (function, file, 6);
+      g_base_info_unref ((GIBaseInfo *)function);
+    }
+
+  if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
+    g_fprintf (file, "    </boxed>\n");
+  else
+    g_fprintf (file, "    </struct>\n");
+}
+
+static void
+write_value_info (GIValueInfo *info,
+                 FILE        *file)
+{
+  const gchar *name;
+  const gchar *short_name;
+  glong value;
+  gboolean deprecated;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  short_name = g_value_info_get_short_name (info);
+  value = g_value_info_get_value (info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_print ("      <member name=\"%s\" cname=\"%s\" value=\"%d\" ",
+          name, short_name, value);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+  
+  g_print (" />\n");
+}
+
+static void
+write_constant_info (GIConstantInfo *info,
+                    FILE           *file,
+                    gint            indent)
+{
+  GITypeInfo *type;
+  const gchar *name;
+  gboolean deprecated;
+  GArgument value;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_print ("%*s<constant name=\"%s\" type=\"", indent, "", name);
+
+  type = g_constant_info_get_type (info);
+  write_type_info (type, file);
+  g_fprintf (file, "\" value=\"");
+
+  g_constant_info_get_value (info, &value);
+  switch (g_type_info_get_tag (type))
+    {
+    case GI_TYPE_TAG_BOOLEAN:
+      g_fprintf (file, "%d", value.v_boolean);
+      break;
+    case GI_TYPE_TAG_INT8:
+      g_fprintf (file, "%d", value.v_int8);
+      break;
+    case GI_TYPE_TAG_UINT8:
+      g_fprintf (file, "%d", value.v_uint8);
+      break;
+    case GI_TYPE_TAG_INT16:
+      g_fprintf (file, "%" G_GINT16_FORMAT, value.v_int16);
+      break;
+    case GI_TYPE_TAG_UINT16:
+      g_fprintf (file, "%" G_GUINT16_FORMAT, value.v_uint16);
+      break;
+    case GI_TYPE_TAG_INT32:
+      g_fprintf (file, "%" G_GINT32_FORMAT, value.v_int32);
+      break;
+    case GI_TYPE_TAG_UINT32:
+      g_fprintf (file, "%" G_GUINT32_FORMAT, value.v_uint32);
+      break;
+    case GI_TYPE_TAG_INT64:
+      g_fprintf (file, "%" G_GINT64_FORMAT, value.v_int64);
+      break;
+    case GI_TYPE_TAG_UINT64:
+      g_fprintf (file, "%" G_GUINT64_FORMAT, value.v_uint64);
+      break;
+    case GI_TYPE_TAG_FLOAT:
+      g_fprintf (file, "%f", value.v_float);
+      break;
+    case GI_TYPE_TAG_DOUBLE:
+      g_fprintf (file, "%Lf", value.v_double);
+      break;
+    case GI_TYPE_TAG_STRING:
+      g_fprintf (file, "%s", value.v_string);
+      break;
+    case GI_TYPE_TAG_INT:
+      g_fprintf (file, "%d", value.v_int);
+      break;
+    case GI_TYPE_TAG_UINT:
+      g_fprintf (file, "%d", value.v_uint);
+      break;
+    case GI_TYPE_TAG_LONG:
+      g_fprintf (file, "%ld", value.v_long);
+      break;
+    case GI_TYPE_TAG_ULONG:
+      g_fprintf (file, "%ld", value.v_ulong);
+      break;
+    }
+  g_fprintf (file, "\" />\n");
+  
+  g_base_info_unref ((GIBaseInfo *)type);
+}
+
+
+static void
+write_enum_info (GIEnumInfo *info,
+                FILE       *file)
+{
+  const gchar *name;
+  const gchar *type_name;
+  const gchar *type_init;
+  gboolean deprecated;
+  gint i;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+  type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+
+  if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
+    g_fprintf (file, "    <enum ");
+  else
+    g_fprintf (file, "    <flags ");
+  g_fprintf (file, "name=\"%s\" cname=\"%s\"", name, type_name, type_init);
+
+  if (type_init)
+    g_fprintf (file, " get-type=\"%s\"", type_init);
+  
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+
+  for (i = 0; i < g_enum_info_get_n_values (info); i++)
+    {
+      GIValueInfo *value = g_enum_info_get_value (info, i);
+      write_value_info (value, file);
+      g_base_info_unref ((GIBaseInfo *)value);
+    }
+
+  if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
+    g_fprintf (file, "    </enum>\n");
+  else
+    g_fprintf (file, "    </flags>\n");
+}
+
+static void
+write_signal_info (GISignalInfo *info,
+                  FILE         *file)
+{
+  GSignalFlags flags;
+  const gchar *name;
+  gboolean deprecated;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  flags = g_signal_info_get_flags (info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_fprintf (file, "      <signal name=\"%s\"", name);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  if (flags & G_SIGNAL_RUN_FIRST)
+    g_fprintf (file, " when=\"FIRST\"");
+  else if (flags & G_SIGNAL_RUN_LAST)
+    g_fprintf (file, " when=\"LAST\"");
+  else if (flags & G_SIGNAL_RUN_CLEANUP)
+    g_fprintf (file, " when=\"CLEANUP\"");
+
+  if (flags & G_SIGNAL_NO_RECURSE)
+    g_fprintf (file, " no-recurse=\"1\"");
+
+  if (flags & G_SIGNAL_DETAILED)
+    g_fprintf (file, " detailed=\"1\"");
+
+  if (flags & G_SIGNAL_ACTION)
+    g_fprintf (file, " action=\"1\"");
+
+  if (flags & G_SIGNAL_NO_HOOKS)
+    g_fprintf (file, " no-hooks=\"1\"");
+
+  g_fprintf (file, ">\n");
+
+  write_callable_info ((GICallableInfo*)info, file, 6);
+  g_fprintf (file, "      </signal>\n");
+}
+
+static void
+write_vfunc_info (GIVFuncInfo *info,
+                 FILE        *file)
+{
+  GIVFuncInfoFlags flags;
+  const gchar *name;
+  gboolean deprecated;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  flags = g_vfunc_info_get_flags (info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_fprintf (file, "      <vfunc name=\"%s\"", name);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  if (flags & GI_VFUNC_MUST_CHAIN_UP)
+    g_fprintf (file, " must-chain-up=\"1\"");
+
+  if (flags & GI_VFUNC_MUST_OVERRIDE)
+    g_fprintf (file, " override=\"always\"");
+  else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE)
+    g_fprintf (file, " override=\"never\"");
+    
+  g_fprintf (file, ">\n");
+
+  write_callable_info ((GICallableInfo*)info, file, 6);
+  g_fprintf (file, "      </vfunc>\n");
+}
+
+static void
+write_property_info (GIPropertyInfo *info,
+                    FILE           *file)
+{
+  GParamFlags flags;
+  const gchar *name;
+  gboolean deprecated;
+  GITypeInfo *type;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  flags = g_property_info_get_flags (info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  g_fprintf (file, "      <property name=\"%s\"", name);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  if (flags & G_PARAM_READABLE)
+    g_fprintf (file, " readable=\"1\"");
+  else
+    g_fprintf (file, " readable=\"0\"");
+
+  if (flags & G_PARAM_WRITABLE)
+    g_fprintf (file, " writable=\"1\"");
+  else
+    g_fprintf (file, " writable=\"0\"");
+
+  if (flags & G_PARAM_CONSTRUCT)
+    g_fprintf (file, " construct=\"1\"");
+
+  if (flags & G_PARAM_CONSTRUCT_ONLY)
+    g_fprintf (file, " construct-only=\"1\"");
+    
+  type = g_property_info_get_type (info);
+  g_fprintf (file, " type=\"");
+  write_type_info (type, file);
+  g_fprintf (file, "\"");
+
+  g_fprintf (file, "/>\n");
+}
+
+static void
+write_object_info (GIObjectInfo *info,
+                  FILE         *file)
+{
+  const gchar *name;
+  const gchar *parent;
+  const gchar *type_name;
+  const gchar *type_init;
+  gboolean deprecated;
+  GIObjectInfo *pnode;
+  gint i;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+  
+  pnode = g_object_info_get_parent (info);
+  if (pnode)
+    parent = g_base_info_get_name ((GIBaseInfo *)pnode);
+  else
+    parent = NULL;
+  g_base_info_unref ((GIBaseInfo *)pnode);
+
+  type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+  type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+  g_fprintf (file, "    <object name=\"%s\"", name);
+
+  if (parent)
+    g_fprintf (file, " parent=\"%s\"", parent);
+
+  g_fprintf (file, " cname=\"%s\" get-type=\"%s\"", type_name, type_init);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+
+  if (g_object_info_get_n_interfaces (info) > 0)
+    {
+      g_fprintf (file, "      <implements>\n");
+      for (i = 0; i < g_object_info_get_n_interfaces (info); i++)
+       {
+         GIInterfaceInfo *imp = g_object_info_get_interface (info, i);
+         g_fprintf (file, "      <interface name=\"%s\" />\n",
+                    g_base_info_get_name ((GIBaseInfo*)imp));
+         g_base_info_unref ((GIBaseInfo*)imp);
+       }
+      g_fprintf (file, "      </implements>\n");
+    }
+
+  for (i = 0; i < g_object_info_get_n_fields (info); i++)
+    {
+      GIFieldInfo *field = g_object_info_get_field (info, i);
+      write_field_info (field, file);
+      g_base_info_unref ((GIBaseInfo *)field);
+    }
+
+  for (i = 0; i < g_object_info_get_n_methods (info); i++)
+    {
+      GIFunctionInfo *function = g_object_info_get_method (info, i);
+      write_function_info (function, file, 6);
+      g_base_info_unref ((GIBaseInfo *)function);
+    }
+
+  for (i = 0; i < g_object_info_get_n_properties (info); i++)
+    {
+      GIPropertyInfo *prop = g_object_info_get_property (info, i);
+      write_property_info (prop, file);
+      g_base_info_unref ((GIBaseInfo *)prop);
+    }
+
+  for (i = 0; i < g_object_info_get_n_signals (info); i++)
+    {
+      GISignalInfo *signal = g_object_info_get_signal (info, i);
+      write_signal_info (signal, file);
+      g_base_info_unref ((GIBaseInfo *)signal);
+    }
+  
+  for (i = 0; i < g_object_info_get_n_vfuncs (info); i++)
+    {
+      GIVFuncInfo *vfunc = g_object_info_get_vfunc (info, i);
+      write_vfunc_info (vfunc, file);
+      g_base_info_unref ((GIBaseInfo *)vfunc);
+    }
+
+  for (i = 0; i < g_object_info_get_n_constants (info); i++)
+    {
+      GIConstantInfo *constant = g_object_info_get_constant (info, i);
+      write_constant_info (constant, file, 6);
+      g_base_info_unref ((GIBaseInfo *)constant);
+    }
+  
+  g_fprintf (file, "    </object>\n");
+}
+
+static void
+write_interface_info (GIInterfaceInfo *info,
+                     FILE            *file)
+{
+  const gchar *name;
+  const gchar *type_name;
+  const gchar *type_init;
+  gboolean deprecated;
+  gint i;
+
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+  type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+  type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+  g_fprintf (file, "    <interface name=\"%s\" cname=\"%s\" get-type=\"%s\"",
+            name, type_name, type_init);
+
+  if (deprecated)
+    g_fprintf (file, " deprecated=\"1\"");
+       
+  g_fprintf (file, ">\n");
+
+  if (g_interface_info_get_n_prerequisites (info) > 0)
+    {
+      g_fprintf (file, "      <requires>\n");
+      for (i = 0; i < g_interface_info_get_n_prerequisites (info); i++)
+       {
+         GIBaseInfo *req = g_interface_info_get_prerequisite (info, i);
+         
+         if (g_base_info_get_type (req) == GI_INFO_TYPE_INTERFACE)
+           g_fprintf (file, "      <interface name=\"%s\" />\n",
+                      g_base_info_get_name (req));
+         else
+           g_fprintf (file, "      <object name=\"%s\" />\n",
+                      g_base_info_get_name (req));
+           
+         g_base_info_unref (req);
+       }
+      g_fprintf (file, "      </requires>\n");
+    }
+
+  for (i = 0; i < g_interface_info_get_n_methods (info); i++)
+    {
+      GIFunctionInfo *function = g_interface_info_get_method (info, i);
+      write_function_info (function, file, 6);
+      g_base_info_unref ((GIBaseInfo *)function);
+    }
+
+  for (i = 0; i < g_interface_info_get_n_properties (info); i++)
+    {
+      GIPropertyInfo *prop = g_interface_info_get_property (info, i);
+      write_property_info (prop, file);
+      g_base_info_unref ((GIBaseInfo *)prop);
+    }
+
+  for (i = 0; i < g_interface_info_get_n_signals (info); i++)
+    {
+      GISignalInfo *signal = g_interface_info_get_signal (info, i);
+      write_signal_info (signal, file);
+      g_base_info_unref ((GIBaseInfo *)signal);
+    }
+  
+  for (i = 0; i < g_interface_info_get_n_vfuncs (info); i++)
+    {
+      GIVFuncInfo *vfunc = g_interface_info_get_vfunc (info, i);
+      write_vfunc_info (vfunc, file);
+      g_base_info_unref ((GIBaseInfo *)vfunc);
+    }
+
+  for (i = 0; i < g_interface_info_get_n_constants (info); i++)
+    {
+      GIConstantInfo *constant = g_interface_info_get_constant (info, i);
+      write_constant_info (constant, file, 6);
+      g_base_info_unref ((GIBaseInfo *)constant);
+    }
+  
+  g_fprintf (file, "    </interface>\n");
+}
+
+static void
+write_error_domain_info (GIErrorDomainInfo *info,
+                        FILE              *file)
+{
+  GIBaseInfo *enum_;
+  const gchar *name, *quark, *codes;
+  
+  name = g_base_info_get_name ((GIBaseInfo *)info);
+  quark = g_error_domain_info_get_quark (info);
+  enum_ = (GIBaseInfo *)g_error_domain_info_get_codes (info);
+  codes = g_base_info_get_name (enum_);
+  g_base_info_unref (enum_);
+  
+  g_fprintf (file,
+            "    <errordomain name=\"%s\" get-quark=\"%s\" codes=\"%s\" />\n",
+            name, quark, codes);
+}
+
+static void
+write_repository (GIRepository *repository,
+                 gboolean      needs_prefix)
+{
+  FILE *file;
+  gchar **namespaces;
+  gint i, j;
+
+  namespaces = g_irepository_get_namespaces (repository);
+
+  if (output == NULL)
+    file = stdout;
+  else
+    {
+      gchar *filename;
+      
+      if (needs_prefix)
+       filename = g_strdup_printf ("%s-%s", namespaces[0], output);  
+      else
+       filename = g_strdup (output);
+      file = g_fopen (filename, "w");
+      
+      if (file == NULL)
+       {
+         g_fprintf (stderr, "failed to open '%s': %s\n",
+                    filename, g_strerror (errno));
+         g_free (filename);
+         
+         return;
+       }
+      
+      g_free (filename);
+    }
+  
+  g_fprintf (file, "<?xml version=\"1.0\"?>\n");
+  g_fprintf (file, "<api version=\"1.0\">\n");
+
+  for (i = 0; namespaces[i]; i++)
+    {
+      g_fprintf (file, "  <namespace name=\"%s\">\n", namespaces[i]);
+      
+      for (j = 0; j < g_irepository_get_n_infos (repository, namespaces[i]); j++)
+       {
+         GIBaseInfo *info = g_irepository_get_info (repository, namespaces[i], j);
+         switch (g_base_info_get_type (info))
+           {
+           case GI_INFO_TYPE_FUNCTION:
+             write_function_info ((GIFunctionInfo *)info, file, 4);
+             break;
+             
+           case GI_INFO_TYPE_CALLBACK:
+             write_callback_info ((GICallbackInfo *)info, file, 4);
+             break;
+
+           case GI_INFO_TYPE_STRUCT:
+           case GI_INFO_TYPE_BOXED:
+             write_struct_info ((GIStructInfo *)info, file);
+             break;
+             
+           case GI_INFO_TYPE_ENUM:
+           case GI_INFO_TYPE_FLAGS:
+             write_enum_info ((GIEnumInfo *)info, file);
+             break;
+             
+           case GI_INFO_TYPE_CONSTANT:
+             write_constant_info ((GIConstantInfo *)info, file, 4);
+             break;
+
+           case GI_INFO_TYPE_OBJECT:
+             write_object_info ((GIObjectInfo *)info, file);
+             break;
+
+           case GI_INFO_TYPE_INTERFACE:
+             write_interface_info ((GIInterfaceInfo *)info, file);
+             break;
+
+           case GI_INFO_TYPE_ERROR_DOMAIN:
+             write_error_domain_info ((GIErrorDomainInfo *)info, file);
+             break;
+           }
+
+         g_base_info_unref (info);
+       }
+
+      g_fprintf (file, "  </namespace>\n");
+    }
+
+  g_fprintf (file, "</api>\n");
+      
+  if (output != NULL)
+    fclose (file);        
+
+  g_strfreev (namespaces);
+}
+
+static GOptionEntry options[] = 
+{
+  { "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "handle raw metadata", NULL },
+  { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" }, 
+  { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
+  { NULL, }
+};
+
+static const guchar *
+load_metadata (const gchar  *filename,
+              void        **dlhandle)
+{
+  guchar *metadata; 
+  void *handle; 
+  char *error; 
+
+  handle = dlopen (filename, RTLD_LAZY);
+  metadata = dlsym (handle, "_G_METADATA");
+  
+  error = dlerror ();
+
+  if (dlhandle)
+    *dlhandle = handle;
+
+  if (error) 
+    { 
+      g_fprintf (stderr, 
+                "Could not load metadata from '%s': %s\n", 
+                filename, error);
+
+      return NULL;
+    }
+
+  return metadata;
+}
+
+int 
+main (int argc, char *argv[])
+{  
+  GOptionContext *context;
+  GError *error = NULL;
+  gboolean needs_prefix;
+  gint i;
+
+  g_type_init ();
+
+  g_metadata_check_sanity ();
+
+  context = g_option_context_new ("");
+  g_option_context_add_main_entries (context, options, NULL);
+  g_option_context_parse (context, &argc, &argv, &error);
+
+  if (!input) 
+    { 
+      g_fprintf (stderr, "no input files\n"); 
+      
+      return 1;
+    }
+
+  for (i = 0; input[i]; i++)
+    {
+      void *dlhandle = NULL;
+      const guchar *metadata;
+
+      if (raw)
+       {
+         if (!g_file_get_contents (input[i], (gchar **)&metadata, NULL, &error))
+           {
+             g_fprintf (stderr, "failed to read '%s': %s\n", 
+                        input[i], error->message);
+             g_clear_error (&error);
+             continue;
+           }
+       }
+      else
+       {
+         metadata = load_metadata (input[i], &dlhandle);
+         if (!metadata)
+           {
+             g_fprintf (stderr, "failed to load metadata from '%s'\n", 
+                        input[i]);
+             continue;
+           }
+       }
+
+      if (input[i + 1] && output)
+       needs_prefix = TRUE;
+      else
+       needs_prefix = FALSE;
+
+      g_irepository_register (g_irepository_get_default (), metadata);
+      write_repository (g_irepository_get_default (), needs_prefix);
+      g_irepository_unregister (g_irepository_get_default (), metadata);
+
+      if (dlhandle)
+       {
+         dlclose (dlhandle);
+         dlhandle = NULL;
+       }
+
+      /* when writing to stdout, stop after the first module */
+      if (input[i + 1] && !output)
+       {
+         g_fprintf (stderr, "warning, %d modules omitted\n",
+                    g_strv_length (input) - 1);
+
+         break;
+       }
+    }
+      
+  return 0;
+}
diff --git a/src/gidlmodule.c b/src/gidlmodule.c
new file mode 100644 (file)
index 0000000..7d0a9c6
--- /dev/null
@@ -0,0 +1,187 @@
+/* GObject introspection: Metadata creation 
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gmetadata.h"
+
+#define ALIGN_VALUE(this, boundary) \
+  (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+
+GIdlModule *
+g_idl_module_new (const gchar *name)
+{
+  GIdlModule *module;
+  
+  module = g_new (GIdlModule, 1);
+
+  module->name = g_strdup (name);
+  module->entries = NULL;
+
+  return module;
+}
+
+void
+g_idl_module_free (GIdlModule *module)
+{
+  GList *e;
+
+  g_free (module->name);
+
+  for (e = module->entries; e; e = e->next)
+    g_idl_node_free ((GIdlNode *)e->data);
+
+  g_list_free (module->entries);
+
+  g_free (module);
+}
+
+void  
+g_idl_module_build_metadata (GIdlModule  *module,
+                            GList       *modules,
+                            guchar     **metadata,
+                            gsize       *length)
+{
+  gint i;
+  GList *e;
+  Header *header;
+  DirEntry *entry;
+  guint32 header_size;
+  guint32 dir_size;
+  guint32 n_entries;
+  guint32 n_local_entries;
+  guint32 size, offset, offset2;
+  GHashTable *strings;
+  GHashTable *types;
+  guchar *data;
+
+  header_size = ALIGN_VALUE (sizeof (Header), 4);
+  n_local_entries = g_list_length (module->entries);
+
+ restart:
+  strings = g_hash_table_new (g_str_hash, g_str_equal);
+  types = g_hash_table_new (g_str_hash, g_str_equal);
+  n_entries = g_list_length (module->entries);
+
+  g_fprintf (stderr, "%d entries (%d local)\n", n_entries, n_local_entries);
+  
+  dir_size = n_entries * 12;  
+  size = header_size + dir_size;
+
+  for (e = module->entries; e; e = e->next)
+    {
+      GIdlNode *node = e->data;
+      
+      size += g_idl_node_get_full_size (node);
+    }
+
+  data = g_malloc (size);
+
+  /* fill in header */
+  header = (Header *)data;
+  memcpy (header, G_IDL_MAGIC, 16);
+  header->major_version = 1;
+  header->minor_version = 0;
+  header->reserved = 0;
+  header->n_entries = n_entries;
+  header->n_local_entries = n_local_entries;
+  header->n_annotations = 0;
+  header->annotations = 0; /* filled in later */
+  header->size = 0; /* filled in later */
+  header->namespace = write_string (module->name, strings, data, &header_size);
+  header->directory = ALIGN_VALUE (header_size, 4);
+  header->entry_blob_size = 12;
+  header->function_blob_size = 16;
+  header->callback_blob_size = 12;
+  header->signal_blob_size = 12;
+  header->vfunc_blob_size = 16;
+  header->arg_blob_size = 12;
+  header->property_blob_size = 12;
+  header->field_blob_size = 12;
+  header->value_blob_size = 16;
+  header->constant_blob_size = 20;
+  header->error_domain_blob_size = 16;
+  header->annotation_blob_size = 12;
+  header->signature_blob_size = 8;
+  header->enum_blob_size = 20;
+  header->struct_blob_size = 20;
+  header->object_blob_size = 32;
+  header->interface_blob_size = 28;
+
+  /* fill in directory and content */
+  entry = (DirEntry *)&data[header->directory];
+
+  offset2 = header->directory + dir_size;
+
+  for (e = module->entries, i = 0; e; e = e->next, i++)
+    {
+      GIdlNode *node = e->data;
+
+      /* we picked up implicit xref nodes, start over */
+      if (i == n_entries)
+       {
+         g_fprintf (stderr, "Found implicit cross references, starting over\n");
+         g_hash_table_destroy (strings);
+         g_hash_table_destroy (types);
+         strings = NULL;
+
+         g_free (data);
+         data = NULL;
+
+         goto restart;
+       }
+       
+      offset = offset2;
+
+      if (node->type == G_IDL_NODE_XREF)
+       {
+         entry->blob_type = 0;
+         entry->local = FALSE;
+         entry->offset = write_string (((GIdlNodeXRef*)node)->namespace, strings, data, &offset2);
+         entry->name = write_string (node->name, strings, data, &offset2);
+       }
+      else
+       {
+         offset2 = offset + g_idl_node_get_size (node);
+
+         entry->blob_type = node->type;
+         entry->local = TRUE;
+         entry->offset = offset;
+         entry->name = write_string (node->name, strings, data, &offset2);
+
+         g_idl_node_build_metadata (node, module, modules, 
+                                    strings, types, data, &offset, &offset2);
+       }
+
+      entry++;
+    }
+
+  g_hash_table_destroy (strings);
+  g_hash_table_destroy (types);
+
+  header->annotations = offset2;
+  
+  *metadata = g_realloc (data, offset2);
+  *length = header->size = offset2;
+}
+
diff --git a/src/gidlmodule.h b/src/gidlmodule.h
new file mode 100644 (file)
index 0000000..1713576
--- /dev/null
@@ -0,0 +1,47 @@
+/* GObject introspection: Parsed IDL
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_IDL_MODULE_H__
+#define __G_IDL_MODULE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _GIdlModule GIdlModule;
+
+struct _GIdlModule
+{ 
+  gchar *name;
+  GList *entries;
+};
+
+GIdlModule *g_idl_module_new            (const gchar *name);
+void        g_idl_module_free           (GIdlModule  *module);
+
+void        g_idl_module_build_metadata (GIdlModule  *module,
+                                        GList       *modules,
+                                        guchar     **metadata,
+                                        gsize       *length);
+
+G_END_DECLS
+
+#endif  /* __G_IDL_MODULE_H__ */
diff --git a/src/gidlnode.c b/src/gidlnode.c
new file mode 100644 (file)
index 0000000..6dea708
--- /dev/null
@@ -0,0 +1,1749 @@
+/* GObject introspection: Metadata creation
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "gidlmodule.h"
+#include "gidlnode.h"
+#include "gmetadata.h"
+
+#define ALIGN_VALUE(this, boundary) \
+  (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+
+GIdlNode *
+g_idl_node_new (GIdlNodeTypeId type)
+{
+  GIdlNode *node = NULL;
+
+  switch (type)
+    {
+   case G_IDL_NODE_FUNCTION:
+      node = g_malloc0 (sizeof (GIdlNodeFunction));
+      break;
+
+   case G_IDL_NODE_PARAM:
+      node = g_malloc0 (sizeof (GIdlNodeParam));
+      break;
+
+   case G_IDL_NODE_TYPE:
+      node = g_malloc0 (sizeof (GIdlNodeType));
+      break;
+
+    case G_IDL_NODE_OBJECT:
+    case G_IDL_NODE_INTERFACE:
+      node = g_malloc0 (sizeof (GIdlNodeInterface));
+      break;
+
+    case G_IDL_NODE_SIGNAL:
+      node = g_malloc0 (sizeof (GIdlNodeSignal));
+      break;
+
+    case G_IDL_NODE_PROPERTY:
+      node = g_malloc0 (sizeof (GIdlNodeProperty));
+      break;
+
+    case G_IDL_NODE_VFUNC:
+      node = g_malloc0 (sizeof (GIdlNodeFunction));
+      break;
+
+    case G_IDL_NODE_FIELD:
+      node = g_malloc0 (sizeof (GIdlNodeField));
+      break;
+
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      node = g_malloc0 (sizeof (GIdlNodeEnum));
+      break;
+
+    case G_IDL_NODE_BOXED:
+      node = g_malloc0 (sizeof (GIdlNodeBoxed));
+      break;
+
+    case G_IDL_NODE_STRUCT:
+      node = g_malloc0 (sizeof (GIdlNodeStruct));
+      break;
+
+    case G_IDL_NODE_VALUE:
+      node = g_malloc0 (sizeof (GIdlNodeValue));
+      break;
+
+    case G_IDL_NODE_CONSTANT:
+      node = g_malloc0 (sizeof (GIdlNodeConstant));
+      break;
+
+    case G_IDL_NODE_ERROR_DOMAIN:
+      node = g_malloc0 (sizeof (GIdlNodeErrorDomain));
+      break;
+
+    case G_IDL_NODE_XREF:
+      node = g_malloc0 (sizeof (GIdlNodeXRef));
+      break;
+
+    default:
+      g_error ("Unhandled node type %d\n", type);
+      break;
+    }
+
+  node->type = type;
+
+  return node;
+}
+
+void
+g_idl_node_free (GIdlNode *node)
+{
+  GList *l;
+
+  switch (node->type)
+    {
+    case G_IDL_NODE_FUNCTION:
+      {
+       GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+       
+       g_free (node->name);
+       g_free (function->c_name);
+       g_idl_node_free ((GIdlNode *)function->result);
+       for (l = function->parameters; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (function->parameters);
+      }
+      break;
+
+    case G_IDL_NODE_TYPE:
+      {
+       GIdlNodeType *type = (GIdlNodeType *)node;
+       
+       g_free (node->name);
+       if (type->parameter_type1)
+         g_idl_node_free ((GIdlNode *)type->parameter_type1);
+       if (type->parameter_type2)
+         g_idl_node_free ((GIdlNode *)type->parameter_type2);
+
+       g_free (type->interface);
+       g_strfreev (type->errors);
+
+      }
+      break;
+
+    case G_IDL_NODE_PARAM:
+      {
+       GIdlNodeParam *param = (GIdlNodeParam *)node;
+       
+       g_free (node->name);
+       g_idl_node_free ((GIdlNode *)param->type);
+      }
+      break;
+
+    case G_IDL_NODE_PROPERTY:
+      {
+       GIdlNodeProperty *property = (GIdlNodeProperty *)node;
+       
+       g_free (node->name);
+       g_idl_node_free ((GIdlNode *)property->type);
+      }
+      break;
+
+    case G_IDL_NODE_SIGNAL:
+      {
+       GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+       
+       g_free (node->name);
+       for (l = signal->parameters; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (signal->parameters);
+       g_idl_node_free ((GIdlNode *)signal->result);
+      }
+      break;
+
+    case G_IDL_NODE_VFUNC:
+      {
+       GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+       
+       g_free (node->name);
+       for (l = vfunc->parameters; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (vfunc->parameters);
+       g_idl_node_free ((GIdlNode *)vfunc->result);
+      }
+      break;
+
+    case G_IDL_NODE_FIELD:
+      {
+       GIdlNodeField *field = (GIdlNodeField *)node;
+       
+       g_free (node->name);
+       g_free (field->c_name);
+       g_idl_node_free ((GIdlNode *)field->type);
+      }
+      break;
+
+    case G_IDL_NODE_OBJECT:
+    case G_IDL_NODE_INTERFACE:
+      {
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+       
+       g_free (node->name);
+       g_free (iface->c_name);
+       g_free (iface->init_func);
+       
+       g_free (iface->parent);
+
+       for (l = iface->interfaces; l; l = l->next)
+         g_free ((GIdlNode *)l->data);
+       g_list_free (iface->interfaces);
+
+       for (l = iface->members; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (iface->members);
+
+      }
+      break;
+    case G_IDL_NODE_VALUE:
+      {
+       GIdlNodeValue *value = (GIdlNodeValue *)node;
+       
+       g_free (node->name);
+       g_free (value->c_name);
+      }
+      break;
+
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      {
+       GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+       
+       g_free (node->name);
+       for (l = enum_->values; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (enum_->values);
+      }
+      break;
+
+    case G_IDL_NODE_BOXED:
+      {
+       GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+       
+       g_free (node->name);
+       g_free (boxed->c_name);
+       g_free (boxed->init_func);
+
+       for (l = boxed->members; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (boxed->members);
+      }
+      break;
+
+    case G_IDL_NODE_STRUCT:
+      {
+       GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+       g_free (node->name);
+       for (l = struct_->members; l; l = l->next)
+         g_idl_node_free ((GIdlNode *)l->data);
+       g_list_free (struct_->members);
+      }
+      break;
+
+    case G_IDL_NODE_CONSTANT:
+      {
+       GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+       
+       g_free (node->name);
+       g_free (constant->value);
+       g_idl_node_free ((GIdlNode *)constant->type);
+      }
+      break;
+
+    case G_IDL_NODE_ERROR_DOMAIN:
+      {
+       GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+       
+       g_free (node->name);
+       g_free (domain->getquark);
+       g_free (domain->codes);
+      }
+      break;
+
+    case G_IDL_NODE_XREF:
+      {
+       GIdlNodeXRef *xref = (GIdlNodeXRef *)node;
+       
+       g_free (node->name);
+       g_free (xref->namespace);
+      }
+      break;
+
+    default:
+      g_error ("Unhandled node type %d\n", node->type);
+      break;
+    } 
+
+  g_free (node);
+}
+
+/* returns the fixed size of the blob */
+guint32
+g_idl_node_get_size (GIdlNode *node)
+{
+  GList *l;
+  gint size, n;
+
+  switch (node->type)
+    {
+    case G_IDL_NODE_CALLBACK:
+      size = 12; 
+      break;
+
+    case G_IDL_NODE_FUNCTION:
+      size = 16; 
+      break;
+
+    case G_IDL_NODE_PARAM:
+      size = 12;
+      break;
+
+    case G_IDL_NODE_TYPE:
+      size = 4;
+      break;
+
+    case G_IDL_NODE_OBJECT:
+      {
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+       n = g_list_length (iface->interfaces);
+       size = 32 + 2 * (n + (n % 2));
+
+       for (l = iface->members; l; l = l->next)
+         size += g_idl_node_get_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_INTERFACE:
+      {
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+       n = g_list_length (iface->prerequisites);
+       size = 28 + 2 * (n + (n % 2));
+
+       for (l = iface->members; l; l = l->next)
+         size += g_idl_node_get_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      {
+       GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+       
+       n = g_list_length (enum_->values);
+       size = 20 + n * 16;
+      }
+      break;
+
+    case G_IDL_NODE_VALUE:
+      size = 16;
+      break;
+
+    case G_IDL_NODE_STRUCT:
+    case G_IDL_NODE_BOXED:
+      {
+       GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+       size = 20;
+       for (l = boxed->members; l; l = l->next)
+         size += g_idl_node_get_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_PROPERTY:
+      size = 12;
+      break;
+
+    case G_IDL_NODE_SIGNAL:
+      size = 12;
+      break;
+
+    case G_IDL_NODE_VFUNC:
+      size = 16;
+      break;
+
+    case G_IDL_NODE_FIELD:
+      size = 12;
+      break;
+
+    case G_IDL_NODE_CONSTANT:
+      size = 20;
+      break;
+
+    case G_IDL_NODE_ERROR_DOMAIN:
+      size = 16;
+      break;
+
+    case G_IDL_NODE_XREF:
+      size = 0;
+      break;
+
+    default: 
+      g_error ("Unhandled node type %d\n", node->type);
+      size = 0;
+    }
+
+  return size;
+}
+
+/* returns the full size of the blob including variable-size parts */
+guint32
+g_idl_node_get_full_size (GIdlNode *node)
+{
+  GList *l;
+  gint size, n;
+
+  switch (node->type)
+    {
+    case G_IDL_NODE_CALLBACK:
+      {
+       GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+       size = 12; 
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       for (l = function->parameters; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+       size += g_idl_node_get_full_size ((GIdlNode *)function->result);
+      }
+      break;
+
+    case G_IDL_NODE_FUNCTION:
+      {
+       GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+       size = 16;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (function->c_name) + 1, 4);
+       for (l = function->parameters; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+       size += g_idl_node_get_full_size ((GIdlNode *)function->result);
+      }
+      break;
+
+    case G_IDL_NODE_PARAM:
+      {
+       GIdlNodeParam *param = (GIdlNodeParam *)node;
+       
+       size = 12;
+       if (node->name)
+         size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += g_idl_node_get_full_size ((GIdlNode *)param->type);     
+      }
+      break;
+
+    case G_IDL_NODE_TYPE:
+      {
+       GIdlNodeType *type = (GIdlNodeType *)node;
+       if (type->tag < 20) 
+         size = 4;
+       else
+         {
+           switch (type->tag)
+             {
+             case 20:
+               size = 4 + 4 + g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1);
+               break;
+             case 21:
+               size = 4 + 4;
+               break;
+             case 22:
+             case 23:
+               size = 4 + 4 + g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1);
+               break;
+             case 24:
+               size = 4 + 4
+                 + g_idl_node_get_full_size ((GIdlNode *)type->parameter_type1)
+                 + g_idl_node_get_full_size ((GIdlNode *)type->parameter_type2);
+               break;
+             case 25:
+               {
+                 gint n = g_strv_length (type->errors);
+                 size = 4 + 4 + 2 * (n + n % 2);
+               }
+               break;
+             default:
+               g_error ("Unknown type tag %d\n", type->tag);
+               break;
+             }
+         }
+      }
+      break;
+
+    case G_IDL_NODE_OBJECT:
+      {
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+       n = g_list_length (iface->interfaces);
+       size = 32;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (iface->c_name) + 1, 4);
+       size += ALIGN_VALUE (strlen (iface->init_func) + 1, 4);
+       size += 2 * (n + (n % 2));
+
+       for (l = iface->members; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_INTERFACE:
+      {
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+
+       n = g_list_length (iface->prerequisites);
+       size = 28;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (iface->c_name) + 1, 4);
+       size += ALIGN_VALUE (strlen (iface->init_func) + 1, 4);
+       size += 2 * (n + (n % 2));
+
+       for (l = iface->members; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      {
+       GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+       
+       size = 20;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (enum_->c_name) + 1, 4);
+       if (enum_->init_func)
+         size += ALIGN_VALUE (strlen (enum_->init_func) + 1, 4);
+
+       for (l = enum_->values; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);       
+      }
+      break;
+
+    case G_IDL_NODE_VALUE:
+      {
+       GIdlNodeValue *value = (GIdlNodeValue *)node;
+       
+       size = 16;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (value->c_name) + 1, 4);
+      }
+      break;
+
+    case G_IDL_NODE_STRUCT:
+      {
+       GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+
+       size = 20;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       for (l = struct_->members; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_BOXED:
+      {
+       GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+       size = 20;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       if (boxed->c_name)
+         size += ALIGN_VALUE (strlen (boxed->c_name) + 1, 4);
+       if (boxed->init_func)
+         size += ALIGN_VALUE (strlen (boxed->init_func) + 1, 4);
+       for (l = boxed->members; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+      }
+      break;
+
+    case G_IDL_NODE_PROPERTY:
+      {
+       GIdlNodeProperty *prop = (GIdlNodeProperty *)node;
+       
+       size = 12;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += g_idl_node_get_full_size ((GIdlNode *)prop->type);      
+      }
+      break;
+
+    case G_IDL_NODE_SIGNAL:
+      {
+       GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+
+       size = 12;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       for (l = signal->parameters; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+       size += g_idl_node_get_full_size ((GIdlNode *)signal->result);
+      }
+      break;
+
+    case G_IDL_NODE_VFUNC:
+      {
+       GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+
+       size = 16;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       for (l = vfunc->parameters; l; l = l->next)
+         size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+       size += g_idl_node_get_full_size ((GIdlNode *)vfunc->result);
+      }
+      break;
+
+    case G_IDL_NODE_FIELD:
+      {
+       GIdlNodeField *field = (GIdlNodeField *)node;
+
+       size = 12;
+       size += ALIGN_VALUE (strlen (field->c_name) + 1, 4);
+       size += g_idl_node_get_full_size ((GIdlNode *)field->type);     
+      }
+      break;
+
+    case G_IDL_NODE_CONSTANT:
+      {
+       GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+
+       size = 20;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       /* FIXME non-string values */
+       size += ALIGN_VALUE (strlen (constant->value) + 1, 4);
+       size += g_idl_node_get_full_size ((GIdlNode *)constant->type);  
+      }
+      break;
+
+    case G_IDL_NODE_ERROR_DOMAIN:
+      {
+       GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+
+       size = 16;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (domain->getquark) + 1, 4);
+      }
+      break;
+
+    case G_IDL_NODE_XREF:
+      {
+       GIdlNodeXRef *xref = (GIdlNodeXRef *)node;
+       
+       size = 0;
+       size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+       size += ALIGN_VALUE (strlen (xref->namespace) + 1, 4);
+      }
+      break;
+
+    default: 
+      g_error ("Unknown type tag %d\n", node->type);
+      size = 0;
+    }
+
+  return size;
+}
+
+static gint64
+parse_int_value (const gchar *str)
+{
+  return strtoll (str, NULL, 0);
+}
+
+static guint64
+parse_uint_value (const gchar *str)
+{
+  return strtoull (str, NULL, 0);
+}
+
+static gdouble
+parse_float_value (const gchar *str)
+{
+  return strtod (str, NULL);
+}
+
+static gboolean
+parse_boolean_value (const gchar *str)
+{
+  if (strcmp (str, "TRUE") == 0)
+    return TRUE;
+  
+  if (strcmp (str, "FALSE") == 0)
+    return FALSE;
+
+  return parse_int_value (str) ? TRUE : FALSE;
+}
+
+static GIdlNode *
+find_entry_node (GIdlModule  *module,
+                GList       *modules,
+                const gchar *name,
+                guint16     *idx)
+{
+  GList *l, *m;
+  gint i;
+
+  for (l = module->entries, i = 0; l; l = l->next, i++)
+    {
+      GIdlNode *node = (GIdlNode *)l->data;
+      
+      if (strcmp (node->name, name) == 0)
+       {
+         if (idx)
+           *idx = i;
+         return node;
+       }
+    }
+
+  for (m = modules; m; m = m->next)
+    {
+      GIdlModule *foreign = (GIdlModule *)m->data;
+
+      if (foreign == module)
+       continue;
+      
+      for (l = foreign->entries; l; l = l->next)
+       {
+         GIdlNode *node = (GIdlNode *)l->data;
+         
+         if (node->type == G_IDL_NODE_XREF)
+           continue;
+
+         if (strcmp (node->name, name) == 0)
+           {
+             GIdlNode *xref = g_idl_node_new (G_IDL_NODE_XREF);
+             xref->name = g_strdup (name);
+             ((GIdlNodeXRef *)xref)->namespace = g_strdup (foreign->name);
+
+             module->entries = g_list_append (module->entries, xref);
+             
+             if (idx)
+               *idx = g_list_length (module->entries) - 1;
+
+             return xref;
+           }
+       }
+    }
+
+  g_warning ("No such entry: '%s'\n", name);
+
+  return NULL;
+}
+
+static guint16
+find_entry (GIdlModule  *module,
+           GList       *modules,
+           const gchar *name)
+{
+  guint16 idx;
+
+  find_entry_node (module, modules, name, &idx);
+
+  return idx;
+}
+
+static void
+serialize_type (GIdlModule   *module, 
+               GList        *modules,
+               GIdlNodeType *node, 
+               GString      *str)
+{
+  gint i;
+  
+  const gchar* basic[] = {
+    "void", 
+    "gboolean", 
+    "gint8", 
+    "guint8", 
+    "gint16", 
+    "guint16", 
+    "gint32", 
+    "guint32", 
+    "gint64", 
+    "guint64", 
+    "gfloat", 
+    "gdouble", 
+    "gchar", 
+    "GString", 
+    "gint", 
+    "guint", 
+    "glong", 
+    "gulong"
+  };
+
+  if (node->tag < 20)
+    {
+      g_string_append_printf (str, "%s%s", 
+                             basic[node->tag], node->is_pointer ? "*" : "");
+    }
+  else if (node->tag == 20)
+    {
+      serialize_type (module, modules, node->parameter_type1, str);
+      g_string_append (str, "[");
+
+      if (node->has_length)
+       g_string_append_printf (str, "length=%d", node->length);
+      
+      if (node->zero_terminated)
+       g_string_append_printf (str, "%szero-terminated=1", 
+                               node->has_length ? "," : "");
+      
+      g_string_append (str, "]");
+    }
+  else if (node->tag == 21)
+    {
+      GIdlNode *iface;
+
+      iface = find_entry_node (module, modules, node->interface, NULL);
+      g_string_append_printf (str, "%s%s", 
+                             iface->name, node->is_pointer ? "*" : "");
+    }
+  else if (node->tag == 22)
+    {
+      g_string_append (str, "GList<");
+      serialize_type (module, modules, node->parameter_type1, str);
+      g_string_append (str, ">"); 
+    }
+  else if (node->tag == 23)
+    {
+      g_string_append (str, "GSList<");
+      serialize_type (module, modules, node->parameter_type1, str);
+      g_string_append (str, ">"); 
+    }
+  else if (node->tag == 24)
+    {
+      g_string_append (str, "GHashTable<");
+      serialize_type (module, modules, node->parameter_type1, str);
+      g_string_append (str, ","); 
+      serialize_type (module, modules, node->parameter_type2, str);
+      g_string_append (str, ">"); 
+    }
+  else if (node->tag == 25) 
+    {
+      g_string_append (str, "GError<");
+      for (i = 0; node->errors[i]; i++)
+       {
+         if (i > 0)
+           g_string_append (str, ",");
+         g_string_append (str, node->errors[i]);
+       }
+      g_string_append (str, ">"); 
+    }
+}
+
+void
+g_idl_node_build_metadata (GIdlNode   *node,
+                          GIdlModule *module,
+                          GList      *modules,
+                          GHashTable *strings,
+                          GHashTable *types,
+                          guchar     *data,
+                          guint32    *offset,
+                           guint32    *offset2)
+{
+  GList *l;
+
+  switch (node->type)
+    {
+    case G_IDL_NODE_TYPE:
+      {
+       GIdlNodeType *type = (GIdlNodeType *)node;
+       SimpleTypeBlob *blob = (SimpleTypeBlob *)&data[*offset];
+
+       *offset += 4;
+       
+       if (type->tag < 20)
+         {
+           blob->reserved = 0;
+           blob->reserved2 = 0;
+           blob->pointer = type->is_pointer;
+           blob->reserved3 = 0;
+           blob->tag = type->tag;
+         }
+       else 
+         {
+           GString *str;
+           gchar *s;
+           gpointer value;
+           
+           str = g_string_new (0);
+           serialize_type (module, modules, type, str);
+           s = g_string_free (str, FALSE);
+           
+           value = g_hash_table_lookup (types, s);
+           if (value)
+             {
+               blob->offset = GPOINTER_TO_INT (value);
+               g_free (s);
+             }
+           else
+             {
+               g_hash_table_insert (types, s, GINT_TO_POINTER(*offset2));
+                                    
+               blob->offset = *offset2;
+               switch (type->tag)
+                 {
+                 case 20:
+                   {
+                     ArrayTypeBlob *array = (ArrayTypeBlob *)&data[*offset2];
+                     guint32 pos;
+                     
+                     array->pointer = 1;
+                     array->reserved = 0;
+                     array->tag = type->tag;
+                     array->zero_terminated = type->zero_terminated;
+                     array->has_length = type->has_length;
+                     array->reserved2 = 0;
+                     array->length = type->length;
+                     
+                     pos = *offset2 + 4;
+                     *offset2 += 8;
+                     
+                     g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1, 
+                                                module, modules, strings, types, 
+                                                data, &pos, offset2);
+                   }
+                   break;
+                   
+                 case 21:
+                   {
+                     InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&data[*offset2];
+                     gint i, interface;
+                     
+                     *offset2 += 4;
+                     
+                     iface->pointer = 1;
+                     iface->reserved = 0;
+                     iface->tag = type->tag;
+                     iface->reserved2 = 0;
+                     iface->interface = 0;
+                     iface->interface = find_entry (module, modules, type->interface);
+                   }
+                   break;
+                   
+                 case 22:
+                 case 23:
+                   {
+                     ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2];
+                     guint32 pos;
+                     
+                     param->pointer = 1;
+                     param->reserved = 0;
+                     param->tag = type->tag;
+                     param->reserved2 = 0;
+                     param->n_types = 1;
+                     
+                     pos = *offset2 + 4;
+                     *offset2 += 8;
+                     
+                     g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1, 
+                                                module, modules, strings, types,
+                                                data, &pos, offset2);
+                   }
+                   break;
+                   
+                 case 24:
+                   {
+                     ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2];
+                     guint32 pos;
+                     
+                     param->pointer = 1;
+                     param->reserved = 0;
+                     param->tag = type->tag;
+                     param->reserved2 = 0;
+                     param->n_types = 2;
+                     
+                     pos = *offset2 + 4;
+                     *offset2 += 12;
+                     
+                     g_idl_node_build_metadata ((GIdlNode *)type->parameter_type1, 
+                                                module, modules, strings, types, 
+                                                data, &pos, offset2);
+                     g_idl_node_build_metadata ((GIdlNode *)type->parameter_type2, 
+                                                module, modules, strings, types, 
+                                                data, &pos, offset2);
+                   }
+                   break;
+                   
+                 case 25:
+                   {
+                     ErrorTypeBlob *blob = (ErrorTypeBlob *)&data[*offset2];
+                     gint i, domain;
+                     
+                     blob->pointer = 1;
+                     blob->reserved = 0;
+                     blob->tag = type->tag;
+                     blob->reserved2 = 0;
+                     blob->n_domains = g_strv_length (type->errors);
+                     
+                     *offset2 = ALIGN_VALUE (*offset2 + 4 + 2 * blob->n_domains, 4);
+                     for (i = 0; type->errors[i]; i++)
+                       blob->domains[i] = find_entry (module, modules, type->errors[i]);
+                   }
+                   break;
+                   
+                 default:
+                   g_error ("Unknown type tag %d\n", type->tag);
+                   break;
+                 }
+             }
+         }
+      }
+      break;
+
+    case G_IDL_NODE_FIELD:
+      {
+       GIdlNodeField *field = (GIdlNodeField *)node;
+       FieldBlob *blob;
+
+       blob = (FieldBlob *)&data[*offset];
+       *offset += 8;
+
+       blob->name = write_string (field->c_name, strings, data, offset2);
+       blob->readable = field->readable;
+       blob->writable = field->writable;
+       blob->reserved = 0;
+       blob->bits = 0;
+       blob->struct_offset = 0;
+
+        g_idl_node_build_metadata ((GIdlNode *)field->type, 
+                                  module, modules, strings, types,
+                                  data, offset, offset2);
+      }
+      break;
+
+    case G_IDL_NODE_PROPERTY:
+      {
+       GIdlNodeProperty *prop = (GIdlNodeProperty *)node;
+       PropertyBlob *blob = (PropertyBlob *)&data[*offset];
+       *offset += 8;
+
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->deprecated = prop->deprecated;
+       blob->readable = prop->readable;
+       blob->writable = prop->writable;
+       blob->construct = prop->construct;
+       blob->construct_only = prop->construct_only;
+       blob->reserved = 0;
+
+        g_idl_node_build_metadata ((GIdlNode *)prop->type, 
+                                  module, modules, strings, types,
+                                  data, offset, offset2);
+      }
+      break;
+
+    case G_IDL_NODE_FUNCTION:
+      {
+       FunctionBlob *blob = (FunctionBlob *)&data[*offset];
+       SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+       GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+       guint32 signature, res;
+       gint n;
+
+       signature = *offset2;
+       n = g_list_length (function->parameters);
+
+       *offset += 16;
+       *offset2 += 8 + n * 12;
+
+       blob->blob_type = BLOB_TYPE_FUNCTION;
+       blob->deprecated = function->deprecated;
+       blob->setter = function->is_setter;
+       blob->getter = function->is_getter;
+       blob->constructor = function->is_constructor;
+       blob->wraps_vfunc = function->wraps_vfunc;
+       blob->reserved = 0;
+       blob->index = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->c_name = write_string (function->c_name, strings, data, offset2);
+       blob->signature = signature;
+       
+        g_idl_node_build_metadata ((GIdlNode *)function->result->type, 
+                                  module, modules, strings, types,
+                                  data, &signature, offset2);
+
+       blob2->may_return_null = function->result->null_ok;
+       blob2->caller_owns_return_value = function->result->transfer;
+       blob2->caller_owns_return_container = function->result->shallow_transfer;
+       blob2->reserved = 0;
+       blob2->n_arguments = n;
+
+       signature += 4;
+       
+       for (l = function->parameters; l; l = l->next)
+         {
+           GIdlNode *param = (GIdlNode *)l->data;
+
+           g_idl_node_build_metadata (param, 
+                                      module, modules, strings, types,
+                                      data, &signature, offset2);
+         }
+      }
+      break;
+
+    case G_IDL_NODE_CALLBACK:
+      {
+       CallbackBlob *blob = (CallbackBlob *)&data[*offset];
+       SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+       GIdlNodeFunction *function = (GIdlNodeFunction *)node;
+       guint32 signature, res;
+       gint n;
+
+       signature = *offset2;
+       n = g_list_length (function->parameters);
+
+       *offset += 12;
+       *offset2 += 8 + n * 12;
+
+       blob->blob_type = BLOB_TYPE_CALLBACK;
+       blob->deprecated = function->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->signature = signature;
+       
+        g_idl_node_build_metadata ((GIdlNode *)function->result->type, 
+                                  module, modules, strings, types,
+                                  data, &signature, offset2);
+
+       blob2->may_return_null = function->result->null_ok;
+       blob2->caller_owns_return_value = function->result->transfer;
+       blob2->caller_owns_return_container = function->result->shallow_transfer;
+       blob2->reserved = 0;
+       blob2->n_arguments = n;
+
+       signature += 4;
+       
+       for (l = function->parameters; l; l = l->next)
+         {
+           GIdlNode *param = (GIdlNode *)l->data;
+
+           g_idl_node_build_metadata (param, 
+                                      module, modules, strings, types,
+                                      data, &signature, offset2);
+         }
+      }
+      break;
+
+    case G_IDL_NODE_SIGNAL:
+      {
+       SignalBlob *blob = (SignalBlob *)&data[*offset];
+       SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+       GIdlNodeSignal *signal = (GIdlNodeSignal *)node;
+       guint32 signature, res;
+       gint n;
+
+       signature = *offset2;
+       n = g_list_length (signal->parameters);
+
+       *offset += 12;
+       *offset2 += 8 + n * 12;
+
+       blob->deprecated = signal->deprecated;
+       blob->run_first = signal->run_first;
+       blob->run_last = signal->run_last;
+       blob->run_cleanup = signal->run_cleanup;
+       blob->no_recurse = signal->no_recurse;
+       blob->detailed = signal->detailed;
+       blob->action = signal->action;
+       blob->no_hooks = signal->no_hooks;
+       blob->has_class_closure = 0; /* FIXME */
+       blob->true_stops_emit = 0; /* FIXME */
+       blob->reserved = 0;
+       blob->class_closure = 0; /* FIXME */
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->signature = signature;
+       
+        g_idl_node_build_metadata ((GIdlNode *)signal->result->type, 
+                                  module, modules, strings, types,
+                                  data, &signature, offset2);
+
+       blob2->may_return_null = signal->result->null_ok;
+       blob2->caller_owns_return_value = signal->result->transfer;
+       blob2->caller_owns_return_container = signal->result->shallow_transfer;
+       blob2->reserved = 0;
+       blob2->n_arguments = n;
+
+       signature += 4;
+       
+       for (l = signal->parameters; l; l = l->next)
+         {
+           GIdlNode *param = (GIdlNode *)l->data;
+
+           g_idl_node_build_metadata (param, module, modules, strings, types,
+                                      data, &signature, offset2);
+         }
+      }
+      break;
+
+    case G_IDL_NODE_VFUNC:
+      {
+       VFuncBlob *blob = (VFuncBlob *)&data[*offset];
+       SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2];
+       GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)node;
+       guint32 signature, res;
+       gint n;
+
+       signature = *offset2;
+       n = g_list_length (vfunc->parameters);
+
+       *offset += 16;
+       *offset2 += 8 + n * 12;
+
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->must_chain_up = 0; /* FIXME */
+       blob->must_be_implemented = 0; /* FIXME */
+       blob->must_not_be_implemented = 0; /* FIXME */
+       blob->class_closure = 0; /* FIXME */
+       blob->reserved = 0;
+
+       blob->struct_offset = 0; /* FIXME */
+       blob->reserved2 = 0;
+       blob->signature = signature;
+       
+        g_idl_node_build_metadata ((GIdlNode *)vfunc->result->type, 
+                                  module, modules, strings, types,
+                                  data, &signature, offset2);
+
+       blob2->may_return_null = vfunc->result->null_ok;
+       blob2->caller_owns_return_value = vfunc->result->transfer;
+       blob2->caller_owns_return_container = vfunc->result->shallow_transfer;
+       blob2->reserved = 0;
+       blob2->n_arguments = n;
+
+       signature += 4;
+       
+       for (l = vfunc->parameters; l; l = l->next)
+         {
+           GIdlNode *param = (GIdlNode *)l->data;
+
+           g_idl_node_build_metadata (param, module, modules, strings, 
+                                      types, data, &signature, offset2);
+         }
+      }
+      break;
+
+    case G_IDL_NODE_PARAM:
+      {
+       ArgBlob *blob = (ArgBlob *)&data[*offset];
+       GIdlNodeParam *param = (GIdlNodeParam *)node;
+       guint32 res;
+
+       *offset += 8;
+
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->in = param->in;
+       blob->out = param->out;
+       blob->dipper = param->dipper;
+       blob->null_ok = param->null_ok;
+       blob->optional = param->optional;
+       blob->transfer_ownership = param->transfer;
+       blob->transfer_container_ownership = param->shallow_transfer;
+       blob->return_value = param->retval;
+       blob->reserved = 0;
+
+        g_idl_node_build_metadata ((GIdlNode *)param->type, module, modules, 
+                                  types, strings, data, offset, offset2);
+      }
+      break;
+
+    case G_IDL_NODE_STRUCT:
+      {
+       StructBlob *blob = (StructBlob *)&data[*offset];
+       GIdlNodeStruct *struct_ = (GIdlNodeStruct *)node;
+       guint32 pos;
+       
+       blob->blob_type = BLOB_TYPE_STRUCT;
+       blob->deprecated = struct_->deprecated;
+       blob->unregistered = TRUE;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->gtype_name = 0;
+       blob->gtype_init = 0;
+
+       blob->n_fields = 0;
+       blob->n_methods = 0;
+
+       *offset += 20; 
+       for (l = struct_->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FIELD)
+             {
+               blob->n_fields++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       for (l = struct_->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+           
+           if (member->type == G_IDL_NODE_FUNCTION)
+             {
+               blob->n_methods++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+      }
+      break;
+
+    case G_IDL_NODE_BOXED:
+      {
+       StructBlob *blob = (StructBlob *)&data[*offset];
+       GIdlNodeBoxed *boxed = (GIdlNodeBoxed *)node;
+
+       blob->blob_type = BLOB_TYPE_BOXED;
+       blob->deprecated = boxed->deprecated;
+       blob->unregistered = FALSE;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->gtype_name = write_string (boxed->c_name, strings, data, offset2);
+       blob->gtype_init = write_string (boxed->init_func, strings, data, offset2);
+
+       blob->n_fields = 0;
+       blob->n_methods = 0;
+
+       *offset += 20; 
+       for (l = boxed->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FIELD)
+             {
+               blob->n_fields++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       for (l = boxed->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FUNCTION)
+             {
+               blob->n_methods++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+      }
+      break;
+
+    case G_IDL_NODE_ENUM:
+    case G_IDL_NODE_FLAGS:
+      {
+       EnumBlob *blob = (EnumBlob *)&data[*offset];
+       GIdlNodeEnum *enum_ = (GIdlNodeEnum *)node;
+
+       *offset += 20; 
+       
+       if (node->type == G_IDL_NODE_ENUM)
+         blob->blob_type = BLOB_TYPE_ENUM;
+       else
+         blob->blob_type = BLOB_TYPE_FLAGS;
+         
+       blob->deprecated = enum_->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->gtype_name = write_string (enum_->c_name, strings, data, offset2);
+       if (enum_->init_func)
+         {
+           blob->unregistered = FALSE;
+           blob->gtype_init = write_string (enum_->init_func, strings, data, offset2);
+         }
+       else
+         {
+           blob->unregistered = TRUE;
+           blob->gtype_init = 0;
+         }
+
+       blob->n_values = 0;
+       blob->reserved2 = 0;
+
+       for (l = enum_->values; l; l = l->next)
+         {
+           GIdlNode *value = (GIdlNode *)l->data;
+
+           blob->n_values++;
+           g_idl_node_build_metadata (value, module, modules, strings, types,
+                                      data, offset, offset2);
+         }
+      }
+      break;
+      
+    case G_IDL_NODE_OBJECT:
+      {
+       ObjectBlob *blob = (ObjectBlob *)&data[*offset];
+       GIdlNodeInterface *object = (GIdlNodeInterface *)node;
+       gint parent;
+
+       blob->blob_type = BLOB_TYPE_OBJECT;
+       blob->deprecated = object->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->gtype_name = write_string (object->c_name, strings, data, offset2);
+       blob->gtype_init = write_string (object->init_func, strings, data, offset2);
+       if (object->parent)
+         blob->parent = find_entry (module, modules, object->parent);
+       else
+         blob->parent = 0;
+
+       blob->n_interfaces = 0;
+       blob->n_fields = 0;
+       blob->n_properties = 0;
+       blob->n_methods = 0;
+       blob->n_signals = 0;
+       blob->n_vfuncs = 0;
+       blob->n_constants = 0;
+       
+       *offset += 32;
+       for (l = object->interfaces; l; l = l->next)
+         {
+           blob->n_interfaces++;
+           *(guint16*)&data[*offset] = find_entry (module, modules, (gchar *)l->data);
+           *offset += 2;
+         }
+       
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FIELD)
+             {
+               blob->n_fields++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_PROPERTY)
+             {
+               blob->n_properties++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FUNCTION)
+             {
+               blob->n_methods++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_SIGNAL)
+             {
+               blob->n_signals++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_VFUNC)
+             {
+               blob->n_vfuncs++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = object->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_CONSTANT)
+             {
+               blob->n_constants++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+      }
+      break;
+
+    case G_IDL_NODE_INTERFACE:
+      {
+       InterfaceBlob *blob = (InterfaceBlob *)&data[*offset];
+       GIdlNodeInterface *iface = (GIdlNodeInterface *)node;
+       gint parent;
+
+       blob->blob_type = BLOB_TYPE_INTERFACE;
+       blob->deprecated = iface->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->gtype_name = write_string (iface->c_name, strings, data, offset2);
+       blob->gtype_init = write_string (iface->init_func, strings, data, offset2);
+       blob->n_prerequisites = 0;
+       blob->n_properties = 0;
+       blob->n_methods = 0;
+       blob->n_signals = 0;
+       blob->n_vfuncs = 0;
+       blob->n_constants = 0;
+       
+       *offset += 28;
+       for (l = iface->prerequisites; l; l = l->next)
+         {
+           blob->n_prerequisites++;
+           *(guint16*)&data[*offset] = find_entry (module, modules, (gchar *)l->data);
+           *offset += 2;
+         }
+       
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = iface->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_PROPERTY)
+             {
+               blob->n_properties++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = iface->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_FUNCTION)
+             {
+               blob->n_methods++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = iface->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_SIGNAL)
+             {
+               blob->n_signals++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = iface->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_VFUNC)
+             {
+               blob->n_vfuncs++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+
+       *offset = ALIGN_VALUE (*offset, 4);
+       for (l = iface->members; l; l = l->next)
+         {
+           GIdlNode *member = (GIdlNode *)l->data;
+
+           if (member->type == G_IDL_NODE_CONSTANT)
+             {
+               blob->n_constants++;
+               g_idl_node_build_metadata (member, module, modules, strings, 
+                                          types, data, offset, offset2);
+             }
+         }
+      }
+      break;
+
+
+    case G_IDL_NODE_VALUE:
+      {
+       GIdlNodeValue *value = (GIdlNodeValue *)node;
+       ValueBlob *blob = (ValueBlob *)&data[*offset];
+       *offset += 16;
+
+       blob->deprecated = value->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->short_name = write_string (value->c_name, strings, data, offset2);
+       blob->value = value->value;
+      }
+      break;
+
+    case G_IDL_NODE_ERROR_DOMAIN:
+      {
+       GIdlNodeErrorDomain *domain = (GIdlNodeErrorDomain *)node;
+       ErrorDomainBlob *blob = (ErrorDomainBlob *)&data[*offset];
+       *offset += 16;
+
+       blob->blob_type = BLOB_TYPE_ERROR_DOMAIN;
+       blob->deprecated = domain->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+       blob->get_quark = write_string (domain->getquark, strings, data, offset2);
+       blob->error_codes = find_entry (module, modules, domain->codes);
+       blob->reserved2 = 0;
+      }
+      break;
+
+    case G_IDL_NODE_CONSTANT:
+      {
+       GIdlNodeConstant *constant = (GIdlNodeConstant *)node;
+       ConstantBlob *blob = (ConstantBlob *)&data[*offset];
+       gint pos;
+
+       pos = *offset + 8;
+       *offset += 20;
+
+       blob->blob_type = BLOB_TYPE_CONSTANT;
+       blob->deprecated = constant->deprecated;
+       blob->reserved = 0;
+       blob->name = write_string (node->name, strings, data, offset2);
+
+       blob->offset = *offset2;
+       switch (constant->type->tag)
+         {
+         case 1:
+           blob->size = 4;
+           *(gboolean*)&data[blob->offset] = parse_boolean_value (constant->value);
+           break;
+           case 2:
+           blob->size = 1;
+             *(gint8*)&data[blob->offset] = (gint8) parse_int_value (constant->value);
+           break;
+         case 3:
+           blob->size = 1;
+           *(guint8*)&data[blob->offset] = (guint8) parse_uint_value (constant->value);
+           break;
+         case 4:
+           blob->size = 2;
+           *(gint16*)&data[blob->offset] = (gint16) parse_int_value (constant->value);
+           break;
+         case 5:
+           blob->size = 2;
+           *(guint16*)&data[blob->offset] = (guint16) parse_uint_value (constant->value);
+           break;
+         case 6:
+           blob->size = 4;
+           *(gint32*)&data[blob->offset] = (gint32) parse_int_value (constant->value);
+           break;
+         case 7:
+           blob->size = 4;
+           *(guint32*)&data[blob->offset] = (guint32) parse_uint_value (constant->value);
+           break;
+         case 8:
+           blob->size = 8;
+           *(gint32*)&data[blob->offset] = (gint64) parse_int_value (constant->value);
+           break;
+         case 9:
+           blob->size = 8;
+           *(guint32*)&data[blob->offset] = (guint64) parse_uint_value (constant->value);
+           break;
+         case 10:
+           blob->size = sizeof (gfloat);
+           *(gfloat*)&data[blob->offset] = (gfloat) parse_float_value (constant->value);
+           break;
+         case 11:
+           blob->size = sizeof (gdouble);
+           *(gdouble*)&data[blob->offset] = (gdouble) parse_float_value (constant->value);
+           break;
+         case 12:
+           blob->size = strlen (constant->value) + 1;
+           memcpy (&data[blob->offset], constant->value, blob->size);
+           break;
+         case 14:
+           blob->size = sizeof (gint);
+           *(gint*)&data[blob->offset] = (gint) parse_int_value (constant->value);
+           break;
+         case 15:
+           blob->size = sizeof (guint);
+           *(gint*)&data[blob->offset] = (guint) parse_uint_value (constant->value);
+           break;
+         case 16:
+           blob->size = sizeof (glong);
+           *(glong*)&data[blob->offset] = (glong) parse_int_value (constant->value);
+           break;
+         case 17:
+           blob->size = sizeof (gulong);
+           *(gulong*)&data[blob->offset] = (gulong) parse_uint_value (constant->value);
+           break;
+         }
+       *offset2 += ALIGN_VALUE (blob->size, 4);
+       
+       g_idl_node_build_metadata ((GIdlNode *)constant->type, module, modules, 
+                                  strings, types, data, &pos, offset2);
+      }
+      break;
+    }
+}
+
+
+/* if str is already in the pool, return previous location, otherwise write str
+ * to the metadata at offset, put it in the pool and update offset. If the 
+ * metadata is not large enough to hold the string, reallocate it.
+ */
+guint32 
+write_string (const gchar *str,
+             GHashTable  *strings, 
+             guchar      *data,
+             guint32     *offset)
+{
+  gpointer value;
+  guint32 start;
+
+  value = g_hash_table_lookup (strings, str);
+  
+  if (value)
+      return GPOINTER_TO_INT (value);
+  
+  g_hash_table_insert (strings, (gpointer)str, GINT_TO_POINTER (*offset));
+
+  start = *offset;
+  *offset = ALIGN_VALUE (start + strlen (str) + 1, 4);
+
+  strcpy (&data[start], str);
+  
+  return start;
+}
diff --git a/src/gidlnode.h b/src/gidlnode.h
new file mode 100644 (file)
index 0000000..08683d3
--- /dev/null
@@ -0,0 +1,313 @@
+/* GObject introspection: Parsed IDL
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_IDL_NODE_H__
+#define __G_IDL_NODE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GIdlNode GIdlNode; 
+typedef struct _GIdlNodeFunction GIdlNodeFunction;
+typedef struct _GIdlNodeParam GIdlNodeParam;
+typedef struct _GIdlNodeType GIdlNodeType;
+typedef struct _GIdlNodeInterface GIdlNodeInterface;
+typedef struct _GIdlNodeSignal GIdlNodeSignal;
+typedef struct _GIdlNodeProperty GIdlNodeProperty;
+typedef struct _GIdlNodeVFunc GIdlNodeVFunc;
+typedef struct _GIdlNodeField GIdlNodeField;
+typedef struct _GIdlNodeValue GIdlNodeValue;
+typedef struct _GIdlNodeEnum GIdlNodeEnum;
+typedef struct _GIdlNodeBoxed GIdlNodeBoxed;
+typedef struct _GIdlNodeStruct GIdlNodeStruct;
+typedef struct _GIdlNodeConstant GIdlNodeConstant;
+typedef struct _GIdlNodeErrorDomain GIdlNodeErrorDomain;
+typedef struct _GIdlNodeXRef GIdlNodeXRef;
+
+typedef enum 
+{
+  G_IDL_NODE_INVALID,
+  G_IDL_NODE_FUNCTION,
+  G_IDL_NODE_CALLBACK,
+  G_IDL_NODE_STRUCT,
+  G_IDL_NODE_BOXED,
+  G_IDL_NODE_ENUM,
+  G_IDL_NODE_FLAGS,
+  G_IDL_NODE_OBJECT,
+  G_IDL_NODE_INTERFACE,
+  G_IDL_NODE_CONSTANT,
+  G_IDL_NODE_ERROR_DOMAIN,
+  G_IDL_NODE_PARAM,
+  G_IDL_NODE_TYPE,
+  G_IDL_NODE_PROPERTY,
+  G_IDL_NODE_SIGNAL,
+  G_IDL_NODE_VALUE,
+  G_IDL_NODE_VFUNC,
+  G_IDL_NODE_FIELD,
+  G_IDL_NODE_XREF
+} GIdlNodeTypeId;
+
+struct _GIdlNode
+{
+  GIdlNodeTypeId type;
+  gchar *name;
+};
+
+struct _GIdlNodeXRef
+{
+  GIdlNode node;
+
+  gchar *namespace;
+};
+
+struct _GIdlNodeFunction
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gboolean is_method;
+  gboolean is_setter;
+  gboolean is_getter;
+  gboolean is_constructor;
+  gboolean wraps_vfunc;
+
+  gchar *c_name;
+
+  GIdlNodeParam *result;
+  GList *parameters;
+};
+
+struct _GIdlNodeType 
+{
+  GIdlNode node;
+
+  gboolean is_pointer;
+  gboolean is_basic;
+  gboolean is_array;
+  gboolean is_glist;
+  gboolean is_gslist;
+  gboolean is_ghashtable;
+  gboolean is_interface;
+  gboolean is_error;
+  gint tag;
+
+  gchar *unparsed;
+
+  gboolean zero_terminated;
+  gboolean has_length;
+  gint length;
+  
+  GIdlNodeType *parameter_type1;
+  GIdlNodeType *parameter_type2;  
+
+  gchar *interface;
+  gchar **errors;
+};
+
+struct _GIdlNodeParam 
+{
+  GIdlNode node;
+
+  gboolean in;
+  gboolean out;
+  gboolean dipper;
+  gboolean optional;
+  gboolean retval;
+  gboolean null_ok;
+  gboolean transfer;
+  gboolean shallow_transfer;
+  
+  GIdlNodeType *type;
+};
+
+struct _GIdlNodeProperty
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+  gboolean readable;
+  gboolean writable;
+  gboolean construct;
+  gboolean construct_only;
+  
+  GIdlNodeType *type;
+};
+
+struct _GIdlNodeSignal 
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+  gboolean run_first;
+  gboolean run_last;
+  gboolean run_cleanup;
+  gboolean no_recurse;
+  gboolean detailed;
+  gboolean action;
+  gboolean no_hooks;
+  
+  gboolean has_class_closure;
+  gboolean true_stops_emit;
+  
+  gint class_closure;
+  
+  GList *parameters;
+  GIdlNodeParam *result;    
+};
+
+struct _GIdlNodeVFunc 
+{
+  GIdlNode node;
+
+  gchar *c_name;
+  gboolean must_chain_up;
+  gboolean must_be_implemented;
+  gboolean must_not_be_implemented;
+  gboolean is_class_closure;
+  
+  GList *parameters;
+  GIdlNodeParam *result;      
+};
+
+struct _GIdlNodeField
+{
+  GIdlNode node;
+
+  gchar *c_name;
+  gboolean readable;
+  gboolean writable;
+  gint bits;
+  
+  GIdlNodeType *type;
+};
+
+struct _GIdlNodeInterface
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+  gchar *init_func;
+
+  gchar *parent;
+  
+  GList *interfaces;
+  GList *prerequisites;
+
+  GList *members;
+};
+
+struct _GIdlNodeValue
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+
+  guint32 value;
+};
+
+struct _GIdlNodeConstant
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  GIdlNodeType *type;
+  
+  gchar *value;
+};
+
+struct _GIdlNodeEnum
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+  gchar *init_func;
+
+  GList *values;
+};
+
+struct _GIdlNodeBoxed
+{ 
+  GIdlNode node;
+
+  gboolean deprecated;
+
+  gchar *c_name;
+  gchar *init_func;
+  
+  GList *members;
+};
+
+struct _GIdlNodeStruct
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+  
+  gchar *c_name;
+  
+  GList *members;
+};
+
+struct _GIdlNodeErrorDomain
+{
+  GIdlNode node;
+
+  gboolean deprecated;
+  
+  gchar *name;
+  gchar *getquark;
+  gchar *codes;
+};
+
+
+GIdlNode *g_idl_node_new             (GIdlNodeTypeId type);
+void      g_idl_node_free            (GIdlNode    *node);
+guint32   g_idl_node_get_size        (GIdlNode    *node);
+guint32   g_idl_node_get_full_size   (GIdlNode    *node);
+void      g_idl_node_build_metadata  (GIdlNode    *node,
+                                     GIdlModule  *module,
+                                     GList       *modules,
+                                      GHashTable  *strings,
+                                      GHashTable  *types,
+                                     guchar      *data,
+                                     guint32     *offset,
+                                      guint32     *offset2);
+
+guint32   write_string               (const gchar *str,
+                                     GHashTable  *strings, 
+                                     guchar      *data,
+                                     guint32     *offset);
+
+G_END_DECLS
+
+#endif  /* __G_IDL_NODE_H__ */
diff --git a/src/gidlparser.c b/src/gidlparser.c
new file mode 100644 (file)
index 0000000..8e340db
--- /dev/null
@@ -0,0 +1,1884 @@
+/* GObject introspection: A parser for the XML IDL format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+#include "gidlmodule.h"
+#include "gidlnode.h"
+
+typedef enum
+{
+  STATE_START,
+  STATE_END,
+  STATE_ROOT,
+  STATE_NAMESPACE,
+  STATE_FUNCTION,
+  STATE_PARAMETERS,
+  STATE_OBJECT,
+  STATE_INTERFACE,
+  STATE_IMPLEMENTS,
+  STATE_REQUIRES,
+  STATE_ENUM,
+  STATE_BOXED,
+  STATE_STRUCT,
+  STATE_SIGNAL,
+  STATE_ERRORDOMAIN
+} ParseState;
+
+typedef struct _ParseContext ParseContext;
+struct _ParseContext
+{
+  ParseState state;
+  ParseState prev_state;
+
+  GList *modules;
+
+  GIdlModule *current_module;
+  GIdlNode *current_node;
+};
+
+#define MISSING_ATTRIBUTE(error,element,attribute)                            \
+  g_set_error (error,                                                         \
+              G_MARKUP_ERROR,                                                \
+              G_MARKUP_ERROR_INVALID_CONTENT,                                \
+              "The attribute '%s' on the element '%s' must be specified",    \
+              attribute, element)
+
+static const gchar *
+find_attribute (const gchar  *name, 
+               const gchar **attribute_names,
+               const gchar **attribute_values)
+{
+  gint i;
+  
+  for (i = 0; attribute_names[i] != NULL; i++)
+    if (strcmp (attribute_names[i], name) == 0)
+      return attribute_values[i];
+  
+  return 0;
+}
+
+static GIdlNodeType *
+parse_type_internal (gchar *str, gchar **rest)
+{
+  gint i;
+
+  static struct {
+    const gchar *str;
+    gint tag;
+    gboolean pointer;
+  } basic[] = {
+    { "void",     0, 0 },
+    { "gpointer", 0, 1 },
+    { "gboolean", 1, 0 },
+    { "int8_t",   2, 0 },
+    { "int8",     2, 0 },
+    { "gint8",    2, 0 },
+    { "uint8_t",  3, 0 },
+    { "uint8",    3, 0 },
+    { "guint8",   3, 0 },
+    { "int16_t",  4, 0 },
+    { "int16",    4, 0 },
+    { "gint16",   4, 0 },
+    { "uint16_t", 5, 0 },
+    { "uint16",   5, 0 },
+    { "guint16",  5, 0 },
+    { "int32_t",  6, 0 },
+    { "int32",    6, 0 },
+    { "gint32",   6, 0 },
+    { "uint32_t", 7, 0 },
+    { "uint32",   7, 0 },
+    { "guint32",  7, 0 },
+    { "int64_t",  8, 0 },
+    { "int64",    8, 0 },
+    { "gint64",   8, 0 },
+    { "uint64_t", 9, 0 },
+    { "uint64",   9, 0 },
+    { "guint64",  9, 0 },
+    { "float",   10, 0 },
+    { "gfloat",  10, 0 },
+    { "double",  11, 0 },
+    { "gdouble", 11, 0 },
+    { "gchar",   12, 0 },  
+    { "char",    12, 0 },
+    { "GString", 13, 0 },
+    { "int",     14, 0 },
+    { "gint",    14, 0 },
+    { "uint",    15, 0 },
+    { "guint",   15, 0 },
+    { "long",    16, 0 },
+    { "glong",   16, 0 },
+    { "ulong",   17, 0 },
+    { "gulong",  17, 0 }
+  };  
+
+  gint n_basic = G_N_ELEMENTS (basic);
+  gchar *start, *end;
+  
+  GIdlNodeType *type;
+  
+  type = (GIdlNodeType *)g_idl_node_new (G_IDL_NODE_TYPE);
+  
+  str = g_strstrip (str);
+
+  type->unparsed = g_strdup (str);
+  *rest = str;
+  for (i = 0; i < n_basic; i++)
+    {
+      if (g_str_has_prefix (*rest, basic[i].str))
+       {
+         type->is_basic = TRUE;
+         type->tag = basic[i].tag;
+         type->is_pointer = basic[i].pointer;
+
+         *rest += strlen(basic[i].str);
+         *rest = g_strchug (*rest);
+         if (**rest == '*')
+           {
+             type->is_pointer = TRUE;
+             (*rest)++;
+           }
+
+         break;
+       }
+    }
+
+  if (i < n_basic)
+    /* found a basic type */;
+  else if (g_str_has_prefix (*rest, "GList") ||
+          g_str_has_prefix (*rest, "GSList"))
+    {
+      if (g_str_has_prefix (*rest, "GList"))
+       {
+         type->tag = 22;
+         type->is_glist = TRUE;
+         type->is_pointer = TRUE;
+         *rest += strlen ("GList");
+       }
+      else
+       {
+         type->tag = 23;
+         type->is_gslist = TRUE;
+         type->is_pointer = TRUE;
+         *rest += strlen ("GSList");
+       }
+      
+      *rest = g_strchug (*rest);
+      
+      if (**rest != '<')
+       goto error;
+      (*rest)++;
+      
+      type->parameter_type1 = parse_type_internal (*rest, rest);
+      if (type->parameter_type1 == NULL)
+       goto error;
+      
+      *rest = g_strchug (*rest);
+      
+      if ((*rest)[0] != '>')
+       goto error;
+      (*rest)++;
+    }
+  else if (g_str_has_prefix (*rest, "GHashTable"))
+    {
+      type->tag = 24;
+      type->is_ghashtable = TRUE;
+      type->is_pointer = TRUE;
+      *rest += strlen ("GHashTable");
+      
+      *rest = g_strchug (*rest);
+      
+      if (**rest != '<')
+       goto error;
+      (*rest)++;
+      
+      type->parameter_type1 = parse_type_internal (*rest, rest);
+      if (type->parameter_type1 == NULL)
+       goto error;
+      
+      *rest = g_strchug (*rest);
+      
+      if ((*rest)[0] != ',')
+       goto error;
+      (*rest)++;
+      
+      type->parameter_type2 = parse_type_internal (*rest, rest);
+      if (type->parameter_type2 == NULL)
+       goto error;
+      
+      if ((*rest)[0] != '>')
+       goto error;
+      (*rest)++;
+    }
+  else if (g_str_has_prefix (*rest, "GError"))
+    {
+      type->tag = 25;
+      type->is_error = TRUE;
+      type->is_pointer = TRUE;
+      *rest += strlen ("GError");
+      
+      *rest = g_strchug (*rest);
+      
+      if (**rest != '<')
+       goto error;
+      (*rest)++;
+      
+      end = strchr (*rest, '>');
+      str = g_strndup (*rest, end - *rest);
+      type->errors = g_strsplit (str, ",", 0);
+      g_free (str);
+
+      *rest = end + 1;
+    }
+  else 
+    {
+      type->tag = 21;
+      type->is_interface = TRUE;
+      start = *rest;
+
+      /* must be an interface type */
+      while (g_ascii_isalnum (**rest) || 
+            **rest == '.' || 
+            **rest == '-' || 
+            **rest == '_' ||
+            **rest == ':')
+       (*rest)++;
+
+      type->interface = g_strndup (start, *rest - start);
+
+      *rest = g_strchug (*rest);
+         if (**rest == '*')
+           {
+             type->is_pointer = TRUE;
+             (*rest)++;
+           }
+    }
+  
+  *rest = g_strchug (*rest);
+  if (g_str_has_prefix (*rest, "["))
+    {
+      GIdlNodeType *array;
+
+      array = (GIdlNodeType *)g_idl_node_new (G_IDL_NODE_TYPE);
+
+      array->tag = 20;
+      array->is_pointer = TRUE;
+      array->is_array = TRUE;
+      
+      array->parameter_type1 = type;
+
+      array->zero_terminated = FALSE;
+      array->has_length = FALSE;
+      array->length = 0;
+
+      if (!g_str_has_prefix (*rest, "[]"))
+       {
+         gchar *end, *str, **opts;
+         
+         end = strchr (*rest, ']');
+         str = g_strndup (*rest + 1, (end - *rest) - 1); 
+         opts = g_strsplit (str, ",", 0);
+         
+         *rest = end + 1;
+
+         for (i = 0; opts[i]; i++)
+           {
+             gchar **vals;
+             
+             vals = g_strsplit (opts[i], "=", 0);
+
+             if (strcmp (vals[0], "zero-terminated") == 0)
+               array->zero_terminated = (strcmp (vals[1], "1") == 0);
+             else if (strcmp (vals[0], "length") == 0)
+               {
+                 array->has_length = TRUE;
+                 array->length = atoi (vals[1]);
+               }
+
+             g_strfreev (vals);
+           }
+
+         g_free (str);
+         g_strfreev (opts);
+       }
+             
+      type = array;
+    }
+
+  return type;
+
+ error:
+  g_idl_node_free ((GIdlNode *)type);
+  
+  return NULL;
+}
+
+static GIdlNodeType *
+parse_type (const gchar *type)
+{
+  gchar *str;
+  gchar *rest;
+  GIdlNodeType *node;
+  
+  str = g_strdup (type);
+  node = parse_type_internal (str, &rest);
+  g_free (str);
+
+  return node;
+}
+
+static gboolean
+start_boxed (GMarkupParseContext *context,
+            const gchar         *element_name,
+            const gchar        **attribute_names,
+            const gchar        **attribute_values,
+            ParseContext        *ctx,
+            GError             **error)
+{
+  if (strcmp (element_name, "boxed") == 0 && 
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *typeinit;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else
+       {
+         GIdlNodeBoxed *boxed;
+
+         boxed = (GIdlNodeBoxed *) g_idl_node_new (G_IDL_NODE_BOXED);
+         
+         ((GIdlNode *)boxed)->name = g_strdup (name);
+         boxed->c_name = g_strdup (cname);
+         boxed->init_func = g_strdup (typeinit);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           boxed->deprecated = TRUE;
+         else
+           boxed->deprecated = FALSE;
+         
+         ctx->current_node = (GIdlNode *)boxed;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, boxed);
+         
+         ctx->state = STATE_BOXED;
+       }
+         
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+start_function (GMarkupParseContext *context,
+               const gchar         *element_name,
+               const gchar        **attribute_names,
+               const gchar        **attribute_values,
+               ParseContext       *ctx,
+               GError             **error)
+{
+  if ((ctx->state == STATE_NAMESPACE &&
+       (strcmp (element_name, "function") == 0 ||
+       strcmp (element_name, "callback") == 0)) ||
+      ((ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_INTERFACE ||
+       ctx->state == STATE_BOXED ||
+       ctx->state == STATE_STRUCT) &&
+       strcmp (element_name, "method") == 0) ||
+      (ctx->state == STATE_OBJECT &&
+       strcmp (element_name, "constructor") == 0))
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *deprecated;
+      const gchar *type;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      type = find_attribute ("type", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (strcmp (element_name, "callback") != 0 && cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else
+       {
+         GIdlNodeFunction *function;
+         
+         function = (GIdlNodeFunction *) g_idl_node_new (G_IDL_NODE_FUNCTION);
+
+         ((GIdlNode *)function)->name = g_strdup (name);
+         function->c_name = g_strdup (cname);
+         function->parameters = NULL;
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           function->deprecated = TRUE;
+         else
+           function->deprecated = FALSE;
+       
+         if (strcmp (element_name, "method") == 0 ||
+             strcmp (element_name, "constructor") == 0)
+           {
+             function->is_method = TRUE;
+
+             if (type && strcmp (type, "setter") == 0)
+               function->is_setter = TRUE;
+             else if (type && strcmp (type, "getter") == 0)
+               function->is_getter = TRUE;               
+
+             if (strcmp (element_name, "constructor") == 0)
+               function->is_constructor = TRUE;
+             else
+               function->is_constructor = FALSE;
+           }
+         else
+           {
+             function->is_method = FALSE;
+             function->is_setter = FALSE;
+             function->is_getter = FALSE;
+             function->is_constructor = FALSE;
+             if (strcmp (element_name, "callback") == 0)
+               ((GIdlNode *)function)->type = G_IDL_NODE_CALLBACK;
+           }
+         
+         if (ctx->current_node == NULL)
+           {
+             ctx->current_module->entries = 
+               g_list_append (ctx->current_module->entries, function);       
+           }
+         else
+           switch (ctx->current_node->type)
+             {
+             case G_IDL_NODE_INTERFACE:
+               {
+                 GIdlNodeInterface *iface;
+                 
+                 iface = (GIdlNodeInterface *)ctx->current_node;
+                 iface->members = g_list_append (iface->members, function);
+               }
+               break;
+             case G_IDL_NODE_BOXED:
+               {
+                 GIdlNodeBoxed *boxed;
+
+                 boxed = (GIdlNodeBoxed *)ctx->current_node;
+                 boxed->members = g_list_append (boxed->members, function);
+               }
+               break;
+             case G_IDL_NODE_STRUCT:
+               {
+                 GIdlNodeStruct *struct_;
+                 
+                 struct_ = (GIdlNodeStruct *)ctx->current_node;
+                 struct_->members = g_list_append (struct_->members, function);                }
+               break;
+             }
+         
+         ctx->current_node = (GIdlNode *)function;
+         ctx->state = STATE_FUNCTION;
+
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+static gboolean
+start_parameter (GMarkupParseContext *context,
+                const gchar         *element_name,
+                const gchar        **attribute_names,
+                const gchar        **attribute_values,
+                ParseContext       *ctx,
+                GError             **error)
+{
+  if (strcmp (element_name, "parameter") == 0 &&
+      ctx->state == STATE_PARAMETERS)
+    {
+      const gchar *type;
+      const gchar *name;
+      const gchar *direction;
+      const gchar *retval;
+      const gchar *dipper;
+      const gchar *optional;
+      const gchar *nullok;
+      const gchar *transfer;
+      
+      type = find_attribute ("type", attribute_names, attribute_values);
+      name = find_attribute ("name", attribute_names, attribute_values);
+      direction = find_attribute ("direction", attribute_names, attribute_values);
+      retval = find_attribute ("retval", attribute_names, attribute_values);
+      dipper = find_attribute ("dipper", attribute_names, attribute_values);
+      optional = find_attribute ("optional", attribute_names, attribute_values);
+      nullok = find_attribute ("null-ok", attribute_names, attribute_values);
+      transfer = find_attribute ("transfer", attribute_names, attribute_values);
+
+      if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else
+       {
+         GIdlNodeParam *param;
+
+         param = (GIdlNodeParam *)g_idl_node_new (G_IDL_NODE_PARAM);
+         
+         if (direction && strcmp (direction, "out") == 0)
+           {
+             param->in = FALSE;
+             param->out = TRUE;
+           }
+         else if (direction && strcmp (direction, "inout") == 0)
+           {
+             param->in = TRUE;
+             param->out = TRUE;
+           }
+         else
+           {
+             param->in = TRUE;
+             param->out = FALSE;
+           }
+
+         if (retval && strcmp (retval, "1") == 0)
+           param->retval = TRUE;
+         else
+           param->retval = FALSE;
+
+         if (dipper && strcmp (dipper, "1") == 0)
+           param->dipper = TRUE;
+         else
+           param->dipper = FALSE;
+
+         if (optional && strcmp (optional, "1") == 0)
+           param->optional = TRUE;
+         else
+           param->optional = FALSE;
+
+         if (nullok && strcmp (nullok, "1") == 0)
+           param->null_ok = TRUE;
+         else
+           param->null_ok = FALSE;
+
+         if (transfer && strcmp (transfer, "none") == 0)
+           {
+             param->transfer = FALSE;
+             param->shallow_transfer = FALSE;
+           }
+         else if (transfer && strcmp (transfer, "shallow") == 0)
+           {
+             param->transfer = FALSE;
+             param->shallow_transfer = TRUE;
+           }
+         else
+           {
+             param->transfer = TRUE;
+             param->shallow_transfer = FALSE;
+           }
+         
+         ((GIdlNode *)param)->name = g_strdup (name);
+         param->type = parse_type (type);
+         
+         switch (ctx->current_node->type)
+           {
+           case G_IDL_NODE_FUNCTION:
+           case G_IDL_NODE_CALLBACK:
+             {
+               GIdlNodeFunction *func;
+
+               func = (GIdlNodeFunction *)ctx->current_node;
+               func->parameters = g_list_append (func->parameters, param);
+             }
+             break;
+           case G_IDL_NODE_SIGNAL:
+             {
+               GIdlNodeSignal *signal;
+
+               signal = (GIdlNodeSignal *)ctx->current_node;
+               signal->parameters = g_list_append (signal->parameters, param);
+             }
+             break;
+           case G_IDL_NODE_VFUNC:
+             {
+               GIdlNodeVFunc *vfunc;
+               
+               vfunc = (GIdlNodeVFunc *)ctx->current_node;
+               vfunc->parameters = g_list_append (vfunc->parameters, param);
+             }
+             break;
+           }
+       }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+start_field (GMarkupParseContext *context,
+            const gchar         *element_name,
+            const gchar        **attribute_names,
+            const gchar        **attribute_values,
+            ParseContext       *ctx,
+            GError             **error)
+{
+  if (strcmp (element_name, "field") == 0 &&
+      (ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_BOXED ||
+       ctx->state == STATE_STRUCT))
+    {
+      const gchar *cname;
+      const gchar *type;
+      const gchar *readable;
+      const gchar *writable;
+      const gchar *bits;
+      
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      type = find_attribute ("type", attribute_names, attribute_values);
+      readable = find_attribute ("readable", attribute_names, attribute_values);
+      writable = find_attribute ("writable", attribute_names, attribute_values);
+      bits = find_attribute ("bits", attribute_names, attribute_values);
+      
+      if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else
+       {
+         GIdlNodeField *field;
+
+         field = (GIdlNodeField *)g_idl_node_new (G_IDL_NODE_FIELD);
+         field->c_name = g_strdup (cname);
+         if (readable && strcmp (readable, "1") == 0)
+           field->readable = TRUE;
+         else
+           field->readable = FALSE;
+         
+         if (writable && strcmp (writable, "1") == 0)
+           field->writable = TRUE;
+         else
+           field->writable = FALSE;
+         
+         if (bits)
+           field->bits = atoi (bits);
+         else
+           field->bits = 0;
+         
+         field->type = parse_type (type);
+         
+         switch (ctx->current_node->type)
+           {
+           case G_IDL_NODE_INTERFACE:
+             {
+               GIdlNodeInterface *iface;
+
+               iface = (GIdlNodeInterface *)ctx->current_node;
+               iface->members = g_list_append (iface->members, field);
+             }
+             break;
+           case G_IDL_NODE_BOXED:
+             {
+               GIdlNodeBoxed *boxed;
+
+               boxed = (GIdlNodeBoxed *)ctx->current_node;
+               boxed->members = g_list_append (boxed->members, field);
+             }
+             break;
+           case G_IDL_NODE_STRUCT:
+             {
+               GIdlNodeStruct *struct_;
+
+               struct_ = (GIdlNodeStruct *)ctx->current_node;
+               struct_->members = g_list_append (struct_->members, field);
+             }
+             break;
+           }
+       }
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+start_enum (GMarkupParseContext *context,
+            const gchar         *element_name,
+            const gchar        **attribute_names,
+            const gchar        **attribute_values,
+            ParseContext       *ctx,
+            GError             **error)
+{
+  if ((strcmp (element_name, "enum") == 0 && ctx->state == STATE_NAMESPACE) ||
+      (strcmp (element_name, "flags") == 0 && ctx->state == STATE_NAMESPACE))
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *type;
+      const gchar *typeinit;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else 
+       {             
+         GIdlNodeEnum *enum_;
+         
+         if (strcmp (element_name, "enum") == 0)
+           enum_ = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_ENUM);
+         else
+           enum_ = (GIdlNodeEnum *) g_idl_node_new (G_IDL_NODE_FLAGS);
+         ((GIdlNode *)enum_)->name = g_strdup (name);
+         enum_->c_name = g_strdup (cname);
+         enum_->init_func = g_strdup (typeinit);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           enum_->deprecated = TRUE;
+         else
+           enum_->deprecated = FALSE;
+
+         ctx->current_node = (GIdlNode *) enum_;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, enum_);              
+         
+         ctx->state = STATE_ENUM;
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_property (GMarkupParseContext *context,
+               const gchar         *element_name,
+               const gchar        **attribute_names,
+               const gchar        **attribute_values,
+               ParseContext       *ctx,
+               GError             **error)
+{
+  if (strcmp (element_name, "property") == 0 &&
+      (ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_INTERFACE))
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *type;
+      const gchar *readable;
+      const gchar *writable;
+      const gchar *construct;
+      const gchar *construct_only;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      type = find_attribute ("type", attribute_names, attribute_values);
+      readable = find_attribute ("readable", attribute_names, attribute_values);
+      writable = find_attribute ("writable", attribute_names, attribute_values);
+      construct = find_attribute ("construct", attribute_names, attribute_values);
+      construct_only = find_attribute ("construct-only", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else 
+       {             
+         GIdlNodeProperty *property;
+         GIdlNodeInterface *iface;
+         
+         property = (GIdlNodeProperty *) g_idl_node_new (G_IDL_NODE_PROPERTY);
+
+         ((GIdlNode *)property)->name = g_strdup (name);
+         property->c_name = g_strdup (cname);
+         
+         if (readable && strcmp (readable, "1") == 0)
+           property->readable = TRUE;
+         else
+           property->readable = FALSE;
+         if (writable && strcmp (writable, "1") == 0)
+           property->writable = TRUE;
+         else
+           property->writable = FALSE;
+         if (construct && strcmp (construct, "1") == 0)
+           property->construct = TRUE;
+         else
+           property->construct = FALSE;
+         if (construct_only && strcmp (construct_only, "1") == 0)
+           property->construct_only = TRUE;
+         else
+           property->construct_only = FALSE;
+
+         property->type = parse_type (type);
+         
+         iface = (GIdlNodeInterface *)ctx->current_node;
+         iface->members = g_list_append (iface->members, property);
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gint
+parse_value (const gchar *str)
+{
+  gchar *shift_op;
+  /* FIXME just a quick hack */
+  shift_op = strstr (str, "<<");
+
+  if (shift_op)
+    {
+      gint base, shift;
+
+      base = strtol (str, NULL, 10);
+      shift = strtol (shift_op + 3, NULL, 10);
+      
+      return base << shift;
+    }
+  else
+    return strtol (str, NULL, 10);
+
+  return 0;
+}
+
+static gboolean
+start_member (GMarkupParseContext *context,
+             const gchar         *element_name,
+             const gchar        **attribute_names,
+             const gchar        **attribute_values,
+             ParseContext       *ctx,
+             GError             **error)
+{
+  if (strcmp (element_name, "member") == 0 &&
+      ctx->state == STATE_ENUM)
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *value;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      value = find_attribute ("value", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else 
+       {             
+         GIdlNodeEnum *enum_;
+         GIdlNodeValue *value_;
+
+         value_ = (GIdlNodeValue *) g_idl_node_new (G_IDL_NODE_VALUE);
+
+         ((GIdlNode *)value_)->name = g_strdup (name);
+         value_->c_name = g_strdup (cname);
+         
+         value_->value = parse_value (value);
+         
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           value_->deprecated = TRUE;
+         else
+           value_->deprecated = FALSE;
+
+         enum_ = (GIdlNodeEnum *)ctx->current_node;
+         enum_->values = g_list_append (enum_->values, value_);
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_constant (GMarkupParseContext *context,
+               const gchar         *element_name,
+               const gchar        **attribute_names,
+               const gchar        **attribute_values,
+               ParseContext       *ctx,
+               GError             **error)
+{
+  if (strcmp (element_name, "constant") == 0 &&
+      (ctx->state == STATE_NAMESPACE ||
+       ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_INTERFACE))
+    {
+      const gchar *name;
+      const gchar *type;
+      const gchar *value;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      type = find_attribute ("type", attribute_names, attribute_values);
+      value = find_attribute ("value", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else if (value == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "value");
+      else 
+       {             
+         GIdlNodeConstant *constant;
+
+         constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+
+         ((GIdlNode *)constant)->name = g_strdup (name);
+         constant->value = g_strdup (value);
+         
+         constant->type = parse_type (type);
+
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           constant->deprecated = TRUE;
+         else
+           constant->deprecated = FALSE;
+
+         if (ctx->state == STATE_NAMESPACE)
+           {
+             ctx->current_node = (GIdlNode *) constant;
+             ctx->current_module->entries = 
+               g_list_append (ctx->current_module->entries, constant);
+           }
+         else
+           {
+             GIdlNodeInterface *iface;
+
+             iface = (GIdlNodeInterface *)ctx->current_node;
+             iface->members = g_list_append (iface->members, constant);
+           }
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_errordomain (GMarkupParseContext *context,
+                  const gchar         *element_name,
+                  const gchar        **attribute_names,
+                  const gchar        **attribute_values,
+                  ParseContext       *ctx,
+                  GError             **error)
+{
+  if (strcmp (element_name, "errordomain") == 0 &&
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *getquark;
+      const gchar *codes;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      getquark = find_attribute ("get-quark", attribute_names, attribute_values);
+      codes = find_attribute ("codes", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (getquark == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "getquark");
+      else if (codes == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "codes");
+      else 
+       {             
+         GIdlNodeErrorDomain *domain;
+
+         domain = (GIdlNodeErrorDomain *) g_idl_node_new (G_IDL_NODE_ERROR_DOMAIN);
+
+         ((GIdlNode *)domain)->name = g_strdup (name);
+         domain->getquark = g_strdup (getquark);
+         domain->codes = g_strdup (codes);
+
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           domain->deprecated = TRUE;
+         else
+           domain->deprecated = FALSE;
+
+         ctx->current_node = (GIdlNode *) domain;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, domain);
+
+         ctx->state = STATE_ERRORDOMAIN;
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_interface (GMarkupParseContext *context,
+                const gchar         *element_name,
+                const gchar        **attribute_names,
+                const gchar        **attribute_values,
+                ParseContext       *ctx,
+                GError             **error)
+{
+  if (strcmp (element_name, "interface") == 0 &&
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *typeinit;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else
+       {
+         GIdlNodeInterface *iface;
+
+         iface = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_INTERFACE);
+         ((GIdlNode *)iface)->name = g_strdup (name);
+         iface->c_name = g_strdup (cname);
+         iface->init_func = g_strdup (typeinit);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           iface->deprecated = TRUE;
+         else
+           iface->deprecated = FALSE;
+         
+         ctx->current_node = (GIdlNode *) iface;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, iface);              
+         
+         ctx->state = STATE_INTERFACE;
+         
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_object (GMarkupParseContext *context,
+             const gchar         *element_name,
+             const gchar        **attribute_names,
+             const gchar        **attribute_values,
+             ParseContext       *ctx,
+             GError             **error)
+{
+  if (strcmp (element_name, "object") == 0 &&
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *parent;
+      const gchar *typeinit;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      parent = find_attribute ("parent", attribute_names, attribute_values);
+      typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else
+       {
+         GIdlNodeInterface *iface;
+
+         iface = (GIdlNodeInterface *) g_idl_node_new (G_IDL_NODE_OBJECT);
+         ((GIdlNode *)iface)->name = g_strdup (name);
+         iface->c_name = g_strdup (cname);
+         iface->init_func = g_strdup (typeinit);
+         iface->parent = g_strdup (parent);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           iface->deprecated = TRUE;
+         else
+           iface->deprecated = FALSE;
+         
+         ctx->current_node = (GIdlNode *) iface;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, iface);              
+         
+         ctx->state = STATE_OBJECT;
+       }
+      
+      return TRUE;
+    }
+  return  FALSE;
+}
+
+static gboolean
+start_return_type (GMarkupParseContext *context,
+                  const gchar         *element_name,
+                  const gchar        **attribute_names,
+                  const gchar        **attribute_values,
+                  ParseContext       *ctx,
+                  GError             **error)
+{
+  if (strcmp (element_name, "return-type") == 0 &&
+      ctx->state == STATE_FUNCTION)
+    {
+      const gchar *type;
+      const gchar *nullok;
+      const gchar *transfer;
+      
+      type = find_attribute ("type", attribute_names, attribute_values);
+      nullok = find_attribute ("null-ok", attribute_names, attribute_values);
+      transfer = find_attribute ("transfer", attribute_names, attribute_values);
+      if (type == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "type");
+      else
+       {
+         GIdlNodeParam *param;
+
+         param = (GIdlNodeParam *)g_idl_node_new (G_IDL_NODE_PARAM);
+         param->in = FALSE;
+         param->out = FALSE;
+         param->retval = TRUE;
+         if (nullok && strcmp (nullok, "1") == 0)
+           param->null_ok = TRUE;
+         else
+           param->null_ok = FALSE;
+         if (transfer && strcmp (transfer, "none") == 0)
+           {
+             param->transfer = FALSE;
+             param->shallow_transfer = FALSE;
+           }
+         else if (transfer && strcmp (transfer, "shallow") == 0)
+           {
+             param->transfer = FALSE;
+             param->shallow_transfer = TRUE;
+           }
+         else
+           {
+             param->transfer = TRUE;
+             param->shallow_transfer = FALSE;
+           }
+         
+         param->type = parse_type (type);
+         
+         switch (ctx->current_node->type)
+           {
+           case G_IDL_NODE_FUNCTION:
+           case G_IDL_NODE_CALLBACK:
+             {
+               GIdlNodeFunction *func = (GIdlNodeFunction *)ctx->current_node;
+               func->result = param;
+             }
+             break;
+           case G_IDL_NODE_SIGNAL:
+             {
+               GIdlNodeSignal *signal = (GIdlNodeSignal *)ctx->current_node;
+               signal->result = param;
+             }
+             break;
+           case G_IDL_NODE_VFUNC:
+             {
+               GIdlNodeVFunc *vfunc = (GIdlNodeVFunc *)ctx->current_node;
+               vfunc->result = param;
+             }
+             break;
+           }
+       }
+      
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+start_signal (GMarkupParseContext *context,
+             const gchar         *element_name,
+             const gchar        **attribute_names,
+             const gchar        **attribute_values,
+             ParseContext       *ctx,
+             GError             **error)
+{
+  if (strcmp (element_name, "signal") == 0 && 
+      (ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_INTERFACE))
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *when;
+      const gchar *no_recurse;
+      const gchar *detailed;
+      const gchar *action;
+      const gchar *no_hooks;
+      const gchar *has_class_closure;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      when = find_attribute ("when", attribute_names, attribute_values);
+      no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values);
+      detailed = find_attribute ("detailed", attribute_names, attribute_values);
+      action = find_attribute ("action", attribute_names, attribute_values);
+      no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values);
+      has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (when == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "when");
+      else
+       {
+         GIdlNodeInterface *iface;
+         GIdlNodeSignal *signal;
+
+         signal = (GIdlNodeSignal *)g_idl_node_new (G_IDL_NODE_SIGNAL);
+         
+         ((GIdlNode *)signal)->name = g_strdup (name);
+         signal->c_name = g_strdup (cname);
+         
+         signal->run_first = FALSE;
+         signal->run_last = FALSE;
+         signal->run_cleanup = FALSE;
+         if (strcmp (when, "FIRST") == 0)
+           signal->run_first = TRUE;
+         else if (strcmp (when, "LAST") == 0)
+           signal->run_last = TRUE;
+         else 
+           signal->run_cleanup = TRUE;
+         
+         if (no_recurse && strcmp (no_recurse, "1") == 0)
+           signal->no_recurse = TRUE;
+         else
+           signal->no_recurse = FALSE;
+         if (detailed && strcmp (detailed, "1") == 0)
+           signal->detailed = TRUE;
+         else
+           signal->detailed = FALSE;
+         if (action && strcmp (action, "1") == 0)
+           signal->action = TRUE;
+         else
+           signal->action = FALSE;
+         if (no_hooks && strcmp (no_hooks, "1") == 0)
+           signal->no_hooks = TRUE;
+         else
+           signal->no_hooks = FALSE;
+         if (has_class_closure && strcmp (has_class_closure, "1") == 0)
+           signal->has_class_closure = TRUE;
+         else
+           signal->has_class_closure = FALSE;
+
+         iface = (GIdlNodeInterface *)ctx->current_node;
+         iface->members = g_list_append (iface->members, signal);
+
+         ctx->current_node = (GIdlNode *)signal;
+         ctx->state = STATE_FUNCTION;
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static gboolean
+start_vfunc (GMarkupParseContext *context,
+            const gchar         *element_name,
+            const gchar        **attribute_names,
+            const gchar        **attribute_values,
+            ParseContext       *ctx,
+            GError             **error)
+{
+  if (strcmp (element_name, "vfunc") == 0 && 
+      (ctx->state == STATE_OBJECT ||
+       ctx->state == STATE_INTERFACE))
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *must_chain_up;
+      const gchar *override;
+      const gchar *is_class_closure;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);       
+      override = find_attribute ("override", attribute_names, attribute_values);
+      is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else
+       {
+         GIdlNodeInterface *iface;
+         GIdlNodeVFunc *vfunc;
+
+         vfunc = (GIdlNodeVFunc *)g_idl_node_new (G_IDL_NODE_VFUNC);
+         
+         ((GIdlNode *)vfunc)->name = g_strdup (name);
+         vfunc->c_name = g_strdup (cname);
+
+         if (must_chain_up && strcmp (must_chain_up, "1") == 0)
+           vfunc->must_chain_up = TRUE;
+         else
+           vfunc->must_chain_up = FALSE;
+
+         if (override && strcmp (override, "always") == 0)
+           {
+             vfunc->must_be_implemented = TRUE;
+             vfunc->must_not_be_implemented = FALSE;
+           }
+         else if (override && strcmp (override, "never") == 0)
+           {
+             vfunc->must_be_implemented = FALSE;
+             vfunc->must_not_be_implemented = TRUE;
+           }
+         else
+           {
+             vfunc->must_be_implemented = FALSE;
+             vfunc->must_not_be_implemented = FALSE;
+           }
+         
+         if (is_class_closure && strcmp (is_class_closure, "1") == 0)
+           vfunc->is_class_closure = TRUE;
+         else
+           vfunc->is_class_closure = FALSE;
+         
+         iface = (GIdlNodeInterface *)ctx->current_node;
+         iface->members = g_list_append (iface->members, vfunc);
+
+         ctx->current_node = (GIdlNode *)vfunc;
+         ctx->state = STATE_FUNCTION;
+       }
+      
+      return TRUE;
+    }
+  return FALSE;
+}
+
+
+static gboolean
+start_struct (GMarkupParseContext *context,
+             const gchar         *element_name,
+             const gchar        **attribute_names,
+             const gchar        **attribute_values,
+             ParseContext       *ctx,
+             GError             **error)
+{
+  if (strcmp (element_name, "struct") == 0 && 
+      ctx->state == STATE_NAMESPACE)
+    {
+      const gchar *name;
+      const gchar *cname;
+      const gchar *deprecated;
+      
+      name = find_attribute ("name", attribute_names, attribute_values);
+      cname = find_attribute ("cname", attribute_names, attribute_values);
+      deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+      
+      if (name == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "name");
+      else if (cname == NULL)
+       MISSING_ATTRIBUTE (error, element_name, "cname");
+      else
+       {
+         GIdlNodeStruct *struct_;
+
+         struct_ = (GIdlNodeStruct *) g_idl_node_new (G_IDL_NODE_STRUCT);
+         
+         ((GIdlNode *)struct_)->name = g_strdup (name);
+         struct_->c_name = g_strdup (cname);
+         if (deprecated && strcmp (deprecated, "1") == 0)
+           struct_->deprecated = TRUE;
+         else
+           struct_->deprecated = FALSE;
+
+         ctx->current_node = (GIdlNode *)struct_;
+         ctx->current_module->entries = 
+           g_list_append (ctx->current_module->entries, struct_);
+         
+         ctx->state = STATE_STRUCT;
+           }
+      return TRUE;
+    }
+  return FALSE;
+}
+  
+static void
+start_element_handler (GMarkupParseContext *context,
+                      const gchar         *element_name,
+                      const gchar        **attribute_names,
+                      const gchar        **attribute_values,
+                      gpointer             user_data,
+                      GError             **error)
+{
+  ParseContext *ctx = user_data;
+  gint i, line_number, char_number;
+
+  switch (element_name[0])
+    {
+    case 'a':
+      if (strcmp (element_name, "api") == 0 && ctx->state == STATE_START)
+       {
+         const gchar *version;
+
+         version = find_attribute ("version", attribute_names, attribute_values);
+         
+         if (version == NULL)
+           MISSING_ATTRIBUTE (error, element_name, "version");
+         else if (strcmp (version, "1.0") != 0)
+           g_set_error (error,
+                        G_MARKUP_ERROR,
+                        G_MARKUP_ERROR_INVALID_CONTENT,
+                        "Unsupported version '%s'",
+                        version);
+         else
+           ctx->state = STATE_ROOT;
+         
+         goto out;
+       }
+      break;
+
+    case 'b':
+      if (start_boxed (context, element_name,
+                      attribute_names, attribute_values,
+                      ctx, error))
+       goto out;
+      break;
+
+    case 'c':
+      if (start_function (context, element_name, 
+                         attribute_names, attribute_values,
+                         ctx, error))
+       goto out;
+      else if (start_constant (context, element_name,
+                              attribute_names, attribute_values,
+                              ctx, error))
+       goto out;
+      break;
+
+    case 'e':
+      if (start_enum (context, element_name, 
+                     attribute_names, attribute_values,
+                     ctx, error))
+       goto out;
+      else if (start_errordomain (context, element_name, 
+                     attribute_names, attribute_values,
+                     ctx, error))
+       goto out;
+      break;
+
+    case 'f':
+      if (start_function (context, element_name, 
+                         attribute_names, attribute_values,
+                         ctx, error))
+       goto out;
+      else if (start_field (context, element_name, 
+                           attribute_names, attribute_values,
+                           ctx, error))
+       goto out;
+      else if (start_enum (context, element_name, 
+                          attribute_names, attribute_values,
+                          ctx, error))
+       goto out;
+      
+      break;
+
+    case 'i':
+      if (start_interface (context, element_name, 
+                          attribute_names, attribute_values,
+                          ctx, error))
+       goto out;
+      if (strcmp (element_name, "implements") == 0 &&
+         ctx->state == STATE_OBJECT)
+       {
+         ctx->state = STATE_IMPLEMENTS;
+
+         goto out;
+       }
+      else if (strcmp (element_name, "interface") == 0 &&
+              ctx->state == STATE_IMPLEMENTS)
+       {
+         const gchar *cname;
+
+         cname = find_attribute ("name", attribute_names, attribute_values);
+
+         if (cname == NULL)
+           MISSING_ATTRIBUTE (error, element_name, "name");
+         else
+           {  
+             GIdlNodeInterface *iface;
+
+             iface = (GIdlNodeInterface *)ctx->current_node;
+             iface ->interfaces = g_list_append (iface->interfaces, g_strdup (cname));
+           }
+
+         goto out;
+       }
+      else if (strcmp (element_name, "interface") == 0 &&
+              ctx->state == STATE_REQUIRES)
+       {
+         const gchar *cname;
+
+         cname = find_attribute ("name", attribute_names, attribute_values);
+
+         if (cname == NULL)
+           MISSING_ATTRIBUTE (error, element_name, "name");
+         else
+           {  
+             GIdlNodeInterface *iface;
+
+             iface = (GIdlNodeInterface *)ctx->current_node;
+             iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (cname));
+           }
+
+         goto out;
+       }
+      break;
+
+    case 'm':
+      if (start_function (context, element_name, 
+                         attribute_names, attribute_values,
+                         ctx, error))
+       goto out;
+      else if (start_member (context, element_name, 
+                         attribute_names, attribute_values,
+                         ctx, error))
+       goto out;
+      break;
+
+    case 'n':
+      if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_ROOT)
+       {
+         const gchar *name;
+         
+         name = find_attribute ("name", attribute_names, attribute_values);
+
+         if (name == NULL)
+           MISSING_ATTRIBUTE (error, element_name, "name");
+         else
+           {
+             ctx->current_module = g_idl_module_new (name);
+             ctx->modules = g_list_append (ctx->modules, ctx->current_module);
+
+             ctx->state = STATE_NAMESPACE;
+           }
+
+         goto out;
+       }
+      break;
+
+    case 'o':
+      if (start_object (context, element_name, 
+                       attribute_names, attribute_values,
+                       ctx, error))
+       goto out;
+      else if (strcmp (element_name, "object") == 0 &&
+              ctx->state == STATE_REQUIRES)
+       {
+         const gchar *cname;
+
+         cname = find_attribute ("cname", attribute_names, attribute_values);
+
+         if (cname == NULL)
+           MISSING_ATTRIBUTE (error, element_name, "cname");
+         else
+           {  
+             GIdlNodeInterface *iface;
+
+             iface = (GIdlNodeInterface *)ctx->current_node;
+             iface ->prerequisites = g_list_append (iface->prerequisites, g_strdup (cname));
+           }
+
+         goto out;
+       }
+      break;
+
+    case 'p':
+      if (start_property (context, element_name,
+                         attribute_names, attribute_values,
+                         ctx, error))
+       goto out;
+      else if (strcmp (element_name, "parameters") == 0 &&
+         ctx->state == STATE_FUNCTION)
+       {
+         ctx->state = STATE_PARAMETERS;
+
+         goto out;
+       }
+      else if (start_parameter (context, element_name,
+                               attribute_names, attribute_values,
+                               ctx, error))
+       goto out;
+
+      break;
+
+    case 'r':
+      if (start_return_type (context, element_name,
+                            attribute_names, attribute_values,
+                            ctx, error))
+       goto out;      
+      else if (strcmp (element_name, "requires") == 0 &&
+              ctx->state == STATE_INTERFACE)
+       {
+         ctx->state = STATE_REQUIRES;
+         
+         goto out;
+       }
+
+      break;
+
+    case 's':
+      if (start_signal (context, element_name,
+                       attribute_names, attribute_values,
+                       ctx, error))
+       goto out;      
+      else if (start_struct (context, element_name,
+                            attribute_names, attribute_values,
+                            ctx, error))
+       goto out;      
+
+      break;
+
+    case 'v':
+      if (start_vfunc (context, element_name,
+                      attribute_names, attribute_values,
+                      ctx, error))
+       goto out;      
+      break;
+    }
+
+  g_markup_parse_context_get_position (context, &line_number, &char_number);
+
+  g_set_error (error,
+              G_MARKUP_ERROR,
+              G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+              "Unexpected start tag '%s' on line %d char %d",
+              element_name,
+              line_number, char_number);
+  
+ out: ;
+      
+}
+
+static void
+end_element_handler (GMarkupParseContext *context,
+                    const gchar         *element_name,
+                    gpointer             user_data,
+                    GError             **error)
+{
+  ParseContext *ctx = user_data;
+
+  switch (ctx->state)
+    {
+    case STATE_START:
+    case STATE_END:
+      /* no need to GError here, GMarkup already catches this */
+      break;
+
+    case STATE_ROOT:
+      ctx->state = STATE_END;
+      break;
+
+    case STATE_NAMESPACE:
+      ctx->current_module = NULL;
+      ctx->state = STATE_ROOT;
+      break;
+
+    case STATE_FUNCTION:
+      if (strcmp (element_name, "return-type") == 0)
+       /* do nothing */ ;
+       
+      else if (ctx->current_node == g_list_last (ctx->current_module->entries)->data)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      else 
+       { 
+         ctx->current_node = g_list_last (ctx->current_module->entries)->data;
+         if (ctx->current_node->type == G_IDL_NODE_INTERFACE)
+           ctx->state = STATE_INTERFACE;
+         else if (ctx->current_node->type == G_IDL_NODE_OBJECT)
+           ctx->state = STATE_OBJECT;
+         else if (ctx->current_node->type == G_IDL_NODE_BOXED)
+           ctx->state = STATE_BOXED;
+         else if (ctx->current_node->type == G_IDL_NODE_STRUCT)
+           ctx->state = STATE_STRUCT;
+       }
+      break;
+
+    case STATE_OBJECT:
+      if (strcmp (element_name, "object") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
+    case STATE_ERRORDOMAIN:
+      if (strcmp (element_name, "errordomain") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
+    case STATE_INTERFACE:
+      if (strcmp (element_name, "interface") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
+    case STATE_ENUM:
+      if (strcmp (element_name, "enum") == 0 ||
+         strcmp (element_name, "flags") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
+    case STATE_BOXED:
+      if (strcmp (element_name, "boxed") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+
+    case STATE_STRUCT:
+      if (strcmp (element_name, "struct") == 0)
+       {
+         ctx->current_node = NULL;
+         ctx->state = STATE_NAMESPACE;
+       }
+      break;
+    case STATE_IMPLEMENTS:
+      ctx->state = STATE_OBJECT;
+      break;
+    case STATE_REQUIRES:
+      ctx->state = STATE_INTERFACE;
+      break;
+    case STATE_PARAMETERS:
+      if (strcmp (element_name, "parameters") == 0)
+       ctx->state = STATE_FUNCTION;
+      break;
+    default:
+      g_error ("Unhandled state %d in end_element_handler\n", ctx->state);
+    }
+}
+
+static void 
+text_handler (GMarkupParseContext *context,
+             const gchar         *text,
+             gsize                text_len,  
+             gpointer             user_data,
+             GError             **error)
+{
+  /* FIXME warn about non-whitespace text */
+}
+
+static void
+cleanup (GMarkupParseContext *context,
+        GError              *error,
+        gpointer             user_data)
+{
+  ParseContext *ctx = user_data;
+  GList *m;
+
+  for (m = ctx->modules; m; m = m->next)
+    g_idl_module_free (m->data);
+  g_list_free (ctx->modules);
+  ctx->modules = NULL;
+  
+  ctx->current_module = NULL;
+}
+
+static GMarkupParser parser = 
+{
+  start_element_handler,
+  end_element_handler,
+  text_handler,
+  NULL,
+  cleanup
+};
+
+GList * 
+g_idl_parse_string (const gchar  *buffer, 
+                   gssize        length,
+                    GError      **error)
+{
+  ParseContext ctx = { 0 };
+  GMarkupParseContext *context;
+
+  ctx.state = STATE_START;
+  
+  context = g_markup_parse_context_new (&parser, 0, &ctx, NULL);
+  if (!g_markup_parse_context_parse (context, buffer, length, error))
+    goto out;
+
+  if (!g_markup_parse_context_end_parse (context, error))
+    goto out;
+
+ out:
+  
+  g_markup_parse_context_free (context);
+  
+  return ctx.modules;
+}
+
+GList *
+g_idl_parse_file (const gchar  *filename,
+                 GError      **error)
+{
+  gchar *buffer;
+  gssize length;
+  GList *modules;
+
+  if (!g_file_get_contents (filename, &buffer, &length, error))
+    return NULL;
+  
+  modules = g_idl_parse_string (buffer, length, error);
+
+  g_free (buffer);
+
+  return modules;
+}
+
+
diff --git a/src/gidlparser.h b/src/gidlparser.h
new file mode 100644 (file)
index 0000000..2d71aaa
--- /dev/null
@@ -0,0 +1,38 @@
+/* GObject introspection: A parser for the XML IDL format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_IDL_PARSER_H__
+#define __G_IDL_PARSER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+GList *g_idl_parse_string (const gchar  *buffer, 
+                          gssize        length,
+                          GError      **error);
+GList *g_idl_parse_file   (const gchar  *filename,
+                          GError      **error);
+
+
+G_END_DECLS
+
+#endif  /* __G_IDL_PARSER_H__ */
diff --git a/src/ginfo.c b/src/ginfo.c
new file mode 100644 (file)
index 0000000..5c9f6a1
--- /dev/null
@@ -0,0 +1,1639 @@
+/* GObject introspection: Repository implementation
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "girepository.h"
+#include "gmetadata.h"
+
+struct _GIBaseInfo 
+{
+  gint type;
+  gint ref_count;
+  GIBaseInfo *container;
+
+  const guchar *metadata;
+  guint32 offset;
+};
+
+struct _GIUnresolvedInfo
+{
+  gint type;
+  gint ref_count;
+  GIBaseInfo *container;
+
+  const gchar *name;
+  const gchar *namespace;
+};
+
+struct _GICallableInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIFunctionInfo
+{
+  GICallableInfo callable;
+};
+
+struct _GICallbackInfo
+{
+  GICallableInfo callable;
+};
+
+struct _GIRegisteredTypeInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIStructInfo
+{
+  GIRegisteredTypeInfo registered;
+};
+
+struct _GIEnumInfo
+{
+  GIRegisteredTypeInfo registered;
+};
+
+struct _GIObjectInfo
+{
+  GIRegisteredTypeInfo registered;
+};
+
+struct _GIInterfaceInfo
+{
+  GIRegisteredTypeInfo registered;
+};
+
+struct _GIConstantInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIValueInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GISignalInfo
+{
+  GICallableInfo callable;
+};
+
+struct _GIVFuncInfo
+{
+  GICallableInfo callable;
+};
+
+struct _GIPropertyInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIFieldInfo
+{
+  GIBaseInfo base;
+};
+
+struct _GIArgInfo
+{
+  GIBaseInfo base;
+};
+
+
+struct _GITypeInfo
+{
+  GIBaseInfo base;
+};
+
+
+/* info creation */
+GIBaseInfo *
+g_info_new (GIInfoType     type,
+           GIBaseInfo    *container,
+           const guchar *metadata, 
+           guint32       offset)
+{
+  GIBaseInfo *info;
+
+  info = g_new0 (GIBaseInfo, 1);
+
+  info->ref_count = 1;
+  info->type = type;
+
+  info->metadata = metadata;
+  info->offset = offset;
+
+  if (container)
+    info->container = g_base_info_ref (container);
+
+  return info;
+}
+
+static GIBaseInfo *
+g_info_from_entry (const guchar *metadata,
+                  guint16       index)
+{
+  GIBaseInfo *result;
+  DirEntry *entry = g_metadata_get_dir_entry (metadata, index);
+  
+  if (entry->local)
+    result = g_info_new (entry->blob_type, NULL, metadata, entry->offset);
+  else 
+    {
+      const gchar *namespace = g_metadata_get_string (metadata, entry->offset);
+      const gchar *name = g_metadata_get_string (metadata, entry->name);
+      
+      GIRepository *repository = g_irepository_get_default ();
+      
+      result = g_irepository_find_by_name (repository, namespace, name);
+      if (result == NULL)
+       {
+         GIUnresolvedInfo *unresolved;
+
+         unresolved = g_new0 (GIUnresolvedInfo, 1);
+         
+         unresolved->type = GI_INFO_TYPE_UNRESOLVED;
+         unresolved->ref_count = 1;
+         unresolved->container = NULL;
+         unresolved->name = name;
+         unresolved->namespace = namespace;
+
+         result = (GIBaseInfo*)unresolved;
+       }
+    }
+
+  return result;
+}
+
+/* GIBaseInfo functions */
+GIBaseInfo *
+g_base_info_ref (GIBaseInfo *info)
+{
+  info->ref_count++;
+
+  return info;
+}
+
+void
+g_base_info_unref (GIBaseInfo *info)
+{
+  info->ref_count--;
+
+  if (!info->ref_count)
+    {
+      if (info->container)
+       g_base_info_unref (info->container);
+
+      g_free (info);
+    }
+}
+
+GIInfoType
+g_base_info_get_type (GIBaseInfo *info)
+{
+  
+  return info->type;
+}
+
+const gchar *
+g_base_info_get_name (GIBaseInfo *info)
+{
+  switch (info->type)
+    {
+    case GI_INFO_TYPE_FUNCTION:
+    case GI_INFO_TYPE_CALLBACK:
+    case GI_INFO_TYPE_STRUCT:
+    case GI_INFO_TYPE_BOXED:
+    case GI_INFO_TYPE_ENUM:
+    case GI_INFO_TYPE_FLAGS:
+    case GI_INFO_TYPE_OBJECT:
+    case GI_INFO_TYPE_INTERFACE:
+    case GI_INFO_TYPE_CONSTANT:
+    case GI_INFO_TYPE_ERROR_DOMAIN:
+      {
+       CommonBlob *blob = (CommonBlob *)&info->metadata[info->offset];
+
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_VALUE:
+      {
+       ValueBlob *blob = (ValueBlob *)&info->metadata[info->offset];
+
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_SIGNAL:
+      {
+       SignalBlob *blob = (SignalBlob *)&info->metadata[info->offset];
+
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_PROPERTY:
+      {
+       PropertyBlob *blob = (PropertyBlob *)&info->metadata[info->offset];
+
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_VFUNC:
+      {
+       VFuncBlob *blob = (VFuncBlob *)&info->metadata[info->offset];
+
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_FIELD:
+      {
+       FieldBlob *blob = (FieldBlob *)&info->metadata[info->offset];
+       
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_ARG:
+      {
+       ArgBlob *blob = (ArgBlob *)&info->metadata[info->offset];
+       
+       return g_metadata_get_string (info->metadata, blob->name);
+      }
+      break;
+
+    case GI_INFO_TYPE_UNRESOLVED:
+      {
+       GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
+
+       return unresolved->name;
+      }
+      break;
+
+    case GI_INFO_TYPE_TYPE:
+    default: ;
+      /* unnamed */
+    }
+
+  return NULL;
+}
+
+const gchar *
+g_base_info_get_namespace (GIBaseInfo *info)
+{
+  Header *header = (Header *)info->metadata;  
+
+  if (info->type == GI_INFO_TYPE_UNRESOLVED)
+    {
+      GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
+      
+      return unresolved->namespace;
+    }
+
+  return g_metadata_get_string (info->metadata, header->namespace);
+}
+
+gboolean 
+g_base_info_is_deprecated (GIBaseInfo *info)
+{
+  switch (info->type)
+    {
+    case GI_INFO_TYPE_FUNCTION:
+    case GI_INFO_TYPE_CALLBACK:
+    case GI_INFO_TYPE_STRUCT:
+    case GI_INFO_TYPE_BOXED:
+    case GI_INFO_TYPE_ENUM:
+    case GI_INFO_TYPE_FLAGS:
+    case GI_INFO_TYPE_OBJECT:
+    case GI_INFO_TYPE_INTERFACE:
+    case GI_INFO_TYPE_CONSTANT:
+    case GI_INFO_TYPE_ERROR_DOMAIN:
+      {
+       CommonBlob *blob = (CommonBlob *)&info->metadata[info->offset];
+
+       return blob->deprecated;
+      }
+      break;
+
+    case GI_INFO_TYPE_VALUE:
+      {
+       ValueBlob *blob = (ValueBlob *)&info->metadata[info->offset];
+
+       return blob->deprecated;
+      }
+      break;
+
+    case GI_INFO_TYPE_SIGNAL:
+      {
+       SignalBlob *blob = (SignalBlob *)&info->metadata[info->offset];
+
+       return blob->deprecated;
+      }
+      break;
+
+    case GI_INFO_TYPE_PROPERTY:
+      {
+       PropertyBlob *blob = (PropertyBlob *)&info->metadata[info->offset];
+
+       return blob->deprecated;
+      }
+      break;
+
+    case GI_INFO_TYPE_VFUNC:
+    case GI_INFO_TYPE_FIELD:
+    case GI_INFO_TYPE_ARG:
+    case GI_INFO_TYPE_TYPE:
+    default: ;
+      /* no deprecation flag for these */
+    }
+  
+  return FALSE;
+}
+
+static int
+cmp_annotation (const void *av,
+               const void *bv)
+{
+  const AnnotationBlob *a = av;
+  const AnnotationBlob *b = bv;
+  if (b->offset < a->offset)
+    return -1;
+
+  if (b->offset > a->offset)
+    return 1;
+  
+  return 0;
+}
+
+const gchar *
+g_base_info_get_annotation (GIBaseInfo   *info,
+                           const gchar *name)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;
+  AnnotationBlob blob, *first, *after, *res, *next;
+  const gchar *rname;
+
+  blob.offset = base->offset;
+  
+  first = (AnnotationBlob *) &base->metadata[header->annotations];
+  after = (AnnotationBlob *) &base->metadata[header->annotations + 
+                                            header->n_annotations * header->annotation_blob_size];
+
+  res = bsearch (&blob, first, header->n_annotations,
+                header->annotation_blob_size, cmp_annotation);
+  
+  if (res == NULL)
+    return NULL;
+
+  next = res;
+  do 
+    {
+      res = next;
+      next = res -= header->annotation_blob_size;
+    }
+  while (next >= first && next->offset == base->offset);
+    
+  next = res;
+  do 
+    {
+      res = next;
+      
+      rname = g_metadata_get_string (base->metadata, res->name);
+      if (strcmp (name, rname) == 0)
+       return g_metadata_get_string (base->metadata, res->value);
+
+      next = res += header->annotation_blob_size;
+    }
+  while (next < after && next->offset == base->offset);
+
+  return NULL;
+}
+
+GIBaseInfo *
+g_base_info_get_container (GIBaseInfo *info)
+{
+  info->container;
+}
+
+
+/* GIFunctionInfo functions */
+const gchar *
+g_function_info_get_symbol (GIFunctionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FunctionBlob *blob = (FunctionBlob *)&base->metadata[base->offset];
+
+  return g_metadata_get_string (base->metadata, blob->c_name);
+}
+
+GIFunctionInfoFlags
+g_function_info_get_flags (GIFunctionInfo *info)
+{
+  GIFunctionInfoFlags flags;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FunctionBlob *blob = (FunctionBlob *)&base->metadata[base->offset];
+  
+  flags = 0;
+
+  if (base->container != NULL)
+    flags = flags | GI_FUNCTION_IS_METHOD;
+    
+  if (blob->constructor)
+    flags = flags | GI_FUNCTION_IS_CONSTRUCTOR;
+
+  if (blob->getter)
+    flags = flags | GI_FUNCTION_IS_GETTER;
+
+  if (blob->setter)
+    flags = flags | GI_FUNCTION_IS_SETTER;
+
+  if (blob->wraps_vfunc)
+    flags = flags | GI_FUNCTION_WRAPS_VFUNC;
+
+  return flags;
+}
+
+GIPropertyInfo *
+g_function_info_get_property (GIFunctionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FunctionBlob *blob = (FunctionBlob *)&base->metadata[base->offset];
+  GIInterfaceInfo *container = (GIInterfaceInfo *)base->container;
+  
+  return g_interface_info_get_property (container, blob->index);  
+}
+
+GIVFuncInfo *
+g_function_info_get_vfunc (GIFunctionInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FunctionBlob *blob = (FunctionBlob *)&base->metadata[base->offset];
+  GIInterfaceInfo *container = (GIInterfaceInfo *)base->container;
+  
+  return g_interface_info_get_vfunc (container, blob->index);  
+}
+
+
+/* GICallableInfo functions */
+static guint32
+signature_offset (GICallableInfo *info)
+{
+  switch (info->base.type)
+    {
+    case GI_INFO_TYPE_FUNCTION:
+    case GI_INFO_TYPE_VFUNC:
+      return *(guint32 *)&info->base.metadata[info->base.offset + 12];
+    case GI_INFO_TYPE_CALLBACK:
+    case GI_INFO_TYPE_SIGNAL:
+      return *(guint32 *)&info->base.metadata[info->base.offset + 8];
+    }
+  
+  return 0;
+}
+
+GITypeInfo *
+g_type_info_new (GIBaseInfo    *container,
+                const guchar *metadata,
+                guint32       offset)
+{
+  Header *header = (Header *)metadata;  
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&metadata[offset];
+
+  return (GITypeInfo *) g_info_new (GI_INFO_TYPE_TYPE, container, metadata, 
+                                   type->reserved == 0 ? offset : type->offset);
+}
+
+GITypeInfo *
+g_callable_info_get_return_type (GICallableInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  guint32 offset;
+
+  offset = signature_offset (info);
+
+  return g_type_info_new (base, base->metadata, offset);
+}
+
+Transfer 
+g_callable_info_get_caller_owns (GICallableInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SignatureBlob *blob = (SignatureBlob *)&base->metadata[signature_offset (info)];
+
+  if (blob->caller_owns_return_value)
+    return GI_TRANSFER_EVERYTHING;
+  else if (blob->caller_owns_return_container)
+    return GI_TRANSFER_CONTAINER;
+  else
+    return GI_TRANSFER_NOTHING;
+}
+
+gint 
+g_callable_info_get_n_args (GICallableInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  gint offset;
+  SignatureBlob *blob;
+
+  offset = signature_offset (info);
+  blob = (SignatureBlob *)&base->metadata[offset];
+
+  return blob->n_arguments;
+}
+
+GIArgInfo *
+g_callable_info_get_arg (GICallableInfo *info,
+                        gint           n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;
+  gint offset;
+
+  offset = signature_offset (info);
+  
+  return (GIArgInfo *) g_info_new (GI_INFO_TYPE_ARG, base, base->metadata, 
+                                  offset + header->signature_blob_size + n * header->arg_blob_size);
+}
+
+/* GIArgInfo function */
+Direction
+g_arg_info_get_direction (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+  
+  if (blob->in && blob->out)
+    return GI_DIRECTION_INOUT;
+  else if (blob->out)
+    return GI_DIRECTION_OUT;
+  else
+    return GI_DIRECTION_IN;
+}
+
+gboolean
+g_arg_info_is_return_value (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+  
+  return blob->return_value;
+}
+
+gboolean
+g_arg_info_is_dipper (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+  
+  return blob->dipper;
+}
+
+gboolean
+g_arg_info_is_optional (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+  
+  return blob->optional;
+}
+
+gboolean
+g_arg_info_may_be_null (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+  
+  return blob->null_ok;
+}
+
+Transfer
+g_arg_info_get_ownership_transfer (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ArgBlob *blob = (ArgBlob *)&base->metadata[base->offset];
+
+  if (blob->transfer_ownership)
+    return GI_TRANSFER_EVERYTHING;
+  else if (blob->transfer_container_ownership)
+    return GI_TRANSFER_CONTAINER;
+  else
+    return GI_TRANSFER_NOTHING;
+}
+
+GITypeInfo *
+g_arg_info_get_type (GIArgInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  return g_type_info_new (base, base->metadata, base->offset + 8);
+}
+
+/* GITypeInfo functions */
+gboolean
+g_type_info_is_pointer (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved == 0)
+    return type->pointer;
+  else
+    {
+      InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&base->metadata[base->offset];
+      
+      return iface->pointer;
+    }
+}
+
+GITypeTag
+g_type_info_get_tag (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+
+  if (type->reserved == 0)
+    return type->tag;
+  else
+    {
+      InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&base->metadata[base->offset];
+
+      return iface->tag;
+    }
+}
+
+GITypeInfo *
+g_type_info_get_param_type (GITypeInfo *info,
+                           gint       n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      ParamTypeBlob *param = (ParamTypeBlob *)&base->metadata[base->offset];
+
+      switch (param->tag)
+       {
+       case GI_TYPE_TAG_ARRAY: 
+       case GI_TYPE_TAG_GLIST:
+       case GI_TYPE_TAG_GSLIST:
+       case GI_TYPE_TAG_GHASH:
+         return g_type_info_new (base, base->metadata, base->offset + 4 + 4 * n);
+         break;
+         
+       default: ;
+       }
+    }
+      
+  return NULL;
+}
+
+GIBaseInfo *
+g_type_info_get_interface (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      InterfaceTypeBlob *blob = (InterfaceTypeBlob *)&base->metadata[base->offset];
+      
+      if (blob->tag == GI_TYPE_TAG_INTERFACE)
+       return g_info_from_entry (base->metadata, blob->interface);
+    }
+
+  return NULL;
+}
+
+gint
+g_type_info_get_array_length (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      ArrayTypeBlob *blob = (ArrayTypeBlob *)&base->metadata[base->offset];
+
+      if (blob->tag == GI_TYPE_TAG_ARRAY)
+       {
+         if (blob->has_length)
+           return blob->length;
+       }
+    }
+
+  return -1;
+}
+
+gboolean
+g_type_info_is_zero_terminated (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      ArrayTypeBlob *blob = (ArrayTypeBlob *)&base->metadata[base->offset];
+
+      if (blob->tag == GI_TYPE_TAG_ARRAY)
+       return blob->zero_terminated;
+    }
+
+  return FALSE;
+}
+
+gint
+g_type_info_get_n_error_domains (GITypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      ErrorTypeBlob *blob = (ErrorTypeBlob *)&base->metadata[base->offset];
+
+      if (blob->tag == GI_TYPE_TAG_ERROR)
+       return blob->n_domains;
+    }
+
+  return 0;
+}
+
+GIErrorDomainInfo *
+g_type_info_get_error_domain (GITypeInfo *info,
+                             gint       n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&base->metadata[base->offset];
+  
+  if (type->reserved != 0)
+    {
+      ErrorTypeBlob *blob = (ErrorTypeBlob *)&base->metadata[base->offset];
+
+      if (blob->tag == GI_TYPE_TAG_ERROR)
+       return (GIErrorDomainInfo *) g_info_from_entry (base->metadata, 
+                                                       blob->domains[n]);
+    }
+
+  return NULL;
+}
+
+
+/* GIErrorDomainInfo functions */
+const gchar *
+g_error_domain_info_get_quark (GIErrorDomainInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ErrorDomainBlob *blob = (ErrorDomainBlob *)&base->metadata[base->offset];
+
+  return g_metadata_get_string (base->metadata, blob->get_quark);
+}
+
+GIInterfaceInfo *
+g_error_domain_info_get_codes (GIErrorDomainInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ErrorDomainBlob *blob = (ErrorDomainBlob *)&base->metadata[base->offset];
+  
+  return (GIInterfaceInfo *) g_info_from_entry (base->metadata, blob->error_codes);
+}
+
+
+
+
+/* GIValueInfo functions */ 
+const gchar *
+g_value_info_get_short_name (GIValueInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ValueBlob *blob = (ValueBlob *)&base->metadata[base->offset];
+
+  return g_metadata_get_string (base->metadata, blob->short_name);
+}
+
+glong
+g_value_info_get_value (GIValueInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ValueBlob *blob = (ValueBlob *)&base->metadata[base->offset];
+
+  return (glong)blob->value;
+}
+
+/* GIFieldInfo functions */
+GIFieldInfoFlags
+g_field_info_get_flags (GIFieldInfo *info)
+{
+  GIFieldInfoFlags flags;
+
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FieldBlob *blob = (FieldBlob *)&base->metadata[base->offset];
+
+  flags = 0;
+
+  if (blob->readable)
+    flags = flags | GI_FIELD_IS_READABLE;
+
+  if (blob->writable)
+    flags = flags | GI_FIELD_IS_WRITABLE;
+
+  return flags;
+}
+
+gint
+g_field_info_get_size (GIFieldInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FieldBlob *blob = (FieldBlob *)&base->metadata[base->offset];
+  
+  return blob->bits;
+}
+
+gint
+g_field_info_get_offset (GIFieldInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  FieldBlob *blob = (FieldBlob *)&base->metadata[base->offset];
+  
+  return blob->struct_offset;
+}
+
+GITypeInfo *
+g_field_info_get_type (GIFieldInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  
+  return g_type_info_new (base, base->metadata, base->offset + 8);
+}
+
+/* GIRegisteredTypeInfo functions */
+const gchar *
+g_registered_type_info_get_type_name (GIRegisteredTypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  RegisteredTypeBlob *blob = (RegisteredTypeBlob *)&base->metadata[base->offset];
+
+  if (blob->gtype_name)
+    return g_metadata_get_string (base->metadata, blob->gtype_name);
+
+  return NULL;
+}
+
+const gchar *
+g_registered_type_info_get_type_init (GIRegisteredTypeInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  RegisteredTypeBlob *blob = (RegisteredTypeBlob *)&base->metadata[base->offset];
+
+  if (blob->gtype_init)
+    return g_metadata_get_string (base->metadata, blob->gtype_init);
+
+  return NULL;
+}
+
+
+/* GIStructInfo functions */
+gint
+g_struct_info_get_n_fields (GIStructInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  StructBlob *blob = (StructBlob *)&base->metadata[base->offset];
+  
+  return blob->n_fields;
+}
+
+GIFieldInfo *
+g_struct_info_get_field (GIStructInfo *info,
+                        gint         n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, 
+                                    base->offset + header->struct_blob_size + 
+                                    n * header->field_blob_size);
+}
+
+gint
+g_struct_info_get_n_methods (GIStructInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  StructBlob *blob = (StructBlob *)&base->metadata[base->offset];
+  
+  return blob->n_methods;
+}
+
+GIFunctionInfo *
+g_struct_info_get_method (GIStructInfo *info,
+                         gint         n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  StructBlob *blob = (StructBlob *)&base->metadata[base->offset];
+  Header *header = (Header *)base->metadata;  
+  gint offset;
+
+  offset = base->offset + header->struct_blob_size 
+    + blob->n_fields * header->field_blob_size 
+    + n * header->function_blob_size;
+  return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, 
+                                       base->metadata, offset);
+}
+
+static GIFunctionInfo *
+find_method (GIBaseInfo   *base,
+            guint32       offset,
+            gint          n_methods,
+            const gchar  *name)
+{
+  /* FIXME hash */
+  Header *header = (Header *)base->metadata;  
+  gint i;
+
+  for (i = 0; i < n_methods; i++)
+    {
+      FunctionBlob *fblob = (FunctionBlob *)&base->metadata[offset];
+      const gchar *fname = (const gchar *)&base->metadata[fblob->name];
+
+      if (strcmp (name, fname) == 0)
+       return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, 
+                                             base->metadata, offset);  
+      
+      offset += header->function_blob_size;
+    }
+      
+  return NULL;
+}
+
+GIFunctionInfo *
+g_struct_info_find_method (GIStructInfo *info,
+                          const gchar  *name)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  StructBlob *blob = (StructBlob *)&base->metadata[base->offset];
+
+  offset = base->offset + header->struct_blob_size
+    + blob->n_fields * header->field_blob_size;
+
+  return find_method (base, offset, blob->n_methods, name);
+}
+
+gint
+g_enum_info_get_n_values (GIEnumInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  EnumBlob *blob = (EnumBlob *)&base->metadata[base->offset];
+
+  return blob->n_values;
+}
+
+GIValueInfo *
+g_enum_info_get_value (GIEnumInfo *info,
+                      gint            n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  EnumBlob *blob = (EnumBlob *)&base->metadata[base->offset];
+  gint offset;
+
+  offset = base->offset + header->enum_blob_size 
+    + n * header->value_blob_size;
+  return (GIValueInfo *) g_info_new (GI_INFO_TYPE_VALUE, base, base->metadata, offset);
+}
+
+/* GIObjectInfo functions */
+GIObjectInfo *
+g_object_info_get_parent (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return (GIObjectInfo *) g_info_from_entry (base->metadata, blob->parent);
+}
+
+gint
+g_object_info_get_n_interfaces (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return blob->n_interfaces;
+}
+
+GIInterfaceInfo *
+g_object_info_get_interface (GIObjectInfo *info,
+                            gint          n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return (GIInterfaceInfo *) g_info_from_entry (base->metadata, blob->interfaces[n]);
+}
+
+gint
+g_object_info_get_n_fields (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return blob->n_fields;
+}
+
+GIFieldInfo *
+g_object_info_get_field (GIObjectInfo *info,
+                        gint          n)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + n * header->field_blob_size;
+  
+  return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata, offset);
+}
+
+gint
+g_object_info_get_n_properties (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return blob->n_properties;  
+}
+
+GIPropertyInfo *
+g_object_info_get_property (GIObjectInfo *info,
+                           gint          n)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + n * header->property_blob_size;
+
+  return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, base, 
+                                       base->metadata, offset);
+}
+
+gint
+g_object_info_get_n_methods (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return blob->n_methods;
+}
+
+GIFunctionInfo *
+g_object_info_get_method (GIObjectInfo *info,
+                         gint          n)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_properties * header->property_blob_size
+    + n * header->function_blob_size;
+
+    return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, 
+                                         base->metadata, offset);  
+}
+
+GIFunctionInfo *
+g_object_info_find_method (GIObjectInfo *info,
+                          const gchar  *name)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size +
+    + blob->n_properties * header->property_blob_size;
+
+  return find_method (base, offset, blob->n_methods, name);
+}
+
+gint
+g_object_info_get_n_signals (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+
+  return blob->n_signals;
+}
+
+GISignalInfo *
+g_object_info_get_signal (GIObjectInfo *info,
+                         gint          n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size 
+    + n * header->signal_blob_size;
+
+  return (GISignalInfo *) g_info_new (GI_INFO_TYPE_SIGNAL, base, 
+                                     base->metadata, offset);  
+}
+
+gint
+g_object_info_get_n_vfuncs (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  return blob->n_vfuncs;
+}
+
+GIVFuncInfo *
+g_object_info_get_vfunc (GIObjectInfo *info,
+                        gint          n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size 
+    + blob->n_signals * header->signal_blob_size 
+    + n * header->vfunc_blob_size;
+
+  return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base, 
+                                    base->metadata, offset);  
+}
+
+gint
+g_object_info_get_n_constants (GIObjectInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  return blob->n_constants;
+}
+
+GIConstantInfo *
+g_object_info_get_constant (GIObjectInfo *info,
+                           gint          n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  ObjectBlob *blob = (ObjectBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size 
+    + blob->n_signals * header->signal_blob_size 
+    + blob->n_vfuncs * header->vfunc_blob_size 
+    + n * header->constant_blob_size;
+
+  return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, 
+                                       base->metadata, offset);  
+}
+
+
+/* GIInterfaceInfo functions */
+gint
+g_interface_info_get_n_prerequisites (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return blob->n_prerequisites;
+}
+
+GIBaseInfo *
+g_interface_info_get_prerequisite (GIInterfaceInfo *info,
+                                  gint            n)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return g_info_from_entry (base->metadata, blob->prerequisites[n]);
+}
+
+
+gint
+g_interface_info_get_n_properties (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return blob->n_properties;  
+}
+
+GIPropertyInfo *
+g_interface_info_get_property (GIInterfaceInfo *info,
+                              gint            n)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->interface_blob_size
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + n * header->property_blob_size;
+
+  return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, base, 
+                                       base->metadata, offset);
+}
+
+gint
+g_interface_info_get_n_methods (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return blob->n_methods;
+}
+
+GIFunctionInfo *
+g_interface_info_get_method (GIInterfaceInfo *info,
+                            gint            n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->interface_blob_size
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + blob->n_properties * header->property_blob_size 
+    + n * header->function_blob_size;
+  
+  return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base, 
+                                       base->metadata, offset);  
+}
+
+GIFunctionInfo *
+g_interface_info_find_method (GIInterfaceInfo *info,
+                             const gchar     *name)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  offset = base->offset + header->object_blob_size
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + blob->n_properties * header->property_blob_size;
+
+  return find_method (base, offset, blob->n_methods, name);
+}
+
+gint
+g_interface_info_get_n_signals (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return blob->n_signals;
+}
+
+GISignalInfo *
+g_interface_info_get_signal (GIInterfaceInfo *info,
+                            gint            n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->interface_blob_size 
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + blob->n_properties * header->property_blob_size 
+    + blob->n_methods * header->function_blob_size 
+    + n * header->signal_blob_size;
+  
+  return (GISignalInfo *) g_info_new (GI_INFO_TYPE_SIGNAL, base, 
+                                     base->metadata, offset);  
+}
+
+gint
+g_interface_info_get_n_vfuncs (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+
+  return blob->n_vfuncs;
+}
+
+GIVFuncInfo *
+g_interface_info_get_vfunc (GIInterfaceInfo *info,
+                           gint            n)
+{
+  gint i, offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->interface_blob_size 
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + blob->n_properties * header->property_blob_size 
+    + blob->n_methods * header->function_blob_size 
+    + blob->n_signals * header->signal_blob_size
+    + n * header->vfunc_blob_size;
+  
+  return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base, 
+                                    base->metadata, offset);  
+}
+
+gint
+g_interface_info_get_n_constants (GIInterfaceInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  return blob->n_constants;
+}
+
+GIConstantInfo *
+g_interface_info_get_constant (GIInterfaceInfo *info,
+                              gint             n)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->metadata;  
+  InterfaceBlob *blob = (InterfaceBlob *)&base->metadata[base->offset];
+  
+  offset = base->offset + header->interface_blob_size
+    + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size 
+    + blob->n_signals * header->signal_blob_size 
+    + blob->n_vfuncs * header->vfunc_blob_size 
+    + n * header->constant_blob_size;
+
+  return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base, 
+                                       base->metadata, offset);  
+}
+
+
+
+
+/* GIPropertyInfo functions */
+GParamFlags
+g_property_info_get_flags (GIPropertyInfo *info)
+{
+  GParamFlags flags;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  PropertyBlob *blob = (PropertyBlob *)&base->metadata[base->offset];
+  
+  flags = 0;
+
+  if (blob->readable)
+    flags = flags | G_PARAM_READABLE;
+
+  if (blob->writable)
+    flags = flags | G_PARAM_WRITABLE;
+
+  if (blob->construct)
+    flags = flags | G_PARAM_CONSTRUCT;
+
+  if (blob->construct_only)
+    flags = flags | G_PARAM_CONSTRUCT_ONLY;
+
+  return flags;
+}
+
+GITypeInfo *
+g_property_info_get_type (GIPropertyInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+
+  return g_type_info_new (base, base->metadata, base->offset + 8);  
+}
+
+
+/* GISignalInfo functions */
+GSignalFlags
+g_signal_info_get_flags (GISignalInfo *info)
+{
+  GSignalFlags flags;
+
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SignalBlob *blob = (SignalBlob *)&base->metadata[base->offset];
+
+  flags = 0;
+
+  if (blob->run_first)
+    flags = flags | G_SIGNAL_RUN_FIRST;
+
+  if (blob->run_last)
+    flags = flags | G_SIGNAL_RUN_LAST;
+
+  if (blob->run_cleanup)
+    flags = flags | G_SIGNAL_RUN_CLEANUP;
+
+  if (blob->no_recurse)
+    flags = flags | G_SIGNAL_NO_RECURSE;
+
+  if (blob->detailed)
+    flags = flags | G_SIGNAL_DETAILED;
+
+  if (blob->action)
+    flags = flags | G_SIGNAL_ACTION;
+
+  if (blob->no_hooks)
+    flags = flags | G_SIGNAL_NO_HOOKS;
+
+  return flags;
+}
+
+GIVFuncInfo *
+g_signal_info_get_class_closure (GISignalInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SignalBlob *blob = (SignalBlob *)&base->metadata[base->offset];
+
+  if (blob->has_class_closure)
+    return g_interface_info_get_vfunc ((GIInterfaceInfo *)base->container, blob->class_closure);
+
+  return NULL;
+}
+
+gboolean
+g_signal_info_true_stops_emit (GISignalInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  SignalBlob *blob = (SignalBlob *)&base->metadata[base->offset];
+
+  return blob->true_stops_emit;
+}
+
+/* GIVFuncInfo functions */
+GIVFuncInfoFlags
+g_vfunc_info_get_flags (GIVFuncInfo *info)
+{
+  GIVFuncInfoFlags flags;
+
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  VFuncBlob *blob = (VFuncBlob *)&base->metadata[base->offset];
+
+  flags = 0;
+
+  if (blob->must_chain_up)
+    flags = flags | GI_VFUNC_MUST_CHAIN_UP;
+
+  if (blob->must_be_implemented)
+    flags = flags | GI_VFUNC_MUST_OVERRIDE;
+
+  if (blob->must_not_be_implemented)
+    flags = flags | GI_VFUNC_MUST_NOT_OVERRIDE;
+
+  return flags;
+}
+
+gint
+g_vfunc_info_get_offset (GIVFuncInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  VFuncBlob *blob = (VFuncBlob *)&base->metadata[base->offset];
+  
+  return blob->struct_offset;
+}
+
+GISignalInfo *
+g_vfunc_info_get_signal (GIVFuncInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  VFuncBlob *blob = (VFuncBlob *)&base->metadata[base->offset];
+
+  if (blob->class_closure)
+    return g_interface_info_get_signal ((GIInterfaceInfo *)base->container, blob->signal);
+  
+  return NULL;
+}
+
+
+/* GIConstantInfo functions */
+GITypeInfo *
+g_constant_info_get_type (GIConstantInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  
+  return g_type_info_new (base, base->metadata, base->offset + 8);
+}
+
+gint
+g_constant_info_get_value (GIConstantInfo *info, 
+                          GArgument      *value)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  ConstantBlob *blob = (ConstantBlob *)&base->metadata[base->offset];
+
+  /* FIXME non-basic types ? */
+  if (blob->type.reserved == 0)
+    {
+      if (blob->type.pointer)
+       value->v_pointer = g_memdup (&base->metadata[blob->offset], blob->size);
+      else
+       {
+         switch (blob->type.tag)
+           {
+           case GI_TYPE_TAG_BOOLEAN:
+             value->v_boolean = *(gboolean*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_INT8:
+             value->v_int8 = *(gint8*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_UINT8:
+             value->v_uint8 = *(guint8*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_INT16:
+             value->v_int16 = *(gint16*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_UINT16:
+             value->v_uint16 = *(guint16*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_INT32:
+             value->v_int32 = *(gint32*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_UINT32:
+             value->v_uint32 = *(guint32*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_INT64:
+             value->v_int64 = *(gint64*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_UINT64:
+             value->v_uint64 = *(guint64*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_FLOAT:
+             value->v_float = *(gfloat*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_DOUBLE:
+             value->v_double = *(gdouble*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_INT:
+             value->v_int = *(gint*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_UINT:
+             value->v_uint = *(guint*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_LONG:
+             value->v_long = *(glong*)&base->metadata[blob->offset];
+             break;
+           case GI_TYPE_TAG_ULONG:
+             value->v_ulong = *(gulong*)&base->metadata[blob->offset];
+             break;
+           }
+       }
+    }
+
+  return blob->size;
+}
diff --git a/src/girepository.c b/src/girepository.c
new file mode 100644 (file)
index 0000000..482107a
--- /dev/null
@@ -0,0 +1,338 @@
+/* GObject introspection: Repository implementation
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include <glib.h>
+#include "girepository.h"
+#include "gmetadata.h"
+
+static GIRepository *default_repository = NULL;
+static GHashTable *default_metadata = NULL;
+
+struct _GIRepositoryPrivate 
+{
+  GHashTable *metadata;
+};
+
+G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
+
+static void 
+g_irepository_init (GIRepository *repository)
+{
+  repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY,
+                                                 GIRepositoryPrivate);
+}
+
+static void
+g_irepository_finalize (GObject *object)
+{
+  GIRepository *repository = G_IREPOSITORY (object);
+
+  g_hash_table_destroy (repository->priv->metadata);
+  
+  (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
+}
+
+static void
+g_irepository_class_init (GIRepositoryClass *class)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+
+  gobject_class->finalize = g_irepository_finalize;
+
+  g_type_class_add_private (class, sizeof (GIRepositoryPrivate)); 
+}
+
+void
+g_irepository_register (GIRepository *repository, 
+                       const guchar *metadata)
+{
+  Header *header = (Header *)metadata;
+  const gchar *name;
+  GHashTable *table;
+
+  if (repository != NULL)
+    {
+      if (repository->priv->metadata == NULL)
+       repository->priv->metadata = g_hash_table_new (g_str_hash, g_str_equal);
+      table = repository->priv->metadata;
+    }
+  else 
+    {
+      if (default_metadata == NULL)
+       default_metadata = g_hash_table_new (g_str_hash, g_str_equal);
+      table = default_metadata;
+    }
+
+  name = g_metadata_get_string (metadata, header->namespace);
+
+  if (g_hash_table_lookup (table, name))
+    {
+      g_fprintf (stderr, "metadata (%p) for '%s' already registered\n",
+                metadata, name);
+
+      return;
+    }
+
+  g_hash_table_insert (table, (void *)name, (void *)metadata);
+}
+
+void
+g_irepository_unregister (GIRepository *repository, 
+                         const guchar *metadata)
+{
+  Header *header = (Header *)metadata;
+  const gchar *name;
+  GHashTable *table;
+
+  if (repository != NULL)
+    table = repository->priv->metadata;
+  else
+    table = default_metadata;
+  
+  name = g_metadata_get_string (metadata, header->namespace);
+
+  if (!g_hash_table_remove (table, name))
+    {
+      g_fprintf (stderr, "metadata (%p) for '%s' not registered\n",
+                metadata, name);
+    }
+}
+
+GIRepository * 
+g_irepository_get_default (void)
+{
+  if (default_repository == NULL) 
+    { 
+      default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
+      if (default_metadata == NULL)
+       default_metadata = g_hash_table_new (g_str_hash, g_str_equal);
+      default_repository->priv->metadata = default_metadata;
+    }
+
+  return default_repository; 
+}
+
+static void 
+count_interfaces (gpointer key,
+                 gpointer value,
+                 gpointer data)
+{
+  guchar *metadata = (guchar *)value;
+  gint *n_interfaces = (gint *)data;
+  
+  *n_interfaces += ((Header *)metadata)->n_local_entries;
+}
+
+gint                   
+g_irepository_get_n_infos (GIRepository *repository,
+                          const gchar  *namespace)
+{
+  gint n_interfaces = 0;
+  if (namespace)
+    {
+      guchar *metadata;
+
+      metadata = g_hash_table_lookup (repository->priv->metadata, namespace);
+
+      if (metadata)
+       n_interfaces = ((Header *)metadata)->n_local_entries;
+    }
+  else
+    {
+      g_hash_table_foreach (repository->priv->metadata, 
+                           count_interfaces, &n_interfaces);
+    }
+
+  return n_interfaces;
+}
+
+typedef struct
+{
+  gint index;
+  const gchar *name;
+  const gchar *type;
+  GIBaseInfo *iface;
+} IfaceData;
+
+static void
+find_interface (gpointer key,
+               gpointer value,
+               gpointer data)
+{
+  gint i;
+  guchar *metadata = (guchar *)value;
+  IfaceData *iface_data = (IfaceData *)data;
+  gint index;
+  gint n_entries;
+  guint32 offset;
+  const gchar *name;
+  const gchar *type;
+  DirEntry *entry;    
+
+  index = -1;
+  n_entries = ((Header *)metadata)->n_local_entries;
+
+  if (iface_data->name)
+    {
+      for (i = 0; i < n_entries; i++)
+       {
+         entry = g_metadata_get_dir_entry (metadata, i);
+         name = g_metadata_get_string (metadata, entry->name);
+         if (strcmp (name, iface_data->name) == 0)
+           {
+             index = i;
+             break;
+           }
+       }
+    }
+  else if (iface_data->type)
+    {
+      for (i = 0; i < n_entries; i++)
+       {
+         entry = g_metadata_get_dir_entry (metadata, i);
+         if (entry->blob_type < 4)
+           continue;
+         
+         offset = *(guint32*)&metadata[entry->offset + 8];
+         type = g_metadata_get_string (metadata, offset);
+         if (strcmp (type, iface_data->type) == 0)
+           {
+             index = i;
+             break;
+           }
+       }
+    }
+  else if (iface_data->index >= n_entries)
+    iface_data->index -= n_entries;
+  else if (iface_data->index >= 0)
+    {
+      index = iface_data->index;
+      iface_data->index = -1;
+    }
+
+  if (index != -1)
+    {
+      entry = g_metadata_get_dir_entry (metadata, index);
+      iface_data->iface = g_info_new (entry->blob_type, NULL,
+                                     metadata, entry->offset);
+    }
+}
+
+GIBaseInfo * 
+g_irepository_get_info (GIRepository *repository,
+                       const gchar  *namespace,
+                       gint          index)
+{
+  IfaceData data;
+
+  data.name = NULL;
+  data.type = NULL;
+  data.index = index;
+  data.iface = NULL;
+
+  if (namespace)
+    {
+      guchar *metadata;
+      
+      metadata = g_hash_table_lookup (repository->priv->metadata, namespace);
+      
+      if (metadata)
+       find_interface ((void *)namespace, metadata, &data);
+    }
+  else
+    g_hash_table_foreach (repository->priv->metadata, find_interface, &data);
+
+  return data.iface;  
+}
+
+GIBaseInfo * 
+g_irepository_find_by_gtype (GIRepository *repository,
+                            GType         type)
+{
+  IfaceData data;
+
+  data.name = NULL;
+  data.type = g_type_name (type);
+  data.index = -1;
+  data.iface = NULL;
+
+  g_hash_table_foreach (repository->priv->metadata, find_interface, &data);
+
+  return data.iface;
+}
+
+GIBaseInfo * 
+g_irepository_find_by_name (GIRepository *repository,
+                           const gchar  *namespace,
+                           const gchar  *name)
+{
+  IfaceData data;
+
+  data.name = name;
+  data.type = NULL;
+  data.index = -1;
+  data.iface = NULL;
+
+  if (namespace)
+    {
+      guchar *metadata;
+      
+      metadata = g_hash_table_lookup (repository->priv->metadata, namespace);
+      
+      if (metadata)
+       find_interface ((void *)namespace, metadata, &data);
+    }
+  else
+    g_hash_table_foreach (repository->priv->metadata, find_interface, &data);
+
+  return data.iface;
+}
+
+static void
+collect_namespaces (gpointer key,
+                   gpointer value,
+                   gpointer data)
+{
+  GList **list = data;
+
+  *list = g_list_append (*list, key);
+}
+
+gchar ** 
+g_irepository_get_namespaces (GIRepository *repository)
+{
+  GList *l, *list = NULL;
+  gchar **names;
+  gint i;
+
+  g_hash_table_foreach (repository->priv->metadata, collect_namespaces, &list);
+
+  names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
+  i = 0;
+  for (l = list; l; l = l->next)
+    names[i++] = g_strdup (l->data); 
+  g_list_free (list);
+
+  return names;
+}
diff --git a/src/girepository.h b/src/girepository.h
new file mode 100644 (file)
index 0000000..84cd619
--- /dev/null
@@ -0,0 +1,388 @@
+/* GObject introspection: Repository
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_IREPOSITORY_H__
+#define __G_IREPOSITORY_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_IREPOSITORY      (g_irepository_get_type ())
+#define G_IREPOSITORY(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_IREPOSITORY, GIRepository))
+
+typedef struct _GIRepository         GIRepository; 
+typedef struct _GIRepositoryClass    GIRepositoryClass; 
+typedef struct _GIRepositoryPrivate  GIRepositoryPrivate; 
+typedef struct _GIBaseInfo           GIBaseInfo;
+typedef struct _GICallableInfo       GICallableInfo;
+typedef struct _GIFunctionInfo       GIFunctionInfo;
+typedef struct _GICallbackInfo       GICallbackInfo;
+typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo;
+typedef struct _GIStructInfo         GIStructInfo;
+typedef struct _GIEnumInfo           GIEnumInfo;
+typedef struct _GIObjectInfo         GIObjectInfo;
+typedef struct _GIInterfaceInfo      GIInterfaceInfo;
+typedef struct _GIConstantInfo       GIConstantInfo;
+typedef struct _GIValueInfo          GIValueInfo;
+typedef struct _GISignalInfo         GISignalInfo;
+typedef struct _GIVFuncInfo          GIVFuncInfo;
+typedef struct _GIPropertyInfo       GIPropertyInfo;
+typedef struct _GIFieldInfo          GIFieldInfo;
+typedef struct _GIArgInfo            GIArgInfo;
+typedef struct _GITypeInfo           GITypeInfo;
+typedef struct _GIErrorDomainInfo    GIErrorDomainInfo;
+typedef struct _GIUnresolvedInfo     GIUnresolvedInfo;
+
+
+struct _GIRepository 
+{ 
+  GObject parent; 
+
+  /*< private >*/
+  GIRepositoryPrivate *priv;
+};
+
+struct _GIRepositoryClass
+{ 
+  GObjectClass parent; 
+};
+
+
+/* Repository */
+
+GType         g_irepository_get_type      (void) G_GNUC_CONST;
+GIRepository *g_irepository_get_default   (void);
+void          g_irepository_register      (GIRepository *repository,
+                                          const guchar *metadata);
+void          g_irepository_unregister    (GIRepository *repository,
+                                          const guchar *metadata);
+GIBaseInfo *  g_irepository_find_by_name  (GIRepository *repository,
+                                          const gchar  *namespace,
+                                          const gchar  *name);
+gchar      ** g_irepository_get_namespaces (GIRepository *repository);
+GIBaseInfo *  g_irepository_find_by_gtype (GIRepository *repository,
+                                          GType         gtype);
+gint          g_irepository_get_n_infos   (GIRepository *repository,
+                                          const gchar  *namespace);
+GIBaseInfo *  g_irepository_get_info      (GIRepository *repository,
+                                          const gchar  *namespace,
+                                          gint          index);
+
+
+/* Types of objects registered in the repository */
+
+typedef enum 
+{
+  GI_INFO_TYPE_INVALID,
+  GI_INFO_TYPE_FUNCTION,
+  GI_INFO_TYPE_CALLBACK,
+  GI_INFO_TYPE_STRUCT,
+  GI_INFO_TYPE_BOXED,
+  GI_INFO_TYPE_ENUM,
+  GI_INFO_TYPE_FLAGS,
+  GI_INFO_TYPE_OBJECT,
+  GI_INFO_TYPE_INTERFACE,
+  GI_INFO_TYPE_CONSTANT,
+  GI_INFO_TYPE_ERROR_DOMAIN,
+  GI_INFO_TYPE_VALUE,
+  GI_INFO_TYPE_SIGNAL,
+  GI_INFO_TYPE_VFUNC,
+  GI_INFO_TYPE_PROPERTY,
+  GI_INFO_TYPE_FIELD,
+  GI_INFO_TYPE_ARG,
+  GI_INFO_TYPE_TYPE,
+  GI_INFO_TYPE_UNRESOLVED
+} GIInfoType;
+
+
+/* GIBaseInfo */
+
+GIBaseInfo *           g_base_info_ref              (GIBaseInfo   *info);
+void                   g_base_info_unref            (GIBaseInfo   *info);
+GIInfoType             g_base_info_get_type         (GIBaseInfo   *info);
+const gchar *          g_base_info_get_name         (GIBaseInfo   *info);
+const gchar *          g_base_info_get_namespace    (GIBaseInfo   *info);
+gboolean               g_base_info_is_deprecated    (GIBaseInfo   *info);
+const gchar *          g_base_info_get_annotation   (GIBaseInfo   *info,
+                                                     const gchar  *name);
+GIBaseInfo *           g_base_info_get_container    (GIBaseInfo   *info);
+
+GIBaseInfo *           g_info_new                   (GIInfoType     type,
+                                                    GIBaseInfo    *container,
+                                                    const guchar *metadata, 
+                                                    guint32       offset);
+
+
+/* GIFunctionInfo */
+
+typedef enum
+{
+  GI_FUNCTION_IS_METHOD      = 1 << 0,
+  GI_FUNCTION_IS_CONSTRUCTOR = 1 << 1,
+  GI_FUNCTION_IS_GETTER      = 1 << 2,
+  GI_FUNCTION_IS_SETTER      = 1 << 3,
+  GI_FUNCTION_WRAPS_VFUNC    = 1 << 4
+} GIFunctionInfoFlags;
+
+const gchar *           g_function_info_get_symbol     (GIFunctionInfo *info);
+GIFunctionInfoFlags     g_function_info_get_flags      (GIFunctionInfo *info);
+GIPropertyInfo *        g_function_info_get_property   (GIFunctionInfo *info);
+GIVFuncInfo *           g_function_info_get_vfunc      (GIFunctionInfo *info);
+
+typedef union 
+{
+  gboolean v_boolean;
+  gint8    v_int8;
+  guint8   v_uint8;
+  gint16   v_int16;
+  guint16  v_uint16;
+  gint32   v_int32;
+  guint32  v_uint32;
+  gint64   v_int64;
+  guint64  v_uint64;
+  gfloat   v_float;
+  gdouble  v_double;
+  gint     v_int;
+  guint    v_uint;
+  glong    v_long;
+  gulong   v_ulong;
+  gchar *  v_string;
+  gpointer v_pointer;
+} GArgument;
+
+gboolean              g_function_info_invoke         (GIFunctionInfo *info, 
+                                                     const GArgument  *in_args,
+                                                     int               n_in_args,
+                                                     const GArgument  *out_args,
+                                                     int               n_out_args,
+                                                     GArgument        *return_value);
+
+
+/* GICallableInfo */
+
+typedef enum {
+  GI_TRANSFER_NOTHING,
+  GI_TRANSFER_CONTAINER,
+  GI_TRANSFER_EVERYTHING
+} Transfer;
+
+GITypeInfo *           g_callable_info_get_return_type (GICallableInfo *info);
+Transfer               g_callable_info_get_caller_owns (GICallableInfo *info);
+gint                   g_callable_info_get_n_args      (GICallableInfo *info);
+GIArgInfo *            g_callable_info_get_arg         (GICallableInfo *info,
+                                                       gint           n);
+
+/* GIArgInfo */
+
+typedef enum {
+  GI_DIRECTION_IN,
+  GI_DIRECTION_OUT,
+  GI_DIRECTION_INOUT
+} Direction;
+
+Direction              g_arg_info_get_direction          (GIArgInfo *info);
+gboolean               g_arg_info_is_dipper              (GIArgInfo *info);
+gboolean               g_arg_info_is_return_value        (GIArgInfo *info);
+gboolean               g_arg_info_is_optional            (GIArgInfo *info);
+gboolean               g_arg_info_may_be_null            (GIArgInfo *info);
+Transfer               g_arg_info_get_ownership_transfer (GIArgInfo *info);
+GITypeInfo *           g_arg_info_get_type               (GIArgInfo *info);
+
+
+/* GITypeInfo */
+
+typedef enum {
+  GI_TYPE_TAG_VOID      =  0,
+  GI_TYPE_TAG_BOOLEAN   =  1,
+  GI_TYPE_TAG_INT8      =  2,
+  GI_TYPE_TAG_UINT8     =  3,
+  GI_TYPE_TAG_INT16     =  4,
+  GI_TYPE_TAG_UINT16    =  5,  
+  GI_TYPE_TAG_INT32     =  6,
+  GI_TYPE_TAG_UINT32    =  7,
+  GI_TYPE_TAG_INT64     =  8,
+  GI_TYPE_TAG_UINT64    =  9,
+  GI_TYPE_TAG_FLOAT     = 10,
+  GI_TYPE_TAG_DOUBLE    = 11,
+  GI_TYPE_TAG_STRING    = 12,
+  GI_TYPE_TAG_GSTRING   = 13,
+  GI_TYPE_TAG_INT       = 14,
+  GI_TYPE_TAG_UINT      = 15,
+  GI_TYPE_TAG_LONG      = 16,
+  GI_TYPE_TAG_ULONG     = 17,
+  GI_TYPE_TAG_ARRAY     = 20,
+  GI_TYPE_TAG_INTERFACE = 21,
+  GI_TYPE_TAG_GLIST     = 22,
+  GI_TYPE_TAG_GSLIST    = 23,
+  GI_TYPE_TAG_GHASH     = 24,
+  GI_TYPE_TAG_ERROR     = 25
+} GITypeTag;
+
+gboolean               g_type_info_is_pointer          (GITypeInfo *info);
+GITypeTag              g_type_info_get_tag             (GITypeInfo *info);
+GITypeInfo *           g_type_info_get_param_type      (GITypeInfo *info,
+                                                       gint       n);
+GIBaseInfo *           g_type_info_get_interface       (GITypeInfo *info);
+gint                   g_type_info_get_array_length    (GITypeInfo *info);
+gboolean               g_type_info_is_zero_terminated  (GITypeInfo *info);
+
+gint                   g_type_info_get_n_error_domains (GITypeInfo *info);
+GIErrorDomainInfo     *g_type_info_get_error_domain    (GITypeInfo *info,
+                                                       gint       n);
+
+/* GIErrorDomainInfo */
+
+const gchar *          g_error_domain_info_get_quark   (GIErrorDomainInfo *info);
+GIInterfaceInfo *           g_error_domain_info_get_codes (GIErrorDomainInfo *info);
+
+
+/* GIValueInfo */
+const gchar *          g_value_info_get_short_name (GIValueInfo *info);
+glong                  g_value_info_get_value      (GIValueInfo *info);
+
+
+/* GIFieldInfo */
+
+typedef enum
+{
+  GI_FIELD_IS_READABLE = 1 << 0,
+  GI_FIELD_IS_WRITABLE = 1 << 1
+} GIFieldInfoFlags;
+
+GIFieldInfoFlags       g_field_info_get_flags      (GIFieldInfo *info);
+gint                   g_field_info_get_size       (GIFieldInfo *info);
+gint                   g_field_info_get_offset     (GIFieldInfo *info);
+GITypeInfo *           g_field_info_get_type       (GIFieldInfo *info);
+
+
+/* GIStructInfo */
+gint                   g_struct_info_get_n_fields  (GIStructInfo *info);
+GIFieldInfo *          g_struct_info_get_field     (GIStructInfo *info,
+                                                   gint         n);
+gint                   g_struct_info_get_n_methods (GIStructInfo *info);
+GIFunctionInfo *       g_struct_info_get_method    (GIStructInfo *info,
+                                                   gint         n);
+GIFunctionInfo *       g_struct_info_find_method   (GIStructInfo *info,
+                                                   const gchar *name);
+
+/* GIRegisteredTypeInfo */
+
+const gchar *          g_registered_type_info_get_type_name (GIRegisteredTypeInfo *info);
+const gchar *          g_registered_type_info_get_type_init (GIRegisteredTypeInfo *info);
+
+
+/* GIEnumInfo */
+
+gint                   g_enum_info_get_n_values             (GIEnumInfo      *info);
+GIValueInfo  *         g_enum_info_get_value                (GIEnumInfo      *info,
+                                                            gint            n);
+
+/* GIObjectInfo */
+
+GIObjectInfo *         g_object_info_get_parent             (GIObjectInfo    *info);
+gint                   g_object_info_get_n_interfaces       (GIObjectInfo    *info);
+GIInterfaceInfo *      g_object_info_get_interface          (GIObjectInfo    *info,
+                                                            gint            n);
+gint                   g_object_info_get_n_fields           (GIObjectInfo    *info);
+GIFieldInfo *          g_object_info_get_field              (GIObjectInfo    *info,
+                                                            gint            n);
+gint                   g_object_info_get_n_properties       (GIObjectInfo    *info);
+GIPropertyInfo *       g_object_info_get_property           (GIObjectInfo    *info,
+                                                            gint            n);
+gint                   g_object_info_get_n_methods          (GIObjectInfo    *info);
+GIFunctionInfo *       g_object_info_get_method             (GIObjectInfo    *info,
+                                                            gint            n);
+GIFunctionInfo *       g_object_info_find_method            (GIObjectInfo *info,
+                                                            const gchar *name);
+gint                   g_object_info_get_n_signals          (GIObjectInfo    *info);
+GISignalInfo *         g_object_info_get_signal             (GIObjectInfo    *info,
+                                                            gint            n);
+gint                   g_object_info_get_n_vfuncs           (GIObjectInfo    *info);
+GIVFuncInfo *          g_object_info_get_vfunc              (GIObjectInfo    *info,
+                                                            gint            n);
+gint                   g_object_info_get_n_constants        (GIObjectInfo    *info);
+GIConstantInfo *       g_object_info_get_constant           (GIObjectInfo    *info,
+                                                            gint            n);
+
+                                                            
+/* GIInterfaceInfo */
+
+gint                   g_interface_info_get_n_prerequisites (GIInterfaceInfo *info);
+GIBaseInfo *           g_interface_info_get_prerequisite    (GIInterfaceInfo *info,
+                                                            gint        n);
+gint                   g_interface_info_get_n_properties    (GIInterfaceInfo *info);
+GIPropertyInfo *       g_interface_info_get_property        (GIInterfaceInfo *info,
+                                                            gint        n);
+gint                   g_interface_info_get_n_methods       (GIInterfaceInfo *info);
+GIFunctionInfo *       g_interface_info_get_method          (GIInterfaceInfo *info,
+                                                            gint        n);
+GIFunctionInfo *       g_interface_info_find_method         (GIInterfaceInfo *info,
+                                                            const gchar *name);
+gint                   g_interface_info_get_n_signals       (GIInterfaceInfo *info);
+GISignalInfo *         g_interface_info_get_signal          (GIInterfaceInfo *info,
+                                                            gint        n);
+gint                   g_interface_info_get_n_vfuncs        (GIInterfaceInfo *info);
+GIVFuncInfo *          g_interface_info_get_vfunc           (GIInterfaceInfo *info,
+                                                            gint        n);
+gint                   g_interface_info_get_n_constants     (GIInterfaceInfo *info);
+GIConstantInfo *       g_interface_info_get_constant        (GIInterfaceInfo *info,
+                                                            gint        n);
+
+
+/* GIPropertyInfo  */
+
+GParamFlags             g_property_info_get_flags                (GIPropertyInfo         *info);
+GITypeInfo *            g_property_info_get_type                 (GIPropertyInfo         *info);
+
+
+/* GISignalInfo */
+
+GSignalFlags            g_signal_info_get_flags                  (GISignalInfo           *info);
+GIVFuncInfo *           g_signal_info_get_class_closure          (GISignalInfo           *info);
+gboolean                g_signal_info_true_stops_emit            (GISignalInfo           *info);
+
+
+/* GIVFuncInfo */
+
+typedef enum
+{
+  GI_VFUNC_MUST_CHAIN_UP     = 1 << 0,
+  GI_VFUNC_MUST_OVERRIDE     = 1 << 1,
+  GI_VFUNC_MUST_NOT_OVERRIDE = 1 << 2
+} GIVFuncInfoFlags;
+
+GIVFuncInfoFlags        g_vfunc_info_get_flags                   (GIVFuncInfo            *info);
+gint                    g_vfunc_info_get_offset                  (GIVFuncInfo            *info);
+GISignalInfo *          g_vfunc_info_get_signal                  (GIVFuncInfo            *info);
+
+
+/* GIConstantInfo */
+
+GITypeInfo *            g_constant_info_get_type                 (GIConstantInfo         *info);
+gint                    g_constant_info_get_value                (GIConstantInfo         *info,
+                                                                 GArgument             *value);
+
+
+G_END_DECLS
+
+#endif  /* __G_IREPOSITORY_H__ */
+
diff --git a/src/gmetadata.c b/src/gmetadata.c
new file mode 100644 (file)
index 0000000..d93a42b
--- /dev/null
@@ -0,0 +1,65 @@
+/* GObject introspection: auxiliary functions related to the binary
+ * metadata format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib.h>
+
+#include "gmetadata.h"
+
+DirEntry *
+g_metadata_get_dir_entry (const guchar *metadata,
+                         guint16       index)
+{
+  Header *header = (Header *)metadata;
+
+  return (DirEntry *)&metadata[header->directory + index * header->entry_blob_size];
+}
+
+void    
+g_metadata_check_sanity (void)
+{
+  /* Check that struct layout is as we expect */
+  g_assert (sizeof (Header) == 80);
+  g_assert (sizeof (DirEntry) == 12);
+  g_assert (sizeof (SimpleTypeBlob) == 4);
+  g_assert (sizeof (ArgBlob) == 12);
+  g_assert (sizeof (SignatureBlob) == 8);
+  g_assert (sizeof (CommonBlob) == 8);
+  g_assert (sizeof (FunctionBlob) == 16);
+  g_assert (sizeof (InterfaceTypeBlob) == 4);
+  g_assert (sizeof (ArrayTypeBlob) == 8);
+  g_assert (sizeof (ParamTypeBlob) == 4);
+  g_assert (sizeof (ErrorTypeBlob) == 4);
+  g_assert (sizeof (ErrorDomainBlob) == 16);
+  g_assert (sizeof (ValueBlob) == 16);
+  g_assert (sizeof (FieldBlob) == 12);
+  g_assert (sizeof (RegisteredTypeBlob) == 16);
+  g_assert (sizeof (StructBlob) == 20);
+  g_assert (sizeof (EnumBlob) == 20);
+  g_assert (sizeof (PropertyBlob) == 12);
+  g_assert (sizeof (SignalBlob) == 12);
+  g_assert (sizeof (VFuncBlob) == 16);
+  g_assert (sizeof (ObjectBlob) == 32);
+  g_assert (sizeof (InterfaceBlob) == 28);
+  g_assert (sizeof (ConstantBlob) == 20);
+  g_assert (sizeof (AnnotationBlob) == 12);
+}
+
+
diff --git a/src/gmetadata.h b/src/gmetadata.h
new file mode 100644 (file)
index 0000000..82cfa63
--- /dev/null
@@ -0,0 +1,462 @@
+/* GObject introspection: struct definitions for the binary
+ * metadata format
+ *
+ * Copyright (C) 2005 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_METADATA_H__
+#define __G_METADATA_H__
+
+G_BEGIN_DECLS
+
+#define G_IDL_MAGIC "GOBJ\nMETADATA\r\n\032"
+
+enum 
+{
+  BLOB_TYPE_INVALID,
+  BLOB_TYPE_FUNCTION,
+  BLOB_TYPE_CALLBACK,
+  BLOB_TYPE_STRUCT,
+  BLOB_TYPE_BOXED,
+  BLOB_TYPE_ENUM,
+  BLOB_TYPE_FLAGS,
+  BLOB_TYPE_OBJECT,
+  BLOB_TYPE_INTERFACE,
+  BLOB_TYPE_CONSTANT,
+  BLOB_TYPE_ERROR_DOMAIN
+};
+
+typedef struct
+{
+  gchar   magic[16];
+  guint8  major_version;
+  guint8  minor_version;
+  guint16 reserved;
+  guint16 n_entries;
+  guint16 n_local_entries;
+  guint32 directory;
+  guint32 n_annotations;
+  guint32 annotations;
+
+  guint32 size;
+  guint32 namespace;
+
+  guint16 entry_blob_size;
+  guint16 function_blob_size;
+  guint16 callback_blob_size;
+  guint16 signal_blob_size;
+  guint16 vfunc_blob_size;
+  guint16 arg_blob_size;
+  guint16 property_blob_size;
+  guint16 field_blob_size;
+  guint16 value_blob_size;
+  guint16 annotation_blob_size;
+  guint16 constant_blob_size;
+  guint16 error_domain_blob_size;
+
+  guint16 signature_blob_size;
+  guint16 enum_blob_size;
+  guint16 struct_blob_size;
+  guint16 object_blob_size;
+  guint16 interface_blob_size;
+} Header;
+
+typedef struct
+{
+  guint16 blob_type;
+
+  guint   local    : 1;
+  guint   reserved :15;
+
+  guint32 name;
+  guint32 offset;
+} DirEntry;
+
+
+#define TYPE_POINTER_MASK 1 << 7
+#define TYPE_TAG_MASK         63
+
+typedef union
+{
+  struct 
+  {
+    guint reserved   : 8;
+    guint reserved2  :16;
+    guint pointer    : 1;
+    guint reserved3  : 2;
+    guint tag        : 5;    
+  };
+  guint32    offset;
+} SimpleTypeBlob;
+
+
+typedef struct
+{
+  guint32        name;
+
+  guint          in                           : 1;
+  guint          out                          : 1;
+  guint          dipper                       : 1;
+  guint          null_ok                      : 1;
+  guint          optional                     : 1;
+  guint          transfer_ownership           : 1;
+  guint          transfer_container_ownership : 1;
+  guint          return_value                 : 1;
+  guint          reserved                     :24;
+
+  SimpleTypeBlob arg_type;
+} ArgBlob;
+
+typedef struct 
+{
+  SimpleTypeBlob return_type;
+
+  guint          may_return_null              : 1;
+  guint          caller_owns_return_value     : 1;
+  guint          caller_owns_return_container : 1;
+  guint          reserved                     :13;
+
+  guint16        n_arguments;
+
+  ArgBlob        arguments[];
+} SignatureBlob;
+
+typedef struct
+{
+  guint16 blob_type;  /* 1 */
+
+  guint   deprecated     : 1;
+  guint   reserved       :15;
+
+  guint32 name;
+} CommonBlob;
+
+typedef struct 
+{
+  guint16 blob_type;  /* 1 */
+
+  guint   deprecated     : 1;
+  guint   setter         : 1; 
+  guint   getter         : 1;
+  guint   constructor    : 1;
+  guint   wraps_vfunc    : 1;
+  guint   reserved       : 1;
+  guint   index          :10;
+
+  guint32 name;
+  guint32 c_name;
+  guint32 signature;
+} FunctionBlob;
+
+typedef struct 
+{
+  guint16 blob_type;  /* 2 */
+
+  guint   deprecated     : 1;
+  guint   reserved       :15;
+
+  guint32 name;
+  guint32 signature;
+} CallbackBlob;
+
+typedef struct 
+{
+  guint pointer    :1;
+  guint reserved   :2;
+  guint tag        :5;    
+  guint8     reserved2;
+  guint16    interface;  
+} InterfaceTypeBlob;
+
+typedef struct
+{
+  guint pointer    :1;
+  guint reserved   :2;
+  guint tag        :5;    
+
+  guint          zero_terminated :1;
+  guint          has_length      :1;
+  guint          reserved2       :6;
+
+  guint16        length;
+
+  SimpleTypeBlob type;
+} ArrayTypeBlob;
+
+typedef struct
+{
+  guint pointer    :1;
+  guint reserved   :2;
+  guint tag        :5;    
+
+  guint8         reserved2;
+  guint16        n_types;
+
+  SimpleTypeBlob type[];
+} ParamTypeBlob;
+
+typedef struct
+{
+  guint pointer    :1;
+  guint reserved   :2;
+  guint tag        :5;    
+
+  guint8     reserved2;
+  guint16    n_domains;
+
+  guint16    domains[];
+}  ErrorTypeBlob;
+
+typedef struct
+{
+  guint16 blob_type;  /* 10 */
+
+  guint   deprecated     : 1;
+  guint   reserved       :15;
+  
+  guint32 name;
+
+  guint32 get_quark;
+  guint16 error_codes;
+  guint16 reserved2;
+} ErrorDomainBlob;
+
+typedef struct
+{
+  guint   deprecated : 1;
+  guint   reserved   :31;
+  guint32 name;
+  guint32 short_name;
+  guint32 value;
+} ValueBlob;
+
+typedef struct 
+{
+  guint32        name;
+
+  guint          readable : 1; 
+  guint          writable : 1;
+  guint          reserved : 6;
+  guint8         bits;
+
+  guint16        struct_offset;      
+
+  SimpleTypeBlob type;
+} FieldBlob;
+
+typedef struct
+{
+  guint16 blob_type;  
+  guint   deprecated   : 1; 
+  guint   unregistered :15;
+  guint32 name; 
+
+  guint32 gtype_name;
+  guint32 gtype_init;
+} RegisteredTypeBlob;
+
+typedef struct
+{
+  guint16   blob_type;
+
+  guint     deprecated   : 1;
+  guint     unregistered : 1;
+  guint     reserved     :14;
+
+  guint32   name;
+
+  guint32   gtype_name;
+  guint32   gtype_init;
+
+  guint16   n_fields;
+  guint16   n_methods;
+
+#if 0
+  /* variable-length parts of the blob */
+  FieldBlob    fields[];   
+  FunctionBlob methods[];
+#endif
+} StructBlob;
+
+typedef struct
+{
+  guint16   blob_type;
+
+  guint     deprecated   : 1; 
+  guint     unregistered : 1;
+  guint     reserved     :14;
+
+  guint32   name; 
+
+  guint32   gtype_name;
+  guint32   gtype_init;
+
+  guint16   n_values;
+  guint16   reserved2;
+
+  ValueBlob values[];    
+} EnumBlob;
+
+typedef struct
+{
+  guint32        name;
+
+  guint          deprecated     : 1;
+  guint          readable       : 1;
+  guint          writable       : 1;
+  guint          construct      : 1;
+  guint          construct_only : 1;
+  guint          reserved       :27;
+
+  SimpleTypeBlob type;
+
+} PropertyBlob;
+
+typedef struct
+{
+  guint   deprecated        : 1;
+  guint   run_first         : 1;
+  guint   run_last          : 1;
+  guint   run_cleanup       : 1;
+  guint   no_recurse        : 1;
+  guint   detailed          : 1;
+  guint   action            : 1;
+  guint   no_hooks          : 1;
+  guint   has_class_closure : 1;
+  guint   true_stops_emit   : 1;
+  guint   reserved          : 6;
+
+  guint16 class_closure;
+
+  guint32 name;
+
+  guint32 signature;
+} SignalBlob;
+
+typedef struct 
+{
+  guint32 name;
+
+  guint   must_chain_up           : 1;
+  guint   must_be_implemented     : 1;
+  guint   must_not_be_implemented : 1;
+  guint   class_closure           : 1;
+  guint   reserved                :12;
+  guint16 signal;
+
+  guint16 struct_offset;
+  guint16 reserved2;
+  guint32 signature;
+} VFuncBlob;
+
+typedef struct
+{
+  guint16   blob_type;  /* 7 */
+  guint     deprecated   : 1; 
+  guint     reserved     :15;
+  guint32   name; 
+
+  guint32   gtype_name;
+  guint32   gtype_init;
+
+  guint16   parent;
+
+  guint16   n_interfaces;
+  guint16   n_fields;
+  guint16   n_properties;
+  guint16   n_methods;
+  guint16   n_signals;
+  guint16   n_vfuncs;
+  guint16   n_constants;
+
+  guint16   interfaces[];
+#if 0
+  /* variable-length parts of the blob */
+  FieldBlob           fields[];
+  PropertyBlob        properties[];
+  FunctionBlob        methods[];
+  SignalBlob          signals[];
+  VFuncBlob           vfuncs[];
+  ConstantBlob        constants[];
+#endif
+} ObjectBlob;
+
+typedef struct 
+{
+  guint16 blob_type;  
+  guint   deprecated   : 1; 
+  guint   reserved     :15;
+  guint32 name; 
+
+  guint32 gtype_name;
+  guint32 gtype_init;
+
+  guint16 n_prerequisites;
+  guint16 n_properties;
+  guint16 n_methods;
+  guint16 n_signals;
+  guint16 n_vfuncs;
+  guint16 n_constants;  
+
+  guint16 prerequisites[];
+
+#if 0 
+  /* variable-length parts of the blob */
+  PropertyBlob        properties[];
+  FunctionBlob        methods[];
+  SignalBlob          signals[];
+  VFuncBlob           vfuncs[];
+  ConstantBlob        constants[];
+#endif
+} InterfaceBlob;
+
+
+typedef struct
+{
+  guint16        blob_type;
+  guint          deprecated   : 1; 
+  guint          reserved     :15;
+  guint32        name; 
+
+  SimpleTypeBlob type;
+
+  guint32        size;
+  guint32        offset;
+} ConstantBlob;
+
+typedef struct
+{ 
+  guint32 offset;
+  guint32 name;
+  guint32 value;
+} AnnotationBlob;
+
+
+DirEntry *g_metadata_get_dir_entry (const guchar *metadata,
+                                   guint16       index);
+
+void      g_metadata_check_sanity (void);
+
+#define   g_metadata_get_string(metadata,offset) ((const gchar*)&(metadata)[(offset)])
+
+
+G_END_DECLS
+
+#endif  /* __G_METADATA_H__ */
+
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..e26c26a
--- /dev/null
@@ -0,0 +1,2 @@
+check: 
+       ./roundtrips.sh
diff --git a/tests/array.test b/tests/array.test
new file mode 100644 (file)
index 0000000..05ea762
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <function name="Foo.test1" cname="test1">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p1" type="gchar*[length=1,zero-terminated=1]" direction="in"/>
+        <parameter name="p2" type="gint" direction="in"/>
+      </parameters>
+    </function>
+    <function name="Foo.test2" cname="test2">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p2" type="gint" direction="out"/>
+        <parameter name="p1" type="gchar*[length=0]" direction="out"/>
+      </parameters>
+    </function>
+    <function name="Foo.test3" cname="test3">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p1" type="gchar*[zero-terminated=1]" direction="in"/>
+      </parameters>
+    </function>
+  </namespace>
+</api>
diff --git a/tests/boxed.test b/tests/boxed.test
new file mode 100644 (file)
index 0000000..70ae196
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <boxed name="Foo.boxed1" cname="BoxedType1" get-type="boxed1_get_type" deprecated="1">
+      <field cname="field1" readable="1" writable="1" offset="0" type="guint32" />
+      <method name="Foo.boxed1.frob_boxed1" cname="frob_boxed1">
+        <return-type type="void"/>
+        <parameters>
+          <parameter name="box" type="Foo.boxed1*" direction="in"/>
+          <parameter name="w" type="GList<Foo.boxed2*>" direction="in"/>
+          <parameter name="t" type="GHashTable<gchar*,gint64>" direction="in"/>
+          <parameter name="e" type="GError<>" direction="out"/>
+        </parameters>
+      </method>
+      <method name="Foo.boxed1.lart" cname="lart">
+        <return-type type="gboolean"/>
+        <parameters>
+          <parameter name="box" type="Foo.boxed2*" direction="in"/>
+          <parameter name="val" type="gint*" direction="inout"/>
+        </parameters>
+      </method>
+    </boxed>
+    <function name="Foo.freefunc" cname="freefunc" deprecated="1">
+      <return-type type="gint"/>
+      <parameters>
+        <parameter name="v1" type="gint" direction="in"/>
+        <parameter name="val2" type="gint" direction="in"/>
+      </parameters>
+    </function>
+    <boxed name="Foo.boxed2" cname="BoxedType2" get-type="boxed2_get_type" deprecated="1">
+    </boxed>
+  </namespace>
+</api>
diff --git a/tests/enum.test b/tests/enum.test
new file mode 100644 (file)
index 0000000..87e9d63
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <enum name="Foo.Enum1" cname="FooEnum" get-type="foo_enum_get_type">
+      <member name="value1" cname="v1" value="0"  />
+      <member name="value2" cname="v1" value="1"  />
+      <member name="value3" cname="v1" value="2"  />
+    </enum>
+    <flags name="Foo.Flags1" cname="FooFlags" get-type="foo_flags_get_type">
+      <member name="value1" cname="v1" value="1"  />
+      <member name="value2" cname="v1" value="2"  />
+      <member name="value3" cname="v1" value="4"  />
+    </flags>
+    <enum name="Foo.Enum2" cname="FooEnum2">
+      <member name="value1" cname="v1" value="0"  />
+      <member name="value2" cname="v1" value="1"  />
+      <member name="value3" cname="v1" value="2"  />
+    </enum>
+  </namespace>
+</api>
diff --git a/tests/errors.test b/tests/errors.test
new file mode 100644 (file)
index 0000000..1e85669
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <enum name="Foo.ErrorCodes1" cname="ErrorCodes1" get-type="foo_error_codes1_get_type">
+      <member name="Foo.ErrorCodes1.e1" cname="e1" value="0"  />
+      <member name="Foo.ErrorCodes1.e2" cname="e2" value="1"  deprecated="1" />
+      <member name="Foo.ErrorCodes1.e3" cname="e3" value="2"  />
+    </enum>
+    <enum name="Foo.ErrorCodes2" cname="ErrorCodes2" get-type="foo_error_codes2_get_type">
+      <member name="Foo.ErrorCodes2.e1" cname="e1" value="0"  />
+    </enum>
+    <errordomain name="Foo.Errors1" get-quark="foo_errors1_get_quark" codes="Foo.ErrorCodes1" />
+    <errordomain name="Foo.Errors2" get-quark="foo_errors2_get_quark" codes="Foo.ErrorCodes2" />
+    <function name="Foo.test1" cname="test1">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p1" type="gint" direction="in" null-ok="1"/>
+        <parameter name="p2" type="GError<Foo.Errors1,Foo.Errors2>" direction="out"/>
+      </parameters>
+    </function>
+  </namespace>
+</api>
diff --git a/tests/function.test b/tests/function.test
new file mode 100644 (file)
index 0000000..7e632da
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <boxed name="Foo.Boxed1" cname="Boxed1" get-type="boxed1_get_type">
+    </boxed>
+    <function name="Foo.test1" cname="test1" deprecated="1">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p1" type="Foo.Boxed1*" direction="in" null-ok="1"/>
+        <parameter name="p2" type="gboolean" direction="out"/>
+      </parameters>
+    </function>
+    <callback name="Foo.callback1" deprecated="1">
+      <return-type type="gboolean"/>
+      <parameters>
+        <parameter name="p1" type="Foo.Boxed1*" direction="in" null-ok="1"/>
+        <parameter name="p2" type="gboolean" direction="out"/>
+      </parameters>
+    </callback>
+  </namespace>
+</api>
diff --git a/tests/gobject.test b/tests/gobject.test
new file mode 100644 (file)
index 0000000..4715291
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="GObject">
+    <object name="GObject.GObject" cname="GObject" get-type="g_object_get_type">
+    </object>
+  </namespace>
+</api>
diff --git a/tests/interface.test b/tests/interface.test
new file mode 100644 (file)
index 0000000..6c9313a
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <interface name="Foo.Iface1" cname="Iface1" get-type="iface1_get_type">
+      <requires>
+      <interface name="Foo.Iface2" />
+      </requires>
+      <method name="Foo.Iface1.method1" cname="method1">
+        <return-type type="Foo.Iface2*"/>
+        <parameters>
+          <parameter name="param1" type="Foo.Iface2*" direction="in"/>
+        </parameters>
+      </method>
+      <property name="prop1" readable="0" writable="0" type="gint"/>
+      <signal name="signal1" when="LAST">
+        <return-type type="gboolean"/>
+        <parameters>
+          <parameter name="obj" type="Foo.Iface1*" direction="in"/>
+        </parameters>
+      </signal>
+      <signal name="signal2" when="FIRST" no-recurse="1" detailed="1" action="1" no-hooks="1">
+        <return-type type="void"/>
+        <parameters>
+          <parameter name="obj" type="Foo.Iface1*" direction="in"/>
+        </parameters>
+      </signal>
+      <vfunc name="Foo.Iface1.vfunc1">
+        <return-type type="Foo.Iface2*"/>
+        <parameters>
+          <parameter name="param1" type="Foo.Iface2*" direction="in"/>
+        </parameters>
+      </vfunc>
+      <constant name="constant1" type="gint" value="42" />
+    </interface>
+    <interface name="Foo.Iface2" cname="Iface2" get-type="iface2_get_type">
+    </interface>
+  </namespace>
+</api>
diff --git a/tests/object.test b/tests/object.test
new file mode 100644 (file)
index 0000000..c4e0cfe
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <object name="Foo.Object1" parent="Foo.Object2" cname="Object1" get-type="object1_get_type">
+      <implements>
+      <interface name="Foo.Iface1" />
+      </implements>
+      <property name="prop1" readable="0" writable="0" type="gint"/>
+      <signal name="signal1" when="LAST">
+        <return-type type="gboolean"/>
+        <parameters>
+          <parameter name="obj" type="Foo.Object1*" direction="in"/>
+        </parameters>
+      </signal>
+      <signal name="signal2" when="FIRST" no-recurse="1" detailed="1" action="1" no-hooks="1">
+        <return-type type="void"/>
+        <parameters>
+          <parameter name="obj" type="Foo.Object1*" direction="in"/>
+        </parameters>
+      </signal>
+      <vfunc name="Foo.Object1.vfunc1">
+        <return-type type="Foo.Object2*"/>
+        <parameters>
+          <parameter name="param1" type="Foo.Object1*" direction="in"/>
+        </parameters>
+      </vfunc>
+      <constant name="constant1" type="gint" value="42" />
+    </object>
+    <interface name="Foo.Iface1" cname="Iface1" get-type="iface1_get_type">
+    </interface>
+    <object name="Foo.Object2" parent="GObject.GObject" cname="Object2" get-type="object2_get_type">
+    </object>
+  </namespace>
+</api>
diff --git a/tests/object.test1 b/tests/object.test1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/roundtrips.sh b/tests/roundtrips.sh
new file mode 100755 (executable)
index 0000000..8ed422a
--- /dev/null
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test"
+
+for i in $SIMPLE_TESTS; do
+       echo $i
+       ../src/g-idl-compiler --raw $i > $i.1; 
+       ../src/g-idl-generate --raw $i.1 > $i.2; 
+       diff -u $i $i.2 || exit 1; 
+       rm $i.1 $i.2
+done
+
+../src/g-idl-compiler --raw --module=Foo object.test gobject.test > object.test.1
+../src/g-idl-generate --raw object.test.1 > object.test.2
+diff -u object.test object.test.2 || exit 1
+rm object.test.1 object.test.2
+
+../src/g-idl-compiler --raw --module=Foo xref1.test xref2.test > xref1.test.1
+../src/g-idl-generate --raw xref1.test.1 > xref1.test.2
+diff -u xref1.test xref1.test.2 || exit 1
+rm xref1.test.1 xref1.test.2
+
+../src/g-idl-compiler --raw --module=Bar xref1.test xref2.test > xref2.test.1
+../src/g-idl-generate --raw xref2.test.1 > xref2.test.2
+diff -u xref2.test xref2.test.2 || exit 1
+rm xref2.test.1 xref2.test.2
diff --git a/tests/xref1.test b/tests/xref1.test
new file mode 100644 (file)
index 0000000..3565802
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Foo">
+    <boxed name="Foo.Boxed" cname="FooBoxed" get-type="foo_boxed_get_type">
+    </boxed>
+    <function name="Foo.test" cname="foo_test">
+      <return-type type="void"/>
+      <parameters>
+        <parameter name="p1" type="Bar.Boxed*" direction="in"/>
+      </parameters>
+    </function>
+  </namespace>
+</api>
diff --git a/tests/xref2.test b/tests/xref2.test
new file mode 100644 (file)
index 0000000..78f95c7
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<api version="1.0">
+  <namespace name="Bar">
+    <boxed name="Bar.Boxed" cname="BarBoxed" get-type="bar_boxed_get_type">
+    </boxed>
+    <function name="Bar.test" cname="bar_test">
+      <return-type type="void"/>
+      <parameters>
+        <parameter name="p1" type="Foo.Boxed*" direction="in"/>
+      </parameters>
+    </function>
+  </namespace>
+</api>