/* -*- Mode: c; c-basic-offset: 2 -*- * * raptor_uri.c - Raptor URI resolving implementation * * Copyright (C) 2002-2008, 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 #endif #ifdef WIN32 #include #endif #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_LIMITS_H #include #endif /* Raptor includes */ #include "raptor.h" #include "raptor_internal.h" #ifdef WIN32_URI_TEST #define WIN32 #endif /* Symbian OS uses similar path mappings as Windows but does not necessarily have the WIN32 flag defined */ #if defined(__SYMBIAN32__) && !defined(WIN32) #define WIN32 #endif #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_set_handler: * @handler: URI handler structure * @context: URI handler context * * Change the URI class implementation to the functions provided by the * * The URI interface in @handler->initialised should be either 1 * or 2 (if raptor_uri_compare_func is implemented). * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_set_handler_v2() if using raptor_world APIs. **/ void raptor_uri_set_handler(const raptor_uri_handler *handler, void *context) { raptor_uri_set_handler_v2(raptor_world_instance(), handler, context); } #endif /** * raptor_uri_set_handler_v2: * @world: raptor_world object * @handler: URI handler structure * @context: URI handler context * * Change the URI class implementation to the functions provided by the * * The URI interface in @handler->initialised should be either 1 * or 2 (if raptor_uri_compare_func is implemented). **/ void raptor_uri_set_handler_v2(raptor_world* world, const raptor_uri_handler *handler, void *context) { RAPTOR_ASSERT_OBJECT_POINTER_RETURN(handler, raptor_uri_handler); /* RAPTOR_ASSERT is the negative of ordinary asserts - it fails if the condition is true */ RAPTOR_ASSERT(!(handler->initialised >= 1 && handler->initialised <= 2), "raptor_uri_handler->initialised not 1..2"); world->uri_handler=handler; world->uri_handler_context=context; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_get_handler: * @handler: URI handler to return * @context: URI context to return * * Return the current raptor URI class implementation @handler and @context * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_get_handler_v2() if using raptor_world APIs. **/ void raptor_uri_get_handler(const raptor_uri_handler **handler, void **context) { raptor_uri_get_handler_v2(raptor_world_instance(), handler, context); } #endif /** * raptor_uri_get_handler_v2: * @handler: URI handler to return * @context: URI context to return * * Return the current raptor URI class implementation @handler and @context **/ void raptor_uri_get_handler_v2(raptor_world* world, const raptor_uri_handler **handler, void **context) { if(handler) *handler=world->uri_handler; if(context) *context=world->uri_handler_context; } static raptor_uri* raptor_default_new_uri(void *context, const unsigned char *uri_string) { raptor_world* world=(raptor_world*)context; unsigned char *p; size_t len; /* If uri_string is "file:path-to-file", turn it into a correct file:URI */ if(raptor_uri_uri_string_is_file_uri(uri_string)) { unsigned char *fragment=NULL; char *filename; raptor_uri* uri=NULL; filename=raptor_uri_uri_string_to_filename_fragment(uri_string, &fragment); if(filename && !access(filename, R_OK)) { uri=(raptor_uri*)raptor_uri_filename_to_uri_string(filename); /* If there was a fragment, reattach it to the new URI */ if(fragment) { unsigned char *new_fragment; raptor_uri* new_uri; new_fragment=(unsigned char*)RAPTOR_MALLOC(cstring, strlen((const char*)fragment) + 1 + sizeof(char*)); if(!new_fragment) return NULL; *new_fragment='#'; strcpy((char*)new_fragment+1, (const char*)fragment); new_uri=raptor_new_uri_relative_to_base_v2(world, uri, new_fragment); RAPTOR_FREE(cstring, new_fragment); raptor_free_uri_v2(world, uri); uri=new_uri; } } if(filename) RAPTOR_FREE(cstring, filename); if(fragment) RAPTOR_FREE(cstring, fragment); if(uri) return uri; } len=strlen((const char*)uri_string); p=(unsigned char*)RAPTOR_MALLOC(raptor_uri, len + sizeof(char*)); if(!p) return NULL; strcpy((char*)p, (const char*)uri_string); return (raptor_uri*)p; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri: * @uri_string: URI string. * * Constructor - create a raptor URI from a UTF-8 encoded Unicode string. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri(const unsigned char *uri_string) { return raptor_new_uri_v2(raptor_world_instance(), uri_string); } #endif /** * raptor_new_uri_v2: * @world: raptor_world object * @uri_string: URI string. * * Constructor - create a raptor URI from a UTF-8 encoded Unicode string. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_v2(raptor_world* world, const unsigned char *uri_string) { if(!uri_string || !*uri_string) return NULL; return (*world->uri_handler->new_uri)(world->uri_handler_context, uri_string); } static raptor_uri* raptor_default_new_uri_from_uri_local_name(void *context, raptor_uri *uri, const unsigned char *local_name) { int uri_length=strlen((char*)uri); unsigned char *p=(unsigned char*)RAPTOR_MALLOC(cstring, uri_length + strlen((const char*)local_name) + sizeof(char*)); if(!p) return NULL; strcpy((char*)p, (const char*)uri); strcpy((char*)p + uri_length, (const char*)local_name); return (raptor_uri*)p; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_from_uri_local_name: * @uri: existing #raptor_uri * @local_name: local name * * Constructor - create a raptor URI from an existing URI and a local name. * * Creates a new URI from the concatenation of the @local_name to the * @uri. This is NOT relative URI resolution, which is done by the * raptor_new_uri_relative_to_base() constructor. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_from_uri_local_name_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_from_uri_local_name(raptor_uri *uri, const unsigned char *local_name) { return raptor_new_uri_from_uri_local_name_v2(raptor_world_instance(), uri, local_name); } #endif /** * raptor_new_uri_from_uri_local_name_v2: * @world: raptor_world object * @uri: existing #raptor_uri * @local_name: local name * * Constructor - create a raptor URI from an existing URI and a local name. * * Creates a new URI from the concatenation of the @local_name to the * @uri. This is NOT relative URI resolution, which is done by the * raptor_new_uri_relative_to_base() constructor. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_from_uri_local_name_v2(raptor_world* world, raptor_uri *uri, const unsigned char *local_name) { if(!uri || !local_name) return NULL; return (*world->uri_handler->new_uri_from_uri_local_name)(world->uri_handler_context, uri, local_name); } static raptor_uri* raptor_default_new_uri_relative_to_base(void *context, raptor_uri *base_uri, const unsigned char *uri_string) { raptor_uri* new_uri; size_t new_uri_len=strlen((const char*)base_uri)+strlen((const char*)uri_string) + sizeof(char*); /* +2 is for \0 plus an extra 1 for adding any missing URI path '/' */ new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, new_uri_len+2); if(!new_uri) return NULL; /* If URI string is empty, just copy base URI */ if(!*uri_string) { strcpy((char*)new_uri, (char*)base_uri); return new_uri; } raptor_uri_resolve_uri_reference((const unsigned char*)base_uri, uri_string, (unsigned char*)new_uri, new_uri_len); return new_uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_relative_to_base: * @base_uri: existing base URI * @uri_string: relative URI string * * Constructor - create a raptor URI from a base URI and a relative URI string. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_relative_to_base_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_relative_to_base(raptor_uri *base_uri, const unsigned char *uri_string) { return raptor_new_uri_relative_to_base_v2(raptor_world_instance(), base_uri, uri_string); } #endif /** * raptor_new_uri_relative_to_base_v2: * @world: raptor_world object * @base_uri: existing base URI * @uri_string: relative URI string * * Constructor - create a raptor URI from a base URI and a relative URI string. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_relative_to_base_v2(raptor_world* world, raptor_uri *base_uri, const unsigned char *uri_string) { if(!base_uri || !uri_string) return NULL; return (*world->uri_handler->new_uri_relative_to_base)(world->uri_handler_context, base_uri, uri_string); } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_from_id: * @base_uri: existing base URI * @id: RDF ID * * Constructor - create a new URI from a base URI and RDF ID. * * This creates a URI equivalent to concatenating @base_uri with * ## and @id. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_from_id_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_from_id(raptor_uri *base_uri, const unsigned char *id) { return raptor_new_uri_from_id_v2(raptor_world_instance(), base_uri, id); } #endif /** * raptor_new_uri_from_id_v2: * @world: raptor_world object * @base_uri: existing base URI * @id: RDF ID * * Constructor - create a new URI from a base URI and RDF ID. * * This creates a URI equivalent to concatenating @base_uri with * ## and @id. * * Return value: a new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_from_id_v2(raptor_world *world, raptor_uri *base_uri, const unsigned char *id) { raptor_uri *new_uri; unsigned char *local_name; int len; if(!base_uri || !id) return NULL; #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 RAPTOR_DEBUG2("Using ID %s\n", id); #endif /* "#id\0" */ len=1+strlen((char*)id) + sizeof(char*); local_name=(unsigned char*)RAPTOR_MALLOC(cstring, len); if(!local_name) return NULL; *local_name='#'; strcpy((char*)local_name+1, (char*)id); new_uri=raptor_new_uri_relative_to_base_v2(world, base_uri, local_name); RAPTOR_FREE(cstring, local_name); return new_uri; } static raptor_uri* raptor_default_new_uri_for_rdf_concept(void *context, const char *name) { raptor_uri *new_uri; const unsigned char *base_uri=raptor_rdf_namespace_uri; unsigned int base_uri_len=raptor_rdf_namespace_uri_len; unsigned int new_uri_len; new_uri_len=base_uri_len+strlen(name) + sizeof(char*); new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, new_uri_len); if(!new_uri) return NULL; strcpy((char*)new_uri, (const char*)base_uri); strcpy((char*)new_uri+base_uri_len, name); return new_uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_for_rdf_concept: * @name: RDF namespace concept * * Constructor - create a raptor URI for the RDF namespace concept name. * * Example: u=raptor_new_uri_for_rdf_concept("value") creates a new * URI for the rdf:value term. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_for_rdf_concept_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure **/ raptor_uri* raptor_new_uri_for_rdf_concept(const char *name) { return raptor_new_uri_for_rdf_concept_v2(raptor_world_instance(), name); } #endif /** * raptor_new_uri_for_rdf_concept_v2: * @world: raptor_world object * @name: RDF namespace concept * * Constructor - create a raptor URI for the RDF namespace concept name. * * Example: u=raptor_new_uri_for_rdf_concept("value") creates a new * URI for the rdf:value term. * * Return value: a new #raptor_uri object or NULL on failure **/ raptor_uri* raptor_new_uri_for_rdf_concept_v2(raptor_world* world, const char *name) { if(!name) return NULL; return (*world->uri_handler->new_uri_for_rdf_concept)(world->uri_handler_context, name); } static void raptor_default_free_uri(void *context, raptor_uri *uri) { RAPTOR_FREE(raptor_uri, uri); } #ifndef RAPTOR_DISABLE_V1 /** * raptor_free_uri: * @uri: URI to destroy * * raptor_init() MUST have been called before calling this function. * Use raptor_free_uri_v2() if using raptor_world APIs. * * Destructor - destroy a #raptor_uri object **/ void raptor_free_uri(raptor_uri *uri) { raptor_free_uri_v2(raptor_world_instance(), uri); } #endif /* FIXME: Refactor the uri abstraction so that raptor_world* can be stored there. */ /** * raptor_free_uri_v2: * @world: raptor_world object * @uri: URI to destroy * * Destructor - destroy a #raptor_uri object **/ void raptor_free_uri_v2(raptor_world* world, raptor_uri *uri) { RAPTOR_ASSERT_OBJECT_POINTER_RETURN(uri, raptor_uri); (*world->uri_handler->free_uri)(world->uri_handler_context, uri); } static int raptor_default_uri_equals(void *context, raptor_uri* uri1, raptor_uri* uri2) { return strcmp((char*)uri1, (char*)uri2)==0; } static int raptor_default_uri_compare(void *context, raptor_uri* uri1, raptor_uri* uri2) { return strcmp((char*)uri1, (char*)uri2); } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_equals: * @uri1: URI 1 (may be NULL) * @uri2: URI 2 (may be NULL) * * Check if two URIs are equal. * * A NULL URI is not equal to a non-NULL URI. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_equals_v2() if using raptor_world APIs. * * Return value: non-0 if the URIs are equal **/ int raptor_uri_equals(raptor_uri* uri1, raptor_uri* uri2) { return raptor_uri_equals_v2(raptor_world_instance(), uri1, uri2); } #endif /** * raptor_uri_equals_v2: * @world: raptor_world object * @uri1: URI 1 (may be NULL) * @uri2: URI 2 (may be NULL) * * Check if two URIs are equal. * * A NULL URI is not equal to a non-NULL URI. * * Return value: non-0 if the URIs are equal **/ int raptor_uri_equals_v2(raptor_world* world, raptor_uri* uri1, raptor_uri* uri2) { if(uri1 && uri2) /* Both not-NULL - check with handler */ return (*world->uri_handler->uri_equals)(world->uri_handler_context, uri1, uri2); else if(uri1 || uri2) /* Only one is NULL - not equal */ return 0; else /* both NULL - equal */ return 1; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_compare: * @uri1: URI 1 (may be NULL) * @uri2: URI 2 (may be NULL) * * Compare two URIs, ala strcmp. * * A NULL URI is always less than (never equal to) a non-NULL URI. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_compare_v2() if using raptor_world APIs. * * Return value: -1 if uri1 < uri2, 0 if equal, 1 if uri1 > uri2 **/ int raptor_uri_compare(raptor_uri* uri1, raptor_uri* uri2) { return raptor_uri_compare_v2(raptor_world_instance(), uri1, uri2); } #endif /** * raptor_uri_compare_v2: * @world: raptor_world object * @uri1: URI 1 (may be NULL) * @uri2: URI 2 (may be NULL) * * Compare two URIs, ala strcmp. * * A NULL URI is always less than (never equal to) a non-NULL URI. * * Return value: -1 if uri1 < uri2, 0 if equal, 1 if uri1 > uri2 **/ int raptor_uri_compare_v2(raptor_world* world, raptor_uri* uri1, raptor_uri* uri2) { if(uri1 && uri2) { /* string compare function is available in API V2 or newer */ if(world->uri_handler->initialised >= 2) return (*world->uri_handler->uri_compare)(world->uri_handler_context, uri1, uri2); else return raptor_default_uri_compare(world->uri_handler_context, uri1, uri2); } else if(uri1) /* uri1 > uri2 (NULL) */ return 1; else /* uri1 (NULL) < uri2 */ return -1; } static raptor_uri* raptor_default_uri_copy(void *context, raptor_uri *uri) { raptor_uri* new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, strlen((char*)uri) + sizeof(char*)); if(!new_uri) return NULL; strcpy((char*)new_uri, (char*)uri); return new_uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_copy: * @uri: URI object * * Constructor - get a copy of a URI. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_copy_v2() if using raptor_world APIs. * * Return value: a new #raptor_uri object or NULL on failure **/ raptor_uri* raptor_uri_copy(raptor_uri *uri) { return raptor_uri_copy_v2(raptor_world_instance(), uri); } #endif /** * raptor_uri_copy_v2: * @world: raptor_world object * @uri: URI object * * Constructor - get a copy of a URI. * * Return value: a new #raptor_uri object or NULL on failure **/ raptor_uri* raptor_uri_copy_v2(raptor_world* world, raptor_uri *uri) { if(!uri) return NULL; return (*world->uri_handler->uri_copy)(world->uri_handler_context, uri); } static unsigned char* raptor_default_uri_as_string(void *context, raptor_uri *uri) { return (unsigned char*)uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_as_string: * @uri: #raptor_uri object * * Get a string representation of a URI. * * Returns a shared pointer to a string representation of @uri. This * string is shared and must not be freed, otherwise see use the * raptor_uri_to_string() or raptor_uri_to_counted_string() methods. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_as_string_v2() if using raptor_world APIs. * * Return value: shared string representation of URI **/ unsigned char* raptor_uri_as_string(raptor_uri *uri) { return raptor_uri_as_string_v2(raptor_world_instance(), uri); } #endif /** * raptor_uri_as_string_v2: * @world: raptor_world object * @uri: #raptor_uri object * * Get a string representation of a URI. * * Returns a shared pointer to a string representation of @uri. This * string is shared and must not be freed, otherwise see use the * raptor_uri_to_string() or raptor_uri_to_counted_string() methods. * * Return value: shared string representation of URI **/ unsigned char* raptor_uri_as_string_v2(raptor_world* world, raptor_uri *uri) { if(!uri) return NULL; return (*world->uri_handler->uri_as_string)(world->uri_handler_context, uri); } static unsigned char* raptor_default_uri_as_counted_string(void *context, raptor_uri *uri, size_t* len_p) { if(len_p) *len_p=strlen((char*)uri); return (unsigned char*)uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_as_counted_string: * @uri: URI object * @len_p: address of length variable or NULL * * Get a string representation of a URI with count. * * Returns a shared pointer to a string representation of @uri along * with the length of the string in @len_p, if not NULL. This * string is shared and must not be freed, otherwise see use the * raptor_uri_to_string() or raptor_uri_to_counted_string() methods. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_as_counted_string_v2() if using raptor_world APIs. * * Return value: shared string representation of URI **/ unsigned char* raptor_uri_as_counted_string(raptor_uri *uri, size_t* len_p) { return raptor_uri_as_counted_string_v2(raptor_world_instance(), uri, len_p); } #endif /** * raptor_uri_as_counted_string_v2: * @world: raptor_world object * @uri: URI object * @len_p: address of length variable or NULL * * Get a string representation of a URI with count. * * Returns a shared pointer to a string representation of @uri along * with the length of the string in @len_p, if not NULL. This * string is shared and must not be freed, otherwise see use the * raptor_uri_to_string() or raptor_uri_to_counted_string() methods. * * Return value: shared string representation of URI **/ unsigned char* raptor_uri_as_counted_string_v2(raptor_world* world, raptor_uri *uri, size_t* len_p) { if(!uri) return NULL; return (*world->uri_handler->uri_as_counted_string)(world->uri_handler_context, uri, len_p); } /** * raptor_uri_filename_to_uri_string: * @filename: The filename to convert * * Converts a filename to a file: URI. * * Handles the OS-specific escaping on turning filenames into URIs * and returns a new buffer that the caller must free(). Turns * a space in the filname into %20 and '%' into %25. * * Return value: A newly allocated string with the URI or NULL on failure **/ unsigned char * raptor_uri_filename_to_uri_string(const char *filename) { unsigned char *buffer=NULL; const char *from; char *to; #ifndef WIN32 char *path=NULL; #endif /* "file://" ... \0 */ size_t len=7 + sizeof(char*); if(!filename) return NULL; #ifdef WIN32 /* * On WIN32, filenames turn into * "file://" + translated filename * where the translation is \\ turns into / and ' ' into %20, '%' into %25 * and if the filename does not start with '\', it is relative * in which case, a . is appended to the authority * * e.g * FILENAME URI * c:\windows\system file:///c:/windows/system * \\server\dir\file.doc file://server/dir/file.doc * a:foo file:///a:./foo * C:\Documents and Settings\myapp\foo.bat * file:///C:/Documents%20and%20Settings/myapp/foo.bat * * There are also UNC names \\server\share\blah * that turn into file:///server/share/blah * using the above algorithm. */ if(filename[1] == ':' && filename[2] != '\\') len+=3; /* relative filename - add / and ./ */ else if(*filename == '\\') len-=2; /* two // from not needed in filename */ else len++; /* / at start of path */ #else /* others - unix: turn spaces into %20, '%' into %25 */ if(*filename != '/') { size_t path_max; #ifdef PATH_MAX path_max=PATH_MAX; #else path_max=1024; /* an initial guess at the length */ #endif path=(char*)malloc(path_max); while(1) { /* malloc() failed or getcwd() succeeded */ if(!path || getcwd(path, path_max)) break; /* failed */ if(errno != ERANGE) break; /* try again with a bigger buffer */ path_max *= 2; path=(char*)realloc(path, path_max); } if(!path) goto path_done; strcat(path, "/"); strcat(path, filename); filename=(const char*)path; } #endif /* add URI-escaped filename length */ for(from=filename; *from ; from++) { len++; if(*from == ' ' || *from == '%') len+=2; /* strlen(%xx)-1 */ } buffer=(unsigned char*)RAPTOR_MALLOC(cstring, len); if(!buffer) goto path_done; strcpy((char*)buffer, "file://"); from=filename; to=(char*)(buffer+7); #ifdef WIN32 if(*from == '\\' && from[1] == '\\') from+=2; else *to++ ='/'; #endif while(*from) { char c=*from++; #ifdef WIN32 if (c == '\\') *to++ ='/'; else if(c == ':') { *to++ = c; if(*from != '\\') { *to++ ='.'; *to++ ='/'; } } else #endif if(c == ' ' || c == '%') { *to++ ='%'; *to++ ='2'; *to++ =(c == ' ') ? '0' : '5'; } else *to++ =c; } *to='\0'; path_done: #ifndef WIN32 if(path) free(path); #endif return buffer; } /** * raptor_uri_uri_string_to_filename_fragment: * @uri_string: The file: URI to convert * @fragment_p: Address of pointer to store any URI fragment or NULL * * Convert a file: URI to a filename and fragment. * * Handles the OS-specific file: URIs to filename mappings. Returns * a new buffer containing the filename that the caller must free. * * If @fragment_p is given, a new string containing the URI fragment * is returned, or NULL if none is present * * Return value: A newly allocated string with the filename or NULL on failure **/ char * raptor_uri_uri_string_to_filename_fragment(const unsigned char *uri_string, unsigned char **fragment_p) { char *filename; size_t len=0; raptor_uri_detail *ud=NULL; unsigned char *from; char *to; #ifdef WIN32 unsigned char *p; #endif if(!uri_string || !*uri_string) return NULL; ud=raptor_new_uri_detail(uri_string); if(!ud) return NULL; if(!ud->scheme || raptor_strcasecmp((const char*)ud->scheme, "file")) { raptor_free_uri_detail(ud); return NULL; } if(ud->authority) { if(!*ud->authority) ud->authority=NULL; else if(!raptor_strcasecmp((const char*)ud->authority, "localhost")) ud->authority=NULL; } /* Cannot do much if there is no path */ if(!ud->path || (ud->path && !*ud->path)) { raptor_free_uri_detail(ud); return NULL; } /* See raptor_uri_filename_to_uri_string for details of the mapping */ #ifdef WIN32 if(ud->authority) len+=ud->authority_len+3; p=ud->path; /* remove leading slash from path if there is one */ if(*p && p[0] == '/') { p++; len--; } /* handle case where path starts with drive letter */ if(*p && (p[1] == '|' || p[1] == ':')) { /* Either * "a:" like in file://a|/... or file://a:/... * or * "a:." like in file://a:./foo * giving device-relative path a:foo */ if(p[2]=='.') { p[2]=*p; p[3]=':'; p+= 2; len-= 2; /* remove 2 for ./ */ } else p[1]=':'; } #endif /* add URI-escaped filename length */ for(from=ud->path; *from ; from++) { len++; if(*from == '%') from+= 2; } /* Something is wrong */ if(!len) { raptor_free_uri_detail(ud); return NULL; } filename=(char*)RAPTOR_MALLOC(cstring, len + sizeof(char*)); if(!filename) { raptor_free_uri_detail(ud); return NULL; } to=filename; #ifdef WIN32 if(ud->authority) { *to++ = '\\'; *to++ = '\\'; from=ud->authority; while( (*to++ = *from++) ) ; to--; *to++ = '\\'; } /* copy path after all /s */ from=p; #else from=ud->path; #endif while(*from) { char c=*from++; #ifdef WIN32 if(c == '/') *to++ ='\\'; else #endif if(c == '%') { if(*from && from[1]) { char hexbuf[3]; char *endptr=NULL; hexbuf[0]=(char)*from; hexbuf[1]=(char)from[1]; hexbuf[2]='\0'; c=(char)strtol((const char*)hexbuf, &endptr, 16); if(endptr == &hexbuf[2]) *to++ = c; } from+= 2; } else *to++ =c; } *to='\0'; if(fragment_p) { if(ud->fragment) { len=ud->fragment_len; *fragment_p=(unsigned char*)RAPTOR_MALLOC(cstring, len + sizeof(char*)); if(*fragment_p) strncpy((char*)*fragment_p, (const char*)ud->fragment, len+1); } else *fragment_p=NULL; } raptor_free_uri_detail(ud); return filename; } /** * raptor_uri_uri_string_to_filename: * @uri_string: The file: URI to convert * * Convert a file: URI to a filename. * * Handles the OS-specific file: URIs to filename mappings. Returns * a new buffer containing the filename that the caller must free. * * Return value: A newly allocated string with the filename or NULL on failure **/ char * raptor_uri_uri_string_to_filename(const unsigned char *uri_string) { return raptor_uri_uri_string_to_filename_fragment(uri_string, NULL); } #ifndef RAPTOR_DISABLE_DEPRECATED /** * raptor_uri_is_file_uri: * @uri_string: The URI string to check * * Check if a URI string is a file: URI. * * @deprecated: use raptor_uri_uri_string_is_file_uri() instead * * Return value: Non zero if URI string is a file: URI **/ int raptor_uri_is_file_uri(const unsigned char* uri_string) { return raptor_uri_uri_string_is_file_uri(uri_string); } #endif /** * raptor_uri_uri_string_is_file_uri: * @uri_string: The URI string to check * * Check if a URI string is a file: URI. * * Return value: Non zero if URI string is a file: URI **/ int raptor_uri_uri_string_is_file_uri(const unsigned char* uri_string) { if(!uri_string || !*uri_string) return 1; return raptor_strncasecmp((const char*)uri_string, "file:", 5)==0; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_for_xmlbase: * @old_uri: URI to transform * * Constructor - create a URI suitable for use as an XML Base. * * Takes an existing URI and ensures it has a path (default /) and has * no fragment or query arguments - XML base does not use these. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_for_xmlbase_v2() if using raptor_world APIs. * * Return value: new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_for_xmlbase(raptor_uri* old_uri) { return raptor_new_uri_for_xmlbase_v2(raptor_world_instance(), old_uri); } #endif /** * raptor_new_uri_for_xmlbase_v2: * @world: raptor_world object * @old_uri: URI to transform * * Constructor - create a URI suitable for use as an XML Base. * * Takes an existing URI and ensures it has a path (default /) and has * no fragment or query arguments - XML base does not use these. * * Return value: new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_for_xmlbase_v2(raptor_world* world, raptor_uri* old_uri) { unsigned char *uri_string; unsigned char *new_uri_string; raptor_uri* new_uri; raptor_uri_detail *ud; if(!old_uri) return NULL; uri_string=raptor_uri_as_string_v2(world, old_uri); ud=raptor_new_uri_detail(uri_string); if(!ud) return NULL; if(!ud->path) { ud->path=(unsigned char*)"/"; ud->path_len=1; } ud->query=NULL; ud->query_len=0; ud->fragment=NULL; ud->fragment_len=0; new_uri_string=raptor_uri_detail_to_string(ud, NULL); raptor_free_uri_detail(ud); if(!new_uri_string) return NULL; new_uri=raptor_new_uri_v2(world, new_uri_string); RAPTOR_FREE(cstring, new_uri_string); return new_uri; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_uri_for_retrieval: * @old_uri: URI to transform * * Constructor - create a URI suitable for retrieval. * * Takes an existing URI and ensures it has a path (default /) and has * no fragment - URI retrieval does not use the fragment part. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_uri_for_retrieval_v2() if using raptor_world APIs. * * Return value: new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_for_retrieval(raptor_uri* old_uri) { return raptor_new_uri_for_retrieval_v2(raptor_world_instance(), old_uri); } #endif /** * raptor_new_uri_for_retrieval_v2: * @world: raptor_world object * @old_uri: URI to transform * * Constructor - create a URI suitable for retrieval. * * Takes an existing URI and ensures it has a path (default /) and has * no fragment - URI retrieval does not use the fragment part. * * Return value: new #raptor_uri object or NULL on failure. **/ raptor_uri* raptor_new_uri_for_retrieval_v2(raptor_world* world, raptor_uri* old_uri) { unsigned char *uri_string; unsigned char *new_uri_string; raptor_uri* new_uri; raptor_uri_detail *ud; if(!old_uri) return NULL; uri_string=raptor_uri_as_string_v2(world, old_uri); ud=raptor_new_uri_detail(uri_string); if(!ud) return NULL; if(!ud->path) { ud->path=(unsigned char*)"/"; ud->path_len=1; } ud->fragment=NULL; ud->fragment_len=0; new_uri_string=raptor_uri_detail_to_string(ud, NULL); raptor_free_uri_detail(ud); if(!new_uri_string) return NULL; new_uri=raptor_new_uri_v2(world, new_uri_string); RAPTOR_FREE(cstring, new_uri_string); return new_uri; } static const raptor_uri_handler raptor_uri_default_handler = { raptor_default_new_uri, raptor_default_new_uri_from_uri_local_name, raptor_default_new_uri_relative_to_base, raptor_default_new_uri_for_rdf_concept, raptor_default_free_uri, raptor_default_uri_equals, raptor_default_uri_copy, raptor_default_uri_as_string, raptor_default_uri_as_counted_string, 2, /* URI Interface Version */ raptor_default_uri_compare /* URI Interface V2 */ }; int raptor_uri_init(raptor_world* world) { raptor_uri_set_handler_v2(world, &raptor_uri_default_handler, world); return 0; } /* * raptor_uri_path_common_base_length: * @first_path: The first path (path only, not a full URI) * @first_path_len: Length of first_path * @second_path: The second path (path only, not a full URI) * @second_path_len: Length of second_path * * Find the common base length of two URI path components. * * Return value: Length of the common base path **/ static int raptor_uri_path_common_base_length(const unsigned char *first_path, size_t first_path_len, const unsigned char *second_path, size_t second_path_len) { int common_len=0; const unsigned char *cur_ptr=first_path; const unsigned char *prev_ptr=first_path; /* Compare each path component of first_path and second_path until there is a mismatch. Then return the length from the start of the path to the last successful match. */ while((cur_ptr=(const unsigned char*)memchr(cur_ptr, '/', first_path_len))) { cur_ptr++; if(strncmp((const char*)first_path+common_len, (const char*)second_path+common_len, cur_ptr-prev_ptr)) break; first_path_len -= cur_ptr - prev_ptr; prev_ptr=cur_ptr; common_len = prev_ptr - first_path; } return prev_ptr - first_path; } /* * raptor_uri_path_make_relative_path: * @from_path: The base path (path only, not a full URI) * @from_path_len: Length of the base path * @to_path: The reference path (path only, not a full URI) * @to_path_len: Length of the reference path * @suffix: String to be appended to the final relative path * @suffix_len: Length of the suffix * @result_length_p: Location to store the length of the string or NULL * * Make a relative URI path. * * Return value: A newly allocated relative path string or NULL on failure. **/ static unsigned char * raptor_uri_path_make_relative_path(const unsigned char *from_path, size_t from_path_len, const unsigned char *to_path, size_t to_path_len, const unsigned char *suffix, size_t suffix_len, size_t *result_length_p) { int common_len, cur_len, final_len, up_dirs = 0, to_dir_len = 0; const unsigned char *cur_ptr, *prev_ptr; unsigned char *final_path, *final_path_cur; common_len=raptor_uri_path_common_base_length(from_path, from_path_len, to_path, to_path_len); if(result_length_p) *result_length_p=0; /* Count how many directories we have to go up */ cur_ptr = from_path + common_len; prev_ptr=cur_ptr; cur_len = from_path_len - common_len; while((cur_ptr = (const unsigned char*)memchr(cur_ptr, '/', cur_len))) { cur_ptr++; up_dirs++; cur_len -= cur_ptr - prev_ptr; prev_ptr=cur_ptr; } /* Calculate how many characters of to_path subdirs (counted from the common base) we have to add. */ cur_ptr = to_path + common_len; prev_ptr=cur_ptr; cur_len = to_path_len - common_len; while((cur_ptr = (const unsigned char*)memchr(cur_ptr, '/', cur_len))) { cur_ptr++; cur_len -= cur_ptr - prev_ptr; prev_ptr=cur_ptr; } to_dir_len = prev_ptr - (to_path + common_len); /* Create the final relative path */ final_len = up_dirs*3 + to_dir_len + suffix_len; /* 3 for each "../" */ final_path=(unsigned char*)RAPTOR_MALLOC(cstring, final_len + sizeof(char*)); if(!final_path) return NULL; *final_path=0; /* First, add the necessary "../" parts */ final_path_cur=final_path; while (up_dirs--) { *final_path_cur++='.'; *final_path_cur++='.'; *final_path_cur++='/'; } /* Then, add the path from the common base to the to_path */ memcpy(final_path_cur, to_path + common_len, to_dir_len); final_path_cur+=to_dir_len; /* Finally, add the suffix */ if(suffix && suffix_len) { /* As a special case, if the suffix begins with a dot (".") and the final output string so far is non-empty, skip the dot. */ if (*suffix == '.' && final_path_cur != final_path) { /* Make sure that the dot really represents a directory and it's not just part of a file name like ".foo". In other words, the dot must either be the only character or the next character must be the fragment or the query character. */ if ((suffix_len == 1) || (suffix_len > 1 && (suffix[1] == '#' || suffix[1] == '?'))) { suffix++; suffix_len--; final_len--; } } if(suffix_len) memcpy(final_path_cur, suffix, suffix_len); } final_path[final_len]=0; if (result_length_p) *result_length_p=final_len; return final_path; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_to_relative_counted_uri_string: * @base_uri: The base absolute URI to resolve against (or NULL) * @reference_uri: The reference absolute URI to use * @length_p: Location to store the length of the relative URI string or NULL * * Get the counted relative URI string of a URI against a base URI. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_to_relative_counted_uri_string_v2() if using raptor_world APIs. * * Return value: A newly allocated relative URI string or NULL on failure **/ unsigned char* raptor_uri_to_relative_counted_uri_string(raptor_uri *base_uri, raptor_uri *reference_uri, size_t *length_p) { return raptor_uri_to_relative_counted_uri_string_v2(raptor_world_instance(), base_uri, reference_uri, length_p); } #endif /** * raptor_uri_to_relative_counted_uri_string_v2: * @world: raptor_world object * @base_uri: The base absolute URI to resolve against (or NULL) * @reference_uri: The reference absolute URI to use * @length_p: Location to store the length of the relative URI string or NULL * * Get the counted relative URI string of a URI against a base URI. * * Return value: A newly allocated relative URI string or NULL on failure **/ unsigned char* raptor_uri_to_relative_counted_uri_string_v2(raptor_world* world, raptor_uri *base_uri, raptor_uri *reference_uri, size_t *length_p) { raptor_uri_detail *base_detail=NULL, *reference_detail; const unsigned char *base, *reference_str, *base_file, *reference_file; unsigned char *suffix, *cur_ptr; size_t base_len, reference_len, reference_file_len, suffix_len; unsigned char *result=NULL; int suffix_is_result=0; if(!reference_uri) return NULL; if(length_p) *length_p=0; reference_str=raptor_uri_as_counted_string_v2(world, reference_uri, &reference_len); reference_detail=raptor_new_uri_detail(reference_str); if(!reference_detail) goto err; if(!base_uri) goto buildresult; base=raptor_uri_as_counted_string_v2(world, base_uri, &base_len); base_detail=raptor_new_uri_detail(base); if(!base_detail) goto err; /* Check if the whole URIs are equal */ if(raptor_uri_equals_v2(world, base_uri, reference_uri)) { reference_len=0; goto buildresult; } /* Check if scheme and authority of the URIs are equal */ if(base_detail->scheme_len == reference_detail->scheme_len && base_detail->authority_len == reference_detail->authority_len && !strncmp((const char*)base_detail->scheme, (const char*)reference_detail->scheme, base_detail->scheme_len) && !strncmp((const char*)base_detail->authority, (const char*)reference_detail->authority, base_detail->authority_len)) { if(!base_detail->path) { if(reference_detail->path) { /* if base has no path then the relative URI is relative * to scheme+authority so assemble that in the suffix * buffer (adding any query part or fragment needed) */ reference_file=reference_detail->path; reference_file_len=reference_detail->path_len; suffix_is_result=1; goto addqueryfragment; } goto buildresult; } /* Find the file name components */ base_file = (const unsigned char*)strrchr((const char*)base_detail->path, '/'); if(!base_file) goto buildresult; base_file++; if(!reference_detail->path) goto buildresult; reference_file=(const unsigned char*)strrchr((const char*)reference_detail->path, '/'); if(!reference_file) goto buildresult; reference_file++; reference_file_len=reference_detail->path_len - (reference_file - reference_detail->path); if(!strcmp((const char*)base_file, (const char*)reference_file)) { /* If the file names are equal, don't put them in the relative URI */ reference_file=NULL; reference_file_len=0; } else if(*base_file && !*reference_file) { /* If the base file is non-empty, but the reference file is * empty, use "." as the file name. */ reference_file=(const unsigned char*)"."; reference_file_len=1; } addqueryfragment: /* Calculate the length of the suffix (file name + query + fragment) */ suffix_len=reference_file_len + reference_detail->query_len + reference_detail->fragment_len; if (reference_detail->query) suffix_len++; /* add one char for the '?' */ if (reference_detail->fragment) suffix_len++; /* add one char for the '#' */ /* Assemble the suffix */ suffix=(unsigned char*)RAPTOR_MALLOC(cstring, suffix_len + sizeof(char*)); if(!suffix) goto err; cur_ptr=suffix; if(reference_file) { memcpy(suffix, reference_file, reference_file_len); cur_ptr+= reference_file_len; } if(reference_detail->query) { *cur_ptr++='?'; memcpy(cur_ptr, reference_detail->query, reference_detail->query_len); cur_ptr+= reference_detail->query_len; } if(reference_detail->fragment) { *cur_ptr++='#'; memcpy(cur_ptr, reference_detail->fragment, reference_detail->fragment_len); cur_ptr+= reference_detail->fragment_len; } *cur_ptr=0; if(suffix_is_result) { /* If suffix is what we need, just use that as the result */ result=suffix; if(length_p) *length_p=suffix_len; } else { /* Otherwise create the full relative path */ result = raptor_uri_path_make_relative_path(base_detail->path, base_detail->path_len, reference_detail->path, reference_detail->path_len, suffix, suffix_len, length_p); RAPTOR_FREE(cstring, suffix); } } buildresult: /* If result is NULL at this point, it means that we were unable to find a relative URI, so we'll return a full absolute URI instead. */ if(!result) { result=(unsigned char*)RAPTOR_MALLOC(cstring, reference_len + sizeof(char*)); if(result) { if(reference_len) memcpy(result, reference_str, reference_len); result[reference_len] = 0; if(length_p) *length_p=reference_len; } } err: if(base_detail) raptor_free_uri_detail(base_detail); raptor_free_uri_detail(reference_detail); return result; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_to_relative_uri_string: * @base_uri: The base absolute URI to resolve against * @reference_uri: The reference absolute URI to use * * Get the relative URI string of a URI against a base URI. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_to_relative_uri_string_v2() if using raptor_world APIs. * * Return value: A newly allocated relative URI string or NULL on failure **/ unsigned char* raptor_uri_to_relative_uri_string(raptor_uri *base_uri, raptor_uri *reference_uri) { return raptor_uri_to_relative_uri_string_v2(raptor_world_instance(), base_uri, reference_uri); } #endif /** * raptor_uri_to_relative_uri_string_v2: * @world: raptor_world instance * @base_uri: The base absolute URI to resolve against * @reference_uri: The reference absolute URI to use * * Get the relative URI string of a URI against a base URI. * * Return value: A newly allocated relative URI string or NULL on failure **/ unsigned char* raptor_uri_to_relative_uri_string_v2(raptor_world *world, raptor_uri *base_uri, raptor_uri *reference_uri) { return raptor_uri_to_relative_counted_uri_string_v2(world, base_uri, reference_uri, NULL); } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_print: * @uri: URI to print * @stream: The file handle to print to * * Print a URI to a file handle. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_print_v2() if using raptor_world APIs. * **/ void raptor_uri_print(const raptor_uri* uri, FILE *stream) { raptor_uri_print_v2(raptor_world_instance(), uri, stream); } #endif /** * raptor_uri_print_v2: * @world: raptor_world object * @uri: URI to print * @stream: The file handle to print to * * Print a URI to a file handle. * **/ void raptor_uri_print_v2(raptor_world* world, const raptor_uri* uri, FILE *stream) { int rc = 0; if(uri) { size_t len; unsigned char *string=raptor_uri_as_counted_string_v2(world, (raptor_uri*)uri, &len); rc = fwrite(string, len, 1, stream); } else rc = fwrite("(NULL URI)", 10, 1, stream); /* FIXME Until world gains an error handler, there is nowhere to * report the IO error */ } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_to_counted_string: * @uri: #raptor_uri object * @len_p: Pointer to length (or NULL) * * Get a new counted string for a URI. * * If @len_p is not NULL, the length of the string is stored in it. * * The memory allocated must be freed by the caller and * raptor_free_memory() should be used for best portability. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_to_counted_string_v2() if using raptor_world APIs. * * Return value: new string or NULL on failure **/ unsigned char* raptor_uri_to_counted_string(raptor_uri *uri, size_t *len_p) { return raptor_uri_to_counted_string_v2(raptor_world_instance(), uri, len_p); } #endif /** * raptor_uri_to_counted_string_v2: * @world: raptor_world object * @uri: #raptor_uri object * @len_p: Pointer to length (or NULL) * * Get a new counted string for a URI. * * If @len_p is not NULL, the length of the string is stored in it. * * The memory allocated must be freed by the caller and * raptor_free_memory() should be used for best portability. * * Return value: new string or NULL on failure **/ unsigned char* raptor_uri_to_counted_string_v2(raptor_world* world, raptor_uri *uri, size_t *len_p) { size_t len; unsigned char *string; unsigned char *new_string; if(!uri) return NULL; string=raptor_uri_as_counted_string_v2(world, uri, &len); if(!string) return NULL; new_string=(unsigned char*)RAPTOR_MALLOC(cstring, len + 1); /* +1 for NUL termination */ if(!new_string) return NULL; memcpy(new_string, string, len+1); if(len_p) *len_p=len; return new_string; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_uri_to_string: * @uri: #raptor_uri object * * Get a new string for a URI. * * The memory allocated must be freed by the caller and * raptor_free_memory() should be used for best portability. * * raptor_init() MUST have been called before calling this function. * Use raptor_uri_to_string_v2() if using raptor_world APIs. * * Return value: new string or NULL on failure **/ unsigned char* raptor_uri_to_string(raptor_uri *uri) { return raptor_uri_to_string_v2(raptor_world_instance(), uri); } #endif /** * raptor_uri_to_string_v2: * @world: raptor_world object * @uri: #raptor_uri object * * Get a new string for a URI. * * The memory allocated must be freed by the caller and * raptor_free_memory() should be used for best portability. * * Return value: new string or NULL on failure **/ unsigned char* raptor_uri_to_string_v2(raptor_world* world, raptor_uri *uri) { return raptor_uri_to_counted_string_v2(world, uri, NULL); } /** * raptor_new_uri_from_rdf_ordinal: * @world: raptor_world object * @ordinal: integer rdf:_n * * Internal - convert an integer rdf:_n ordinal to the resource URI * * Return value: new URI object or NULL on failure **/ raptor_uri* raptor_new_uri_from_rdf_ordinal(raptor_world* world, int ordinal) { /* 55 = strlen(rdf namespace URI) + _ + 10-digit number + \0 */ unsigned char uri_string[55]; strncpy((char*)uri_string, (const char*)raptor_rdf_namespace_uri, raptor_rdf_namespace_uri_len); sprintf((char*)uri_string+raptor_rdf_namespace_uri_len, "_%d", ordinal); return raptor_new_uri_v2(world, uri_string); } #ifdef STANDALONE #include #ifdef HAVE_SYS_STAT_H #include #endif /* one more prototype */ int main(int argc, char *argv[]); static const char *program; static int assert_filename_to_uri (const char *filename, const char *reference_uri) { unsigned char *uri; uri=raptor_uri_filename_to_uri_string(filename); if (!uri || strcmp((const char*)uri, (const char*)reference_uri)) { fprintf(stderr, "%s: raptor_uri_filename_to_uri_string(%s) FAILED gaving URI %s != %s\n", program, filename, uri, reference_uri); if(uri) RAPTOR_FREE(cstring, uri); return 1; } RAPTOR_FREE(cstring, uri); return 0; } static int assert_uri_to_filename (const char *uri, const char *reference_filename) { char *filename; filename=raptor_uri_uri_string_to_filename((const unsigned char*)uri); if(filename && !reference_filename) { fprintf(stderr, "%s: raptor_uri_uri_string_to_filename(%s) FAILED giving filename %s != NULL\n", program, uri, filename); if(filename) RAPTOR_FREE(cstring, filename); return 1; } else if (filename && strcmp(filename, reference_filename)) { fprintf(stderr, "%s: raptor_uri_uri_string_to_filename(%s) FAILED gaving filename %s != %s\n", program, uri, filename, reference_filename); if(filename) RAPTOR_FREE(cstring, filename); return 1; } RAPTOR_FREE(cstring, filename); return 0; } static int assert_uri_to_relative(raptor_world *world, const char *base, const char *uri, const char *relative) { unsigned char *output; int result; raptor_uri* base_uri=NULL; raptor_uri* reference_uri=raptor_new_uri_v2(world, (const unsigned char*)uri); size_t length=0; if(base) base_uri=raptor_new_uri_v2(world, (const unsigned char*)base); output=raptor_uri_to_relative_counted_uri_string_v2(world, base_uri, reference_uri, &length); result=strcmp(relative, (const char*)output); if (result) { fprintf(stderr, "%s: raptor_uri_string_to_relative_uri_string FAILED: base='%s', uri='%s', expected='%s', got='%s'\n", program, base, uri, relative, output); RAPTOR_FREE(cstring, output); return 1; } RAPTOR_FREE(cstring, output); if(base_uri) raptor_free_uri_v2(world, base_uri); raptor_free_uri_v2(world, reference_uri); return 0; } static int raptor_test_uri_compare(void *context, raptor_uri* uri1, raptor_uri* uri2) { int* called_p=(int*)context; *called_p=1; return strcmp((char*)uri1, (char*)uri2); } int main(int argc, char *argv[]) { raptor_world *world; const char *base_uri = "http://example.org/bpath/cpath/d;p?querystr#frag"; const char *base_uri_xmlbase = "http://example.org/bpath/cpath/d;p"; const char *base_uri_retrievable = "http://example.org/bpath/cpath/d;p?querystr"; #ifndef WIN32 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_STAT_H) const char* dirs[6] = { "/etc", "/bin", "/tmp", "/lib", "/var", NULL }; unsigned char uri_buffer[16]; /* strlen("file:///DIR/foo")+1 */ int i; const char *dir; #endif #endif unsigned char *str; raptor_uri *uri1, *uri2, *uri3; int failures=0; world = raptor_new_world(); if(!world || raptor_world_open(world)) exit(1); if((program=strrchr(argv[0], '/'))) program++; else if((program=strrchr(argv[0], '\\'))) program++; else program=argv[0]; #ifdef WIN32 failures += assert_filename_to_uri ("c:\\windows\\system", "file:///c:/windows/system"); failures += assert_filename_to_uri ("\\\\server\\share\\file.doc", "file://server/share/file.doc"); failures += assert_filename_to_uri ("a:foo", "file:///a:./foo"); failures += assert_filename_to_uri ("C:\\Documents and Settings\\myapp\\foo.bat", "file:///C:/Documents%20and%20Settings/myapp/foo.bat"); failures += assert_filename_to_uri ("C:\\My Documents\\%age.txt", "file:///C:/My%20Documents/%25age.txt"); failures += assert_uri_to_filename ("file:///c|/windows/system", "c:\\windows\\system"); failures += assert_uri_to_filename ("file:///c:/windows/system", "c:\\windows\\system"); failures += assert_uri_to_filename ("file://server/share/file.doc", "\\\\server\\share\\file.doc"); failures += assert_uri_to_filename ("file:///a:./foo", "a:foo"); failures += assert_uri_to_filename ("file:///C:/Documents%20and%20Settings/myapp/foo.bat", "C:\\Documents and Settings\\myapp\\foo.bat"); failures += assert_uri_to_filename ("file:///C:/My%20Documents/%25age.txt", "C:\\My Documents\\%age.txt"); failures += assert_uri_to_filename ("file:c:\\thing", "c:\\thing"); failures += assert_uri_to_filename ("file:/c:\\thing", "c:\\thing"); failures += assert_uri_to_filename ("file://c:\\thing", NULL); failures += assert_uri_to_filename ("file:///c:\\thing", "c:\\thing"); failures += assert_uri_to_filename ("file://localhost/", NULL); failures += assert_uri_to_filename ("file://c:\\foo\\bar\\x.rdf", NULL); #else failures += assert_filename_to_uri ("/path/to/file", "file:///path/to/file"); failures += assert_filename_to_uri ("/path/to/file with spaces", "file:///path/to/file%20with%20spaces"); failures += assert_uri_to_filename ("file:///path/to/file", "/path/to/file"); failures += assert_uri_to_filename ("file:///path/to/file%20with%20spaces", "/path/to/file with spaces"); /* Tests for Issue#0000268 http://bugs.librdf.org/mantis/view.php?id=268 */ failures += assert_uri_to_filename ("file:///path/to/http%253A%252F%252Fwww.example.org%252Fa%252Fb%252Fc", "/path/to/http%3A%2F%2Fwww.example.org%2Fa%2Fb%2Fc"); failures += assert_filename_to_uri ("/path/to/http%3A%2F%2Fwww.example.org%2Fa%2Fb%2Fc", "file:///path/to/http%253A%252F%252Fwww.example.org%252Fa%252Fb%252Fc"); #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_STAT_H) /* Need to test this with a real dir (preferably not /) * This is just a test so pretty likely to work on all development systems * that are not WIN32 */ for(i=0; (dir=dirs[i]); i++) { struct stat buf; if(!lstat(dir, &buf) && S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode)) { if(!chdir(dir)) break; } } if(!dir) fprintf(stderr, "%s: WARNING: Found no convenient directory - not testing relative files\n", program); else { sprintf((char*)uri_buffer, "file://%s/foo", dir); fprintf(stderr, "%s: Checking relative file name 'foo' in dir %s expecting URI %s\n", program, dir, uri_buffer); failures += assert_filename_to_uri ("foo", (const char*)uri_buffer); } #endif #endif uri1=raptor_new_uri_v2(world, (const unsigned char*)base_uri); str=raptor_uri_as_string_v2(world, uri1); if(strcmp((const char*)str, base_uri)) { fprintf(stderr, "%s: raptor_uri_as_string(%s) FAILED gaving %s != %s\n", program, base_uri, str, base_uri); failures++; } uri2=raptor_new_uri_for_xmlbase_v2(world, uri1); str=raptor_uri_as_string_v2(world, uri2); if(strcmp((const char*)str, base_uri_xmlbase)) { fprintf(stderr, "%s: raptor_new_uri_for_xmlbase(URI %s) FAILED giving %s != %s\n", program, base_uri, str, base_uri_xmlbase); failures++; } uri3=raptor_new_uri_for_retrieval_v2(world, uri1); str=raptor_uri_as_string_v2(world, uri3); if(strcmp((const char*)str, base_uri_retrievable)) { fprintf(stderr, "%s: raptor_new_uri_for_retrievable(%s) FAILED gaving %s != %s\n", program, base_uri, str, base_uri_retrievable); failures++; } raptor_free_uri_v2(world, uri3); raptor_free_uri_v2(world, uri2); raptor_free_uri_v2(world, uri1); failures += assert_uri_to_relative(world, NULL, "http://example.com/foo/bar", "http://example.com/foo/bar"); failures += assert_uri_to_relative(world, "", "http://example.com/foo/bar", "http://example.com/foo/bar"); failures += assert_uri_to_relative(world, "foo:", "http://example.com/foo/bar", "http://example.com/foo/bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo?foo#foo", "http://example.com/base/bar?bar#bar", "bar?bar#bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/", "foo/"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/.foo", "foo/.foo"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/.foo#bar", "foo/.foo#bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/bar", "foo/bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo#bar", "#bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/bar#foo", "bar#foo"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/otherbase/bar", "../otherbase/bar"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/#foo", ".#foo"); failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example2.com/base/bar", "http://example2.com/base/bar"); failures += assert_uri_to_relative(world, "http://example.com/base/one?path=/should/be/ignored", "http://example.com/base/two?path=/should/be/ignored", "two?path=/should/be/ignored"); failures += assert_uri_to_relative(world, "http://example.org/base#", "http://www.foo.org", "http://www.foo.org"); failures += assert_uri_to_relative(world, "http://example.org", "http://a.example.org/", "http://a.example.org/"); failures += assert_uri_to_relative(world, "http://example.org", "http://a.example.org", "http://a.example.org"); failures += assert_uri_to_relative(world, "http://abcdefgh.example.org/foo/bar/", "http://ijklmnop.example.org/", "http://ijklmnop.example.org/"); failures += assert_uri_to_relative(world, "http://example.org", "http://example.org/a/b/c/d/efgh", "/a/b/c/d/efgh"); if(1) { raptor_uri_handler uri_handler; int ret; raptor_uri* u1; raptor_uri* u2; int called; /* URI Interface V1 */ uri_handler.new_uri = raptor_default_new_uri; uri_handler.free_uri = raptor_default_free_uri; uri_handler.uri_compare = raptor_test_uri_compare; uri_handler.initialised=1; called=0; raptor_uri_set_handler_v2(world, &uri_handler, &called); u1=raptor_new_uri_v2(world, (const unsigned char *)"http://example.org/abc"); u2=raptor_new_uri_v2(world, (const unsigned char *)"http://example.org/def"); ret=raptor_uri_compare_v2(world, u1, u2); if(!(ret < 0)) { fprintf(stderr, "%s: raptor_uri_compare(%s, %s) FAILED V1 gave %d expected <0\n", program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2), ret); failures++; } if(called) { fprintf(stderr, "%s: raptor_uri_compare(%s, %s) FAILED V1 called user handler\n", program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2)); failures++; } /* URI Interface V2 */ uri_handler.initialised=2; called=0; raptor_uri_set_handler_v2(world, &uri_handler, &called); ret=raptor_uri_compare_v2(world, u1, u2); if(!(ret < 0)) { fprintf(stderr, "%s: raptor_uri_compare(%s, %s) FAILED V2 gave %d expected <0\n", program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2), ret); failures++; } if(!called) { fprintf(stderr, "%s: raptor_uri_compare(%s, %s) FAILED V2 did not call user handler\n", program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2)); failures++; } raptor_free_uri_v2(world, u1); raptor_free_uri_v2(world, u2); } raptor_free_world(world); return failures ; } #endif