diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2005-05-09 14:24:46 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2005-05-09 14:24:46 +0000 |
commit | 1675d0574f188d627d1f18d7c1c78279bb4ae102 (patch) | |
tree | 7e5ff6e1c60b4e314524e76e25501cb1432fb6a0 | |
download | gobject-introspection-1675d0574f188d627d1f18d7c1c78279bb4ae102.tar.gz |
Initial revision
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | TODO | 30 | ||||
-rw-r--r-- | gidl.dtd | 132 | ||||
-rw-r--r-- | metadata-format.txt | 995 | ||||
-rw-r--r-- | src/Makefile | 38 | ||||
-rw-r--r-- | src/compiler.c | 214 | ||||
-rw-r--r-- | src/generate.c | 999 | ||||
-rw-r--r-- | src/gidlmodule.c | 187 | ||||
-rw-r--r-- | src/gidlmodule.h | 47 | ||||
-rw-r--r-- | src/gidlnode.c | 1749 | ||||
-rw-r--r-- | src/gidlnode.h | 313 | ||||
-rw-r--r-- | src/gidlparser.c | 1884 | ||||
-rw-r--r-- | src/gidlparser.h | 38 | ||||
-rw-r--r-- | src/ginfo.c | 1639 | ||||
-rw-r--r-- | src/girepository.c | 338 | ||||
-rw-r--r-- | src/girepository.h | 388 | ||||
-rw-r--r-- | src/gmetadata.c | 65 | ||||
-rw-r--r-- | src/gmetadata.h | 462 | ||||
-rw-r--r-- | tests/Makefile | 2 | ||||
-rw-r--r-- | tests/array.test | 25 | ||||
-rw-r--r-- | tests/boxed.test | 33 | ||||
-rw-r--r-- | tests/enum.test | 20 | ||||
-rw-r--r-- | tests/errors.test | 22 | ||||
-rw-r--r-- | tests/function.test | 21 | ||||
-rw-r--r-- | tests/gobject.test | 7 | ||||
-rw-r--r-- | tests/interface.test | 38 | ||||
-rw-r--r-- | tests/object.test | 34 | ||||
-rw-r--r-- | tests/object.test1 | 0 | ||||
-rwxr-xr-x | tests/roundtrips.sh | 26 | ||||
-rw-r--r-- | tests/xref1.test | 13 | ||||
-rw-r--r-- | tests/xref2.test | 13 |
31 files changed, 9790 insertions, 0 deletions
@@ -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. @@ -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 index 00000000..26bd3f0b --- /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 index 00000000..d9b7fd7e --- /dev/null +++ b/metadata-format.txt @@ -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 index 00000000..fe96a1fc --- /dev/null +++ b/src/Makefile @@ -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 index 00000000..c985d05b --- /dev/null +++ b/src/compiler.c @@ -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 index 00000000..7d863656 --- /dev/null +++ b/src/generate.c @@ -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 index 00000000..7d0a9c6a --- /dev/null +++ b/src/gidlmodule.c @@ -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 index 00000000..17135764 --- /dev/null +++ b/src/gidlmodule.h @@ -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 index 00000000..6dea7087 --- /dev/null +++ b/src/gidlnode.c @@ -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 index 00000000..08683d31 --- /dev/null +++ b/src/gidlnode.h @@ -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 index 00000000..8e340db4 --- /dev/null +++ b/src/gidlparser.c @@ -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 index 00000000..2d71aaa0 --- /dev/null +++ b/src/gidlparser.h @@ -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 index 00000000..5c9f6a14 --- /dev/null +++ b/src/ginfo.c @@ -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 index 00000000..482107a7 --- /dev/null +++ b/src/girepository.c @@ -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 index 00000000..84cd6192 --- /dev/null +++ b/src/girepository.h @@ -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 index 00000000..d93a42b1 --- /dev/null +++ b/src/gmetadata.c @@ -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 index 00000000..82cfa638 --- /dev/null +++ b/src/gmetadata.h @@ -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 index 00000000..e26c26a1 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,2 @@ +check: + ./roundtrips.sh diff --git a/tests/array.test b/tests/array.test new file mode 100644 index 00000000..05ea7625 --- /dev/null +++ b/tests/array.test @@ -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 index 00000000..70ae1966 --- /dev/null +++ b/tests/boxed.test @@ -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 index 00000000..87e9d638 --- /dev/null +++ b/tests/enum.test @@ -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 index 00000000..1e85669a --- /dev/null +++ b/tests/errors.test @@ -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 index 00000000..7e632da2 --- /dev/null +++ b/tests/function.test @@ -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 index 00000000..47152914 --- /dev/null +++ b/tests/gobject.test @@ -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 index 00000000..6c9313a6 --- /dev/null +++ b/tests/interface.test @@ -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 index 00000000..c4e0cfeb --- /dev/null +++ b/tests/object.test @@ -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 index 00000000..e69de29b --- /dev/null +++ b/tests/object.test1 diff --git a/tests/roundtrips.sh b/tests/roundtrips.sh new file mode 100755 index 00000000..8ed422af --- /dev/null +++ b/tests/roundtrips.sh @@ -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 index 00000000..35658028 --- /dev/null +++ b/tests/xref1.test @@ -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 index 00000000..78f95c72 --- /dev/null +++ b/tests/xref2.test @@ -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> |