diff --git a/ChangeLog b/ChangeLog index 4694dee..336ea86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ - xmpp_conn_is_connecting() - xmpp_conn_is_connected() - xmpp_conn_is_disconnected() + - xmpp_stanza_new_from_string() - xmpp_stanza_add_child_ex() - xmpp_stanza_get_context() - xmpp_global_timed_handler_add() diff --git a/src/stanza.c b/src/stanza.c index 1879037..c3c8d77 100644 --- a/src/stanza.c +++ b/src/stanza.c @@ -22,6 +22,7 @@ #include "strophe.h" #include "common.h" #include "hash.h" +#include "parser.h" /** Create a stanza object. * This function allocates and initializes a blank stanza object. @@ -1461,3 +1462,59 @@ xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, return error; } + +static void _stub_stream_start(char *name, char **attrs, void *userdata) +{ + UNUSED(name); + UNUSED(attrs); + UNUSED(userdata); +} + +static void _stub_stream_end(char *name, void *userdata) +{ + UNUSED(name); + UNUSED(userdata); +} + +static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata) +{ + stanza = xmpp_stanza_clone(stanza); + *(xmpp_stanza_t **)userdata = stanza; +} + +/** Create a stanza object from the string. + * This function allocates and initializes a stanza object which represents + * stanza located in the string. + * The stanza will have a reference count of one, so the caller does not + * need to clone it. + * + * @param ctx a Strophe context object + * @param str stanza in NULL terminated string representation + * + * @return a stanza object or NULL on an error + * + * @ingroup Stanza + */ +xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str) +{ + xmpp_stanza_t *stanza = NULL; + parser_t *parser; + int ret; + + static const char *start = ""; + static const char *end = ""; + + parser = parser_new(ctx, _stub_stream_start, _stub_stream_end, + _stream_stanza, &stanza); + if (parser) { + ret = parser_feed(parser, (char *)start, strlen(start)) && + parser_feed(parser, (char *)str, strlen(str)) && + parser_feed(parser, (char *)end, strlen(end)); + parser_free(parser); + if (!ret && stanza) { + xmpp_stanza_release(stanza); + stanza = NULL; + } + } + return stanza; +} diff --git a/strophe.h b/strophe.h index 19898bb..aa448ed 100644 --- a/strophe.h +++ b/strophe.h @@ -330,6 +330,7 @@ void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler) /* allocate and initialize a blank stanza */ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx); +xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str); /* clone a stanza */ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *const stanza); diff --git a/tests/test_stanza.c b/tests/test_stanza.c index 8b522de..0b28c5f 100644 --- a/tests/test_stanza.c +++ b/tests/test_stanza.c @@ -15,6 +15,7 @@ #include #include +#include #define MAGICPTR ((void *)0xfeedbeef) static unsigned long used_blocks = 0; @@ -31,7 +32,10 @@ static void stanza_free(void *ptr, void *userdata) { assert(userdata == MAGICPTR); - --used_blocks; + if (ptr != NULL) { + assert(used_blocks > 0); + --used_blocks; + } free(ptr); } @@ -39,6 +43,14 @@ static void *stanza_realloc(void *ptr, size_t size, void *userdata) { assert(userdata == MAGICPTR); + if (ptr != NULL && size == 0) { + /* equivalent to free(ptr) */ + assert(used_blocks > 0); + --used_blocks; + } else if (ptr == NULL) { + /* equivalent to malloc(size) */ + ++used_blocks; + } return realloc(ptr, size); } @@ -78,6 +90,28 @@ static void test_stanza_add_child(xmpp_ctx_t *ctx) assert(used_blocks == baseline); } +static void test_stanza_from_string(xmpp_ctx_t *ctx) +{ + xmpp_stanza_t *stanza; + char *buf; + size_t buflen; + int ret; + + static const char *str = + ""; + + stanza = xmpp_stanza_new_from_string(ctx, str); + assert(stanza != NULL); + ret = xmpp_stanza_to_text(stanza, &buf, &buflen); + assert(ret == XMPP_EOK); + assert(strcmp(buf, str) == 0); + xmpp_free(ctx, buf); + xmpp_stanza_release(stanza); +} + int main() { xmpp_ctx_t *ctx; @@ -87,6 +121,7 @@ int main() assert(ctx != NULL); test_stanza_add_child(ctx); + test_stanza_from_string(ctx); xmpp_ctx_free(ctx); xmpp_shutdown();