コード例 #1
0
ファイル: xnode.c プロジェクト: luciomarinelli/gtk-gnutella
/**
 * Add namespace declaration to element.
 *
 * There must not be any ':' in the prefix string.
 * The prefix must not have been already declared locally.
 *
 * @param element		the element node
 * @param prefix		the shorthand prefix for the namespace
 * @param uri			the namespace URI
 */
void
xnode_add_namespace(xnode_t *element, const char *prefix, const char *uri)
{
	size_t uri_len;

	xnode_check(element);
	g_assert(XNODE_T_ELEMENT == element->type);
	g_assert(prefix != NULL);
	g_assert(uri != NULL);
	g_assert(NULL == strchr(prefix, ':'));

	if (NULL == element->u.e.ns)
		element->u.e.ns = nv_table_make(TRUE);

	/* Prefix must not be redeclared in the same element */
	g_assert(NULL == nv_table_lookup(element->u.e.ns, prefix));

	uri_len = strlen(uri);
	nv_table_insert(element->u.e.ns, prefix, uri, uri_len + 1);
}
コード例 #2
0
/**
 * Successful SOAP RPC reply callback.
 *
 * @param sr	the SOAP RPC request
 * @param root	XML tree of SOAP reply
 * @param arg	the UPnP control request
 */
static void
upnp_ctrl_soap_reply(const soap_rpc_t *sr, xnode_t *root, void *arg)
{
	upnp_ctrl_t *ucd = arg;
	xnode_t *xn;
	nv_table_t *nvt;
	void *reply;
	size_t reply_len;
	host_addr_t local_addr;
	int code;

	upnp_ctrl_check(ucd);

	if (GNET_PROPERTY(upnp_debug) > 1) {
		g_debug("UPNP got SOAP reply for %s", ucd->action);

		if (GNET_PROPERTY(upnp_debug) > 2)
			xfmt_tree_dump(root, stderr);
	}

	ucd->sr = NULL;		/* Done with SOAP request */

	if (soap_rpc_local_addr(sr, &local_addr))
		upnp_set_local_addr(local_addr);

	/*
	 * Decompile the returned values.
	 *
	 * <u:actionResponse xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
	 *	 <arg1>out value1</arg1>
	 *	 <arg2>out value2</arg2>
	 *       :  :  :  :
	 *   <argn>out valuen</argn>
	 * </u:actionResponse>
	 *
	 * Values are inserted in name / value pairs: "arg1" -> "out value 1" and
	 * given to the launch callback for extracting and decompiling the values.
	 */

	nvt = nv_table_make(TRUE);

	for (xn = xnode_first_child(root); xn; xn = xnode_next_sibling(xn)) {
		nv_pair_t *nv;
		xnode_t *xt;

		if (!xnode_is_element(xn)) {
			if (GNET_PROPERTY(upnp_debug)) {
				g_warning("UPNP \"%s\" skipping XML node %s",
					ucd->action, xnode_to_string(xn));
			}
			continue;
		}

		xt = xnode_first_child(xn);

		if (NULL == xt || !xnode_is_text(xt)) {
			if (GNET_PROPERTY(upnp_debug)) {
				g_warning("UPNP \"%s\" bad child node %s in %s",
					ucd->action, xnode_to_string(xt), xnode_to_string2(xn));
			}
		} else {
			/*
			 * Name/value strings point in the tree, which is going to be
			 * alive for the duration of the processing, so we can use the
			 * strings without copying them.
			 */

			nv = nv_pair_make_static_str(
				xnode_element_name(xn), xnode_text(xt));

			nv_table_insert_pair(nvt, nv);

			if (xnode_next_sibling(xt) != NULL) {
				if (GNET_PROPERTY(upnp_debug)) {
					g_warning("UPNP \"%s\" content of %s is not pure text",
						ucd->action, xnode_to_string(xt));
				}
			}
		}
	}

	/*
	 * Attempt to decompile the replied values, if any are expected.
	 *
	 * Allocated data is done via walloc(), and the returned structure is flat.
	 * It will be freed after invoking the user callback.
	 */

	if (ucd->lcb != NULL) {
		reply = (*ucd->lcb)(nvt, &reply_len);
		code = NULL == reply ? UPNP_ERR_OK : UPNP_ERR_BAD_REPLY;
	} else {
		code = UPNP_ERR_OK;
		reply = NULL;
		reply_len = 0;
	}

	/*
	 * Let UPnP control invoker know about the result of the query.
	 */

	(*ucd->cb)(code, reply, reply_len, ucd->cb_arg);

	/*
	 * Done, final cleanup.
	 */

	WFREE_NULL(reply, reply_len);
	nv_table_free(nvt);
	upnp_ctrl_free(ucd);
}
コード例 #3
0
/**
 * Extended XML formatting of a tree.
 *
 * Namespaces, if any, are automatically assigned a prefix, whose format
 * is "ns%u", the counter being incremented from 0.
 *
 * Users can supply a vector mapping namespaces to prefixes, so that they
 * can force specific prefixes for a given well-known namespace.
 *
 * If there is a default namespace, all the tags belonging to that namespace
 * are emitted without any prefix.
 *
 * The output stream must be explicitly closed by the user upon return.
 *
 * Options can be supplied to tune the output:
 *
 * - XFMT_O_SKIP_BLANKS will skip pure white space nodes.
 * - XFMT_O_COLLAPSE_BLANKS will replace consecutive blanks with 1 space
 * - XFMT_O_NO_INDENT requests that no indentation of the tree be made.
 * - XFMT_O_PROLOGUE emits a leading <?xml?> prologue.
 * - XFMT_O_FORCE_10 force generation of XML 1.0
 * - XFMT_O_SINGLE_LINE emits XML as one big line (implies XFMT_O_NO_INDENT).
 *
 * @param root			the root of the tree to dump
 * @param os			the output stream where tree is dumped
 * @param options		formatting options, as documented above
 * @param pvec			a vector of prefixes to be used for namespaces
 * @param pvcnt			amount of entries in vector
 * @param default_ns	default namespace to install at root element
 *
 * @return TRUE on success.
 */
