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 =
+ "Hello World!";
+
+ 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();