1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * raptor_xml_writer.c - Raptor XML Writer for SAX2 events API
4  *
5  * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2003-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 
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <stdarg.h>
39 #ifdef HAVE_ERRNO_H
40 #include <errno.h>
41 #endif
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45 
46 /* Raptor includes */
47 #include "raptor.h"
48 #include "raptor_internal.h"
49 
50 #ifndef STANDALONE
51 
52 
53 typedef enum {
54   XML_WRITER_AUTO_INDENT = 1,
55   XML_WRITER_AUTO_EMPTY  = 2
56 } raptor_xml_writer_flags;
57 
58 
59 #define XML_WRITER_AUTO_INDENT(xml_writer) ((xml_writer->flags & XML_WRITER_AUTO_INDENT) != 0)
60 #define XML_WRITER_AUTO_EMPTY(xml_writer) ((xml_writer->flags & XML_WRITER_AUTO_EMPTY) != 0)
61 
62 #define XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer)              \
63   if ((xml_writer->flags & XML_WRITER_AUTO_EMPTY) &&            \
64       xml_writer->current_element &&                            \
65       !(xml_writer->current_element->content_cdata_seen ||      \
66         xml_writer->current_element->content_element_seen)) {   \
67     raptor_iostream_write_byte(xml_writer->iostr, '>');         \
68   }
69 
70 
71 /* Define this for far too much output */
72 #undef RAPTOR_DEBUG_CDATA
73 
74 
75 struct raptor_xml_writer_s {
76   int canonicalize;
77 
78   int depth;
79 
80   int my_nstack;
81   raptor_namespace_stack *nstack;
82   int nstack_depth;
83 
84   const raptor_uri_handler *uri_handler;
85   void *uri_context;
86 
87   raptor_simple_message_handler error_handler;
88   void *error_data;
89 
90   raptor_xml_element* current_element;
91 
92   /* outputting to this iostream */
93   raptor_iostream *iostr;
94 
95   /* XML Writer flags - bits defined in enum raptor_xml_writer_flags */
96   int flags;
97 
98   /* indentation per level if formatting */
99   int indent;
100 
101   /* XML 1.0 (10) or XML 1.1 (11) */
102   int xml_version;
103 
104   /* Write XML 1.0 or 1.1 declaration (default 1) */
105   int xml_declaration;
106 
107   /* Has writing the XML declaration writing been checked? */
108   int xml_declaration_checked;
109 
110   /* An extra newline is wanted */
111   int pending_newline;
112 };
113 
114 
115 /* 16 spaces */
116 #define SPACES_BUFFER_SIZE sizeof(spaces_buffer)
117 static const unsigned char spaces_buffer[] = {
118   ' ', ' ', ' ', ' ',
119   ' ', ' ', ' ', ' ',
120   ' ', ' ', ' ', ' ',
121   ' ', ' ', ' ', ' '
122 };
123 
124 
125 
126 /* helper functions */
127 
128 /* Handle printing a pending newline OR newline with indenting */
129 static int
raptor_xml_writer_indent(raptor_xml_writer * xml_writer)130 raptor_xml_writer_indent(raptor_xml_writer *xml_writer)
131 {
132   int num_spaces;
133 
134   if(!XML_WRITER_AUTO_INDENT(xml_writer)) {
135     if(xml_writer->pending_newline) {
136       raptor_iostream_write_byte(xml_writer->iostr, '\n');
137       xml_writer->pending_newline=0;
138 
139       if(xml_writer->current_element)
140         xml_writer->current_element->content_cdata_seen=1;
141     }
142     return 0;
143   }
144 
145   num_spaces = xml_writer->depth * xml_writer->indent;
146 
147   /* Do not write an extra newline at the start of the document
148    * (after the XML declaration or XMP processing instruction has
149    * been writtten)
150    */
151   if(xml_writer->xml_declaration_checked == 1)
152     xml_writer->xml_declaration_checked++;
153   else {
154     raptor_iostream_write_byte(xml_writer->iostr, '\n');
155     xml_writer->pending_newline=0;
156   }
157 
158   while (num_spaces > 0) {
159 
160     int count = (num_spaces > (int)SPACES_BUFFER_SIZE) ? (int)SPACES_BUFFER_SIZE : num_spaces;
161 
162     raptor_iostream_write_counted_string(xml_writer->iostr, spaces_buffer, count);
163 
164     num_spaces -= count;
165   }
166 
167   if(xml_writer->current_element)
168     xml_writer->current_element->content_cdata_seen=1;
169 
170   return 0;
171 }
172 
173 
174 struct nsd {
175   const raptor_namespace *nspace;
176   unsigned char *declaration;
177   size_t length;
178 };
179 
180 
181 /*
182  * FIXME: This is duplicate code taken from raptor_sax2.c:
183  *   struct nsd
184  *  raptor_xml_writer_nsd_compare (from raptor_nsd_compare)
185  */
186 
187 static int
raptor_xml_writer_nsd_compare(const void * a,const void * b)188 raptor_xml_writer_nsd_compare(const void *a, const void *b)
189 {
190   struct nsd* nsd_a=(struct nsd*)a;
191   struct nsd* nsd_b=(struct nsd*)b;
192   return strcmp((const char*)nsd_a->declaration, (const char*)nsd_b->declaration);
193 }
194 
195 
196 static int
raptor_xml_writer_start_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int auto_empty)197 raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer,
198                                        raptor_xml_element* element,
199                                        int auto_empty)
200 {
201   raptor_iostream* iostr=xml_writer->iostr;
202   raptor_namespace_stack *nstack=xml_writer->nstack;
203   raptor_simple_message_handler error_handler=xml_writer->error_handler;
204   void *error_data=xml_writer->error_data;
205   int depth=xml_writer->depth;
206   int auto_indent=XML_WRITER_AUTO_INDENT(xml_writer);
207   int xml_version=xml_writer->xml_version;
208   struct nsd *nspace_declarations=NULL;
209   size_t nspace_declarations_count=0;
210   unsigned int i;
211 
212   /* max is 1 per element and 1 for each attribute + size of declared */
213   if(nstack) {
214     int nspace_max_count=element->attribute_count+1;
215     if(element->declared_nspaces)
216       nspace_max_count += raptor_sequence_size(element->declared_nspaces);
217 
218     nspace_declarations=(struct nsd*)RAPTOR_CALLOC(nsdarray, nspace_max_count, sizeof(struct nsd));
219     if(!nspace_declarations)
220       return 1;
221   }
222 
223   if(element->name->nspace) {
224     if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) {
225       nspace_declarations[0].declaration=
226         raptor_namespaces_format(element->name->nspace,
227                                  &nspace_declarations[0].length);
228       if(!nspace_declarations[0].declaration)
229         goto error;
230       nspace_declarations[0].nspace=element->name->nspace;
231       nspace_declarations_count++;
232     }
233   }
234 
235   if (element->attributes) {
236     for(i=0; i < element->attribute_count; i++) {
237       /* qname */
238       if(element->attributes[i]->nspace) {
239         if(nstack &&
240            !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) {
241           /* not in scope and not same as element (so already going to be declared)*/
242           unsigned int j;
243           int declare_me=1;
244 
245           /* check it wasn't an earlier declaration too */
246           for (j=0; j < nspace_declarations_count; j++)
247             if(nspace_declarations[j].nspace == element->attributes[j]->nspace) {
248               declare_me=0;
249               break;
250             }
251 
252           if(declare_me) {
253             nspace_declarations[nspace_declarations_count].declaration=
254               raptor_namespaces_format(element->attributes[i]->nspace,
255                                        &nspace_declarations[nspace_declarations_count].length);
256             if(!nspace_declarations[nspace_declarations_count].declaration)
257               goto error;
258             nspace_declarations[nspace_declarations_count].nspace=element->attributes[i]->nspace;
259             nspace_declarations_count++;
260           }
261         }
262       }
263     }
264   }
265 
266   if(nstack && element->declared_nspaces &&
267      raptor_sequence_size(element->declared_nspaces) > 0) {
268     for(i=0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) {
269       raptor_namespace* nspace=(raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i);
270       unsigned int j;
271       int declare_me=1;
272 
273       /* check it wasn't an earlier declaration too */
274       for (j=0; j < nspace_declarations_count; j++)
275         if(nspace_declarations[j].nspace == nspace) {
276           declare_me=0;
277           break;
278         }
279 
280       if(declare_me) {
281         nspace_declarations[nspace_declarations_count].declaration=
282           raptor_namespaces_format(nspace,
283                                    &nspace_declarations[nspace_declarations_count].length);
284         if(!nspace_declarations[nspace_declarations_count].declaration)
285           goto error;
286         nspace_declarations[nspace_declarations_count].nspace=nspace;
287         nspace_declarations_count++;
288       }
289 
290     }
291   }
292 
293   raptor_iostream_write_byte(iostr, '<');
294 
295   if(element->name->nspace && element->name->nspace->prefix_length > 0) {
296     raptor_iostream_write_counted_string(iostr,
297                                          (const char*)element->name->nspace->prefix,
298                                          element->name->nspace->prefix_length);
299     raptor_iostream_write_byte(iostr, ':');
300   }
301   raptor_iostream_write_counted_string(iostr,
302                                        (const char*)element->name->local_name,
303                                        element->name->local_name_length);
304 
305   /* declare namespaces */
306   if(nspace_declarations_count) {
307     /* sort them into the canonical order */
308     qsort((void*)nspace_declarations,
309           nspace_declarations_count, sizeof(struct nsd),
310           raptor_xml_writer_nsd_compare);
311     /* add them */
312     for (i=0; i < nspace_declarations_count; i++) {
313       if(auto_indent && nspace_declarations_count > 1) {
314         /* indent xmlns namespace attributes */
315         raptor_xml_writer_newline(xml_writer);
316         xml_writer->depth++;
317         raptor_xml_writer_indent(xml_writer);
318         xml_writer->depth--;
319       }
320       raptor_iostream_write_byte(iostr, ' ');
321       raptor_iostream_write_counted_string(iostr,
322                                            (const char*)nspace_declarations[i].declaration,
323                                            nspace_declarations[i].length);
324       RAPTOR_FREE(cstring, nspace_declarations[i].declaration);
325       nspace_declarations[i].declaration=NULL;
326 
327       if(raptor_namespace_copy(nstack,
328                                (raptor_namespace*)nspace_declarations[i].nspace,
329                                depth))
330         goto error;
331     }
332   }
333 
334 
335   if(element->attributes) {
336     for(i=0; i < element->attribute_count; i++) {
337       raptor_iostream_write_byte(iostr, ' ');
338 
339       if(element->attributes[i]->nspace &&
340          element->attributes[i]->nspace->prefix_length > 0) {
341         raptor_iostream_write_counted_string(iostr,
342                                              (char*)element->attributes[i]->nspace->prefix,
343                                              element->attributes[i]->nspace->prefix_length);
344         raptor_iostream_write_byte(iostr, ':');
345       }
346 
347       raptor_iostream_write_counted_string(iostr,
348                                            (const char*)element->attributes[i]->local_name,
349                                            element->attributes[i]->local_name_length);
350 
351       raptor_iostream_write_counted_string(iostr, "=\"", 2);
352 
353       raptor_iostream_write_xml_any_escaped_string(iostr,
354                                                    element->attributes[i]->value,
355                                                    element->attributes[i]->value_length,
356                                                    '"',
357                                                    xml_version,
358                                                    error_handler, error_data);
359       raptor_iostream_write_byte(iostr, '"');
360     }
361   }
362 
363   if (!auto_empty)
364     raptor_iostream_write_byte(iostr, '>');
365 
366   if(nstack)
367     RAPTOR_FREE(stringarray, nspace_declarations);
368 
369   return 0;
370 
371   /* Clean up nspace_declarations on error */
372   error:
373 
374   for (i=0; i < nspace_declarations_count; i++) {
375     if(nspace_declarations[i].declaration)
376       RAPTOR_FREE(cstring, nspace_declarations[i].declaration);
377   }
378 
379   if(nspace_declarations)
380     RAPTOR_FREE(stringarray, nspace_declarations);
381 
382   return 1;
383 }
384 
385 
386 static int
raptor_xml_writer_end_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int is_empty)387 raptor_xml_writer_end_element_common(raptor_xml_writer* xml_writer,
388                                      raptor_xml_element *element,
389                                      int is_empty)
390 {
391   raptor_iostream* iostr=xml_writer->iostr;
392 
393   if (is_empty)
394     raptor_iostream_write_byte(iostr, '/');
395   else {
396 
397     raptor_iostream_write_byte(iostr, '<');
398 
399     raptor_iostream_write_byte(iostr, '/');
400 
401     if(element->name->nspace && element->name->nspace->prefix_length > 0) {
402       raptor_iostream_write_counted_string(iostr,
403                                            (const char*)element->name->nspace->prefix,
404                                            element->name->nspace->prefix_length);
405       raptor_iostream_write_byte(iostr, ':');
406     }
407     raptor_iostream_write_counted_string(iostr,
408                                          (const char*)element->name->local_name,
409                                          element->name->local_name_length);
410   }
411 
412   raptor_iostream_write_byte(iostr, '>');
413 
414   return 0;
415 
416 }
417 
418 
419 #ifndef RAPTOR_DISABLE_V1
420 /**
421  * raptor_new_xml_writer:
422  * @nstack: Namespace stack for the writer to start with (or NULL)
423  * @uri_handler: URI handler function (ignored)
424  * @uri_context: URI handler context data (ignored)
425  * @iostr: I/O stream to write to
426  * @error_handler: error handler function
427  * @error_data: error handler data
428  * @canonicalize: unused
429  *
430  * Constructor - Create a new XML Writer writing XML to a raptor_iostream
431  *
432  * @uri_handler and @uri_context parameters are ignored but are retained
433  * in the API for backwards compatibility. Internally the same uri handler
434  * as returned by raptor_uri_get_handler() will be used.
435  *
436  * raptor_init() MUST have been called before calling this function.
437  * Use raptor_new_xml_writer_v2() if using raptor_world APIs.
438  *
439  * Return value: a new #raptor_xml_writer object or NULL on failure
440  **/
441 raptor_xml_writer*
raptor_new_xml_writer(raptor_namespace_stack * nstack,const raptor_uri_handler * uri_handler,void * uri_context,raptor_iostream * iostr,raptor_simple_message_handler error_handler,void * error_data,int canonicalize)442 raptor_new_xml_writer(raptor_namespace_stack *nstack,
443                       const raptor_uri_handler *uri_handler,
444                       void *uri_context,
445                       raptor_iostream* iostr,
446                       raptor_simple_message_handler error_handler,
447                       void *error_data,
448                       int canonicalize)
449 {
450   return raptor_new_xml_writer_v2(raptor_world_instance(),
451                                   nstack,
452                                   iostr,
453                                   error_handler,
454                                   error_data,
455                                   canonicalize);
456 }
457 #endif
458 
459 
460 /**
461  * raptor_new_xml_writer_v2:
462  * @world: raptor_world object
463  * @nstack: Namespace stack for the writer to start with (or NULL)
464  * @iostr: I/O stream to write to
465  * @error_handler: error handler function
466  * @error_data: error handler data
467  * @canonicalize: unused
468  *
469  * Constructor - Create a new XML Writer writing XML to a raptor_iostream
470  *
471  * Return value: a new #raptor_xml_writer object or NULL on failure
472  **/
473 raptor_xml_writer*
raptor_new_xml_writer_v2(raptor_world * world,raptor_namespace_stack * nstack,raptor_iostream * iostr,raptor_simple_message_handler error_handler,void * error_data,int canonicalize)474 raptor_new_xml_writer_v2(raptor_world* world,
475                          raptor_namespace_stack *nstack,
476                          raptor_iostream* iostr,
477                          raptor_simple_message_handler error_handler,
478                          void *error_data,
479                          int canonicalize)
480 {
481   raptor_xml_writer* xml_writer;
482 
483   xml_writer=(raptor_xml_writer*)RAPTOR_CALLOC(raptor_xml_writer, 1, sizeof(raptor_xml_writer)+1);
484   if(!xml_writer)
485     return NULL;
486 
487   xml_writer->nstack_depth=0;
488 
489   xml_writer->error_handler=error_handler;
490   xml_writer->error_data=error_data;
491 
492   xml_writer->nstack=nstack;
493   if(!xml_writer->nstack) {
494     xml_writer->nstack=nstack=raptor_new_namespaces_v2(world,
495                                                        error_handler, error_data,
496                                                        1);
497     xml_writer->my_nstack=1;
498   }
499 
500   xml_writer->iostr=iostr;
501 
502   xml_writer->flags = 0;
503   xml_writer->indent = 2;
504 
505   xml_writer->xml_version = 10;
506 
507   /* Write XML declaration */
508   xml_writer->xml_declaration=1;
509 
510   return xml_writer;
511 }
512 
513 
514 /**
515  * raptor_free_xml_writer:
516  * @xml_writer: XML writer object
517  *
518  * Destructor - Free XML Writer
519  *
520  **/
521 void
raptor_free_xml_writer(raptor_xml_writer * xml_writer)522 raptor_free_xml_writer(raptor_xml_writer* xml_writer)
523 {
524   RAPTOR_ASSERT_OBJECT_POINTER_RETURN(xml_writer, raptor_xml_writer);
525 
526   if(xml_writer->nstack && xml_writer->my_nstack)
527     raptor_free_namespaces(xml_writer->nstack);
528 
529   RAPTOR_FREE(raptor_xml_writer, xml_writer);
530 }
531 
532 
533 static void
raptor_xml_writer_write_xml_declaration(raptor_xml_writer * xml_writer)534 raptor_xml_writer_write_xml_declaration(raptor_xml_writer* xml_writer)
535 {
536   if(!xml_writer->xml_declaration_checked) {
537     /* check that it should be written once only */
538     xml_writer->xml_declaration_checked=1;
539 
540     if(xml_writer->xml_declaration) {
541       raptor_iostream_write_string(xml_writer->iostr,
542                                    (const unsigned char*)"<?xml version=\"");
543       raptor_iostream_write_counted_string(xml_writer->iostr,
544                                            (xml_writer->xml_version == 10) ?
545                                            (const unsigned char*)"1.0" :
546                                            (const unsigned char*)"1.1",
547                                            3);
548       raptor_iostream_write_string(xml_writer->iostr,
549                                    (const unsigned char*)"\" encoding=\"utf-8\"?>\n");
550     }
551   }
552 
553 }
554 
555 
556 /**
557  * raptor_xml_writer_empty_element:
558  * @xml_writer: XML writer object
559  * @element: XML element object
560  *
561  * Write an empty XML element to the XML writer.
562  *
563  * Closes any previous empty element if XML writer feature AUTO_EMPTY
564  * is enabled.
565  **/
566 void
raptor_xml_writer_empty_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)567 raptor_xml_writer_empty_element(raptor_xml_writer* xml_writer,
568                                 raptor_xml_element *element)
569 {
570   raptor_xml_writer_write_xml_declaration(xml_writer);
571 
572   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
573 
574   if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
575     raptor_xml_writer_indent(xml_writer);
576 
577   raptor_xml_writer_start_element_common(xml_writer, element, 1);
578 
579   raptor_xml_writer_end_element_common(xml_writer, element, 1);
580 
581   raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
582 }
583 
584 
585 /**
586  * raptor_xml_writer_start_element:
587  * @xml_writer: XML writer object
588  * @element: XML element object
589  *
590  * Write a start XML element to the XML writer.
591  *
592  * Closes any previous empty element if XML writer feature AUTO_EMPTY
593  * is enabled.
594  *
595  * Indents the start element if XML writer feature AUTO_INDENT is enabled.
596  **/
597 void
raptor_xml_writer_start_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)598 raptor_xml_writer_start_element(raptor_xml_writer* xml_writer,
599                                 raptor_xml_element *element)
600 {
601   raptor_xml_writer_write_xml_declaration(xml_writer);
602 
603   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
604 
605   if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
606     raptor_xml_writer_indent(xml_writer);
607 
608   raptor_xml_writer_start_element_common(xml_writer, element,
609                                          XML_WRITER_AUTO_EMPTY(xml_writer));
610 
611   xml_writer->depth++;
612 
613   /* SJS Note: This "if" clause is necessary because raptor_rdfxml.c
614    * uses xml_writer for parseType="literal" and passes in elements
615    * whose parent field is already set. The first time this function
616    * is called, it sets element->parent to 0, causing the warn-07.rdf
617    * test to fail. Subsequent calls to this function set
618    * element->parent to its existing value.
619    */
620   if(xml_writer->current_element)
621     element->parent = xml_writer->current_element;
622 
623   xml_writer->current_element=element;
624   if(element && element->parent)
625     element->parent->content_element_seen=1;
626 }
627 
628 
629 /**
630  * raptor_xml_writer_end_element:
631  * @xml_writer: XML writer object
632  * @element: XML element object
633  *
634  * Write an end XML element to the XML writer.
635  *
636  * Indents the end element if XML writer feature AUTO_INDENT is enabled.
637  **/
638 void
raptor_xml_writer_end_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)639 raptor_xml_writer_end_element(raptor_xml_writer* xml_writer,
640                               raptor_xml_element* element)
641 {
642   int is_empty;
643 
644   xml_writer->depth--;
645 
646   if(xml_writer->pending_newline ||
647      (XML_WRITER_AUTO_INDENT(xml_writer) && element->content_element_seen))
648     raptor_xml_writer_indent(xml_writer);
649 
650   is_empty = XML_WRITER_AUTO_EMPTY(xml_writer) ?
651     !(element->content_cdata_seen || element->content_element_seen) : 0;
652 
653   raptor_xml_writer_end_element_common(xml_writer, element, is_empty);
654 
655   raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
656 
657   if(xml_writer->current_element)
658     xml_writer->current_element = xml_writer->current_element->parent;
659 }
660 
661 
662 /**
663  * raptor_xml_writer_newline:
664  * @xml_writer: XML writer object
665  *
666  * Write a newline to the XML writer.
667  *
668  * Indents the next line if XML writer feature AUTO_INDENT is enabled.
669  **/
670 void
raptor_xml_writer_newline(raptor_xml_writer * xml_writer)671 raptor_xml_writer_newline(raptor_xml_writer* xml_writer)
672 {
673   xml_writer->pending_newline=1;
674 }
675 
676 
677 /**
678  * raptor_xml_writer_cdata:
679  * @xml_writer: XML writer object
680  * @s: string to XML escape and write
681  *
682  * Write CDATA XML-escaped to the XML writer.
683  *
684  * Closes any previous empty element if XML writer feature AUTO_EMPTY
685  * is enabled.
686  *
687  **/
688 void
raptor_xml_writer_cdata(raptor_xml_writer * xml_writer,const unsigned char * s)689 raptor_xml_writer_cdata(raptor_xml_writer* xml_writer,
690                         const unsigned char *s)
691 {
692   raptor_xml_writer_write_xml_declaration(xml_writer);
693 
694   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
695 
696   raptor_iostream_write_xml_any_escaped_string(xml_writer->iostr,
697                                                s, strlen((const char*)s),
698                                                '\0',
699                                                xml_writer->xml_version,
700                                                xml_writer->error_handler,
701                                                xml_writer->error_data);
702 
703   if(xml_writer->current_element)
704     xml_writer->current_element->content_cdata_seen=1;
705 }
706 
707 
708 /**
709  * raptor_xml_writer_cdata_counted:
710  * @xml_writer: XML writer object
711  * @s: string to XML escape and write
712  * @len: length of string
713  *
714  * Write counted CDATA XML-escaped to the XML writer.
715  *
716  * Closes any previous empty element if XML writer feature AUTO_EMPTY
717  * is enabled.
718  *
719  **/
720 void
raptor_xml_writer_cdata_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)721 raptor_xml_writer_cdata_counted(raptor_xml_writer* xml_writer,
722                                 const unsigned char *s, unsigned int len)
723 {
724   raptor_xml_writer_write_xml_declaration(xml_writer);
725 
726   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
727 
728   raptor_iostream_write_xml_any_escaped_string(xml_writer->iostr,
729                                                s, len,
730                                                '\0',
731                                                xml_writer->xml_version,
732                                                xml_writer->error_handler,
733                                                xml_writer->error_data);
734 
735   if(xml_writer->current_element)
736     xml_writer->current_element->content_cdata_seen=1;
737 }
738 
739 
740 /**
741  * raptor_xml_writer_raw:
742  * @xml_writer: XML writer object
743  * @s: string to write
744  *
745  * Write a string raw to the XML writer.
746  *
747  * Closes any previous empty element if XML writer feature AUTO_EMPTY
748  * is enabled.
749  *
750  **/
751 void
raptor_xml_writer_raw(raptor_xml_writer * xml_writer,const unsigned char * s)752 raptor_xml_writer_raw(raptor_xml_writer* xml_writer,
753                       const unsigned char *s)
754 {
755   raptor_xml_writer_write_xml_declaration(xml_writer);
756 
757   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
758 
759   raptor_iostream_write_string(xml_writer->iostr, s);
760 
761   if(xml_writer->current_element)
762     xml_writer->current_element->content_cdata_seen=1;
763 }
764 
765 
766 /**
767  * raptor_xml_writer_raw_counted:
768  * @xml_writer: XML writer object
769  * @s: string to write
770  * @len: length of string
771  *
772  * Write a counted string raw to the XML writer.
773  *
774  * Closes any previous empty element if XML writer feature AUTO_EMPTY
775  * is enabled.
776  *
777  **/
778 void
raptor_xml_writer_raw_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)779 raptor_xml_writer_raw_counted(raptor_xml_writer* xml_writer,
780                               const unsigned char *s, unsigned int len)
781 {
782   raptor_xml_writer_write_xml_declaration(xml_writer);
783 
784   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
785 
786   raptor_iostream_write_counted_string(xml_writer->iostr, s, len);
787 
788   if(xml_writer->current_element)
789     xml_writer->current_element->content_cdata_seen=1;
790 }
791 
792 
793 /**
794  * raptor_xml_writer_comment:
795  * @xml_writer: XML writer object
796  * @s: comment string to write
797  *
798  * Write an XML comment to the XML writer.
799  *
800  * Closes any previous empty element if XML writer feature AUTO_EMPTY
801  * is enabled.
802  *
803  **/
804 void
raptor_xml_writer_comment(raptor_xml_writer * xml_writer,const unsigned char * s)805 raptor_xml_writer_comment(raptor_xml_writer* xml_writer,
806                           const unsigned char *s)
807 {
808   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
809 
810   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
811   raptor_xml_writer_cdata(xml_writer, s);
812   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
813 }
814 
815 
816 /**
817  * raptor_xml_writer_comment_counted:
818  * @xml_writer: XML writer object
819  * @s: comment string to write
820  * @len: length of string
821  *
822  * Write a counted XML comment to the XML writer.
823  *
824  * Closes any previous empty element if XML writer feature AUTO_EMPTY
825  * is enabled.
826  *
827  **/
828 void
raptor_xml_writer_comment_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)829 raptor_xml_writer_comment_counted(raptor_xml_writer* xml_writer,
830                                   const unsigned char *s, unsigned int len)
831 {
832   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
833 
834   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
835   raptor_xml_writer_cdata_counted(xml_writer, s, len);
836   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
837 }
838 
839 
840 #ifndef RAPTOR_DISABLE_V1
841 /**
842  * raptor_xml_writer_features_enumerate:
843  * @feature: feature enumeration (0+)
844  * @name: pointer to store feature short name (or NULL)
845  * @uri: pointer to store feature URI (or NULL)
846  * @label: pointer to feature label (or NULL)
847  *
848  * Get list of xml_writer features.
849  *
850  * If uri is not NULL, a pointer to a new raptor_uri is returned
851  * that must be freed by the caller with raptor_free_uri().
852  *
853  * raptor_init() MUST have been called before calling this function.
854  * Use raptor_xml_writer_features_enumerate_v2() if using raptor_world APIs.
855  *
856  * Return value: 0 on success, <0 on failure, >0 if feature is unknown
857  **/
858 int
raptor_xml_writer_features_enumerate(const raptor_feature feature,const char ** name,raptor_uri ** uri,const char ** label)859 raptor_xml_writer_features_enumerate(const raptor_feature feature,
860                                      const char **name,
861                                      raptor_uri **uri, const char **label)
862 {
863   return raptor_xml_writer_features_enumerate_v2(raptor_world_instance(),
864                                                  feature, name, uri, label);
865 }
866 #endif
867 
868 
869 /**
870  * raptor_xml_writer_features_enumerate_v2:
871  * @world: raptor_world object
872  * @feature: feature enumeration (0+)
873  * @name: pointer to store feature short name (or NULL)
874  * @uri: pointer to store feature URI (or NULL)
875  * @label: pointer to feature label (or NULL)
876  *
877  * Get list of xml_writer features.
878  *
879  * If uri is not NULL, a pointer to a new raptor_uri is returned
880  * that must be freed by the caller with raptor_free_uri_v2().
881  *
882  * Return value: 0 on success, <0 on failure, >0 if feature is unknown
883  **/
884 int
raptor_xml_writer_features_enumerate_v2(raptor_world * world,const raptor_feature feature,const char ** name,raptor_uri ** uri,const char ** label)885 raptor_xml_writer_features_enumerate_v2(raptor_world* world,
886                                         const raptor_feature feature,
887                                         const char **name,
888                                         raptor_uri **uri, const char **label)
889 {
890   return raptor_features_enumerate_common(world, feature, name, uri, label, 8);
891 }
892 
893 
894 /**
895  * raptor_xml_writer_flush:
896  * @xml_writer: XML writer object
897  *
898  * Finish the XML writer.
899  *
900  **/
901 void
raptor_xml_writer_flush(raptor_xml_writer * xml_writer)902 raptor_xml_writer_flush(raptor_xml_writer* xml_writer)
903 {
904   if(xml_writer->pending_newline) {
905     raptor_iostream_write_byte(xml_writer->iostr, '\n');
906     xml_writer->pending_newline=0;
907   }
908 }
909 
910 
911 /**
912  * raptor_xml_writer_set_feature:
913  * @xml_writer: #raptor_xml_writer xml_writer object
914  * @feature: feature to set from enumerated #raptor_feature values
915  * @value: integer feature value (0 or larger)
916  *
917  * Set xml_writer features with integer values.
918  *
919  * The allowed features are available via raptor_features_enumerate().
920  *
921  * Return value: non 0 on failure or if the feature is unknown
922  **/
923 int
raptor_xml_writer_set_feature(raptor_xml_writer * xml_writer,raptor_feature feature,int value)924 raptor_xml_writer_set_feature(raptor_xml_writer *xml_writer,
925                               raptor_feature feature, int value)
926 {
927   if(value < 0)
928     return -1;
929 
930   switch(feature) {
931     case RAPTOR_FEATURE_WRITER_AUTO_INDENT:
932       if (value)
933         xml_writer->flags |= XML_WRITER_AUTO_INDENT;
934       else
935         xml_writer->flags &= ~XML_WRITER_AUTO_INDENT;
936       break;
937 
938     case RAPTOR_FEATURE_WRITER_AUTO_EMPTY:
939       if (value)
940         xml_writer->flags |= XML_WRITER_AUTO_EMPTY;
941       else
942         xml_writer->flags &= ~XML_WRITER_AUTO_EMPTY;
943       break;
944 
945     case RAPTOR_FEATURE_WRITER_INDENT_WIDTH:
946       xml_writer->indent = value;
947       break;
948 
949     case RAPTOR_FEATURE_WRITER_XML_VERSION:
950       if(value == 10 || value == 11)
951         xml_writer->xml_version = value;
952       break;
953 
954     case RAPTOR_FEATURE_WRITER_XML_DECLARATION:
955       xml_writer->xml_declaration = value;
956       break;
957 
958     /* parser features */
959     case RAPTOR_FEATURE_SCANNING:
960     case RAPTOR_FEATURE_ASSUME_IS_RDF:
961     case RAPTOR_FEATURE_ALLOW_NON_NS_ATTRIBUTES:
962     case RAPTOR_FEATURE_ALLOW_OTHER_PARSETYPES:
963     case RAPTOR_FEATURE_ALLOW_BAGID:
964     case RAPTOR_FEATURE_ALLOW_RDF_TYPE_RDF_LIST:
965     case RAPTOR_FEATURE_NORMALIZE_LANGUAGE:
966     case RAPTOR_FEATURE_NON_NFC_FATAL:
967     case RAPTOR_FEATURE_WARN_OTHER_PARSETYPES:
968     case RAPTOR_FEATURE_CHECK_RDF_ID:
969     case RAPTOR_FEATURE_HTML_TAG_SOUP:
970     case RAPTOR_FEATURE_MICROFORMATS:
971     case RAPTOR_FEATURE_HTML_LINK:
972     case RAPTOR_FEATURE_WWW_TIMEOUT:
973 
974     /* Shared */
975     case RAPTOR_FEATURE_NO_NET:
976     case RAPTOR_FEATURE_LOAD_EXTERNAL_ENTITIES:
977 
978     /* XML writer features */
979     case RAPTOR_FEATURE_RELATIVE_URIS:
980     case RAPTOR_FEATURE_START_URI:
981 
982     /* DOT serializer features */
983     case RAPTOR_FEATURE_RESOURCE_BORDER:
984     case RAPTOR_FEATURE_LITERAL_BORDER:
985     case RAPTOR_FEATURE_BNODE_BORDER:
986     case RAPTOR_FEATURE_RESOURCE_FILL:
987     case RAPTOR_FEATURE_LITERAL_FILL:
988     case RAPTOR_FEATURE_BNODE_FILL:
989 
990     /* JSON serializer features */
991     case RAPTOR_FEATURE_JSON_CALLBACK:
992     case RAPTOR_FEATURE_JSON_EXTRA_DATA:
993     case RAPTOR_FEATURE_RSS_TRIPLES:
994     case RAPTOR_FEATURE_ATOM_ENTRY_URI:
995     case RAPTOR_FEATURE_PREFIX_ELEMENTS:
996 
997     /* Turtle serializer feature */
998     case RAPTOR_FEATURE_WRITE_BASE_URI:
999 
1000     /* WWW feature */
1001     case RAPTOR_FEATURE_WWW_HTTP_CACHE_CONTROL:
1002     case RAPTOR_FEATURE_WWW_HTTP_USER_AGENT:
1003 
1004     default:
1005       return -1;
1006       break;
1007   }
1008 
1009   return 0;
1010 }
1011 
1012 
1013 /**
1014  * raptor_xml_writer_set_feature_string:
1015  * @xml_writer: #raptor_xml_writer xml_writer object
1016  * @feature: feature to set from enumerated #raptor_feature values
1017  * @value: feature value
1018  *
1019  * Set xml_writer features with string values.
1020  *
1021  * The allowed features are available via raptor_xml_writer_features_enumerate().
1022  * If the feature type is integer, the value is interpreted as an integer.
1023  *
1024  * Return value: non 0 on failure or if the feature is unknown
1025  **/
1026 int
raptor_xml_writer_set_feature_string(raptor_xml_writer * xml_writer,raptor_feature feature,const unsigned char * value)1027 raptor_xml_writer_set_feature_string(raptor_xml_writer *xml_writer,
1028                                      raptor_feature feature,
1029                                      const unsigned char *value)
1030 {
1031   int value_is_string=(raptor_feature_value_type(feature) == 1);
1032   if(!value_is_string)
1033     return raptor_xml_writer_set_feature(xml_writer, feature,
1034                                          atoi((const char*)value));
1035   else
1036     return -1;
1037 }
1038 
1039 
1040 /**
1041  * raptor_xml_writer_get_feature:
1042  * @xml_writer: #raptor_xml_writer xml writer object
1043  * @feature: feature to get value
1044  *
1045  * Get various xml_writer features.
1046  *
1047  * The allowed features are available via raptor_features_enumerate().
1048  *
1049  * Note: no feature value is negative
1050  *
1051  * Return value: feature value or < 0 for an illegal feature
1052  **/
1053 int
raptor_xml_writer_get_feature(raptor_xml_writer * xml_writer,raptor_feature feature)1054 raptor_xml_writer_get_feature(raptor_xml_writer *xml_writer,
1055                               raptor_feature feature)
1056 {
1057   int result= -1;
1058 
1059   switch(feature) {
1060     case RAPTOR_FEATURE_WRITER_AUTO_INDENT:
1061       result=XML_WRITER_AUTO_INDENT(xml_writer);
1062       break;
1063 
1064     case RAPTOR_FEATURE_WRITER_AUTO_EMPTY:
1065       result=XML_WRITER_AUTO_EMPTY(xml_writer);
1066       break;
1067 
1068     case RAPTOR_FEATURE_WRITER_INDENT_WIDTH:
1069       result=xml_writer->indent;
1070       break;
1071 
1072     case RAPTOR_FEATURE_WRITER_XML_VERSION:
1073       result=xml_writer->xml_version;
1074       break;
1075 
1076     case RAPTOR_FEATURE_WRITER_XML_DECLARATION:
1077       result=xml_writer->xml_declaration;
1078       break;
1079 
1080     /* parser features */
1081     case RAPTOR_FEATURE_SCANNING:
1082     case RAPTOR_FEATURE_ASSUME_IS_RDF:
1083     case RAPTOR_FEATURE_ALLOW_NON_NS_ATTRIBUTES:
1084     case RAPTOR_FEATURE_ALLOW_OTHER_PARSETYPES:
1085     case RAPTOR_FEATURE_ALLOW_BAGID:
1086     case RAPTOR_FEATURE_ALLOW_RDF_TYPE_RDF_LIST:
1087     case RAPTOR_FEATURE_NORMALIZE_LANGUAGE:
1088     case RAPTOR_FEATURE_NON_NFC_FATAL:
1089     case RAPTOR_FEATURE_WARN_OTHER_PARSETYPES:
1090     case RAPTOR_FEATURE_CHECK_RDF_ID:
1091     case RAPTOR_FEATURE_HTML_TAG_SOUP:
1092     case RAPTOR_FEATURE_MICROFORMATS:
1093     case RAPTOR_FEATURE_HTML_LINK:
1094     case RAPTOR_FEATURE_WWW_TIMEOUT:
1095 
1096     /* Shared */
1097     case RAPTOR_FEATURE_NO_NET:
1098     case RAPTOR_FEATURE_LOAD_EXTERNAL_ENTITIES:
1099 
1100     /* XML writer features */
1101     case RAPTOR_FEATURE_RELATIVE_URIS:
1102     case RAPTOR_FEATURE_START_URI:
1103 
1104     /* DOT serializer features */
1105     case RAPTOR_FEATURE_RESOURCE_BORDER:
1106     case RAPTOR_FEATURE_LITERAL_BORDER:
1107     case RAPTOR_FEATURE_BNODE_BORDER:
1108     case RAPTOR_FEATURE_RESOURCE_FILL:
1109     case RAPTOR_FEATURE_LITERAL_FILL:
1110     case RAPTOR_FEATURE_BNODE_FILL:
1111 
1112     /* JSON serializer features */
1113     case RAPTOR_FEATURE_JSON_CALLBACK:
1114     case RAPTOR_FEATURE_JSON_EXTRA_DATA:
1115     case RAPTOR_FEATURE_RSS_TRIPLES:
1116     case RAPTOR_FEATURE_ATOM_ENTRY_URI:
1117     case RAPTOR_FEATURE_PREFIX_ELEMENTS:
1118 
1119     /* Turtle serializer feature */
1120     case RAPTOR_FEATURE_WRITE_BASE_URI:
1121 
1122     /* WWW feature */
1123     case RAPTOR_FEATURE_WWW_HTTP_CACHE_CONTROL:
1124     case RAPTOR_FEATURE_WWW_HTTP_USER_AGENT:
1125 
1126     default:
1127       break;
1128   }
1129 
1130   return result;
1131 }
1132 
1133 
1134 /**
1135  * raptor_xml_writer_get_feature_string:
1136  * @xml_writer: #raptor_xml_writer xml writer object
1137  * @feature: feature to get value
1138  *
1139  * Get xml_writer features with string values.
1140  *
1141  * The allowed features are available via raptor_features_enumerate().
1142  *
1143  * Return value: feature value or NULL for an illegal feature or no value
1144  **/
1145 const unsigned char *
raptor_xml_writer_get_feature_string(raptor_xml_writer * xml_writer,raptor_feature feature)1146 raptor_xml_writer_get_feature_string(raptor_xml_writer *xml_writer,
1147                                      raptor_feature feature)
1148 {
1149   return NULL;
1150 }
1151 
1152 
1153 /**
1154  * raptor_xml_writer_get_depth:
1155  * @xml_writer: #raptor_xml_writer xml writer object
1156  *
1157  * Get the current XML Writer element depth
1158  *
1159  * Return value: element stack depth
1160  */
1161 int
raptor_xml_writer_get_depth(raptor_xml_writer * xml_writer)1162 raptor_xml_writer_get_depth(raptor_xml_writer *xml_writer)
1163 {
1164   return xml_writer->depth;
1165 }
1166 
1167 
1168 #endif
1169 
1170 
1171 
1172 #ifdef STANDALONE
1173 
1174 /* one more prototype */
1175 int main(int argc, char *argv[]);
1176 
1177 
1178 const unsigned char *base_uri_string=(const unsigned char*)"http://example.org/base#";
1179 
1180 #define OUT_BYTES_COUNT 135
1181 
1182 int
main(int argc,char * argv[])1183 main(int argc, char *argv[])
1184 {
1185   raptor_world *world;
1186   const char *program=raptor_basename(argv[0]);
1187   raptor_iostream *iostr;
1188   raptor_namespace_stack *nstack;
1189   raptor_namespace* foo_ns;
1190   raptor_xml_writer* xml_writer;
1191   raptor_uri* base_uri;
1192   raptor_qname* el_name;
1193   raptor_xml_element *element;
1194   unsigned long offset;
1195   raptor_qname **attrs;
1196   raptor_uri* base_uri_copy=NULL;
1197 
1198   /* for raptor_new_iostream_to_string */
1199   void *string=NULL;
1200   size_t string_len=0;
1201 
1202   world = raptor_new_world();
1203   if(!world || raptor_world_open(world))
1204     exit(1);
1205 
1206   iostr=raptor_new_iostream_to_string(&string, &string_len, NULL);
1207   if(!iostr) {
1208     fprintf(stderr, "%s: Failed to create iostream to string\n", program);
1209     exit(1);
1210   }
1211 
1212   nstack=raptor_new_namespaces_v2(world,
1213                                   NULL, NULL, /* errors */
1214                                   1);
1215 
1216   xml_writer=raptor_new_xml_writer_v2(world,
1217                                       nstack,
1218                                       iostr,
1219                                       NULL, NULL, /* errors */
1220                                       1);
1221   if(!xml_writer) {
1222     fprintf(stderr, "%s: Failed to create xml_writer to iostream\n", program);
1223     exit(1);
1224   }
1225 
1226   base_uri=raptor_new_uri_v2(world, base_uri_string);
1227 
1228   foo_ns=raptor_new_namespace(nstack,
1229                               (const unsigned char*)"foo",
1230                               (const unsigned char*)"http://example.org/foo-ns#",
1231                               0);
1232 
1233 
1234   el_name=raptor_new_qname_from_namespace_local_name_v2(world,
1235                                                         foo_ns,
1236                                                         (const unsigned char*)"bar",
1237                                                         NULL);
1238   base_uri_copy=base_uri ? raptor_uri_copy_v2(world, base_uri) : NULL;
1239   element=raptor_new_xml_element(el_name,
1240                                   NULL, /* language */
1241                                   base_uri_copy);
1242 
1243   raptor_xml_writer_start_element(xml_writer, element);
1244   raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"hello\n", 6);
1245   raptor_xml_writer_comment_counted(xml_writer, (const unsigned char*)"comment", 7);
1246   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1247   raptor_xml_writer_end_element(xml_writer, element);
1248 
1249   raptor_free_xml_element(element);
1250 
1251   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1252 
1253   el_name=raptor_new_qname(nstack,
1254                            (const unsigned char*)"blah",
1255                            NULL, /* no attribute value - element */
1256                            NULL, NULL); /* errors */
1257   base_uri_copy=base_uri ? raptor_uri_copy_v2(world, base_uri) : NULL;
1258   element=raptor_new_xml_element(el_name,
1259                                   NULL, /* language */
1260                                   base_uri_copy);
1261 
1262   attrs=(raptor_qname **)RAPTOR_CALLOC(qnamearray, 1, sizeof(raptor_qname*));
1263   attrs[0]=raptor_new_qname(nstack,
1264                             (const unsigned char*)"a",
1265                             (const unsigned char*)"b", /* attribute value */
1266                             NULL, NULL); /* errors */
1267   raptor_xml_element_set_attributes(element, attrs, 1);
1268 
1269   raptor_xml_writer_empty_element(xml_writer, element);
1270 
1271   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1272 
1273   raptor_free_xml_writer(xml_writer);
1274 
1275   raptor_free_xml_element(element);
1276 
1277   raptor_free_namespace(foo_ns);
1278 
1279   raptor_free_namespaces(nstack);
1280 
1281   raptor_free_uri_v2(world, base_uri);
1282 
1283 
1284   offset=raptor_iostream_tell(iostr);
1285 
1286 #if RAPTOR_DEBUG > 1
1287   fprintf(stderr, "%s: Freeing iostream\n", program);
1288 #endif
1289   raptor_free_iostream(iostr);
1290 
1291   if(offset != OUT_BYTES_COUNT) {
1292     fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
1293             (int)offset, (int)OUT_BYTES_COUNT);
1294     fputs("[[", stderr);
1295     (void)fwrite(string, 1, string_len, stderr);
1296     fputs("]]\n", stderr);
1297     return 1;
1298   }
1299 
1300   if(!string) {
1301     fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
1302     return 1;
1303   }
1304   string_len=strlen((const char*)string);
1305   if(string_len != offset) {
1306     fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)offset);
1307     return 1;
1308   }
1309 
1310 #if RAPTOR_DEBUG > 1
1311   fprintf(stderr, "%s: Made XML string of %d bytes\n", program, (int)string_len);
1312   fputs("[[", stderr);
1313   (void)fwrite(string, 1, string_len, stderr);
1314   fputs("]]\n", stderr);
1315 #endif
1316 
1317   raptor_free_memory(string);
1318 
1319   raptor_free_world(world);
1320 
1321   /* keep gcc -Wall happy */
1322   return(0);
1323 }
1324 
1325 #endif
1326