aboutsummaryrefslogtreecommitdiffstats
path: root/lib/xmltree.h
blob: a41cbac188e0097df08d489e7edb14cff269f8e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/***************************************************************************\
*                                                                           *
*  BitlBee - An IRC to IM gateway                                           *
*  Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly)       *
*                                                                           *
*  Copyright 2006-2012 Wilmer van der Gaast <wilmer@gaast.net>              *
*                                                                           *
*  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, version            *
*  2.1.                                                                     *
*                                                                           *
*  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA           *
*                                                                           *
****************************************************************************/

#ifndef _XMLTREE_H
#define _XMLTREE_H

typedef enum
{
	XT_COMPLETE	= 1,	/* </tag> reached */
	XT_SEEN		= 2,	/* Handler called (or not defined) */
} xt_flags;

typedef enum
{
	XT_ABORT,		/* Abort, don't handle the rest anymore */
	XT_HANDLED,		/* Handled this tag properly, go to the next one */
	XT_NEXT			/* Try if there's another matching handler */
} xt_status;

struct xt_attr
{
	char *key, *value;
};

struct xt_node
{
	struct xt_node *parent;
	struct xt_node *children;
	
	char *name;
	struct xt_attr *attr;
	char *text;
	int text_len;
	
	struct xt_node *next;
	xt_flags flags;
};

typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data );

struct xt_handler_entry
{
	char *name, *parent;
	xt_handler_func func;
};

struct xt_parser
{
	GMarkupParseContext *parser;
	struct xt_node *root;
	struct xt_node *cur;
	
	const struct xt_handler_entry *handlers;
	gpointer data;
	
	GError *gerr;
};

struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data );
void xt_reset( struct xt_parser *xt );
int xt_feed( struct xt_parser *xt, const char *text, int text_len );
int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth );
void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth );
struct xt_node *xt_from_string( const char *in, int text_len );
char *xt_to_string( struct xt_node *node );
char *xt_to_string_i( struct xt_node *node );
void xt_print( struct xt_node *node );
struct xt_node *xt_dup( struct xt_node *node );
void xt_free_node( struct xt_node *node );
void xt_free( struct xt_parser *xt );
struct xt_node *xt_find_node( struct xt_node *node, const char *name );
struct xt_node *xt_find_path( struct xt_node *node, const char *name );
char *xt_find_attr( struct xt_node *node, const char *key );

struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children );
void xt_add_child( struct xt_node *parent, struct xt_node *child );
void xt_insert_child( struct xt_node *parent, struct xt_node *child );
void xt_add_attr( struct xt_node *node, const char *key, const char *value );
int xt_remove_attr( struct xt_node *node, const char *key );

