1 /*
2 ##############################################################################
3 # 	Copyright (c) 2000-2006 All rights reserved
4 # 	Alberto Reggiori <areggiori@webweaving.org>
5 #	Dirk-Willem van Gulik <dirkx@webweaving.org>
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # 1. Redistributions of source code must retain the above copyright
12 #    notice, this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 #    notice, this list of conditions and the following disclaimer in
16 #    the documentation and/or other materials provided with the
17 #    distribution.
18 #
19 # 3. The end-user documentation included with the redistribution,
20 #    if any, must include the following acknowledgment:
21 #       "This product includes software developed by
22 #        Alberto Reggiori <areggiori@webweaving.org> and
23 #        Dirk-Willem van Gulik <dirkx@webweaving.org>."
24 #    Alternately, this acknowledgment may appear in the software itself,
25 #    if and wherever such third-party acknowledgments normally appear.
26 #
27 # 4. All advertising materials mentioning features or use of this software
28 #    must display the following acknowledgement:
29 #    This product includes software developed by the University of
30 #    California, Berkeley and its contributors.
31 #
32 # 5. Neither the name of the University nor the names of its contributors
33 #    may be used to endorse or promote products derived from this software
34 #    without specific prior written permission.
35 #
36 # 6. Products derived from this software may not be called "RDFStore"
37 #    nor may "RDFStore" appear in their names without prior written
38 #    permission.
39 #
40 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 # ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 # FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 # OF THE POSSIBILITY OF SUCH DAMAGE.
52 #
53 # ====================================================================
54 #
55 # This software consists of work developed by Alberto Reggiori and
56 # Dirk-Willem van Gulik. The RDF specific part is based based on public
57 # domain software written at the Stanford University Database Group by
58 # Sergey Melnik. For more information on the RDF API Draft work,
59 # please see <http://www-db.stanford.edu/~melnik/rdf/api.html>
60 # The DBMS TCP/IP server part is based on software originally written
61 # by Dirk-Willem van Gulik for Web Weaving Internet Engineering m/v Enschede,
62 # The Netherlands.
63 #
64 ##############################################################################
65 #
66 # $Id: rdfstore_serializer.c,v 1.9 2006/06/19 10:10:22 areggiori Exp $
67 #
68 */
69 
70 #if !defined(WIN32)
71 #include <sys/param.h>
72 #endif
73 
74 #include <sys/types.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <errno.h>
78 #include <strings.h>
79 #include <fcntl.h>
80 #include <ctype.h>
81 
82 #include <time.h>
83 #include <sys/stat.h>
84 
85 #include "rdfstore_log.h"
86 #include "rdfstore.h"
87 #include "rdfstore_serializer.h"
88 #include "rdfstore_digest.h"
89 #include "rdfstore_utf8.h"
90 
91 /*
92 #define RDFSTORE_DEBUG
93 */
94 
95 /*
96 	See also:
97 
98 	o-> N-Triples http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
99         o-> Quads http://robustai.net/sailor/grammar/Quads.html
100 
101 */
102 
103 int rdfstore_ntriples_hex2c(const char *x);
104 void rdfstore_ntriples_c2hex(int ch, char *x);
105 
106 char *
rdfstore_get_localname(char * uri)107 rdfstore_get_localname ( char * uri ) {
108         char * nc=NULL;
109         char * localname=NULL;
110 
111 	if ( uri == NULL )
112 		return NULL;
113 
114         /* try to get out XML QName LocalName from resource identifier */
115         nc = uri + strlen(uri)-1;
116         while( nc >= uri ) {
117                 if( rdfstore_is_xml_name( nc ) )
118                         localname = nc;
119                 nc--;
120                 };
121 
122         if( !localname ) {
123 		localname = uri; /* we can not split it up; so we default to the whole uri - correct? */
124                 };
125 
126         return localname;
127         };
128 
129 int
rdfstore_get_namespace(char * uri)130 rdfstore_get_namespace ( char * uri ) {
131         char * nc=NULL;
132 
133 	if ( uri == NULL )
134 		return 0;
135 
136 	nc = rdfstore_get_localname( uri );
137         if ( nc == NULL ) {
138 		return ( uri != NULL ) ? strlen(uri) : 0;
139 	} else {
140         	return (int)( nc - uri );
141 		};
142 	};
143 
144 /* see http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName */
145 int
rdfstore_is_xml_name(char * name_char)146 rdfstore_is_xml_name( char *name_char ) {
147 
148 	if (	( ! isalpha((int)*name_char) ) &&
149 		( *name_char != '_' ) )
150 		return 0;
151 
152 	name_char++;
153 	while( *name_char ) {
154 		if (	( ! isalnum((int)*name_char) ) &&
155 			( *name_char != '_' ) &&
156 			( *name_char != '-' ) &&
157 			( *name_char != '.' ) )
158 			return 0;
159 		name_char++;
160 		};
161 
162 	return 1;
163 	};
164 
165 int
rdfstore_statement_getLabel(RDF_Statement * statement,char * label)166 rdfstore_statement_getLabel( RDF_Statement   * statement, char * label ) {
167 	if ( statement->node != NULL ) { /* use the statement as resource identifier if possible */
168 		/* XXX is the following copy to char * (string) correct????? */
169         	memcpy( label, statement->node->value.resource.identifier, statement->node->value.resource.identifier_len );
170 		memcpy( label+statement->node->value.resource.identifier_len, "\0", 1);
171 		return statement->node->value.resource.identifier_len;
172         } else {
173         	int i=0,status=0;
174                 unsigned char dd[RDFSTORE_SHA_DIGESTSIZE];
175 
176                 /* e.g. urn:rdf:SHA-1-d2619b606c7ecac3dcf9151dae104c4ae7554786 */
177                 sprintf( label, "urn:rdf:%s-", rdfstore_digest_get_digest_algorithm() );
178                 status = rdfstore_digest_get_statement_digest( statement, NULL, dd );
179                 if ( status != 0 )
180 			return 0;
181 
182                 for ( i=0; i< RDFSTORE_SHA_DIGESTSIZE ; i++ ) {
183 			char cc[2];
184                 	sprintf( cc, "%02X", dd[i] );
185 			strncat(label, cc, 2);
186                         };
187 		return 9 + strlen( rdfstore_digest_get_digest_algorithm() ) + (RDFSTORE_SHA_DIGESTSIZE*2);
188 		};
189 	};
190 
rdfstore_ntriples_statement(RDF_Statement * statement,RDF_Node * given_context)191 char * rdfstore_ntriples_statement (
192 	RDF_Statement   * statement,
193         RDF_Node	* given_context
194 	) {
195 	RDF_Node * context = NULL;
196 	int i=0;
197 	char * buff=NULL;
198 	char * buff1=NULL;
199 	int s_len=0,p_len=0,o_len=0,c_len=0, reification_len=0;
200 
201         buff=NULL;
202 
203         if (    ( statement             == NULL ) ||
204                 ( statement->subject    == NULL ) ||
205                 ( statement->predicate  == NULL ) ||
206                 ( statement->subject->value.resource.identifier   == NULL ) ||
207                 ( statement->predicate->value.resource.identifier   == NULL ) ||
208                 ( statement->object     == NULL ) ||
209 		(	( statement->object->type != 1 ) &&
210 			( statement->object->value.resource.identifier   == NULL ) ) ||
211 		(	( context != NULL ) &&
212 			( context->value.resource.identifier   == NULL ) ) ||
213 		(	( statement->node != NULL ) &&
214 			( statement->node->value.resource.identifier   == NULL ) ) )
215                 return NULL;
216 
217 	if (given_context == NULL) {
218 		if (statement->context != NULL)
219                 	context = statement->context;
220 	} else {
221 		/* use given context instead */
222 		context = given_context;
223 		};
224 
225 	/* try to allocate just the necessary - see http://www.w3.org/TR/rdf-testcases/#ntriples */
226 	if ( statement->subject->type == 0 ) {
227 		s_len = statement->subject->value.resource.identifier_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 4;
228 	} else {
229 		s_len = statement->subject->value.resource.identifier_len + 4;
230 		};
231 	if ( statement->predicate->type == 0 ) {
232 		p_len = statement->predicate->value.resource.identifier_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 4;
233 	} else {
234 		p_len = statement->predicate->value.resource.identifier_len + 4;
235 		};
236 	if ( statement->object->type == 0 ) {
237 		o_len = statement->object->value.resource.identifier_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 4;
238 	} else if ( statement->object->type == 2 ) {
239 		o_len = statement->object->value.resource.identifier_len + 4;
240 	} else {
241 		o_len = ( statement->object->value.literal.string != NULL ) ?
242 				statement->object->value.literal.string_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 3 : 0;
243 		if (	(statement->object->value.literal.lang != NULL) &&
244 			(strlen(statement->object->value.literal.lang) > 0) )
245 			o_len += strlen(statement->object->value.literal.lang) + 1;
246 		/* we propably should croak or warn the user if something is fishy with the rdf:dataType property */
247 		if ( statement->object->value.literal.parseType == 1 )
248 			o_len += strlen(RDFSTORE_RDF_PARSETYPE_LITERAL) + 4;
249 		else if ( statement->object->value.literal.dataType != NULL )
250 			o_len += strlen(statement->object->value.literal.dataType) + 4;
251 		o_len++;
252 		};
253 	if ( context != NULL )
254 		c_len = context->value.resource.identifier_len + 4;
255 
256 	if (    (statement->isreified) &&
257                 (statement->node != NULL) ) {
258 		reification_len = ( statement->node->value.resource.identifier_len + 4 ) * 4;
259 		reification_len += strlen(RDFMS_type) + 4;
260 		reification_len += strlen(RDFMS_Statement) + 4;
261 		reification_len += strlen(RDFMS_subject) + 4;
262 		reification_len += s_len;
263 		reification_len += strlen(RDFMS_predicate) + 4;
264 		reification_len += p_len;
265 		reification_len += strlen(RDFMS_object) + 4;
266 		reification_len += o_len;
267 		};
268 
269         buff = (char *) RDFSTORE_MALLOC( sizeof(char) * ( s_len + p_len + o_len + c_len + 3 + reification_len ) );
270 
271 	if ( buff == NULL )
272                 return NULL;
273 
274         /* try to generate an N-Triples/Quads like string here */
275 
276 	i=0;
277 
278 	buff1=NULL;
279 	if( (buff1=rdfstore_ntriples_node( statement->subject )) == NULL ) {
280 		RDFSTORE_FREE( buff );
281 		return NULL;
282 		};
283         memcpy(buff+i, buff1, strlen(buff1));
284 	i+=strlen(buff1);
285 	RDFSTORE_FREE( buff1 );
286 	memcpy(buff+i," ",1);
287 	i++;
288 
289 	buff1=NULL;
290 	if( (buff1=rdfstore_ntriples_node( statement->predicate )) == NULL ) {
291 		RDFSTORE_FREE( buff );
292 		return NULL;
293 		};
294         memcpy(buff+i, buff1, strlen(buff1));
295 	i+=strlen(buff1);
296 	RDFSTORE_FREE( buff1 );
297 	memcpy(buff+i," ",1);
298 	i++;
299 
300 	buff1=NULL;
301 	if( (buff1=rdfstore_ntriples_node( statement->object )) == NULL ) {
302 		RDFSTORE_FREE( buff );
303 		return NULL;
304 		};
305         memcpy(buff+i, buff1, strlen(buff1));
306 	i+=strlen(buff1);
307 	RDFSTORE_FREE( buff1 );
308 	memcpy(buff+i," ",1);
309 	i++;
310 
311 	if ( context != NULL ) {
312 		buff1=NULL;
313 		if( (buff1=rdfstore_ntriples_node( context )) == NULL ) {
314 			RDFSTORE_FREE( buff );
315 			return NULL;
316 			};
317         	memcpy(buff+i, buff1, strlen(buff1));
318 		i+=strlen(buff1);
319 		RDFSTORE_FREE( buff1 );
320 		memcpy(buff+i," ",1);
321 		i++;
322 		};
323 
324 	memcpy(buff+i,". ",2); /* not cr/lf */
325 	i+=2;
326 
327 	/* add the reification triples if necessary */
328 	if (	(statement->isreified) &&
329 		(statement->node != NULL) ) {
330 		memcpy(buff+i,"\n",1);
331 		i++;
332 
333 		buff1=NULL;
334 		if( (buff1=rdfstore_ntriples_node( statement->node )) == NULL ) {
335 			RDFSTORE_FREE( buff );
336 			return NULL;
337 			};
338         	memcpy(buff+i, buff1, strlen(buff1));
339 		i+=strlen(buff1);
340 		RDFSTORE_FREE( buff1 );
341 		memcpy(buff+i," ",1);
342 		i++;
343 
344 		memcpy(buff+i,"<",1);
345 		i++;
346         	memcpy(buff+i, RDFMS_type, strlen(RDFMS_type));
347 		i+=strlen(RDFMS_type);
348 		memcpy(buff+i,">",1);
349 		i++;
350 		memcpy(buff+i," ",1);
351 		i++;
352 
353 		memcpy(buff+i,"<",1);
354 		i++;
355         	memcpy(buff+i, RDFMS_Statement, strlen(RDFMS_Statement));
356 		i+=strlen(RDFMS_Statement);
357 		memcpy(buff+i,">",1);
358 		i++;
359 		memcpy(buff+i," ",1);
360 		i++;
361 
362 		memcpy(buff+i,". ",2); /* not cr/lf */
363 		i+=2;
364 		memcpy(buff+i,"\n",1);
365 		i++;
366 
367 		buff1=NULL;
368 		if( (buff1=rdfstore_ntriples_node( statement->node )) == NULL ) {
369 			RDFSTORE_FREE( buff );
370 			return NULL;
371 			};
372         	memcpy(buff+i, buff1, strlen(buff1));
373 		i+=strlen(buff1);
374 		RDFSTORE_FREE( buff1 );
375 		memcpy(buff+i," ",1);
376 		i++;
377 
378 		memcpy(buff+i,"<",1);
379 		i++;
380         	memcpy(buff+i, RDFMS_subject, strlen(RDFMS_subject));
381 		i+=strlen(RDFMS_subject);
382 		memcpy(buff+i,">",1);
383 		i++;
384 		memcpy(buff+i," ",1);
385 		i++;
386 
387 		buff1=NULL;
388 		if( (buff1=rdfstore_ntriples_node( statement->subject )) == NULL ) {
389 			RDFSTORE_FREE( buff );
390 			return NULL;
391 			};
392         	memcpy(buff+i, buff1, strlen(buff1));
393 		i+=strlen(buff1);
394 		RDFSTORE_FREE( buff1 );
395 		memcpy(buff+i," ",1);
396 		i++;
397 
398 		memcpy(buff+i,". ",2); /* not cr/lf */
399 		i+=2;
400 		memcpy(buff+i,"\n",1);
401 		i++;
402 
403 		buff1=NULL;
404 		if( (buff1=rdfstore_ntriples_node( statement->node )) == NULL ) {
405 			RDFSTORE_FREE( buff );
406 			return NULL;
407 			};
408         	memcpy(buff+i, buff1, strlen(buff1));
409 		i+=strlen(buff1);
410 		RDFSTORE_FREE( buff1 );
411 		memcpy(buff+i," ",1);
412 		i++;
413 
414 		memcpy(buff+i,"<",1);
415 		i++;
416         	memcpy(buff+i, RDFMS_predicate, strlen(RDFMS_predicate));
417 		i+=strlen(RDFMS_predicate);
418 		memcpy(buff+i,">",1);
419 		i++;
420 		memcpy(buff+i," ",1);
421 		i++;
422 
423 		buff1=NULL;
424 		if( (buff1=rdfstore_ntriples_node( statement->predicate )) == NULL ) {
425 			RDFSTORE_FREE( buff );
426 			return NULL;
427 			};
428         	memcpy(buff+i, buff1, strlen(buff1));
429 		i+=strlen(buff1);
430 		RDFSTORE_FREE( buff1 );
431 		memcpy(buff+i," ",1);
432 		i++;
433 
434 		memcpy(buff+i,". ",2); /* not cr/lf */
435 		i+=2;
436 		memcpy(buff+i,"\n",1);
437 		i++;
438 
439 		buff1=NULL;
440 		if( (buff1=rdfstore_ntriples_node( statement->node )) == NULL ) {
441 			RDFSTORE_FREE( buff );
442 			return NULL;
443 			};
444         	memcpy(buff+i, buff1, strlen(buff1));
445 		i+=strlen(buff1);
446 		RDFSTORE_FREE( buff1 );
447 		memcpy(buff+i," ",1);
448 		i++;
449 
450 		memcpy(buff+i,"<",1);
451 		i++;
452         	memcpy(buff+i, RDFMS_object, strlen(RDFMS_object));
453 		i+=strlen(RDFMS_object);
454 		memcpy(buff+i,">",1);
455 		i++;
456 		memcpy(buff+i," ",1);
457 		i++;
458 
459 		buff1=NULL;
460 		if( (buff1=rdfstore_ntriples_node( statement->object )) == NULL ) {
461 			RDFSTORE_FREE( buff );
462 			return NULL;
463 			};
464         	memcpy(buff+i, buff1, strlen(buff1));
465 		i+=strlen(buff1);
466 		RDFSTORE_FREE( buff1 );
467 		memcpy(buff+i," ",1);
468 		i++;
469 
470 		memcpy(buff+i,". ",2); /* not cr/lf */
471 		i+=2;
472 		};
473 
474 	memcpy(buff+i,"\0",1);
475 	i++;
476 
477 	return buff;
478 	};
479 
rdfstore_ntriples_node(RDF_Node * node)480 char * rdfstore_ntriples_node (
481 	RDF_Node    * node
482 	) {
483         int j=0,len=0;
484         char * buff=NULL;
485         register unsigned int i=0;
486         unsigned int utf8_size=0;
487 
488         if (	( node == NULL ) ||
489 		(	( node->type != 1 ) &&
490 			( node->value.resource.identifier == NULL ) ) )
491                 return NULL;
492 
493 	if ( node->type == 0 ) {
494 		len = node->value.resource.identifier_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 3;
495 	} else if ( node->type == 2 ) {
496 		len = node->value.resource.identifier_len + 3;
497 	} else {
498 		len = (node->value.literal.string != NULL ) ?
499 				node->value.literal.string_len*(RDFSTORE_UTF8_MAXLEN+1+2) + 3 : 0;
500 		if (	(node->value.literal.lang != NULL) &&
501 			(strlen(node->value.literal.lang) > 0) )
502 			len += strlen(node->value.literal.lang) + 1;
503 		/* we propably should croak or warn the user if something is fishy with the rdf:dataType property */
504 		if ( node->value.literal.parseType == 1 )
505 			len += strlen(RDFSTORE_RDF_PARSETYPE_LITERAL) + 4;
506 		else if ( node->value.literal.dataType != NULL )
507 			len += strlen(node->value.literal.dataType) + 4;
508 		};
509 
510         buff = (char *) RDFSTORE_MALLOC( sizeof(char) * len );
511         if ( buff == NULL )
512                 return NULL;
513 
514         j=0;
515 
516 	/* NOTE: we should check that all the absoluteURI generated would be properly escaped accordingly to http://www.w3.org/TR/rdf-testcases/#sec-uri-encoding */
517 
518         if ( node->type == 2 ) {
519         	memcpy(buff+j,"_:",2);
520         	j+=2;
521         	memcpy(buff+j,node->value.resource.identifier,node->value.resource.identifier_len);
522         	j+=node->value.resource.identifier_len;
523         } else if ( node->type == 0 ) {
524 		int uri_len = 0;
525         	memcpy(buff+j,"<",1);
526         	j++;
527 		uri_len = node->value.resource.identifier_len;
528         	for(i=0; i < uri_len; ) {
529 			if( node->value.resource.identifier[i] == 0x09 ) {
530         			memcpy(buff+j,"\\t",2);
531         			j+=2;
532 				i++;
533 				continue;
534 			} else if( node->value.resource.identifier[i] == 0x0a ) {
535         			memcpy(buff+j,"\\n",2);
536         			j+=2;
537 				i++;
538 				continue;
539 			} else if( node->value.resource.identifier[i] == 0x0d ) {
540         			memcpy(buff+j,"\\r",2);
541         			j+=2;
542 				i++;
543 				continue;
544 			} else if( node->value.resource.identifier[i] == 0x5c ) {
545         			memcpy(buff+j,"\\\\",2);
546         			j+=2;
547 				i++;
548 				continue;
549 			} else if( node->value.resource.identifier[i] == 0x22 ) {
550         			memcpy(buff+j,"\\\"",2);
551         			j+=2;
552 				i++;
553 				continue;
554 				};
555                 	if ( ( rdfstore_utf8_is_utf8( node->value.resource.identifier+i, &utf8_size ) ) && ( utf8_size > 1 ) ) {
556 				unsigned long cp=0;
557 				unsigned char es[8];
558 
559 				if ( rdfstore_utf8_utf8_to_cp( utf8_size, node->value.resource.identifier+i, &cp ) ) {
560 					RDFSTORE_FREE( buff );
561                                		return NULL;
562                                		};
563 
564 				if(utf8_size<=4) {
565        					sprintf(es, "\\u%04lX", cp);
566 				} else {
567        					sprintf(es, "\\U%08lX", cp);
568 					};
569        				memcpy(buff+j,es,strlen(es));
570        				j+=strlen(es);
571 				i+=utf8_size;
572                		} else {
573        				memcpy(buff+j,node->value.resource.identifier+i,utf8_size);
574 				j+=utf8_size;
575 				i++;
576                        		};
577                		};
578 		memcpy(buff+j,">",1);
579         	j++;
580         } else if ( node->type == 1 ) {
581         	memcpy(buff+j,"\"",1);
582         	j++;
583 
584 		if ( node->value.literal.string != NULL ) {
585 
586 			/* here we convert the string to RDFSTORE_UTF8 and then escape it accordingly to http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
587         		for(i=0; i < node->value.literal.string_len; ) {
588 				if( node->value.literal.string[i] == 0x09 ) {
589         				memcpy(buff+j,"\\t",2);
590         				j+=2;
591 					i++;
592 					continue;
593 				} else if( node->value.literal.string[i] == 0x0a ) {
594         				memcpy(buff+j,"\\n",2);
595         				j+=2;
596 					i++;
597 					continue;
598 				} else if( node->value.literal.string[i] == 0x0d ) {
599         				memcpy(buff+j,"\\r",2);
600         				j+=2;
601 					i++;
602 					continue;
603 				} else if( node->value.literal.string[i] == 0x5c ) {
604         				memcpy(buff+j,"\\\\",2);
605         				j+=2;
606 					i++;
607 					continue;
608 				} else if( node->value.literal.string[i] == 0x22 ) {
609         				memcpy(buff+j,"\\\"",2);
610         				j+=2;
611 					i++;
612 					continue;
613 					};
614                 		if ( ( rdfstore_utf8_is_utf8( node->value.literal.string+i, &utf8_size ) ) && ( utf8_size > 1 ) ) {
615 					unsigned long cp=0;
616 					unsigned char es[8];
617 
618 					if ( rdfstore_utf8_utf8_to_cp( utf8_size, node->value.literal.string+i, &cp ) ) {
619 						RDFSTORE_FREE( buff );
620                                 		return NULL;
621                                 		};
622 
623 					if(utf8_size<=4) {
624         					sprintf(es, "\\u%04lX", cp);
625 					} else {
626         					sprintf(es, "\\U%08lX", cp);
627 						};
628         				memcpy(buff+j,es,strlen(es));
629         				j+=strlen(es);
630 					i+=utf8_size;
631                 		} else {
632         				memcpy(buff+j,node->value.literal.string+i,utf8_size);
633 					j+=utf8_size;
634 					i++;
635                         		};
636                 		};
637 			};
638 
639         	memcpy(buff+j,"\"",1);
640         	j++;
641 
642         	if(	(node->value.literal.lang != NULL) &&
643 			(strlen(node->value.literal.lang) > 0) ) {
644         		memcpy(buff+j,"@",1);
645         		j++;
646         		/* we should check that the language tag is also well-formed and escaped */
647         		memcpy(buff+j,node->value.literal.lang,strlen(node->value.literal.lang));
648         		j+=strlen(node->value.literal.lang);
649 			};
650 
651         	if( node->value.literal.parseType == 1 ) {
652         		memcpy(buff+j,"^^",2);
653         		j+=2;
654         		memcpy(buff+j,"<",1);
655         		j++;
656         		memcpy(buff+j,RDFSTORE_RDF_PARSETYPE_LITERAL,strlen(RDFSTORE_RDF_PARSETYPE_LITERAL));
657         		j+=strlen(RDFSTORE_RDF_PARSETYPE_LITERAL);
658         		memcpy(buff+j,">",1);
659         		j++;
660 		} else if ( node->value.literal.dataType != NULL ) {
661         		memcpy(buff+j,"^^",2);
662         		j+=2;
663         		memcpy(buff+j,"<",1);
664         		j++;
665         		/* we should check that the data type URI ref is a valid XMLSchema data type perhpas */
666         		memcpy(buff+j,node->value.literal.dataType,strlen(node->value.literal.dataType));
667         		j+=strlen(node->value.literal.dataType);
668         		memcpy(buff+j,">",1);
669         		j++;
670 			};
671 	} else {
672 		RDFSTORE_FREE( buff );
673 		perror("rdfstore_ntriples_node");
674                 fprintf(stderr,"Could not generate ntriple for node: unknown node type\n");
675 		return NULL;
676 		};
677 
678 	memcpy(buff+j,"\0",1);
679 	j++;
680 
681 	return buff;
682 	};
683 
684 /* the following two subroutines do not consider EBCDIC codes still! */
rdfstore_ntriples_hex2c(const char * x)685 int rdfstore_ntriples_hex2c(const char *x) {
686 	int i;
687 	int ch;
688 
689 	ch = x[0];
690 
691 	if (isdigit( ((unsigned char)(ch)) ))
692         	i = ch - '0';
693 	else if (isupper( ((unsigned char)(ch)) ))
694 		i = ch - ('A' - 10);
695 	else
696 		i = ch - ('a' - 10);
697 
698 	i <<= 4;
699 
700 	ch = x[1];
701 	if (isdigit( ((unsigned char)(ch)) ))
702         	i += ch - '0';
703 	else if (isupper( ((unsigned char)(ch)) ))
704 		i += ch - ('A' - 10);
705 	else
706 		i += ch - ('a' - 10);
707 
708 	return i;
709 	};
710 
rdfstore_ntriples_c2hex(int ch,char * x)711 void rdfstore_ntriples_c2hex(int ch, char *x) {
712 	int i;
713 
714 	x[0] = '%';
715 	i = (ch & 0xF0) >> 4;
716 
717 	if (i >= 10)
718 		x[1] = ('A' - 10) + i;
719 	else
720 		x[1] = '0' + i;
721 
722 	i = ch & 0x0F;
723 
724 	if (i >= 10)
725 		x[2] = ('A' - 10) + i;
726 	else
727 		x[2] = '0' + i;
728 	};
729