1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * raptor_uri.c - Raptor URI resolving implementation
4  *
5  * Copyright (C) 2002-2008, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2002-2005, University of Bristol, UK http://www.bristol.ac.uk/
7  *
8  * This package is Free Software and part of Redland http://librdf.org/
9  *
10  * It is licensed under the following three licenses as alternatives:
11  *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12  *   2. GNU General Public License (GPL) V2 or any newer version
13  *   3. Apache License, V2.0 or any newer version
14  *
15  * You may not use this file except in compliance with at least one of
16  * the above three licenses.
17  *
18  * See LICENSE.html or LICENSE.txt at the top of this package for the
19  * complete terms and further detail along with the license texts for
20  * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21  *
22  *
23  */
24 
25 
26 #ifdef HAVE_CONFIG_H
27 #include <raptor_config.h>
28 #endif
29 
30 #ifdef WIN32
31 #include <win32_raptor_config.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #ifdef HAVE_ERRNO_H
39 #include <errno.h>
40 #endif
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #ifdef HAVE_LIMITS_H
48 #include <limits.h>
49 #endif
50 
51 /* Raptor includes */
52 #include "raptor.h"
53 #include "raptor_internal.h"
54 
55 
56 #ifdef WIN32_URI_TEST
57 #define WIN32
58 #endif
59 
60 
61 /* Symbian OS uses similar path mappings as Windows but does not necessarily have the WIN32 flag defined */
62 #if defined(__SYMBIAN32__) && !defined(WIN32)
63 #define WIN32
64 #endif
65 
66 
67 #ifndef RAPTOR_DISABLE_V1
68 /**
69  * raptor_uri_set_handler:
70  * @handler: URI handler structure
71  * @context: URI handler context
72  *
73  * Change the URI class implementation to the functions provided by the
74  *
75  * The URI interface in @handler->initialised should be either 1
76  * or 2 (if raptor_uri_compare_func is implemented).
77  *
78  * raptor_init() MUST have been called before calling this function.
79  * Use raptor_uri_set_handler_v2() if using raptor_world APIs.
80  **/
81 void
raptor_uri_set_handler(const raptor_uri_handler * handler,void * context)82 raptor_uri_set_handler(const raptor_uri_handler *handler, void *context)
83 {
84   raptor_uri_set_handler_v2(raptor_world_instance(), handler, context);
85 }
86 #endif
87 
88 
89 /**
90  * raptor_uri_set_handler_v2:
91  * @world: raptor_world object
92  * @handler: URI handler structure
93  * @context: URI handler context
94  *
95  * Change the URI class implementation to the functions provided by the
96  *
97  * The URI interface in @handler->initialised should be either 1
98  * or 2 (if raptor_uri_compare_func is implemented).
99  **/
100 void
raptor_uri_set_handler_v2(raptor_world * world,const raptor_uri_handler * handler,void * context)101 raptor_uri_set_handler_v2(raptor_world* world, const raptor_uri_handler *handler, void *context)
102 {
103   RAPTOR_ASSERT_OBJECT_POINTER_RETURN(handler, raptor_uri_handler);
104   /* RAPTOR_ASSERT is the negative of ordinary asserts - it fails if the condition is true */
105   RAPTOR_ASSERT(!(handler->initialised >= 1 && handler->initialised <= 2),
106     "raptor_uri_handler->initialised not 1..2");
107 
108   world->uri_handler=handler;
109   world->uri_handler_context=context;
110 }
111 
112 
113 #ifndef RAPTOR_DISABLE_V1
114 /**
115  * raptor_uri_get_handler:
116  * @handler: URI handler to return
117  * @context: URI context to return
118  *
119  * Return the current raptor URI class implementation @handler and @context
120  *
121  * raptor_init() MUST have been called before calling this function.
122  * Use raptor_uri_get_handler_v2() if using raptor_world APIs.
123  **/
124 void
raptor_uri_get_handler(const raptor_uri_handler ** handler,void ** context)125 raptor_uri_get_handler(const raptor_uri_handler **handler, void **context)
126 {
127   raptor_uri_get_handler_v2(raptor_world_instance(), handler, context);
128 }
129 #endif
130 
131 
132 /**
133  * raptor_uri_get_handler_v2:
134  * @handler: URI handler to return
135  * @context: URI context to return
136  *
137  * Return the current raptor URI class implementation @handler and @context
138  **/
139 void
raptor_uri_get_handler_v2(raptor_world * world,const raptor_uri_handler ** handler,void ** context)140 raptor_uri_get_handler_v2(raptor_world* world, const raptor_uri_handler **handler, void **context)
141 {
142   if(handler)
143     *handler=world->uri_handler;
144   if(context)
145     *context=world->uri_handler_context;
146 }
147 
148 
149 static raptor_uri*
raptor_default_new_uri(void * context,const unsigned char * uri_string)150 raptor_default_new_uri(void *context, const unsigned char *uri_string)
151 {
152   raptor_world* world=(raptor_world*)context;
153   unsigned char *p;
154   size_t len;
155 
156   /* If uri_string is "file:path-to-file", turn it into a correct file:URI */
157   if(raptor_uri_uri_string_is_file_uri(uri_string)) {
158     unsigned char *fragment=NULL;
159     char *filename;
160     raptor_uri* uri=NULL;
161 
162     filename=raptor_uri_uri_string_to_filename_fragment(uri_string, &fragment);
163     if(filename && !access(filename, R_OK)) {
164       uri=(raptor_uri*)raptor_uri_filename_to_uri_string(filename);
165       /* If there was a fragment, reattach it to the new URI */
166       if(fragment) {
167         unsigned char *new_fragment;
168         raptor_uri* new_uri;
169 
170         new_fragment=(unsigned char*)RAPTOR_MALLOC(cstring, strlen((const char*)fragment) + 1 + sizeof(char*));
171         if(!new_fragment)
172           return NULL;
173         *new_fragment='#';
174         strcpy((char*)new_fragment+1, (const char*)fragment);
175         new_uri=raptor_new_uri_relative_to_base_v2(world, uri, new_fragment);
176         RAPTOR_FREE(cstring, new_fragment);
177         raptor_free_uri_v2(world, uri);
178         uri=new_uri;
179       }
180     }
181     if(filename)
182       RAPTOR_FREE(cstring, filename);
183     if(fragment)
184       RAPTOR_FREE(cstring, fragment);
185     if(uri)
186       return uri;
187   }
188 
189   len=strlen((const char*)uri_string);
190   p=(unsigned char*)RAPTOR_MALLOC(raptor_uri, len + sizeof(char*));
191   if(!p)
192     return NULL;
193   strcpy((char*)p, (const char*)uri_string);
194   return (raptor_uri*)p;
195 }
196 
197 
198 #ifndef RAPTOR_DISABLE_V1
199 /**
200  * raptor_new_uri:
201  * @uri_string: URI string.
202  *
203  * Constructor - create a raptor URI from a UTF-8 encoded Unicode string.
204  *
205  * raptor_init() MUST have been called before calling this function.
206  * Use raptor_new_uri_v2() if using raptor_world APIs.
207  *
208  * Return value: a new #raptor_uri object or NULL on failure.
209  **/
210 raptor_uri*
raptor_new_uri(const unsigned char * uri_string)211 raptor_new_uri(const unsigned char *uri_string)
212 {
213   return raptor_new_uri_v2(raptor_world_instance(), uri_string);
214 }
215 #endif
216 
217 
218 /**
219  * raptor_new_uri_v2:
220  * @world: raptor_world object
221  * @uri_string: URI string.
222  *
223  * Constructor - create a raptor URI from a UTF-8 encoded Unicode string.
224  *
225  * Return value: a new #raptor_uri object or NULL on failure.
226  **/
227 raptor_uri*
raptor_new_uri_v2(raptor_world * world,const unsigned char * uri_string)228 raptor_new_uri_v2(raptor_world* world, const unsigned char *uri_string)
229 {
230   if(!uri_string || !*uri_string)
231     return NULL;
232 
233   return (*world->uri_handler->new_uri)(world->uri_handler_context, uri_string);
234 }
235 
236 
237 static raptor_uri*
raptor_default_new_uri_from_uri_local_name(void * context,raptor_uri * uri,const unsigned char * local_name)238 raptor_default_new_uri_from_uri_local_name(void *context,
239                                            raptor_uri *uri,
240                                            const unsigned char *local_name)
241 {
242   int uri_length=strlen((char*)uri);
243   unsigned char *p=(unsigned char*)RAPTOR_MALLOC(cstring,
244                                                  uri_length + strlen((const char*)local_name) + sizeof(char*));
245   if(!p)
246     return NULL;
247 
248   strcpy((char*)p, (const char*)uri);
249   strcpy((char*)p + uri_length, (const char*)local_name);
250 
251   return (raptor_uri*)p;
252 }
253 
254 
255 #ifndef RAPTOR_DISABLE_V1
256 /**
257  * raptor_new_uri_from_uri_local_name:
258  * @uri: existing #raptor_uri
259  * @local_name: local name
260  *
261  * Constructor - create a raptor URI from an existing URI and a local name.
262  *
263  * Creates a new URI from the concatenation of the @local_name to the
264  * @uri.  This is NOT relative URI resolution, which is done by the
265  * raptor_new_uri_relative_to_base() constructor.
266  *
267  * raptor_init() MUST have been called before calling this function.
268  * Use raptor_new_uri_from_uri_local_name_v2() if using raptor_world APIs.
269  *
270  * Return value: a new #raptor_uri object or NULL on failure.
271  **/
272 raptor_uri*
raptor_new_uri_from_uri_local_name(raptor_uri * uri,const unsigned char * local_name)273 raptor_new_uri_from_uri_local_name(raptor_uri *uri, const unsigned char *local_name)
274 {
275   return raptor_new_uri_from_uri_local_name_v2(raptor_world_instance(), uri, local_name);
276 }
277 #endif
278 
279 
280 /**
281  * raptor_new_uri_from_uri_local_name_v2:
282  * @world: raptor_world object
283  * @uri: existing #raptor_uri
284  * @local_name: local name
285  *
286  * Constructor - create a raptor URI from an existing URI and a local name.
287  *
288  * Creates a new URI from the concatenation of the @local_name to the
289  * @uri.  This is NOT relative URI resolution, which is done by the
290  * raptor_new_uri_relative_to_base() constructor.
291  *
292  * Return value: a new #raptor_uri object or NULL on failure.
293  **/
294 raptor_uri*
raptor_new_uri_from_uri_local_name_v2(raptor_world * world,raptor_uri * uri,const unsigned char * local_name)295 raptor_new_uri_from_uri_local_name_v2(raptor_world* world, raptor_uri *uri, const unsigned char *local_name)
296 {
297   if(!uri || !local_name)
298     return NULL;
299 
300   return (*world->uri_handler->new_uri_from_uri_local_name)(world->uri_handler_context, uri, local_name);
301 }
302 
303 
304 static raptor_uri*
raptor_default_new_uri_relative_to_base(void * context,raptor_uri * base_uri,const unsigned char * uri_string)305 raptor_default_new_uri_relative_to_base(void *context,
306                                         raptor_uri *base_uri,
307                                         const unsigned char *uri_string)
308 {
309   raptor_uri* new_uri;
310   size_t new_uri_len=strlen((const char*)base_uri)+strlen((const char*)uri_string) + sizeof(char*);
311 
312   /* +2 is for \0 plus an extra 1 for adding any missing URI path '/' */
313   new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, new_uri_len+2);
314   if(!new_uri)
315     return NULL;
316 
317   /* If URI string is empty, just copy base URI */
318   if(!*uri_string) {
319     strcpy((char*)new_uri, (char*)base_uri);
320     return new_uri;
321   }
322 
323   raptor_uri_resolve_uri_reference((const unsigned char*)base_uri, uri_string,
324                                    (unsigned char*)new_uri, new_uri_len);
325   return new_uri;
326 }
327 
328 
329 #ifndef RAPTOR_DISABLE_V1
330 /**
331  * raptor_new_uri_relative_to_base:
332  * @base_uri: existing base URI
333  * @uri_string: relative URI string
334  *
335  * Constructor - create a raptor URI from a base URI and a relative URI string.
336  *
337  * raptor_init() MUST have been called before calling this function.
338  * Use raptor_new_uri_relative_to_base_v2() if using raptor_world APIs.
339  *
340  * Return value: a new #raptor_uri object or NULL on failure.
341  **/
342 raptor_uri*
raptor_new_uri_relative_to_base(raptor_uri * base_uri,const unsigned char * uri_string)343 raptor_new_uri_relative_to_base(raptor_uri *base_uri,
344                                 const unsigned char *uri_string)
345 {
346   return raptor_new_uri_relative_to_base_v2(raptor_world_instance(),
347                                             base_uri, uri_string);
348 }
349 #endif
350 
351 
352 /**
353  * raptor_new_uri_relative_to_base_v2:
354  * @world: raptor_world object
355  * @base_uri: existing base URI
356  * @uri_string: relative URI string
357  *
358  * Constructor - create a raptor URI from a base URI and a relative URI string.
359  *
360  * Return value: a new #raptor_uri object or NULL on failure.
361  **/
362 raptor_uri*
raptor_new_uri_relative_to_base_v2(raptor_world * world,raptor_uri * base_uri,const unsigned char * uri_string)363 raptor_new_uri_relative_to_base_v2(raptor_world* world,
364                                    raptor_uri *base_uri,
365                                    const unsigned char *uri_string)
366 {
367   if(!base_uri || !uri_string)
368     return NULL;
369 
370   return (*world->uri_handler->new_uri_relative_to_base)(world->uri_handler_context, base_uri, uri_string);
371 }
372 
373 
374 #ifndef RAPTOR_DISABLE_V1
375 /**
376  * raptor_new_uri_from_id:
377  * @base_uri: existing base URI
378  * @id: RDF ID
379  *
380  * Constructor - create a new URI from a base URI and RDF ID.
381  *
382  * This creates a URI equivalent to concatenating @base_uri with
383  * ## and @id.
384  *
385  * raptor_init() MUST have been called before calling this function.
386  * Use raptor_new_uri_from_id_v2() if using raptor_world APIs.
387  *
388  * Return value: a new #raptor_uri object or NULL on failure.
389  **/
390 raptor_uri*
raptor_new_uri_from_id(raptor_uri * base_uri,const unsigned char * id)391 raptor_new_uri_from_id(raptor_uri *base_uri, const unsigned char *id)
392 {
393   return raptor_new_uri_from_id_v2(raptor_world_instance(), base_uri, id);
394 }
395 #endif
396 
397 
398 /**
399  * raptor_new_uri_from_id_v2:
400  * @world: raptor_world object
401  * @base_uri: existing base URI
402  * @id: RDF ID
403  *
404  * Constructor - create a new URI from a base URI and RDF ID.
405  *
406  * This creates a URI equivalent to concatenating @base_uri with
407  * ## and @id.
408  *
409  * Return value: a new #raptor_uri object or NULL on failure.
410  **/
411 raptor_uri*
raptor_new_uri_from_id_v2(raptor_world * world,raptor_uri * base_uri,const unsigned char * id)412 raptor_new_uri_from_id_v2(raptor_world *world, raptor_uri *base_uri, const unsigned char *id)
413 {
414   raptor_uri *new_uri;
415   unsigned char *local_name;
416   int len;
417 
418   if(!base_uri || !id)
419     return NULL;
420 
421 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
422   RAPTOR_DEBUG2("Using ID %s\n", id);
423 #endif
424 
425   /* "#id\0" */
426   len=1+strlen((char*)id) + sizeof(char*);
427   local_name=(unsigned char*)RAPTOR_MALLOC(cstring, len);
428   if(!local_name)
429     return NULL;
430   *local_name='#';
431   strcpy((char*)local_name+1, (char*)id);
432   new_uri=raptor_new_uri_relative_to_base_v2(world, base_uri, local_name);
433   RAPTOR_FREE(cstring, local_name);
434   return new_uri;
435 }
436 
437 
438 static raptor_uri*
raptor_default_new_uri_for_rdf_concept(void * context,const char * name)439 raptor_default_new_uri_for_rdf_concept(void *context, const char *name)
440 {
441   raptor_uri *new_uri;
442   const unsigned char *base_uri=raptor_rdf_namespace_uri;
443   unsigned int base_uri_len=raptor_rdf_namespace_uri_len;
444   unsigned int new_uri_len;
445 
446   new_uri_len=base_uri_len+strlen(name) + sizeof(char*);
447   new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, new_uri_len);
448   if(!new_uri)
449     return NULL;
450   strcpy((char*)new_uri, (const char*)base_uri);
451   strcpy((char*)new_uri+base_uri_len, name);
452   return new_uri;
453 }
454 
455 
456 #ifndef RAPTOR_DISABLE_V1
457 /**
458  * raptor_new_uri_for_rdf_concept:
459  * @name: RDF namespace concept
460  *
461  * Constructor - create a raptor URI for the RDF namespace concept name.
462  *
463  * Example: u=raptor_new_uri_for_rdf_concept("value") creates a new
464  * URI for the rdf:value term.
465  *
466  * raptor_init() MUST have been called before calling this function.
467  * Use raptor_new_uri_for_rdf_concept_v2() if using raptor_world APIs.
468  *
469  * Return value: a new #raptor_uri object or NULL on failure
470  **/
471 raptor_uri*
raptor_new_uri_for_rdf_concept(const char * name)472 raptor_new_uri_for_rdf_concept(const char *name)
473 {
474   return raptor_new_uri_for_rdf_concept_v2(raptor_world_instance(), name);
475 }
476 #endif
477 
478 
479 /**
480  * raptor_new_uri_for_rdf_concept_v2:
481  * @world: raptor_world object
482  * @name: RDF namespace concept
483  *
484  * Constructor - create a raptor URI for the RDF namespace concept name.
485  *
486  * Example: u=raptor_new_uri_for_rdf_concept("value") creates a new
487  * URI for the rdf:value term.
488  *
489  * Return value: a new #raptor_uri object or NULL on failure
490  **/
491 raptor_uri*
raptor_new_uri_for_rdf_concept_v2(raptor_world * world,const char * name)492 raptor_new_uri_for_rdf_concept_v2(raptor_world* world, const char *name)
493 {
494   if(!name)
495     return NULL;
496 
497   return (*world->uri_handler->new_uri_for_rdf_concept)(world->uri_handler_context, name);
498 }
499 
500 
501 static void
raptor_default_free_uri(void * context,raptor_uri * uri)502 raptor_default_free_uri(void *context, raptor_uri *uri)
503 {
504   RAPTOR_FREE(raptor_uri, uri);
505 }
506 
507 
508 #ifndef RAPTOR_DISABLE_V1
509 /**
510  * raptor_free_uri:
511  * @uri: URI to destroy
512  *
513  * raptor_init() MUST have been called before calling this function.
514  * Use raptor_free_uri_v2() if using raptor_world APIs.
515  *
516  * Destructor - destroy a #raptor_uri object
517  **/
518 void
raptor_free_uri(raptor_uri * uri)519 raptor_free_uri(raptor_uri *uri)
520 {
521   raptor_free_uri_v2(raptor_world_instance(), uri);
522 }
523 #endif
524 
525 
526 /* FIXME: Refactor the uri abstraction so that raptor_world* can be stored there. */
527 
528 /**
529  * raptor_free_uri_v2:
530  * @world: raptor_world object
531  * @uri: URI to destroy
532  *
533  * Destructor - destroy a #raptor_uri object
534  **/
535 void
raptor_free_uri_v2(raptor_world * world,raptor_uri * uri)536 raptor_free_uri_v2(raptor_world* world, raptor_uri *uri)
537 {
538   RAPTOR_ASSERT_OBJECT_POINTER_RETURN(uri, raptor_uri);
539 
540   (*world->uri_handler->free_uri)(world->uri_handler_context, uri);
541 }
542 
543 
544 static int
raptor_default_uri_equals(void * context,raptor_uri * uri1,raptor_uri * uri2)545 raptor_default_uri_equals(void *context, raptor_uri* uri1, raptor_uri* uri2)
546 {
547   return strcmp((char*)uri1, (char*)uri2)==0;
548 }
549 
550 
551 static int
raptor_default_uri_compare(void * context,raptor_uri * uri1,raptor_uri * uri2)552 raptor_default_uri_compare(void *context, raptor_uri* uri1, raptor_uri* uri2)
553 {
554   return strcmp((char*)uri1, (char*)uri2);
555 }
556 
557 
558 #ifndef RAPTOR_DISABLE_V1
559 /**
560  * raptor_uri_equals:
561  * @uri1: URI 1 (may be NULL)
562  * @uri2: URI 2 (may be NULL)
563  *
564  * Check if two URIs are equal.
565  *
566  * A NULL URI is not equal to a non-NULL URI.
567  *
568  * raptor_init() MUST have been called before calling this function.
569  * Use raptor_uri_equals_v2() if using raptor_world APIs.
570  *
571  * Return value: non-0 if the URIs are equal
572  **/
573 int
raptor_uri_equals(raptor_uri * uri1,raptor_uri * uri2)574 raptor_uri_equals(raptor_uri* uri1, raptor_uri* uri2)
575 {
576   return raptor_uri_equals_v2(raptor_world_instance(), uri1, uri2);
577 }
578 #endif
579 
580 
581 /**
582  * raptor_uri_equals_v2:
583  * @world: raptor_world object
584  * @uri1: URI 1 (may be NULL)
585  * @uri2: URI 2 (may be NULL)
586  *
587  * Check if two URIs are equal.
588  *
589  * A NULL URI is not equal to a non-NULL URI.
590  *
591  * Return value: non-0 if the URIs are equal
592  **/
593 int
raptor_uri_equals_v2(raptor_world * world,raptor_uri * uri1,raptor_uri * uri2)594 raptor_uri_equals_v2(raptor_world* world, raptor_uri* uri1, raptor_uri* uri2)
595 {
596   if(uri1 && uri2)
597     /* Both not-NULL - check with handler */
598     return (*world->uri_handler->uri_equals)(world->uri_handler_context, uri1, uri2);
599   else if(uri1 || uri2)
600     /* Only one is NULL - not equal */
601     return 0;
602   else
603     /* both NULL - equal */
604     return 1;
605 }
606 
607 
608 #ifndef RAPTOR_DISABLE_V1
609 /**
610  * raptor_uri_compare:
611  * @uri1: URI 1 (may be NULL)
612  * @uri2: URI 2 (may be NULL)
613  *
614  * Compare two URIs, ala strcmp.
615  *
616  * A NULL URI is always less than (never equal to) a non-NULL URI.
617  *
618  * raptor_init() MUST have been called before calling this function.
619  * Use raptor_uri_compare_v2() if using raptor_world APIs.
620  *
621  * Return value: -1 if uri1 < uri2, 0 if equal, 1 if uri1 > uri2
622  **/
623 int
raptor_uri_compare(raptor_uri * uri1,raptor_uri * uri2)624 raptor_uri_compare(raptor_uri* uri1, raptor_uri* uri2)
625 {
626   return raptor_uri_compare_v2(raptor_world_instance(), uri1, uri2);
627 }
628 #endif
629 
630 
631 /**
632  * raptor_uri_compare_v2:
633  * @world: raptor_world object
634  * @uri1: URI 1 (may be NULL)
635  * @uri2: URI 2 (may be NULL)
636  *
637  * Compare two URIs, ala strcmp.
638  *
639  * A NULL URI is always less than (never equal to) a non-NULL URI.
640  *
641  * Return value: -1 if uri1 < uri2, 0 if equal, 1 if uri1 > uri2
642  **/
643 int
raptor_uri_compare_v2(raptor_world * world,raptor_uri * uri1,raptor_uri * uri2)644 raptor_uri_compare_v2(raptor_world* world, raptor_uri* uri1, raptor_uri* uri2)
645 {
646   if(uri1 && uri2) {
647     /* string compare function is available in API V2 or newer */
648     if(world->uri_handler->initialised >= 2)
649       return (*world->uri_handler->uri_compare)(world->uri_handler_context, uri1, uri2);
650     else
651       return raptor_default_uri_compare(world->uri_handler_context,
652                                         uri1, uri2);
653   } else if(uri1)
654     /* uri1 > uri2 (NULL) */
655     return 1;
656   else
657     /* uri1 (NULL) < uri2 */
658     return -1;
659 }
660 
661 
662 static raptor_uri*
raptor_default_uri_copy(void * context,raptor_uri * uri)663 raptor_default_uri_copy(void *context, raptor_uri *uri)
664 {
665   raptor_uri* new_uri=(raptor_uri*)RAPTOR_MALLOC(cstring, strlen((char*)uri) + sizeof(char*));
666   if(!new_uri)
667     return NULL;
668   strcpy((char*)new_uri, (char*)uri);
669   return new_uri;
670 }
671 
672 
673 #ifndef RAPTOR_DISABLE_V1
674 /**
675  * raptor_uri_copy:
676  * @uri: URI object
677  *
678  * Constructor - get a copy of a URI.
679  *
680  * raptor_init() MUST have been called before calling this function.
681  * Use raptor_uri_copy_v2() if using raptor_world APIs.
682  *
683  * Return value: a new #raptor_uri object or NULL on failure
684  **/
685 raptor_uri*
raptor_uri_copy(raptor_uri * uri)686 raptor_uri_copy(raptor_uri *uri)
687 {
688   return raptor_uri_copy_v2(raptor_world_instance(), uri);
689 }
690 #endif
691 
692 
693 /**
694  * raptor_uri_copy_v2:
695  * @world: raptor_world object
696  * @uri: URI object
697  *
698  * Constructor - get a copy of a URI.
699  *
700  * Return value: a new #raptor_uri object or NULL on failure
701  **/
702 raptor_uri*
raptor_uri_copy_v2(raptor_world * world,raptor_uri * uri)703 raptor_uri_copy_v2(raptor_world* world, raptor_uri *uri)
704 {
705   if(!uri)
706     return NULL;
707 
708   return (*world->uri_handler->uri_copy)(world->uri_handler_context, uri);
709 }
710 
711 
712 static unsigned char*
raptor_default_uri_as_string(void * context,raptor_uri * uri)713 raptor_default_uri_as_string(void *context, raptor_uri *uri)
714 {
715   return (unsigned char*)uri;
716 }
717 
718 
719 #ifndef RAPTOR_DISABLE_V1
720 /**
721  * raptor_uri_as_string:
722  * @uri: #raptor_uri object
723  *
724  * Get a string representation of a URI.
725  *
726  * Returns a shared pointer to a string representation of @uri.  This
727  * string is shared and must not be freed, otherwise see use the
728  * raptor_uri_to_string() or raptor_uri_to_counted_string() methods.
729  *
730  * raptor_init() MUST have been called before calling this function.
731  * Use raptor_uri_as_string_v2() if using raptor_world APIs.
732  *
733  * Return value: shared string representation of URI
734  **/
735 unsigned char*
raptor_uri_as_string(raptor_uri * uri)736 raptor_uri_as_string(raptor_uri *uri)
737 {
738   return raptor_uri_as_string_v2(raptor_world_instance(), uri);
739 }
740 #endif
741 
742 
743 /**
744  * raptor_uri_as_string_v2:
745  * @world: raptor_world object
746  * @uri: #raptor_uri object
747  *
748  * Get a string representation of a URI.
749  *
750  * Returns a shared pointer to a string representation of @uri.  This
751  * string is shared and must not be freed, otherwise see use the
752  * raptor_uri_to_string() or raptor_uri_to_counted_string() methods.
753  *
754  * Return value: shared string representation of URI
755  **/
756 unsigned char*
raptor_uri_as_string_v2(raptor_world * world,raptor_uri * uri)757 raptor_uri_as_string_v2(raptor_world* world, raptor_uri *uri)
758 {
759   if(!uri)
760     return NULL;
761 
762   return (*world->uri_handler->uri_as_string)(world->uri_handler_context, uri);
763 }
764 
765 
766 static unsigned char*
raptor_default_uri_as_counted_string(void * context,raptor_uri * uri,size_t * len_p)767 raptor_default_uri_as_counted_string(void *context, raptor_uri *uri,
768                                      size_t* len_p)
769 {
770   if(len_p)
771     *len_p=strlen((char*)uri);
772   return (unsigned char*)uri;
773 }
774 
775 
776 #ifndef RAPTOR_DISABLE_V1
777 /**
778  * raptor_uri_as_counted_string:
779  * @uri: URI object
780  * @len_p: address of length variable or NULL
781  *
782  * Get a string representation of a URI with count.
783  *
784  * Returns a shared pointer to a string representation of @uri along
785  * with the length of the string in @len_p, if not NULL.  This
786  * string is shared and must not be freed, otherwise see use the
787  * raptor_uri_to_string() or raptor_uri_to_counted_string() methods.
788  *
789  * raptor_init() MUST have been called before calling this function.
790  * Use raptor_uri_as_counted_string_v2() if using raptor_world APIs.
791  *
792  * Return value: shared string representation of URI
793  **/
794 unsigned char*
raptor_uri_as_counted_string(raptor_uri * uri,size_t * len_p)795 raptor_uri_as_counted_string(raptor_uri *uri, size_t* len_p)
796 {
797   return raptor_uri_as_counted_string_v2(raptor_world_instance(), uri, len_p);
798 }
799 #endif
800 
801 
802 /**
803  * raptor_uri_as_counted_string_v2:
804  * @world: raptor_world object
805  * @uri: URI object
806  * @len_p: address of length variable or NULL
807  *
808  * Get a string representation of a URI with count.
809  *
810  * Returns a shared pointer to a string representation of @uri along
811  * with the length of the string in @len_p, if not NULL.  This
812  * string is shared and must not be freed, otherwise see use the
813  * raptor_uri_to_string() or raptor_uri_to_counted_string() methods.
814  *
815  * Return value: shared string representation of URI
816  **/
817 unsigned char*
raptor_uri_as_counted_string_v2(raptor_world * world,raptor_uri * uri,size_t * len_p)818 raptor_uri_as_counted_string_v2(raptor_world* world, raptor_uri *uri, size_t* len_p)
819 {
820   if(!uri)
821     return NULL;
822 
823   return (*world->uri_handler->uri_as_counted_string)(world->uri_handler_context, uri, len_p);
824 }
825 
826 
827 /**
828  * raptor_uri_filename_to_uri_string:
829  * @filename: The filename to convert
830  *
831  * Converts a filename to a file: URI.
832  *
833  * Handles the OS-specific escaping on turning filenames into URIs
834  * and returns a new buffer that the caller must free().  Turns
835  * a space in the filname into %20 and '%' into %25.
836  *
837  * Return value: A newly allocated string with the URI or NULL on failure
838  **/
839 unsigned char *
raptor_uri_filename_to_uri_string(const char * filename)840 raptor_uri_filename_to_uri_string(const char *filename)
841 {
842   unsigned char *buffer=NULL;
843   const char *from;
844   char *to;
845 #ifndef WIN32
846   char *path=NULL;
847 #endif
848   /*     "file://" ... \0 */
849   size_t len=7 + sizeof(char*);
850 
851   if(!filename)
852     return NULL;
853 
854 #ifdef WIN32
855 /*
856  * On WIN32, filenames turn into
857  *   "file://" + translated filename
858  * where the translation is \\ turns into / and ' ' into %20, '%' into %25
859  * and if the filename does not start with '\', it is relative
860  * in which case, a . is appended to the authority
861  *
862  * e.g
863  *  FILENAME              URI
864  *  c:\windows\system     file:///c:/windows/system
865  *  \\server\dir\file.doc file://server/dir/file.doc
866  *  a:foo                 file:///a:./foo
867  *  C:\Documents and Settings\myapp\foo.bat
868  *                        file:///C:/Documents%20and%20Settings/myapp/foo.bat
869  *
870  * There are also UNC names \\server\share\blah
871  * that turn into file:///server/share/blah
872  * using the above algorithm.
873  */
874   if(filename[1] == ':' && filename[2] != '\\')
875     len+=3; /* relative filename - add / and ./ */
876   else if(*filename == '\\')
877     len-=2; /* two // from not needed in filename */
878   else
879     len++; /* / at start of path */
880 
881 #else
882 /* others - unix: turn spaces into %20, '%' into %25 */
883 
884   if(*filename != '/') {
885     size_t path_max;
886 #ifdef PATH_MAX
887     path_max=PATH_MAX;
888 #else
889     path_max=1024; /* an initial guess at the length */
890 #endif
891     path=(char*)malloc(path_max);
892     while(1) {
893       /* malloc() failed or getcwd() succeeded */
894       if(!path || getcwd(path, path_max))
895         break;
896 
897       /* failed */
898       if(errno != ERANGE)
899         break;
900 
901       /* try again with a bigger buffer */
902       path_max *= 2;
903       path=(char*)realloc(path, path_max);
904     }
905     if(!path)
906       goto path_done;
907 
908     strcat(path, "/");
909     strcat(path, filename);
910     filename=(const char*)path;
911   }
912 #endif
913 
914   /* add URI-escaped filename length */
915   for(from=filename; *from ; from++) {
916     len++;
917     if(*from == ' ' || *from == '%')
918       len+=2; /* strlen(%xx)-1 */
919   }
920 
921   buffer=(unsigned char*)RAPTOR_MALLOC(cstring, len);
922   if(!buffer)
923     goto path_done;
924 
925   strcpy((char*)buffer, "file://");
926   from=filename;
927   to=(char*)(buffer+7);
928 #ifdef WIN32
929   if(*from == '\\' && from[1] == '\\')
930     from+=2;
931   else
932     *to++ ='/';
933 #endif
934   while(*from) {
935     char c=*from++;
936 #ifdef WIN32
937     if (c == '\\')
938       *to++ ='/';
939     else if(c == ':') {
940       *to++ = c;
941       if(*from != '\\') {
942         *to++ ='.';
943         *to++ ='/';
944       }
945     } else
946 #endif
947     if(c == ' ' || c == '%') {
948       *to++ ='%';
949       *to++ ='2';
950       *to++ =(c == ' ') ? '0' : '5';
951     } else
952       *to++ =c;
953   }
954   *to='\0';
955 
956   path_done:
957 #ifndef WIN32
958   if(path)
959     free(path);
960 #endif
961 
962   return buffer;
963 }
964 
965 
966 /**
967  * raptor_uri_uri_string_to_filename_fragment:
968  * @uri_string: The file: URI to convert
969  * @fragment_p: Address of pointer to store any URI fragment or NULL
970  *
971  * Convert a file: URI to a filename and fragment.
972  *
973  * Handles the OS-specific file: URIs to filename mappings.  Returns
974  * a new buffer containing the filename that the caller must free.
975  *
976  * If @fragment_p is given, a new string containing the URI fragment
977  * is returned, or NULL if none is present
978  *
979  * Return value: A newly allocated string with the filename or NULL on failure
980  **/
981 char *
raptor_uri_uri_string_to_filename_fragment(const unsigned char * uri_string,unsigned char ** fragment_p)982 raptor_uri_uri_string_to_filename_fragment(const unsigned char *uri_string,
983                                            unsigned char **fragment_p)
984 {
985   char *filename;
986   size_t len=0;
987   raptor_uri_detail *ud=NULL;
988   unsigned char *from;
989   char *to;
990 #ifdef WIN32
991   unsigned char *p;
992 #endif
993 
994   if(!uri_string || !*uri_string)
995     return NULL;
996 
997   ud=raptor_new_uri_detail(uri_string);
998   if(!ud)
999     return NULL;
1000 
1001 
1002   if(!ud->scheme || raptor_strcasecmp((const char*)ud->scheme, "file")) {
1003     raptor_free_uri_detail(ud);
1004     return NULL;
1005   }
1006 
1007   if(ud->authority) {
1008     if(!*ud->authority)
1009       ud->authority=NULL;
1010     else if(!raptor_strcasecmp((const char*)ud->authority, "localhost"))
1011       ud->authority=NULL;
1012   }
1013 
1014   /* Cannot do much if there is no path */
1015   if(!ud->path || (ud->path && !*ud->path)) {
1016     raptor_free_uri_detail(ud);
1017     return NULL;
1018   }
1019 
1020   /* See raptor_uri_filename_to_uri_string for details of the mapping */
1021 #ifdef WIN32
1022   if(ud->authority)
1023     len+=ud->authority_len+3;
1024 
1025   p=ud->path;
1026   /* remove leading slash from path if there is one */
1027   if(*p && p[0] == '/') {
1028 	  p++;
1029 	  len--;
1030   }
1031   /* handle case where path starts with drive letter */
1032   if(*p && (p[1] == '|' || p[1] == ':')) {
1033     /* Either
1034      *   "a:" like in file://a|/... or file://a:/...
1035      * or
1036      *   "a:." like in file://a:./foo
1037      * giving device-relative path a:foo
1038      */
1039     if(p[2]=='.') {
1040       p[2]=*p;
1041       p[3]=':';
1042       p+= 2;
1043       len-= 2; /* remove 2 for ./ */
1044     } else
1045       p[1]=':';
1046   }
1047 #endif
1048 
1049 
1050   /* add URI-escaped filename length */
1051   for(from=ud->path; *from ; from++) {
1052     len++;
1053     if(*from == '%')
1054       from+= 2;
1055   }
1056 
1057 
1058   /* Something is wrong */
1059   if(!len) {
1060     raptor_free_uri_detail(ud);
1061     return NULL;
1062   }
1063 
1064   filename=(char*)RAPTOR_MALLOC(cstring, len + sizeof(char*));
1065   if(!filename) {
1066     raptor_free_uri_detail(ud);
1067     return NULL;
1068   }
1069 
1070 
1071   to=filename;
1072 
1073 #ifdef WIN32
1074   if(ud->authority) {
1075     *to++ = '\\';
1076     *to++ = '\\';
1077     from=ud->authority;
1078     while( (*to++ = *from++) )
1079       ;
1080     to--;
1081     *to++ = '\\';
1082   }
1083 
1084   /* copy path after all /s */
1085   from=p;
1086 #else
1087   from=ud->path;
1088 #endif
1089 
1090   while(*from) {
1091     char c=*from++;
1092 #ifdef WIN32
1093     if(c == '/')
1094       *to++ ='\\';
1095     else
1096 #endif
1097     if(c == '%') {
1098       if(*from && from[1]) {
1099         char hexbuf[3];
1100         char *endptr=NULL;
1101         hexbuf[0]=(char)*from;
1102         hexbuf[1]=(char)from[1];
1103         hexbuf[2]='\0';
1104         c=(char)strtol((const char*)hexbuf, &endptr, 16);
1105         if(endptr == &hexbuf[2])
1106           *to++ = c;
1107       }
1108       from+= 2;
1109     } else
1110       *to++ =c;
1111   }
1112   *to='\0';
1113 
1114   if(fragment_p) {
1115     if(ud->fragment) {
1116       len=ud->fragment_len;
1117       *fragment_p=(unsigned char*)RAPTOR_MALLOC(cstring, len + sizeof(char*));
1118       if(*fragment_p)
1119         strncpy((char*)*fragment_p, (const char*)ud->fragment, len+1);
1120     } else
1121       *fragment_p=NULL;
1122   }
1123 
1124   raptor_free_uri_detail(ud);
1125 
1126   return filename;
1127 }
1128 
1129 
1130 /**
1131  * raptor_uri_uri_string_to_filename:
1132  * @uri_string: The file: URI to convert
1133  *
1134  * Convert a file: URI to a filename.
1135  *
1136  * Handles the OS-specific file: URIs to filename mappings.  Returns
1137  * a new buffer containing the filename that the caller must free.
1138  *
1139  * Return value: A newly allocated string with the filename or NULL on failure
1140  **/
1141 char *
raptor_uri_uri_string_to_filename(const unsigned char * uri_string)1142 raptor_uri_uri_string_to_filename(const unsigned char *uri_string)
1143 {
1144   return raptor_uri_uri_string_to_filename_fragment(uri_string, NULL);
1145 }
1146 
1147 
1148 #ifndef RAPTOR_DISABLE_DEPRECATED
1149 /**
1150  * raptor_uri_is_file_uri:
1151  * @uri_string: The URI string to check
1152  *
1153  * Check if a URI string is a file: URI.
1154  *
1155  * @deprecated: use raptor_uri_uri_string_is_file_uri() instead
1156  *
1157  * Return value: Non zero if URI string is a file: URI
1158  **/
1159 int
raptor_uri_is_file_uri(const unsigned char * uri_string)1160 raptor_uri_is_file_uri(const unsigned char* uri_string) {
1161   return raptor_uri_uri_string_is_file_uri(uri_string);
1162 }
1163 #endif
1164 
1165 
1166 /**
1167  * raptor_uri_uri_string_is_file_uri:
1168  * @uri_string: The URI string to check
1169  *
1170  * Check if a URI string is a file: URI.
1171  *
1172  * Return value: Non zero if URI string is a file: URI
1173  **/
1174 int
raptor_uri_uri_string_is_file_uri(const unsigned char * uri_string)1175 raptor_uri_uri_string_is_file_uri(const unsigned char* uri_string) {
1176   if(!uri_string || !*uri_string)
1177     return 1;
1178 
1179   return raptor_strncasecmp((const char*)uri_string, "file:", 5)==0;
1180 }
1181 
1182 
1183 #ifndef RAPTOR_DISABLE_V1
1184 /**
1185  * raptor_new_uri_for_xmlbase:
1186  * @old_uri: URI to transform
1187  *
1188  * Constructor - create a URI suitable for use as an XML Base.
1189  *
1190  * Takes an existing URI and ensures it has a path (default /) and has
1191  * no fragment or query arguments - XML base does not use these.
1192  *
1193  * raptor_init() MUST have been called before calling this function.
1194  * Use raptor_new_uri_for_xmlbase_v2() if using raptor_world APIs.
1195  *
1196  * Return value: new #raptor_uri object or NULL on failure.
1197  **/
1198 raptor_uri*
raptor_new_uri_for_xmlbase(raptor_uri * old_uri)1199 raptor_new_uri_for_xmlbase(raptor_uri* old_uri)
1200 {
1201   return raptor_new_uri_for_xmlbase_v2(raptor_world_instance(), old_uri);
1202 }
1203 #endif
1204 
1205 
1206 /**
1207  * raptor_new_uri_for_xmlbase_v2:
1208  * @world: raptor_world object
1209  * @old_uri: URI to transform
1210  *
1211  * Constructor - create a URI suitable for use as an XML Base.
1212  *
1213  * Takes an existing URI and ensures it has a path (default /) and has
1214  * no fragment or query arguments - XML base does not use these.
1215  *
1216  * Return value: new #raptor_uri object or NULL on failure.
1217  **/
1218 raptor_uri*
raptor_new_uri_for_xmlbase_v2(raptor_world * world,raptor_uri * old_uri)1219 raptor_new_uri_for_xmlbase_v2(raptor_world* world, raptor_uri* old_uri)
1220 {
1221   unsigned char *uri_string;
1222   unsigned char *new_uri_string;
1223   raptor_uri* new_uri;
1224   raptor_uri_detail *ud;
1225 
1226   if(!old_uri)
1227     return NULL;
1228 
1229   uri_string=raptor_uri_as_string_v2(world, old_uri);
1230 
1231   ud=raptor_new_uri_detail(uri_string);
1232   if(!ud)
1233     return NULL;
1234 
1235   if(!ud->path) {
1236     ud->path=(unsigned char*)"/";
1237     ud->path_len=1;
1238   }
1239 
1240   ud->query=NULL; ud->query_len=0;
1241   ud->fragment=NULL; ud->fragment_len=0;
1242   new_uri_string=raptor_uri_detail_to_string(ud, NULL);
1243   raptor_free_uri_detail(ud);
1244   if(!new_uri_string)
1245     return NULL;
1246 
1247   new_uri=raptor_new_uri_v2(world, new_uri_string);
1248   RAPTOR_FREE(cstring, new_uri_string);
1249 
1250   return new_uri;
1251 }
1252 
1253 
1254 #ifndef RAPTOR_DISABLE_V1
1255 /**
1256  * raptor_new_uri_for_retrieval:
1257  * @old_uri: URI to transform
1258  *
1259  * Constructor - create a URI suitable for retrieval.
1260  *
1261  * Takes an existing URI and ensures it has a path (default /) and has
1262  * no fragment - URI retrieval does not use the fragment part.
1263  *
1264  * raptor_init() MUST have been called before calling this function.
1265  * Use raptor_new_uri_for_retrieval_v2() if using raptor_world APIs.
1266  *
1267  * Return value: new #raptor_uri object or NULL on failure.
1268  **/
1269 raptor_uri*
raptor_new_uri_for_retrieval(raptor_uri * old_uri)1270 raptor_new_uri_for_retrieval(raptor_uri* old_uri)
1271 {
1272   return raptor_new_uri_for_retrieval_v2(raptor_world_instance(), old_uri);
1273 }
1274 #endif
1275 
1276 
1277 /**
1278  * raptor_new_uri_for_retrieval_v2:
1279  * @world: raptor_world object
1280  * @old_uri: URI to transform
1281  *
1282  * Constructor - create a URI suitable for retrieval.
1283  *
1284  * Takes an existing URI and ensures it has a path (default /) and has
1285  * no fragment - URI retrieval does not use the fragment part.
1286  *
1287  * Return value: new #raptor_uri object or NULL on failure.
1288  **/
1289 raptor_uri*
raptor_new_uri_for_retrieval_v2(raptor_world * world,raptor_uri * old_uri)1290 raptor_new_uri_for_retrieval_v2(raptor_world* world, raptor_uri* old_uri)
1291 {
1292   unsigned char *uri_string;
1293   unsigned char *new_uri_string;
1294   raptor_uri* new_uri;
1295   raptor_uri_detail *ud;
1296 
1297   if(!old_uri)
1298     return NULL;
1299 
1300   uri_string=raptor_uri_as_string_v2(world, old_uri);
1301 
1302   ud=raptor_new_uri_detail(uri_string);
1303   if(!ud)
1304     return NULL;
1305 
1306   if(!ud->path) {
1307     ud->path=(unsigned char*)"/";
1308     ud->path_len=1;
1309   }
1310 
1311   ud->fragment=NULL; ud->fragment_len=0;
1312   new_uri_string=raptor_uri_detail_to_string(ud, NULL);
1313   raptor_free_uri_detail(ud);
1314   if(!new_uri_string)
1315     return NULL;
1316 
1317   new_uri=raptor_new_uri_v2(world, new_uri_string);
1318   RAPTOR_FREE(cstring, new_uri_string);
1319 
1320   return new_uri;
1321 }
1322 
1323 
1324 static const raptor_uri_handler raptor_uri_default_handler = {
1325   raptor_default_new_uri,
1326   raptor_default_new_uri_from_uri_local_name,
1327   raptor_default_new_uri_relative_to_base,
1328   raptor_default_new_uri_for_rdf_concept,
1329   raptor_default_free_uri,
1330   raptor_default_uri_equals,
1331   raptor_default_uri_copy,
1332   raptor_default_uri_as_string,
1333   raptor_default_uri_as_counted_string,
1334   2, /* URI Interface Version */
1335   raptor_default_uri_compare /* URI Interface V2 */
1336 };
1337 
1338 
1339 int
raptor_uri_init(raptor_world * world)1340 raptor_uri_init(raptor_world* world)
1341 {
1342   raptor_uri_set_handler_v2(world, &raptor_uri_default_handler, world);
1343   return 0;
1344 }
1345 
1346 
1347 /*
1348  * raptor_uri_path_common_base_length:
1349  * @first_path: The first path (path only, not a full URI)
1350  * @first_path_len: Length of first_path
1351  * @second_path: The second path (path only, not a full URI)
1352  * @second_path_len: Length of second_path
1353  *
1354  * Find the common base length of two URI path components.
1355  *
1356  * Return value: Length of the common base path
1357  **/
1358 
1359 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)1360 raptor_uri_path_common_base_length(const unsigned char *first_path, size_t first_path_len,
1361                                    const unsigned char *second_path, size_t second_path_len)
1362 {
1363   int common_len=0;
1364   const unsigned char *cur_ptr=first_path;
1365   const unsigned char *prev_ptr=first_path;
1366 
1367   /* Compare each path component of first_path and second_path until there is
1368      a mismatch. Then return the length from the start of the path to the last
1369      successful match. */
1370   while((cur_ptr=(const unsigned char*)memchr(cur_ptr, '/', first_path_len))) {
1371     cur_ptr++;
1372     if(strncmp((const char*)first_path+common_len,
1373                (const char*)second_path+common_len, cur_ptr-prev_ptr))
1374       break;
1375 
1376     first_path_len -= cur_ptr - prev_ptr;
1377     prev_ptr=cur_ptr;
1378     common_len = prev_ptr - first_path;
1379   }
1380   return prev_ptr - first_path;
1381 }
1382 
1383 
1384 /*
1385  * raptor_uri_path_make_relative_path:
1386  * @from_path: The base path (path only, not a full URI)
1387  * @from_path_len: Length of the base path
1388  * @to_path: The reference path (path only, not a full URI)
1389  * @to_path_len: Length of the reference path
1390  * @suffix: String to be appended to the final relative path
1391  * @suffix_len: Length of the suffix
1392  * @result_length_p: Location to store the length of the string or NULL
1393  *
1394  * Make a relative URI path.
1395  *
1396  * Return value: A newly allocated relative path string or NULL on failure.
1397  **/
1398 
1399 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)1400 raptor_uri_path_make_relative_path(const unsigned char *from_path, size_t from_path_len,
1401                                    const unsigned char *to_path, size_t to_path_len,
1402                                    const unsigned char *suffix, size_t suffix_len,
1403                                    size_t *result_length_p)
1404 {
1405   int common_len, cur_len, final_len, up_dirs = 0, to_dir_len = 0;
1406   const unsigned char *cur_ptr, *prev_ptr;
1407   unsigned char *final_path, *final_path_cur;
1408 
1409   common_len=raptor_uri_path_common_base_length(from_path, from_path_len,
1410                                                 to_path, to_path_len);
1411 
1412   if(result_length_p)
1413     *result_length_p=0;
1414 
1415   /* Count how many directories we have to go up */
1416   cur_ptr = from_path + common_len;
1417   prev_ptr=cur_ptr;
1418   cur_len = from_path_len - common_len;
1419   while((cur_ptr = (const unsigned char*)memchr(cur_ptr, '/', cur_len))) {
1420     cur_ptr++;
1421     up_dirs++;
1422     cur_len -= cur_ptr - prev_ptr;
1423     prev_ptr=cur_ptr;
1424   }
1425 
1426   /* Calculate how many characters of to_path subdirs (counted from the
1427      common base) we have to add. */
1428   cur_ptr = to_path + common_len;
1429   prev_ptr=cur_ptr;
1430   cur_len = to_path_len - common_len;
1431   while((cur_ptr = (const unsigned char*)memchr(cur_ptr, '/', cur_len))) {
1432     cur_ptr++;
1433     cur_len -= cur_ptr - prev_ptr;
1434     prev_ptr=cur_ptr;
1435   }
1436   to_dir_len = prev_ptr - (to_path + common_len);
1437 
1438   /* Create the final relative path */
1439   final_len = up_dirs*3 + to_dir_len + suffix_len; /* 3 for each "../" */
1440   final_path=(unsigned char*)RAPTOR_MALLOC(cstring, final_len + sizeof(char*));
1441   if(!final_path)
1442     return NULL;
1443   *final_path=0;
1444 
1445   /* First, add the necessary "../" parts */
1446   final_path_cur=final_path;
1447   while (up_dirs--) {
1448     *final_path_cur++='.';
1449     *final_path_cur++='.';
1450     *final_path_cur++='/';
1451   }
1452 
1453   /* Then, add the path from the common base to the to_path */
1454   memcpy(final_path_cur, to_path + common_len, to_dir_len);
1455   final_path_cur+=to_dir_len;
1456 
1457   /* Finally, add the suffix */
1458   if(suffix && suffix_len) {
1459     /* As a special case, if the suffix begins with a dot (".") and the final
1460        output string so far is non-empty, skip the dot. */
1461     if (*suffix == '.' && final_path_cur != final_path) {
1462       /* Make sure that the dot really represents a directory and it's not
1463          just part of a file name like ".foo". In other words, the dot must
1464          either be the only character or the next character must be the
1465          fragment or the query character. */
1466       if ((suffix_len == 1) ||
1467           (suffix_len > 1 && (suffix[1] == '#' || suffix[1] == '?'))) {
1468         suffix++;
1469         suffix_len--;
1470         final_len--;
1471       }
1472     }
1473     if(suffix_len)
1474       memcpy(final_path_cur, suffix, suffix_len);
1475   }
1476 
1477   final_path[final_len]=0;
1478 
1479   if (result_length_p)
1480     *result_length_p=final_len;
1481 
1482   return final_path;
1483 }
1484 
1485 
1486 #ifndef RAPTOR_DISABLE_V1
1487 /**
1488  * raptor_uri_to_relative_counted_uri_string:
1489  * @base_uri: The base absolute URI to resolve against (or NULL)
1490  * @reference_uri: The reference absolute URI to use
1491  * @length_p: Location to store the length of the relative URI string or NULL
1492  *
1493  * Get the counted relative URI string of a URI against a base URI.
1494  *
1495  * raptor_init() MUST have been called before calling this function.
1496  * Use raptor_uri_to_relative_counted_uri_string_v2() if using raptor_world APIs.
1497  *
1498  * Return value: A newly allocated relative URI string or NULL on failure
1499  **/
1500 unsigned char*
raptor_uri_to_relative_counted_uri_string(raptor_uri * base_uri,raptor_uri * reference_uri,size_t * length_p)1501 raptor_uri_to_relative_counted_uri_string(raptor_uri *base_uri,
1502                                           raptor_uri *reference_uri,
1503                                           size_t *length_p)
1504 {
1505   return raptor_uri_to_relative_counted_uri_string_v2(raptor_world_instance(),
1506                                                       base_uri,
1507                                                       reference_uri,
1508                                                       length_p);
1509 }
1510 #endif
1511 
1512 
1513 /**
1514  * raptor_uri_to_relative_counted_uri_string_v2:
1515  * @world: raptor_world object
1516  * @base_uri: The base absolute URI to resolve against (or NULL)
1517  * @reference_uri: The reference absolute URI to use
1518  * @length_p: Location to store the length of the relative URI string or NULL
1519  *
1520  * Get the counted relative URI string of a URI against a base URI.
1521  *
1522  * Return value: A newly allocated relative URI string or NULL on failure
1523  **/
1524 
1525 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)1526 raptor_uri_to_relative_counted_uri_string_v2(raptor_world* world,
1527                                              raptor_uri *base_uri,
1528                                              raptor_uri *reference_uri,
1529                                              size_t *length_p) {
1530   raptor_uri_detail *base_detail=NULL, *reference_detail;
1531   const unsigned char *base, *reference_str, *base_file, *reference_file;
1532   unsigned char *suffix, *cur_ptr;
1533   size_t base_len, reference_len, reference_file_len, suffix_len;
1534   unsigned char *result=NULL;
1535   int suffix_is_result=0;
1536 
1537   if(!reference_uri)
1538     return NULL;
1539 
1540   if(length_p)
1541     *length_p=0;
1542 
1543   reference_str=raptor_uri_as_counted_string_v2(world, reference_uri, &reference_len);
1544   reference_detail=raptor_new_uri_detail(reference_str);
1545   if(!reference_detail)
1546     goto err;
1547 
1548   if(!base_uri)
1549     goto buildresult;
1550 
1551   base=raptor_uri_as_counted_string_v2(world, base_uri, &base_len);
1552   base_detail=raptor_new_uri_detail(base);
1553   if(!base_detail)
1554     goto err;
1555 
1556   /* Check if the whole URIs are equal */
1557   if(raptor_uri_equals_v2(world, base_uri, reference_uri)) {
1558     reference_len=0;
1559     goto buildresult;
1560   }
1561 
1562   /* Check if scheme and authority of the URIs are equal */
1563   if(base_detail->scheme_len == reference_detail->scheme_len &&
1564      base_detail->authority_len == reference_detail->authority_len &&
1565      !strncmp((const char*)base_detail->scheme,
1566               (const char*)reference_detail->scheme,
1567               base_detail->scheme_len) &&
1568      !strncmp((const char*)base_detail->authority,
1569               (const char*)reference_detail->authority,
1570               base_detail->authority_len)) {
1571 
1572     if(!base_detail->path) {
1573       if(reference_detail->path) {
1574         /* if base has no path then the relative URI is relative
1575          * to scheme+authority so assemble that in the suffix
1576          * buffer (adding any query part or fragment needed)
1577          */
1578         reference_file=reference_detail->path;
1579         reference_file_len=reference_detail->path_len;
1580         suffix_is_result=1;
1581         goto addqueryfragment;
1582       }
1583       goto buildresult;
1584     }
1585 
1586     /* Find the file name components */
1587     base_file = (const unsigned char*)strrchr((const char*)base_detail->path, '/');
1588     if(!base_file)
1589       goto buildresult;
1590     base_file++;
1591 
1592     if(!reference_detail->path)
1593       goto buildresult;
1594     reference_file=(const unsigned char*)strrchr((const char*)reference_detail->path, '/');
1595     if(!reference_file)
1596       goto buildresult;
1597     reference_file++;
1598 
1599     reference_file_len=reference_detail->path_len -
1600                        (reference_file - reference_detail->path);
1601 
1602     if(!strcmp((const char*)base_file, (const char*)reference_file)) {
1603       /* If the file names are equal, don't put them in the relative URI */
1604       reference_file=NULL;
1605       reference_file_len=0;
1606     } else if(*base_file && !*reference_file) {
1607       /* If the base file is non-empty, but the reference file is
1608        * empty, use "."  as the file name.
1609        */
1610       reference_file=(const unsigned char*)".";
1611       reference_file_len=1;
1612     }
1613 
1614   addqueryfragment:
1615     /* Calculate the length of the suffix (file name + query + fragment) */
1616     suffix_len=reference_file_len + reference_detail->query_len +
1617                reference_detail->fragment_len;
1618 
1619     if (reference_detail->query)
1620       suffix_len++; /* add one char for the '?' */
1621     if (reference_detail->fragment)
1622       suffix_len++; /* add one char for the '#' */
1623 
1624     /* Assemble the suffix */
1625     suffix=(unsigned char*)RAPTOR_MALLOC(cstring, suffix_len + sizeof(char*));
1626     if(!suffix)
1627       goto err;
1628     cur_ptr=suffix;
1629     if(reference_file) {
1630       memcpy(suffix, reference_file, reference_file_len);
1631       cur_ptr+= reference_file_len;
1632     }
1633 
1634     if(reference_detail->query) {
1635       *cur_ptr++='?';
1636       memcpy(cur_ptr, reference_detail->query, reference_detail->query_len);
1637       cur_ptr+= reference_detail->query_len;
1638     }
1639 
1640     if(reference_detail->fragment) {
1641       *cur_ptr++='#';
1642       memcpy(cur_ptr, reference_detail->fragment, reference_detail->fragment_len);
1643       cur_ptr+= reference_detail->fragment_len;
1644     }
1645     *cur_ptr=0;
1646 
1647     if(suffix_is_result) {
1648       /* If suffix is what we need, just use that as the result */
1649       result=suffix;
1650       if(length_p)
1651         *length_p=suffix_len;
1652     } else {
1653       /* Otherwise create the full relative path */
1654       result = raptor_uri_path_make_relative_path(base_detail->path,
1655                                                   base_detail->path_len,
1656                                                   reference_detail->path,
1657                                                   reference_detail->path_len,
1658                                                   suffix,
1659                                                   suffix_len,
1660                                                   length_p);
1661       RAPTOR_FREE(cstring, suffix);
1662     }
1663   }
1664 
1665 
1666  buildresult:
1667   /* If result is NULL at this point, it means that we were unable to find a
1668      relative URI, so we'll return a full absolute URI instead. */
1669   if(!result) {
1670     result=(unsigned char*)RAPTOR_MALLOC(cstring, reference_len + sizeof(char*));
1671     if(result) {
1672       if(reference_len)
1673         memcpy(result, reference_str, reference_len);
1674       result[reference_len] = 0;
1675       if(length_p)
1676         *length_p=reference_len;
1677     }
1678   }
1679 
1680   err:
1681   if(base_detail)
1682     raptor_free_uri_detail(base_detail);
1683   raptor_free_uri_detail(reference_detail);
1684 
1685   return result;
1686 }
1687 
1688 
1689 #ifndef RAPTOR_DISABLE_V1
1690 /**
1691  * raptor_uri_to_relative_uri_string:
1692  * @base_uri: The base absolute URI to resolve against
1693  * @reference_uri: The reference absolute URI to use
1694  *
1695  * Get the relative URI string of a URI against a base URI.
1696  *
1697  * raptor_init() MUST have been called before calling this function.
1698  * Use raptor_uri_to_relative_uri_string_v2() if using raptor_world APIs.
1699  *
1700  * Return value: A newly allocated relative URI string or NULL on failure
1701  **/
1702 unsigned char*
raptor_uri_to_relative_uri_string(raptor_uri * base_uri,raptor_uri * reference_uri)1703 raptor_uri_to_relative_uri_string(raptor_uri *base_uri,
1704                                   raptor_uri *reference_uri)
1705 {
1706   return raptor_uri_to_relative_uri_string_v2(raptor_world_instance(),
1707                                               base_uri,
1708                                               reference_uri);
1709 }
1710 #endif
1711 
1712 
1713 /**
1714  * raptor_uri_to_relative_uri_string_v2:
1715  * @world: raptor_world instance
1716  * @base_uri: The base absolute URI to resolve against
1717  * @reference_uri: The reference absolute URI to use
1718  *
1719  * Get the relative URI string of a URI against a base URI.
1720  *
1721  * Return value: A newly allocated relative URI string or NULL on failure
1722  **/
1723 unsigned char*
raptor_uri_to_relative_uri_string_v2(raptor_world * world,raptor_uri * base_uri,raptor_uri * reference_uri)1724 raptor_uri_to_relative_uri_string_v2(raptor_world *world,
1725                                      raptor_uri *base_uri,
1726                                      raptor_uri *reference_uri)
1727 {
1728   return raptor_uri_to_relative_counted_uri_string_v2(world,
1729                                                       base_uri,
1730                                                       reference_uri,
1731                                                       NULL);
1732 }
1733 
1734 
1735 #ifndef RAPTOR_DISABLE_V1
1736 /**
1737  * raptor_uri_print:
1738  * @uri: URI to print
1739  * @stream: The file handle to print to
1740  *
1741  * Print a URI to a file handle.
1742  *
1743  * raptor_init() MUST have been called before calling this function.
1744  * Use raptor_uri_print_v2() if using raptor_world APIs.
1745  *
1746  **/
1747 void
raptor_uri_print(const raptor_uri * uri,FILE * stream)1748 raptor_uri_print(const raptor_uri* uri, FILE *stream) {
1749   raptor_uri_print_v2(raptor_world_instance(), uri, stream);
1750 }
1751 #endif
1752 
1753 
1754 /**
1755  * raptor_uri_print_v2:
1756  * @world: raptor_world object
1757  * @uri: URI to print
1758  * @stream: The file handle to print to
1759  *
1760  * Print a URI to a file handle.
1761  *
1762  **/
1763 void
raptor_uri_print_v2(raptor_world * world,const raptor_uri * uri,FILE * stream)1764 raptor_uri_print_v2(raptor_world* world, const raptor_uri* uri, FILE *stream)
1765 {
1766   int rc = 0;
1767 
1768   if(uri) {
1769     size_t len;
1770     unsigned char *string=raptor_uri_as_counted_string_v2(world, (raptor_uri*)uri, &len);
1771     rc = fwrite(string, len, 1, stream);
1772   } else
1773     rc = fwrite("(NULL URI)", 10, 1, stream);
1774 
1775   /* FIXME  Until world gains an error handler, there is nowhere to
1776    * report the IO error
1777    */
1778 }
1779 
1780 
1781 #ifndef RAPTOR_DISABLE_V1
1782 /**
1783  * raptor_uri_to_counted_string:
1784  * @uri: #raptor_uri object
1785  * @len_p: Pointer to length (or NULL)
1786  *
1787  * Get a new counted string for a URI.
1788  *
1789  * If @len_p is not NULL, the length of the string is stored in it.
1790  *
1791  * The memory allocated must be freed by the caller and
1792  * raptor_free_memory() should be used for best portability.
1793  *
1794  * raptor_init() MUST have been called before calling this function.
1795  * Use raptor_uri_to_counted_string_v2() if using raptor_world APIs.
1796  *
1797  * Return value: new string or NULL on failure
1798  **/
1799 unsigned char*
raptor_uri_to_counted_string(raptor_uri * uri,size_t * len_p)1800 raptor_uri_to_counted_string(raptor_uri *uri, size_t *len_p)
1801 {
1802   return raptor_uri_to_counted_string_v2(raptor_world_instance(), uri, len_p);
1803 }
1804 #endif
1805 
1806 
1807 /**
1808  * raptor_uri_to_counted_string_v2:
1809  * @world: raptor_world object
1810  * @uri: #raptor_uri object
1811  * @len_p: Pointer to length (or NULL)
1812  *
1813  * Get a new counted string for a URI.
1814  *
1815  * If @len_p is not NULL, the length of the string is stored in it.
1816  *
1817  * The memory allocated must be freed by the caller and
1818  * raptor_free_memory() should be used for best portability.
1819  *
1820  * Return value: new string or NULL on failure
1821  **/
1822 unsigned char*
raptor_uri_to_counted_string_v2(raptor_world * world,raptor_uri * uri,size_t * len_p)1823 raptor_uri_to_counted_string_v2(raptor_world* world, raptor_uri *uri, size_t *len_p)
1824 {
1825   size_t len;
1826   unsigned char *string;
1827   unsigned char *new_string;
1828 
1829   if(!uri)
1830     return NULL;
1831 
1832   string=raptor_uri_as_counted_string_v2(world, uri, &len);
1833   if(!string)
1834     return NULL;
1835 
1836   new_string=(unsigned char*)RAPTOR_MALLOC(cstring, len + 1); /* +1 for NUL termination */
1837   if(!new_string)
1838     return NULL;
1839 
1840   memcpy(new_string, string, len+1);
1841 
1842   if(len_p)
1843     *len_p=len;
1844   return new_string;
1845 }
1846 
1847 
1848 #ifndef RAPTOR_DISABLE_V1
1849 /**
1850  * raptor_uri_to_string:
1851  * @uri: #raptor_uri object
1852  *
1853  * Get a new string for a URI.
1854  *
1855  * The memory allocated must be freed by the caller and
1856  * raptor_free_memory() should be used for best portability.
1857  *
1858  * raptor_init() MUST have been called before calling this function.
1859  * Use raptor_uri_to_string_v2() if using raptor_world APIs.
1860  *
1861  * Return value: new string or NULL on failure
1862  **/
1863 unsigned char*
raptor_uri_to_string(raptor_uri * uri)1864 raptor_uri_to_string(raptor_uri *uri)
1865 {
1866   return raptor_uri_to_string_v2(raptor_world_instance(), uri);
1867 }
1868 #endif
1869 
1870 
1871 /**
1872  * raptor_uri_to_string_v2:
1873  * @world: raptor_world object
1874  * @uri: #raptor_uri object
1875  *
1876  * Get a new string for a URI.
1877  *
1878  * The memory allocated must be freed by the caller and
1879  * raptor_free_memory() should be used for best portability.
1880  *
1881  * Return value: new string or NULL on failure
1882  **/
1883 unsigned char*
raptor_uri_to_string_v2(raptor_world * world,raptor_uri * uri)1884 raptor_uri_to_string_v2(raptor_world* world, raptor_uri *uri)
1885 {
1886   return raptor_uri_to_counted_string_v2(world, uri, NULL);
1887 }
1888 
1889 
1890 /**
1891  * raptor_new_uri_from_rdf_ordinal:
1892  * @world: raptor_world object
1893  * @ordinal: integer rdf:_n
1894  *
1895  * Internal - convert an integer rdf:_n ordinal to the resource URI
1896  *
1897  * Return value: new URI object or NULL on failure
1898  **/
1899 raptor_uri*
raptor_new_uri_from_rdf_ordinal(raptor_world * world,int ordinal)1900 raptor_new_uri_from_rdf_ordinal(raptor_world* world, int ordinal)
1901 {
1902   /* 55 = strlen(rdf namespace URI) + _ + 10-digit number + \0 */
1903   unsigned char uri_string[55];
1904   strncpy((char*)uri_string, (const char*)raptor_rdf_namespace_uri,
1905           raptor_rdf_namespace_uri_len);
1906   sprintf((char*)uri_string+raptor_rdf_namespace_uri_len, "_%d",
1907           ordinal);
1908   return raptor_new_uri_v2(world, uri_string);
1909 }
1910 
1911 
1912 #ifdef STANDALONE
1913 
1914 #include <stdio.h>
1915 #ifdef HAVE_SYS_STAT_H
1916 #include <sys/stat.h>
1917 #endif
1918 
1919 /* one more prototype */
1920 int main(int argc, char *argv[]);
1921 
1922 static const char *program;
1923 
1924 
1925 static int
assert_filename_to_uri(const char * filename,const char * reference_uri)1926 assert_filename_to_uri (const char *filename, const char *reference_uri)
1927 {
1928   unsigned char *uri;
1929 
1930   uri=raptor_uri_filename_to_uri_string(filename);
1931 
1932   if (!uri || strcmp((const char*)uri, (const char*)reference_uri)) {
1933     fprintf(stderr,
1934             "%s: raptor_uri_filename_to_uri_string(%s) FAILED gaving URI %s != %s\n",
1935             program, filename, uri, reference_uri);
1936     if(uri)
1937       RAPTOR_FREE(cstring, uri);
1938     return 1;
1939   }
1940 
1941   RAPTOR_FREE(cstring, uri);
1942   return 0;
1943 }
1944 
1945 
1946 static int
assert_uri_to_filename(const char * uri,const char * reference_filename)1947 assert_uri_to_filename (const char *uri, const char *reference_filename)
1948 {
1949   char *filename;
1950 
1951   filename=raptor_uri_uri_string_to_filename((const unsigned char*)uri);
1952 
1953   if(filename && !reference_filename) {
1954     fprintf(stderr,
1955             "%s: raptor_uri_uri_string_to_filename(%s) FAILED giving filename %s != NULL\n",
1956             program, uri, filename);
1957     if(filename)
1958       RAPTOR_FREE(cstring, filename);
1959     return 1;
1960   } else if (filename && strcmp(filename, reference_filename)) {
1961     fprintf(stderr,
1962             "%s: raptor_uri_uri_string_to_filename(%s) FAILED gaving filename %s != %s\n",
1963             program, uri, filename, reference_filename);
1964     if(filename)
1965       RAPTOR_FREE(cstring, filename);
1966     return 1;
1967   }
1968 
1969   RAPTOR_FREE(cstring, filename);
1970   return 0;
1971 }
1972 
1973 
1974 static int
assert_uri_to_relative(raptor_world * world,const char * base,const char * uri,const char * relative)1975 assert_uri_to_relative(raptor_world *world, const char *base, const char *uri, const char *relative)
1976 {
1977   unsigned char *output;
1978   int result;
1979   raptor_uri* base_uri=NULL;
1980   raptor_uri* reference_uri=raptor_new_uri_v2(world, (const unsigned char*)uri);
1981   size_t length=0;
1982 
1983   if(base)
1984     base_uri=raptor_new_uri_v2(world, (const unsigned char*)base);
1985 
1986   output=raptor_uri_to_relative_counted_uri_string_v2(world,
1987                                                       base_uri, reference_uri,
1988                                                       &length);
1989   result=strcmp(relative, (const char*)output);
1990   if (result) {
1991     fprintf(stderr,
1992             "%s: raptor_uri_string_to_relative_uri_string FAILED: base='%s', uri='%s', expected='%s', got='%s'\n",
1993             program, base, uri, relative, output);
1994     RAPTOR_FREE(cstring, output);
1995     return 1;
1996   }
1997   RAPTOR_FREE(cstring, output);
1998   if(base_uri)
1999     raptor_free_uri_v2(world, base_uri);
2000   raptor_free_uri_v2(world, reference_uri);
2001   return 0;
2002 }
2003 
2004 
2005 static int
raptor_test_uri_compare(void * context,raptor_uri * uri1,raptor_uri * uri2)2006 raptor_test_uri_compare(void *context, raptor_uri* uri1, raptor_uri* uri2)
2007 {
2008   int* called_p=(int*)context;
2009   *called_p=1;
2010   return strcmp((char*)uri1, (char*)uri2);
2011 }
2012 
2013 
2014 int
main(int argc,char * argv[])2015 main(int argc, char *argv[])
2016 {
2017   raptor_world *world;
2018   const char *base_uri = "http://example.org/bpath/cpath/d;p?querystr#frag";
2019   const char *base_uri_xmlbase = "http://example.org/bpath/cpath/d;p";
2020   const char *base_uri_retrievable = "http://example.org/bpath/cpath/d;p?querystr";
2021 #ifndef WIN32
2022 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_STAT_H)
2023   const char* dirs[6] = { "/etc", "/bin", "/tmp", "/lib", "/var", NULL };
2024   unsigned char uri_buffer[16]; /* strlen("file:///DIR/foo")+1 */
2025   int i;
2026   const char *dir;
2027 #endif
2028 #endif
2029   unsigned char *str;
2030   raptor_uri *uri1, *uri2, *uri3;
2031 
2032   int failures=0;
2033 
2034   world = raptor_new_world();
2035   if(!world || raptor_world_open(world))
2036     exit(1);
2037 
2038   if((program=strrchr(argv[0], '/')))
2039     program++;
2040   else if((program=strrchr(argv[0], '\\')))
2041     program++;
2042   else
2043     program=argv[0];
2044 
2045 #ifdef WIN32
2046   failures += assert_filename_to_uri ("c:\\windows\\system", "file:///c:/windows/system");
2047   failures += assert_filename_to_uri ("\\\\server\\share\\file.doc", "file://server/share/file.doc");
2048   failures += assert_filename_to_uri ("a:foo", "file:///a:./foo");
2049 
2050   failures += assert_filename_to_uri ("C:\\Documents and Settings\\myapp\\foo.bat", "file:///C:/Documents%20and%20Settings/myapp/foo.bat");
2051   failures += assert_filename_to_uri ("C:\\My Documents\\%age.txt", "file:///C:/My%20Documents/%25age.txt");
2052 
2053   failures += assert_uri_to_filename ("file:///c|/windows/system", "c:\\windows\\system");
2054   failures += assert_uri_to_filename ("file:///c:/windows/system", "c:\\windows\\system");
2055   failures += assert_uri_to_filename ("file://server/share/file.doc", "\\\\server\\share\\file.doc");
2056   failures += assert_uri_to_filename ("file:///a:./foo", "a:foo");
2057   failures += assert_uri_to_filename ("file:///C:/Documents%20and%20Settings/myapp/foo.bat", "C:\\Documents and Settings\\myapp\\foo.bat");
2058   failures += assert_uri_to_filename ("file:///C:/My%20Documents/%25age.txt", "C:\\My Documents\\%age.txt");
2059 
2060 
2061   failures += assert_uri_to_filename ("file:c:\\thing",     "c:\\thing");
2062   failures += assert_uri_to_filename ("file:/c:\\thing",    "c:\\thing");
2063   failures += assert_uri_to_filename ("file://c:\\thing",   NULL);
2064   failures += assert_uri_to_filename ("file:///c:\\thing",  "c:\\thing");
2065   failures += assert_uri_to_filename ("file://localhost/",  NULL);
2066   failures += assert_uri_to_filename ("file://c:\\foo\\bar\\x.rdf",  NULL);
2067 
2068 #else
2069 
2070   failures += assert_filename_to_uri ("/path/to/file", "file:///path/to/file");
2071   failures += assert_filename_to_uri ("/path/to/file with spaces", "file:///path/to/file%20with%20spaces");
2072   failures += assert_uri_to_filename ("file:///path/to/file", "/path/to/file");
2073   failures += assert_uri_to_filename ("file:///path/to/file%20with%20spaces", "/path/to/file with spaces");
2074 
2075   /* Tests for Issue#0000268 http://bugs.librdf.org/mantis/view.php?id=268 */
2076   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");
2077   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");
2078 
2079 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_STAT_H)
2080   /* Need to test this with a real dir (preferably not /)
2081    * This is just a test so pretty likely to work on all development systems
2082    * that are not WIN32
2083    */
2084 
2085   for(i=0; (dir=dirs[i]); i++) {
2086     struct stat buf;
2087     if(!lstat(dir, &buf) && S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode)) {
2088       if(!chdir(dir))
2089         break;
2090     }
2091   }
2092   if(!dir)
2093     fprintf(stderr,
2094             "%s: WARNING: Found no convenient directory - not testing relative files\n",
2095             program);
2096   else {
2097     sprintf((char*)uri_buffer, "file://%s/foo", dir);
2098     fprintf(stderr,
2099             "%s: Checking relative file name 'foo' in dir %s expecting URI %s\n",
2100             program, dir, uri_buffer);
2101     failures += assert_filename_to_uri ("foo", (const char*)uri_buffer);
2102   }
2103 #endif
2104 
2105 #endif
2106 
2107   uri1=raptor_new_uri_v2(world, (const unsigned char*)base_uri);
2108 
2109   str=raptor_uri_as_string_v2(world, uri1);
2110   if(strcmp((const char*)str, base_uri)) {
2111     fprintf(stderr,
2112             "%s: raptor_uri_as_string(%s) FAILED gaving %s != %s\n",
2113             program, base_uri, str, base_uri);
2114     failures++;
2115   }
2116 
2117   uri2=raptor_new_uri_for_xmlbase_v2(world, uri1);
2118   str=raptor_uri_as_string_v2(world, uri2);
2119   if(strcmp((const char*)str, base_uri_xmlbase)) {
2120     fprintf(stderr,
2121             "%s: raptor_new_uri_for_xmlbase(URI %s) FAILED giving %s != %s\n",
2122             program, base_uri, str, base_uri_xmlbase);
2123     failures++;
2124   }
2125 
2126   uri3=raptor_new_uri_for_retrieval_v2(world, uri1);
2127 
2128   str=raptor_uri_as_string_v2(world, uri3);
2129   if(strcmp((const char*)str, base_uri_retrievable)) {
2130     fprintf(stderr,
2131             "%s: raptor_new_uri_for_retrievable(%s) FAILED gaving %s != %s\n",
2132             program, base_uri, str, base_uri_retrievable);
2133     failures++;
2134   }
2135 
2136   raptor_free_uri_v2(world, uri3);
2137   raptor_free_uri_v2(world, uri2);
2138   raptor_free_uri_v2(world, uri1);
2139 
2140   failures += assert_uri_to_relative(world, NULL, "http://example.com/foo/bar", "http://example.com/foo/bar");
2141   failures += assert_uri_to_relative(world, "", "http://example.com/foo/bar", "http://example.com/foo/bar");
2142   failures += assert_uri_to_relative(world, "foo:", "http://example.com/foo/bar", "http://example.com/foo/bar");
2143   failures += assert_uri_to_relative(world, "http://example.com/base/foo?foo#foo", "http://example.com/base/bar?bar#bar", "bar?bar#bar");
2144   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/", "foo/");
2145   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/.foo", "foo/.foo");
2146   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/.foo#bar", "foo/.foo#bar");
2147   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo/bar", "foo/bar");
2148   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/foo#bar", "#bar");
2149   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/bar#foo", "bar#foo");
2150   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/otherbase/bar", "../otherbase/bar");
2151   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example.com/base/#foo", ".#foo");
2152   failures += assert_uri_to_relative(world, "http://example.com/base/foo", "http://example2.com/base/bar", "http://example2.com/base/bar");
2153   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");
2154   failures += assert_uri_to_relative(world, "http://example.org/base#", "http://www.foo.org", "http://www.foo.org");
2155   failures += assert_uri_to_relative(world, "http://example.org", "http://a.example.org/", "http://a.example.org/");
2156   failures += assert_uri_to_relative(world, "http://example.org", "http://a.example.org", "http://a.example.org");
2157   failures += assert_uri_to_relative(world, "http://abcdefgh.example.org/foo/bar/", "http://ijklmnop.example.org/", "http://ijklmnop.example.org/");
2158   failures += assert_uri_to_relative(world, "http://example.org", "http://example.org/a/b/c/d/efgh", "/a/b/c/d/efgh");
2159 
2160   if(1) {
2161     raptor_uri_handler uri_handler;
2162     int ret;
2163     raptor_uri* u1;
2164     raptor_uri* u2;
2165     int called;
2166 
2167     /* URI Interface V1 */
2168     uri_handler.new_uri     = raptor_default_new_uri;
2169     uri_handler.free_uri    = raptor_default_free_uri;
2170     uri_handler.uri_compare = raptor_test_uri_compare;
2171     uri_handler.initialised=1;
2172     called=0;
2173     raptor_uri_set_handler_v2(world, &uri_handler, &called);
2174 
2175     u1=raptor_new_uri_v2(world, (const unsigned char *)"http://example.org/abc");
2176     u2=raptor_new_uri_v2(world, (const unsigned char *)"http://example.org/def");
2177 
2178     ret=raptor_uri_compare_v2(world, u1, u2);
2179     if(!(ret < 0)) {
2180       fprintf(stderr,
2181               "%s: raptor_uri_compare(%s, %s) FAILED V1 gave %d expected <0\n",
2182               program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2),
2183               ret);
2184       failures++;
2185     }
2186 
2187     if(called) {
2188       fprintf(stderr,
2189               "%s: raptor_uri_compare(%s, %s) FAILED V1 called user handler\n",
2190               program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2));
2191       failures++;
2192     }
2193 
2194 
2195     /* URI Interface V2 */
2196     uri_handler.initialised=2;
2197     called=0;
2198     raptor_uri_set_handler_v2(world, &uri_handler, &called);
2199 
2200     ret=raptor_uri_compare_v2(world, u1, u2);
2201     if(!(ret < 0)) {
2202       fprintf(stderr,
2203               "%s: raptor_uri_compare(%s, %s) FAILED V2 gave %d expected <0\n",
2204               program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2),
2205               ret);
2206       failures++;
2207     }
2208 
2209     if(!called) {
2210       fprintf(stderr,
2211               "%s: raptor_uri_compare(%s, %s) FAILED V2 did not call user handler\n",
2212               program, raptor_uri_as_string_v2(world, u1), raptor_uri_as_string_v2(world, u2));
2213       failures++;
2214     }
2215 
2216     raptor_free_uri_v2(world, u1);
2217     raptor_free_uri_v2(world, u2);
2218   }
2219 
2220   raptor_free_world(world);
2221 
2222   return failures ;
2223 }
2224 
2225 #endif
2226