#endif
an class="p">) { aim_tlvlist_t *list = NULL, *cur; guint16 type, length; while (aim_bstream_empty(bs)) { type = aimbs_get16(bs); length = aimbs_get16(bs); cur = g_new0(aim_tlvlist_t, 1); cur->tlv = g_new0(aim_tlv_t, 1); cur->tlv->type = type; if ((cur->tlv->length = length)) { cur->tlv->value = aimbs_getraw(bs, length); } cur->next = list; list = cur; } return list; } /** * aim_freetlvchain - Free a TLV chain structure * @list: Chain to be freed * * Walks the list of TLVs in the passed TLV chain and * frees each one. Note that any references to this data * should be removed before calling this. * */ void aim_freetlvchain(aim_tlvlist_t **list) { aim_tlvlist_t *cur; if (!list || !*list) { return; } for (cur = *list; cur; ) { aim_tlvlist_t *tmp; freetlv(&cur->tlv); tmp = cur->next; g_free(cur); cur = tmp; } list = NULL; return; } /** * aim_counttlvchain - Count the number of TLVs in a chain * @list: Chain to be counted * * Returns the number of TLVs stored in the passed chain. * */ int aim_counttlvchain(aim_tlvlist_t **list) { aim_tlvlist_t *cur; int count; if (!list || !*list) { return 0; } for (cur = *list, count = 0; cur; cur = cur->next) { count++; } return count; } /** * aim_sizetlvchain - Count the number of bytes in a TLV chain * @list: Chain to be sized * * Returns the number of bytes that would be needed to * write the passed TLV chain to a data buffer. * */ int aim_sizetlvchain(aim_tlvlist_t **list) { aim_tlvlist_t *cur; int size; if (!list || !*list) { return 0; } for (cur = *list, size = 0; cur; cur = cur->next) { size += (4 + cur->tlv->length); } return size; } /** * aim_addtlvtochain_str - Add a string to a TLV chain * @list: Designation chain (%NULL pointer if empty) * @type: TLV type * @str: String to add * @len: Length of string to add (not including %NULL) * * Adds the passed string as a TLV element of the passed type * to the TLV chain. * */ int aim_addtlvtochain_raw(aim_tlvlist_t **list, const guint16 t, const guint16 l, const guint8 *v) { aim_tlvlist_t *newtlv, *cur; if (!list) { return 0; } if (!(newtlv = g_new0(aim_tlvlist_t, 1))) { return 0; } if (!(newtlv->tlv = g_new0(aim_tlv_t, 1))) { g_free(newtlv); return 0; } newtlv->tlv->type = t; if ((newtlv->tlv->length = l)) { newtlv->tlv->value = (guint8 *) g_malloc(newtlv->tlv->length); memcpy(newtlv->tlv->value, v, newtlv->tlv->length); } if (!*list) { *list = newtlv; } else { for (cur = *list; cur->next; cur = cur->next) { ; } cur->next = newtlv; } return newtlv->tlv->length; } /** * aim_addtlvtochain8 - Add a 8bit integer to a TLV chain * @list: Destination chain * @type: TLV type to add * @val: Value to add * * Adds a one-byte unsigned integer to a TLV chain. * */ int aim_addtlvtochain8(aim_tlvlist_t **list, const guint16 t, const guint8 v) { guint8 v8[1]; (void) aimutil_put8(v8, v); return aim_addtlvtochain_raw(list, t, 1, v8); } /** * aim_addtlvtochain16 - Add a 16bit integer to a TLV chain * @list: Destination chain * @type: TLV type to add * @val: Value to add * * Adds a two-byte unsigned integer to a TLV chain. * */ int aim_addtlvtochain16(aim_tlvlist_t **list, const guint16 t, const guint16 v) { guint8 v16[2]; (void) aimutil_put16(v16, v); return aim_addtlvtochain_raw(list, t, 2, v16); } /** * aim_addtlvtochain32 - Add a 32bit integer to a TLV chain * @list: Destination chain * @type: TLV type to add * @val: Value to add * * Adds a four-byte unsigned integer to a TLV chain. * */ int aim_addtlvtochain32(aim_tlvlist_t **list, const guint16 t, const guint32 v) { guint8 v32[4]; (void) aimutil_put32(v32, v); return aim_addtlvtochain_raw(list, t, 4, v32); } /** * aim_addtlvtochain_caps - Add a capability block to a TLV chain * @list: Destination chain * @type: TLV type to add * @caps: Bitfield of capability flags to send * * Adds a block of capability blocks to a TLV chain. The bitfield * passed in should be a bitwise %OR of any of the %AIM_CAPS constants: * */ int aim_addtlvtochain_caps(aim_tlvlist_t **list, const guint16 t, const guint32 caps) { guint8 buf[16 * 16]; /* XXX icky fixed length buffer */ aim_bstream_t bs; if (!caps) { return 0; /* nothing there anyway */ } aim_bstream_init(&bs, buf, sizeof(buf)); aim_putcap(&bs, caps); return aim_addtlvtochain_raw(list, t, aim_bstream_curpos(&bs), buf); } /** * aim_addtlvtochain_noval - Add a blank TLV to a TLV chain * @list: Destination chain * @type: TLV type to add * * Adds a TLV with a zero length to a TLV chain. * */ int aim_addtlvtochain_noval(aim_tlvlist_t **list, const guint16 t) { return aim_addtlvtochain_raw(list, t, 0, NULL); } /* * Note that the inner TLV chain will not be modifiable as a tlvchain once * it is written using this. Or rather, it can be, but updates won't be * made to this. * * XXX should probably support sublists for real. * * This is so neat. * */ int aim_addtlvtochain_frozentlvlist(aim_tlvlist_t **list, guint16 type, aim_tlvlist_t **tl) { guint8 *buf; int buflen; aim_bstream_t bs; buflen = aim_sizetlvchain(tl); if (buflen <= 0) { return 0; } if (!(buf = g_malloc(buflen))) { return 0; } aim_bstream_init(&bs, buf, buflen); aim_writetlvchain(&bs, tl); aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); g_free(buf); return buflen; } int aim_addtlvtochain_chatroom(aim_tlvlist_t **list, guint16 type, guint16 exchange, const char *roomname, guint16 instance) { guint8 *buf; int buflen; aim_bstream_t bs; buflen = 2 + 1 + strlen(roomname) + 2; if (!(buf = g_malloc(buflen))) { return 0; } aim_bstream_init(&bs, buf, buflen); aimbs_put16(&bs, exchange); aimbs_put8(&bs, strlen(roomname)); aimbs_putraw(&bs, (guint8 *) roomname, strlen(roomname)); aimbs_put16(&bs, instance); aim_addtlvtochain_raw(list, type, aim_bstream_curpos(&bs), buf); g_free(buf); return 0; } /** * aim_writetlvchain - Write a TLV chain into a data buffer. * @buf: Destination buffer * @buflen: Maximum number of bytes that will be written to buffer * @list: Source TLV chain * * Copies a TLV chain into a raw data buffer, writing only the number * of bytes specified. This operation does not free the chain; * aim_freetlvchain() must still be called to free up the memory used * by the chain structures. * * XXX clean this up, make better use of bstreams */ int aim_writetlvchain(aim_bstream_t *bs, aim_tlvlist_t **list) { int goodbuflen; aim_tlvlist_t *cur; /* do an initial run to test total length */ for (cur = *list, goodbuflen = 0; cur; cur = cur->next) { goodbuflen += 2 + 2; /* type + len */ goodbuflen += cur->tlv->length; } if (goodbuflen > aim_bstream_empty(bs)) { return 0; /* not enough buffer */ } /* do the real write-out */ for (cur = *list; cur; cur = cur->next) { aimbs_put16(bs, cur->tlv->type); aimbs_put16(bs, cur->tlv->length); if (cur->tlv->length) { aimbs_putraw(bs, cur->tlv->value, cur->tlv->length); } } return 1; /* XXX this is a nonsensical return */ } /** * aim_gettlv - Grab the Nth TLV of type type in the TLV list list. * @list: Source chain * @type: Requested TLV type * @nth: Index of TLV of type to get * * Returns a pointer to an aim_tlv_t of the specified type; * %NULL on error. The @nth parameter is specified starting at %1. * In most cases, there will be no more than one TLV of any type * in a chain. * */ aim_tlv_t *aim_gettlv(aim_tlvlist_t *list, const guint16 t, const int n) { aim_tlvlist_t *cur; int i; for (cur = list, i = 0; cur; cur = cur->next) { if (cur && cur->tlv) { if (cur->tlv->type == t) { i++; } if (i >= n) { return cur->tlv; } } } return NULL; } /** * aim_gettlv_str - Retrieve the Nth TLV in chain as a string. * @list: Source TLV chain * @type: TLV type to search for * @nth: Index of TLV to return * * Same as aim_gettlv(), except that the return value is a %NULL- * terminated string instead of an aim_tlv_t. This is a * dynamic buffer and must be freed by the caller. * */ char *aim_gettlv_str(aim_tlvlist_t *list, const guint16 t, const int n) { aim_tlv_t *tlv; char *newstr; if (!(tlv = aim_gettlv(list, t, n))) { return NULL; } newstr = (char *) g_malloc(tlv->length + 1); memcpy(newstr, tlv->value, tlv->length); *(newstr + tlv->length) = '\0'; return newstr; } /** * aim_gettlv8 - Retrieve the Nth TLV in chain as a 8bit integer. * @list: Source TLV chain * @type: TLV type to search for * @nth: Index of TLV to return * * Same as aim_gettlv(), except that the return value is a * 8bit integer instead of an aim_tlv_t. * */ guint8 aim_gettlv8(aim_tlvlist_t *list, const guint16 t, const int n) { aim_tlv_t *tlv; if (!(tlv = aim_gettlv(list, t, n))) { return 0; /* erm */ } return aimutil_get8(tlv->value); } /** * aim_gettlv16 - Retrieve the Nth TLV in chain as a 16bit integer. * @list: Source TLV chain * @type: TLV type to search for * @nth: Index of TLV to return * * Same as aim_gettlv(), except that the return value is a * 16bit integer instead of an aim_tlv_t. * */ guint16 aim_gettlv16(aim_tlvlist_t *list, const guint16 t, const int n) { aim_tlv_t *tlv; if (!(tlv = aim_gettlv(list, t, n))) { return 0; /* erm */ } return aimutil_get16(tlv->value); } /** * aim_gettlv32 - Retrieve the Nth TLV in chain as a 32bit integer. * @list: Source TLV chain * @type: TLV type to search for * @nth: Index of TLV to return * * Same as aim_gettlv(), except that the return value is a * 32bit integer instead of an aim_tlv_t. * */ guint32 aim_gettlv32(aim_tlvlist_t *list, const guint16 t, const int n) { aim_tlv_t *tlv; if (!(tlv = aim_gettlv(list, t, n))) { return 0; /* erm */ } return aimutil_get32(tlv->value); } #if 0 /** * aim_puttlv_8 - Write a one-byte TLV. * @buf: Destination buffer * @t: TLV type * @v: Value * * Writes a TLV with a one-byte integer value portion. * */ int aim_puttlv_8(guint8 *buf, const guint16 t, const guint8 v) { guint8 v8[1]; aimutil_put8(v8, v); return aim_puttlv_raw(buf, t, 1, v8); } /** * aim_puttlv_16 - Write a two-byte TLV. * @buf: Destination buffer * @t: TLV type * @v: Value * * Writes a TLV with a two-byte integer value portion. * */ int aim_puttlv_16(guint8 *buf, const guint16 t, const guint16 v) { guint8 v16[2]; aimutil_put16(v16, v); return aim_puttlv_raw(buf, t, 2, v16); } /** * aim_puttlv_32 - Write a four-byte TLV. * @buf: Destination buffer * @t: TLV type * @v: Value * * Writes a TLV with a four-byte integer value portion. * */ int aim_puttlv_32(guint8 *buf, const guint16 t, const guint32 v) { guint8 v32[4]; aimutil_put32(v32, v); return aim_puttlv_raw(buf, t, 4, v32); } /** * aim_puttlv_raw - Write a raw TLV. * @buf: Destination buffer * @t: TLV type * @l: Length of string * @v: String to write * * Writes a TLV with a raw value portion. (Only the first @l * bytes of the passed buffer will be written, which should not * include a terminating NULL.) * */ int aim_puttlv_raw(guint8 *buf, const guint16 t, const guint16 l, const guint8 *v) { int i; i = aimutil_put16(buf, t); i += aimutil_put16(buf + i, l); if (l) { memcpy(buf + i, v, l); } i += l; return i; } #endif