diff options
Diffstat (limited to 'src/raptor_namespace.c')
-rw-r--r-- | src/raptor_namespace.c | 1160 |
1 files changed, 1160 insertions, 0 deletions
diff --git a/src/raptor_namespace.c b/src/raptor_namespace.c new file mode 100644 index 0000000..20c769e --- /dev/null +++ b/src/raptor_namespace.c @@ -0,0 +1,1160 @@ +/* -*- Mode: c; c-basic-offset: 2 -*- + * + * raptor_namespace.c - Raptor XML namespace classes + * + * Copyright (C) 2002-2009, David Beckett http://www.dajobe.org/ + * Copyright (C) 2002-2005, University of Bristol, UK http://www.bristol.ac.uk/ + * + * This package is Free Software and part of Redland http://librdf.org/ + * + * It is licensed under the following three licenses as alternatives: + * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version + * 2. GNU General Public License (GPL) V2 or any newer version + * 3. Apache License, V2.0 or any newer version + * + * You may not use this file except in compliance with at least one of + * the above three licenses. + * + * See LICENSE.html or LICENSE.txt at the top of this package for the + * complete terms and further detail along with the license texts for + * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively. + * + * + */ + + +#ifdef HAVE_CONFIG_H +#include <raptor_config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Raptor includes */ +#include "raptor2.h" +#include "raptor_internal.h" + + +/* Define these for far too much output */ +#undef RAPTOR_DEBUG_VERBOSE + + +/* + * Namespaces in XML + * http://www.w3.org/TR/1999/REC-xml-names-19990114/#nsc-NSDeclared + * (section 4) says: + * + * -------------------------------------------------------------------- + * The prefix xml is by definition bound to the namespace name + * http://www.w3.org/XML/1998/namespace + * -------------------------------------------------------------------- + * + * Errata NE05 + * http://www.w3.org/XML/xml-names-19990114-errata#NE05 + * changes that to read: + * + * -------------------------------------------------------------------- + * The prefix xml is by definition bound to the namespace name + * http://www.w3.org/XML/1998/namespace. It may, but need not, be + * declared, and must not be bound to any other namespace name. No + * other prefix may be bound to this namespace name. + * + * The prefix xmlns is used only to declare namespace bindings and is + * by definition bound to the namespace name + * http://www.w3.org/2000/xmlns/. It must not be declared. No other + * prefix may be bound to this namespace name. + * + * All other prefixes beginning with the three-letter sequence x, m, l, + * in any case combination, are reserved. This means that + * * users should not use them except as defined by later specifications + * * processors must not treat them as fatal errors. + * -------------------------------------------------------------------- + * + * Thus should define it in the table of namespaces before we start. + * + * We *can* also define others, but let's not. + * + */ + +#ifndef STANDALONE +const unsigned char * const raptor_xml_namespace_uri = (const unsigned char *)"http://www.w3.org/XML/1998/namespace"; +const unsigned char * const raptor_rdf_namespace_uri = (const unsigned char *)"http://www.w3.org/1999/02/22-rdf-syntax-ns#"; +const unsigned int raptor_rdf_namespace_uri_len = 43; +const unsigned char * const raptor_rdf_schema_namespace_uri = (const unsigned char *)"http://www.w3.org/2000/01/rdf-schema#"; +const unsigned int raptor_rdf_schema_namespace_uri_len = 37; +const unsigned char * const raptor_xmlschema_datatypes_namespace_uri = (const unsigned char *)"http://www.w3.org/2001/XMLSchema#"; +const unsigned char * const raptor_owl_namespace_uri = (const unsigned char *)"http://www.w3.org/2002/07/owl#"; + + +/* hash function to hash namespace prefix strings (usually short strings) + * + * Uses DJ Bernstein original hash function - good on short text keys. + */ +static unsigned int +raptor_hash_ns_string(const unsigned char *str, int length) +{ + unsigned int hash = 5381; + int c; + + for(; length && (c = *str++); length--) { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + + return hash; +} + + +#define RAPTOR_NAMESPACES_HASHTABLE_SIZE 1024 +/** + * raptor_namespaces_init: + * @world: raptor_world object + * @nstack: #raptor_namespace_stack to initialise + * @defaults: namespaces to initialise. + * + * Initialise an existing namespaces stack object + * + * This sets up the stack optionally with some common RDF namespaces. + * + * @defaults can be 0 for none, 1 for just XML, 2 for RDF, RDFS, OWL + * and XSD (RDQL uses this) or 3+ undefined. + * + * Return value: non-0 on error + */ +int +raptor_namespaces_init(raptor_world* world, + raptor_namespace_stack *nstack, + int defaults) +{ + int failures = 0; + + nstack->world = world; + + nstack->size = 0; + + nstack->table_size = RAPTOR_NAMESPACES_HASHTABLE_SIZE; + nstack->table = RAPTOR_CALLOC(raptor_namespace**, + RAPTOR_NAMESPACES_HASHTABLE_SIZE, + sizeof(raptor_namespace*)); + if(!nstack->table) + return -1; + + nstack->def_namespace = NULL; + + nstack->rdf_ms_uri = raptor_new_uri_from_counted_string(nstack->world, + (const unsigned char*)raptor_rdf_namespace_uri, + raptor_rdf_namespace_uri_len); + failures += !nstack->rdf_ms_uri; + + nstack->rdf_schema_uri = raptor_new_uri_from_counted_string(nstack->world, + (const unsigned char*)raptor_rdf_schema_namespace_uri, + raptor_rdf_schema_namespace_uri_len); + failures += !nstack->rdf_schema_uri; + + /* raptor_new_namespace_from_uri() that eventually gets called by + * raptor_new_namespace() in raptor_namespaces_start_namespace_full() + * needs rdf_ms_uri and rdf_schema_uri + * - do not call if we had failures initializing those uris */ + if(defaults && !failures) { + /* defined at level -1 since always 'present' when inside the XML world */ + failures += raptor_namespaces_start_namespace_full(nstack, + (const unsigned char*)"xml", + raptor_xml_namespace_uri, -1); + if(defaults >= 2) { + failures += raptor_namespaces_start_namespace_full(nstack, + (const unsigned char*)"rdf", + raptor_rdf_namespace_uri, 0); + failures += raptor_namespaces_start_namespace_full(nstack, + (const unsigned char*)"rdfs", + raptor_rdf_schema_namespace_uri, 0); + failures += raptor_namespaces_start_namespace_full(nstack, + (const unsigned char*)"xsd", + raptor_xmlschema_datatypes_namespace_uri, 0); + failures += raptor_namespaces_start_namespace_full(nstack, + (const unsigned char*)"owl", + raptor_owl_namespace_uri, 0); + } + } + return failures; +} + + +/** + * raptor_new_namespaces: + * @world: raptor_world object + * @defaults: namespaces to initialise + * + * Constructor - create a new #raptor_namespace_stack. + * + * See raptor_namespaces_init() for the values of @defaults. + * + * Return value: a new namespace stack or NULL on failure + **/ +raptor_namespace_stack * +raptor_new_namespaces(raptor_world* world, int defaults) +{ + raptor_namespace_stack *nstack; + + RAPTOR_CHECK_CONSTRUCTOR_WORLD(world); + + raptor_world_open(world); + + nstack = RAPTOR_CALLOC(raptor_namespace_stack*, 1, sizeof(*nstack)); + if(!nstack) + return NULL; + + if(raptor_namespaces_init(world, nstack, defaults)) { + raptor_free_namespaces(nstack); + nstack = NULL; + } + + return nstack; +} + + +/** + * raptor_namespaces_start_namespace: + * @nstack: namespace stack + * @nspace: namespace to start + * + * Start a namespace on a stack of namespaces. + **/ +void +raptor_namespaces_start_namespace(raptor_namespace_stack *nstack, + raptor_namespace *nspace) +{ + unsigned int hash = raptor_hash_ns_string(nspace->prefix, + nspace->prefix_length); + const int bucket = hash % nstack->table_size; + + nstack->size++; + + if(nstack->table[bucket]) + nspace->next = nstack->table[bucket]; + nstack->table[bucket] = nspace; + + if(!nstack->def_namespace) + nstack->def_namespace = nspace; + +#ifndef STANDALONE +#ifdef RAPTOR_DEBUG_VERBOSE + RAPTOR_DEBUG3("start namespace prefix %s depth %d\n", nspace->prefix ? (char*)nspace->prefix : "(default)", nspace->depth); +#endif +#endif + +} + + +/** + * raptor_namespaces_start_namespace_full: + * @nstack: namespace stack + * @prefix: new namespace prefix (or NULL) + * @ns_uri_string: new namespace URI (or NULL) + * @depth: new namespace depth + * + * Create a new namespace and start it on a stack of namespaces. + * + * See raptor_new_namespace() for the meanings of @prefix, + * @ns_uri_string and @depth for namespaces. + * + * Return value: non-0 on failure + **/ +int +raptor_namespaces_start_namespace_full(raptor_namespace_stack *nstack, + const unsigned char *prefix, + const unsigned char *ns_uri_string, + int depth) +{ + raptor_namespace *ns; + + ns = raptor_new_namespace(nstack, prefix, ns_uri_string, depth); + if(!ns) + return 1; + + raptor_namespaces_start_namespace(nstack, ns); + return 0; +} + + +/** + * raptor_namespaces_clear: + * @nstack: namespace stack + * + * Empty a namespace stack of namespaces and any other resources. + **/ +void +raptor_namespaces_clear(raptor_namespace_stack *nstack) +{ + if(nstack->table) { + int bucket; + + for(bucket = 0; bucket < nstack->table_size; bucket++) { + raptor_namespace *ns = nstack->table[bucket]; + while(ns) { + raptor_namespace* next_ns = ns->next; + + raptor_free_namespace(ns); + nstack->size--; + ns = next_ns; + } + nstack->table[bucket] = NULL; + } + + RAPTOR_FREE(raptor_namespaces, nstack->table); + nstack->table = NULL; + nstack->table_size = 0; + } + + if(nstack->world) { + if(nstack->rdf_ms_uri) { + raptor_free_uri(nstack->rdf_ms_uri); + nstack->rdf_ms_uri = NULL; + } + if(nstack->rdf_schema_uri) { + raptor_free_uri(nstack->rdf_schema_uri); + nstack->rdf_schema_uri = NULL; + } + } + + nstack->size = 0; + + nstack->world = NULL; +} + + +/** + * raptor_free_namespaces: + * @nstack: namespace stack + * + * Destructor - destroy a namespace stack + **/ +void +raptor_free_namespaces(raptor_namespace_stack *nstack) +{ + if(!nstack) + return; + + raptor_namespaces_clear(nstack); + + RAPTOR_FREE(raptor_namespace_stack, nstack); +} + + +/** + * raptor_namespaces_end_for_depth: + * @nstack: namespace stack + * @depth: depth + * + * End all namespaces at the given depth in the namespace stack. + **/ +void +raptor_namespaces_end_for_depth(raptor_namespace_stack *nstack, int depth) +{ + int bucket; + for(bucket = 0; bucket < nstack->table_size; bucket++) { + while(nstack->table[bucket] && + nstack->table[bucket]->depth == depth) { + raptor_namespace* ns = nstack->table[bucket]; + raptor_namespace* next_ns = ns->next; + +#ifndef STANDALONE +#ifdef RAPTOR_DEBUG_VERBOSE + RAPTOR_DEBUG3("namespace prefix %s depth %d\n", + ns->prefix ? (char*)ns->prefix : "(default)", depth); +#endif +#endif + raptor_free_namespace(ns); + nstack->size--; + + nstack->table[bucket] = next_ns; + } + } +} + + +/** + * raptor_namespaces_get_default_namespace: + * @nstack: namespace stack + * + * Get the current default namespace in-scope in a stack. + * + * Return value: #raptor_namespace or NULL if no default namespace is in scope + **/ +raptor_namespace* +raptor_namespaces_get_default_namespace(raptor_namespace_stack *nstack) +{ + unsigned int hash = raptor_hash_ns_string((const unsigned char *)"", 0); + const int bucket = hash % nstack->table_size; + raptor_namespace* ns; + + for(ns = nstack->table[bucket]; ns && ns->prefix; ns = ns->next) + ; + return ns; +} + + +/** + * raptor_namespaces_find_namespace: + * @nstack: namespace stack + * @prefix: namespace prefix to find + * @prefix_length: length of prefix. + * + * Find a namespace in a namespace stack by prefix. + * + * Note that this uses the @length so that the prefix may be a prefix (sic) + * of a longer string. If @prefix is NULL, the default namespace will + * be returned if present, @prefix_length length is ignored in this case. + * + * Return value: #raptor_namespace for the prefix or NULL on failure + **/ +raptor_namespace* +raptor_namespaces_find_namespace(raptor_namespace_stack *nstack, + const unsigned char *prefix, int prefix_length) +{ + raptor_namespace* ns; + unsigned int hash = raptor_hash_ns_string(prefix, prefix_length); + int bucket; + + if(!nstack || !nstack->table_size) + return NULL; + + bucket = hash % (nstack->table_size); + for(ns = nstack->table[bucket]; ns ; ns = ns->next) { + if(!prefix) { + if(!ns->prefix) + break; + } else { + if((unsigned int)prefix_length == ns->prefix_length && + !strncmp((char*)prefix, (char*)ns->prefix, prefix_length)) + break; + } + } + + return ns; +} + + +/** + * raptor_namespaces_find_namespace_by_uri: + * @nstack: namespace stack + * @ns_uri: namespace URI to find + * + * Find a namespace in a namespace stack by namespace URI. + * + * Return value: #raptor_namespace for the URI or NULL on failure + **/ +raptor_namespace* +raptor_namespaces_find_namespace_by_uri(raptor_namespace_stack *nstack, + raptor_uri *ns_uri) +{ + int bucket; + + if(!ns_uri) + return NULL; + + for(bucket = 0; bucket < nstack->table_size; bucket++) { + raptor_namespace* ns; + for(ns = nstack->table[bucket]; ns ; ns = ns->next) + if(raptor_uri_equals(ns->uri, ns_uri)) + return ns; + } + + return NULL; +} + + +/** + * raptor_namespaces_namespace_in_scope: + * @nstack: namespace stack + * @nspace: namespace + * + * Test if a given namespace is in-scope in the namespace stack. + * + * Return value: non-0 if the namespace is in scope. + **/ +int +raptor_namespaces_namespace_in_scope(raptor_namespace_stack *nstack, + const raptor_namespace *nspace) +{ + raptor_namespace* ns; + int bucket; + + for(bucket = 0; bucket < nstack->table_size; bucket++) { + for(ns = nstack->table[bucket]; ns ; ns = ns->next) + if(raptor_uri_equals(ns->uri, nspace->uri)) + return 1; + } + return 0; +} + + +/** + * raptor_new_namespace_from_uri: + * @nstack: namespace stack + * @prefix: namespace prefix string + * @ns_uri: namespace URI + * @depth: depth of namespace in the stack + * + * Constructor - create a new namespace from a prefix and URI object. + * + * This declares but does not enable the namespace declaration (or 'start' it) + * Use raptor_namespaces_start_namespace() to make the namespace + * enabled and in scope for binding prefixes. + * + * Alternatively use raptor_namespaces_start_namespace_full() can construct + * and enable a namespace in one call. + * + * Return value: a new #raptor_namespace or NULL on failure + **/ +raptor_namespace* +raptor_new_namespace_from_uri(raptor_namespace_stack *nstack, + const unsigned char *prefix, + raptor_uri* ns_uri, int depth) +{ + unsigned int prefix_length = 0; + unsigned int len; + raptor_namespace *ns; + unsigned char *p; + +#ifndef STANDALONE +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + RAPTOR_DEBUG4("namespace prefix %s uri %s depth %d\n", + prefix ? (char*)prefix : "(default)", + ns_uri ? (char*)raptor_uri_as_string(ns_uri) : "(none)", + depth); +#endif +#endif + + if(prefix && !ns_uri) { + /* failed to find namespace - now what? */ + raptor_log_error_formatted(nstack->world, RAPTOR_LOG_LEVEL_ERROR, + /* locator */ NULL, + "The namespace URI for prefix \"%s\" is empty.", + prefix); + return NULL; + } + + + len = sizeof(raptor_namespace); + if(prefix) { + prefix_length = (unsigned int)strlen((char*)prefix); + len += prefix_length + 1; + } + + /* Just one malloc for structure + namespace (maybe) + prefix (maybe)*/ + ns = RAPTOR_CALLOC(raptor_namespace*, 1, len); + if(!ns) + return NULL; + + p = (unsigned char*)ns + sizeof(raptor_namespace); + if(ns_uri) { + ns->uri = raptor_uri_copy(ns_uri); + if(!ns->uri) { + RAPTOR_FREE(raptor_namespace, ns); + return NULL; + } + } + if(prefix) { + ns->prefix = (const unsigned char*)memcpy(p, prefix, prefix_length + 1); + ns->prefix_length = prefix_length; + + if(!strcmp((char*)ns->prefix, "xml")) + ns->is_xml = 1; + } + ns->depth = depth; + + /* set convienience flags when there is a defined namespace URI */ + if(ns->uri) { + if(raptor_uri_equals(ns->uri, nstack->rdf_ms_uri)) + ns->is_rdf_ms = 1; + else if(raptor_uri_equals(ns->uri, nstack->rdf_schema_uri)) + ns->is_rdf_schema = 1; + } + + ns->nstack = nstack; + + return ns; +} + + +/** + * raptor_new_namespace: + * @nstack: namespace stack + * @prefix: namespace prefix string + * @ns_uri_string: namespace URI string + * @depth: depth of namespace in the stack + * + * Constructor - create a new namespace from a prefix and URI string with a depth scope. + * + * This declares but does not enable the namespace declaration (or 'start' it) + * Use raptor_namespaces_start_namespace() to make the namespace + * enabled and in scope for binding prefixes. + * + * Alternatively use raptor_namespaces_start_namespace_full() can construct + * and enable a namespace in one call. + * + * The @depth is a way to use the stack of namespaces for providing scoped + * namespaces where inner scope namespaces override outer scope namespaces. + * This is primarily for RDF/XML and XML syntaxes that have hierarchical + * elements. The main use of this is raptor_namespaces_end_for_depth() + * to disable ('end') all namespaces at a given depth. Otherwise set this + * to 0. + * + * Return value: a new #raptor_namespace or NULL on failure + **/ +raptor_namespace* +raptor_new_namespace(raptor_namespace_stack *nstack, + const unsigned char *prefix, + const unsigned char *ns_uri_string, int depth) +{ + raptor_uri* ns_uri = NULL; + raptor_namespace* ns; + + /* Convert an empty namespace string "" to a NULL pointer */ + if(ns_uri_string && !*ns_uri_string) + ns_uri_string = NULL; + + if(ns_uri_string) { + ns_uri = raptor_new_uri(nstack->world, ns_uri_string); + if(!ns_uri) + return NULL; + } + ns = raptor_new_namespace_from_uri(nstack, prefix, ns_uri, depth); + if(ns_uri) + raptor_free_uri(ns_uri); + + return ns; +} + + +/** + * raptor_namespace_stack_start_namespace: + * @nstack: namespace stack + * @ns: namespace + * @new_depth: new depth + * + * Copy an existing namespace to a namespace stack with a new depth + * and start it. + * + * The @depth is a way to use the stack of namespaces for providing scoped + * namespaces where inner scope namespaces override outer scope namespaces. + * This is primarily for RDF/XML and XML syntaxes that have hierarchical + * elements. The main use of this is raptor_namespaces_end_for_depth() + * to disable ('end') all namespaces at a given depth. If depths are + * not being needed it is unlikely this call is ever needed to copy an + * existing namespace at a new depth. + * + * Return value: non-0 on failure + **/ +int +raptor_namespace_stack_start_namespace(raptor_namespace_stack *nstack, + raptor_namespace *ns, + int new_depth) +{ + raptor_namespace *new_ns; + + RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(nstack, raptor_namespace_stack, 1); + RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(ns, raptor_namespace, 1); + + new_ns = raptor_new_namespace_from_uri(nstack, ns->prefix, ns->uri, new_depth); + if(!new_ns) + return 1; + + raptor_namespaces_start_namespace(nstack, new_ns); + return 0; +} + + +/** + * raptor_free_namespace: + * @ns: namespace object + * + * Destructor - destroy a namespace. + **/ +void +raptor_free_namespace(raptor_namespace *ns) +{ + if(!ns) + return; + + if(ns->uri) + raptor_free_uri(ns->uri); + + RAPTOR_FREE(raptor_namespace, ns); +} + + +/** + * raptor_namespace_get_uri: + * @ns: namespace object + * + * Get the namespace URI. + * + * Return value: namespace URI or NULL + **/ +raptor_uri* +raptor_namespace_get_uri(const raptor_namespace *ns) +{ + return ns->uri; +} + + +/** + * raptor_namespace_get_prefix: + * @ns: namespace object + * + * Get the namespace prefix. + * + * Return value: prefix string or NULL + **/ +const unsigned char* +raptor_namespace_get_prefix(const raptor_namespace *ns) +{ + return (const unsigned char*)ns->prefix; +} + + +/** + * raptor_namespace_get_counted_prefix: + * @ns: namespace object + * @length_p: pointer to store length or NULL + * + * Get the namespace prefix and length. + * + * Return value: prefix string or NULL + **/ +const unsigned char* +raptor_namespace_get_counted_prefix(const raptor_namespace *ns, size_t *length_p) +{ + if(length_p) + *length_p=ns->prefix_length; + return (const unsigned char*)ns->prefix; +} + + +/** + * raptor_namespace_format_as_xml: + * @ns: namespace object + * @length_p: pointer to length (or NULL) + * + * Format a namespace in an XML style into a newly allocated string. + * + * Generates a string of the form xmlns:prefix="uri", + * xmlns="uri", xmlns:prefix="" or xmlns="" depending on the + * namespace's prefix or URI. Double quotes are always used. + * + * If @length_p is not NULL, the length of the string is + * stored in the address it points to. + * + * See also raptor_xml_namespace_string_parse() + * + * Return value: namespace formatted as newly allocated string or NULL on failure + **/ +unsigned char * +raptor_namespace_format_as_xml(const raptor_namespace *ns, size_t *length_p) +{ + size_t uri_length = 0L; + const unsigned char *uri_string = NULL; + size_t xml_uri_length = 0L; + size_t length; + unsigned char *buffer; + const char quote='"'; + unsigned char *p; + + if(ns->uri) { + int xlength; + + uri_string = raptor_uri_as_counted_string(ns->uri, &uri_length); + xlength = raptor_xml_escape_string(ns->nstack->world, + uri_string, uri_length, + NULL, 0, quote); + if(xlength < 0) + return NULL; + xml_uri_length = RAPTOR_GOOD_CAST(size_t, xlength); + } + + /* 8 = length of [[xmlns=""] */ + length = 8 + xml_uri_length + ns->prefix_length; + + if(ns->prefix) + length++; /* for : */ + + if(length_p) + *length_p = length; + + buffer = RAPTOR_MALLOC(unsigned char*, length + 1); + if(!buffer) + return NULL; + + p = buffer; + + memcpy(p, "xmlns", 5); + p += 5; + + if(ns->prefix) { + *p++ = ':'; + memcpy(p, ns->prefix, ns->prefix_length); + p += ns->prefix_length; + } + *p++ = '='; + *p++ = quote; + if(uri_length) { + int xlength; + + xlength = raptor_xml_escape_string(ns->nstack->world, + uri_string, uri_length, + p, xml_uri_length, quote); + if(xlength < 0) + return NULL; + p += RAPTOR_GOOD_CAST(size_t, xlength); + } + *p++ = quote; + /* *p used here since we never need to use value of p again [CLANG] */ + *p = '\0'; + + return buffer; +} + + +/** + * raptor_namespace_write: + * @ns: namespace to write + * @iostr: raptor iosteram + * + * Write a formatted namespace to an iostream + * + * Return value: non-0 on failure + **/ +int +raptor_namespace_write(raptor_namespace *ns, raptor_iostream* iostr) +{ + size_t uri_length = 0L; + const unsigned char *uri_string = NULL; + + if(!ns || !iostr) + return 1; + + if(ns->uri) + uri_string = raptor_uri_as_counted_string(ns->uri, &uri_length); + + raptor_iostream_counted_string_write("xmlns", 5, iostr); + if(ns->prefix) { + raptor_iostream_write_byte(':', iostr); + raptor_iostream_string_write(ns->prefix, iostr); + } + raptor_iostream_counted_string_write("=\"", 2, iostr); + if(uri_length) + raptor_iostream_counted_string_write(uri_string, uri_length, iostr); + raptor_iostream_write_byte('"', iostr); + + return 0; +} + + +/** + * raptor_xml_namespace_string_parse: + * @string: string to parse + * @prefix: pointer to location to store namespace prefix + * @uri_string: pointer to location to store namespace URI + * + * Parse a string containing an XML style namespace declaration + * into a namespace prefix and URI pair. + * + * The string is of the form xmlns:prefix="uri", + * xmlns="uri", xmlns:prefix="" or xmlns="". + * The quotes can be single or double quotes. + * + * Two values are returned from this function into *@prefix and + * *@uri_string. Either but not both may be NULL. + * + * See also raptor_namespace_format_as_xml() + * + * Return value: non-0 on failure. + **/ +int +raptor_xml_namespace_string_parse(const unsigned char *string, + unsigned char **prefix, + unsigned char **uri_string) +{ + const unsigned char *t; + unsigned char quote; + + if((!prefix || !uri_string)) + return 1; + + if(!string || (string && !*string)) + return 1; + + if(strncmp((const char*)string, "xmlns", 5)) + return 1; + + *prefix = NULL; + *uri_string = NULL; + + /* + * Four cases are expected and handled: + * xmlns="" + * xmlns="uri" + * xmlns:foo="" + * xmlns:foo="uri" + * + * (with " or ' quotes) + */ + + /* skip "xmlns" */ + string += 5; + + if(*string == ':') { + /* non-empty prefix */ + t = ++string; + while(*string && *string != '=') + string++; + if(!*string || string == t) + return 1; + + *prefix = RAPTOR_MALLOC(unsigned char*, string - t + 1); + if(!*prefix) + return 1; + memcpy(*prefix, t, string - t); + (*prefix)[string-t] = '\0'; + } + + if(*string++ != '=') + return 1; + + if(*string != '"' && *string != '\'') + return 1; + quote = *string++; + + t = string; + while(*string && *string != quote) + string++; + + if(*string != quote) + return 1; + + if(!(string - t)) + /* xmlns...="" */ + *uri_string = NULL; + else { + *uri_string = RAPTOR_MALLOC(unsigned char*, string - t + 1); + if(!*uri_string) + return 1; + memcpy(*uri_string, t, string - t); + (*uri_string)[string - t] = '\0'; + } + + return 0; +} + + +/** + * raptor_new_qname_from_namespace_uri: + * @nstack: namespace stack + * @uri: URI to use to make qname + * @xml_version: XML Version + * + * Make an appropriate XML Qname from the namespaces on a namespace stack + * + * Makes a qname from the in-scope namespaces in a stack if the URI matches + * the prefix and the rest is a legal XML name. + * + * Return value: #raptor_qname for the URI or NULL on failure + **/ +raptor_qname* +raptor_new_qname_from_namespace_uri(raptor_namespace_stack *nstack, + raptor_uri *uri, int xml_version) +{ + unsigned char *uri_string; + size_t uri_len; + raptor_namespace* ns = NULL; + unsigned char *ns_uri_string; + size_t ns_uri_len; + unsigned char *name = NULL; + int bucket; + + if(!uri) + return NULL; + + uri_string = raptor_uri_as_counted_string(uri, &uri_len); + + for(bucket = 0; bucket < nstack->table_size; bucket++) { + for(ns = nstack->table[bucket]; ns ; ns = ns->next) { + if(!ns->uri) + continue; + + ns_uri_string = raptor_uri_as_counted_string(ns->uri, + &ns_uri_len); + if(ns_uri_len >= uri_len) + continue; + if(strncmp((const char*)uri_string, (const char*)ns_uri_string, + ns_uri_len)) + continue; + + /* uri_string is a prefix of ns_uri_string */ + name = uri_string + ns_uri_len; + if(!raptor_xml_name_check(name, uri_len-ns_uri_len, xml_version)) + name = NULL; + + /* If name is set, we've found a prefix with a legal XML name value */ + if(name) + break; + } + if(name) + break; + } + + if(!ns) + return NULL; + + return raptor_new_qname_from_namespace_local_name(nstack->world, ns, + name, NULL); +} + + +#ifdef RAPTOR_DEBUG +void +raptor_namespace_print(FILE *stream, raptor_namespace* ns) +{ + const unsigned char *uri_string; + + uri_string = raptor_uri_as_string(ns->uri); + if(ns->prefix) + fprintf(stream, "%s:%s", ns->prefix, uri_string); + else + fprintf(stream, "(default):%s", uri_string); +} +#endif + + +raptor_namespace** +raptor_namespace_stack_to_array(raptor_namespace_stack *nstack, + size_t *size_p) +{ + raptor_namespace** ns_list; + size_t size = 0; + int bucket; + + ns_list = RAPTOR_CALLOC(raptor_namespace**, nstack->size, + sizeof(raptor_namespace*)); + if(!ns_list) + return NULL; + + for(bucket = 0; bucket < nstack->table_size; bucket++) { + raptor_namespace* ns; + + for(ns = nstack->table[bucket]; ns; ns = ns->next) { + int skip = 0; + unsigned int i; + if(ns->depth < 1) + continue; + + for(i = 0; i < size; i++) { + raptor_namespace* ns2 = ns_list[i]; + if((!ns->prefix && !ns2->prefix) || + (ns->prefix && ns2->prefix && + !strcmp((const char*)ns->prefix, (const char*)ns2->prefix))) { + /* this prefix was seen (overridden) earlier so skip */ + skip = 1; + break; + } + } + if(!skip) + ns_list[size++] = ns; + } + } + + if(size_p) + *size_p = size; + + return ns_list; +} + +#endif /* !STANDALONE */ + + +#ifdef STANDALONE + + +/* one more prototype */ +int main(int argc, char *argv[]); + + +int +main(int argc, char *argv[]) +{ + raptor_world *world; + const char *program = raptor_basename(argv[0]); + raptor_namespace_stack namespaces; /* static */ + raptor_namespace* ns; + + world = raptor_new_world(); + if(!world || raptor_world_open(world)) + exit(1); + + raptor_namespaces_init(world, &namespaces, 1); + + raptor_namespaces_start_namespace_full(&namespaces, + (const unsigned char*)"ex1", + (const unsigned char*)"http://example.org/ns1", + 0); + + raptor_namespaces_start_namespace_full(&namespaces, + (const unsigned char*)"ex2", + (const unsigned char*)"http://example.org/ns2", + 1); + + if(raptor_namespaces_find_namespace(&namespaces, NULL, 0)) { + fprintf(stderr, "%s: Default namespace found when should not be found, returning error\n", + program); + return(1); + } + + raptor_namespaces_start_namespace_full(&namespaces, + NULL, + (const unsigned char*)"http://example.org/ns3", + 2); + + ns = raptor_namespaces_find_namespace(&namespaces, NULL, 0); + if(!ns) { + fprintf(stderr, "%s: Default namespace not found when should not be found, returning error\n", + program); + return(1); + } + + ns = raptor_namespaces_find_namespace(&namespaces, (const unsigned char*)"ex2", 3); + if(!ns) { + fprintf(stderr, "%s: namespace ex2 not found when should not be found, returning error\n", + program); + return(1); + } + + raptor_namespaces_end_for_depth(&namespaces, 2); + + raptor_namespaces_end_for_depth(&namespaces, 1); + + raptor_namespaces_end_for_depth(&namespaces, 0); + + raptor_namespaces_clear(&namespaces); + + raptor_free_world(world); + + /* keep gcc -Wall happy */ + return(0); +} + +#endif + +/* + * Local Variables: + * mode:c + * c-basic-offset: 2 + * End: + */ |