bool
xfmt_tree_extended(const xnode_t *root, ostream_t *os, uint32 options,
                   const struct xfmt_prefix *pvec, size_t pvcnt, const char *default_ns)
{
    struct xfmt_pass1 xp1;
    struct xfmt_pass2 xp2;
    struct xfmt_invert_ctx ictx;
    const char *dflt_ns;

    g_assert(root != NULL);
    g_assert(os != NULL);

    if (options & XFMT_O_COLLAPSE_BLANKS) {
        /* FIXME */
        g_carp("XFMT_O_COLLAPSE_BLANKS not supported yet");
        stacktrace_where_print(stderr);
    }

    if (options & XFMT_O_SINGLE_LINE)
        options |= XFMT_O_NO_INDENT;

    /*
     * First pass: look at namespaces and construct a table recording the
     * earliest tree depth at which a namespace is used.
     */

    ZERO(&xp1);
    xp1.uri2node = htable_create(HASH_KEY_STRING, 0);
    xp1.uri2prefix = nv_table_make(FALSE);

    if (default_ns != NULL)
        xp1.attr_uris = hset_create(HASH_KEY_STRING, 0);

    htable_insert_const(xp1.uri2node, VXS_XML_URI, root);

    xnode_tree_enter_leave(deconstify_pointer(root),
                           xfmt_handle_pass1_enter, xfmt_handle_pass1_leave, &xp1);

    g_assert(0 == xp1.depth);		/* Sound traversal */

    /*
     * If there was a default namespace, make sure it is used in the tree.
     * Otherwise, discard it.
     */

    if (default_ns != NULL) {
        if (NULL == htable_lookup(xp1.uri2node, default_ns)) {
            g_carp("XFMT default namespace '%s' is not needed", default_ns);
            dflt_ns = NULL;
        } else {
            dflt_ns = default_ns;
        }
    } else {
        dflt_ns = NULL;
    }

    /*
     * Prepare context for second pass.
     */

    ZERO(&xp2);
    xp2.node2uri = htable_create(HASH_KEY_SELF, 0);
    xp2.os = os;
    xp2.options = options;
    xp2.default_ns = dflt_ns;
    xp2.attr_uris = xp1.attr_uris;
    xp2.uri2prefix = xp1.uri2prefix;
    xp2.uris = symtab_make();
    xp2.prefixes = symtab_make();
    xp2.depth = 0;
    xp2.pcount = 0;
    xp2.last_was_nl = TRUE;

    /*
     * Iterate over the hash table we've built to create a table indexed
     * by tree node and listing the namespaces to declare for that node.
     */

    ictx.uri2node = xp1.uri2node;
    ictx.node2uri = xp2.node2uri;

    htable_foreach(xp1.uri2node, xfmt_invert_uri_kv, &ictx);
    htable_free_null(&xp1.uri2node);

    /*
     * Emit prologue if requested.
     */

    if (options & XFMT_O_PROLOGUE) {
        if (options & XFMT_O_FORCE_10) {
            ostream_write(os, XFMT_DECL_10, CONST_STRLEN(XFMT_DECL_10));
        } else {
            ostream_write(os, XFMT_DECL, CONST_STRLEN(XFMT_DECL));
        }
        if (!(options & XFMT_O_SINGLE_LINE)) {
            ostream_putc(os, '\n');
        }
    }

    xfmt_prefix_declare(&xp2, VXS_XML_URI, VXS_XML);

    /*
     * Prepare user-defined URI -> prefix mappings.
     */

    if (pvcnt != 0) {
        size_t i;

        for (i = 0; i < pvcnt; i++) {
            const struct xfmt_prefix *p = &pvec[i];

            xfmt_prefix_declare(&xp2, p->uri, p->prefix);
        }
    }

    /*
     * Second pass: generation.
     */

    xnode_tree_enter_leave(deconstify_pointer(root),
                           xfmt_handle_pass2_enter, xfmt_handle_pass2_leave, &xp2);

    g_assert(0 == xp2.depth);		/* Sound traversal */

    /*
     * Done, cleanup.
     */

    nv_table_free_null(&xp2.uri2prefix);
    symtab_free_null(&xp2.prefixes);
    symtab_free_null(&xp2.uris);
    htable_free_null(&xp2.node2uri);
    hset_free_null(&xp2.attr_uris);

    return !ostream_has_ioerr(os);
}