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-2010, 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 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdarg.h>
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 
41 /* Raptor includes */
42 #include "raptor2.h"
43 #include "raptor_internal.h"
44 
45 #ifndef STANDALONE
46 
47 
48 #define XML_WRITER_AUTO_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_INDENT)
49 #define XML_WRITER_AUTO_EMPTY(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_EMPTY)
50 #define XML_WRITER_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_INDENT_WIDTH)
51 #define XML_WRITER_XML_VERSION(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_XML_VERSION)
52 
53 
54 #define XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer)              \
55   if((XML_WRITER_AUTO_EMPTY(xml_writer)) && \
56       xml_writer->current_element &&                            \
57       !(xml_writer->current_element->content_cdata_seen ||      \
58         xml_writer->current_element->content_element_seen)) {   \
59     raptor_iostream_write_byte('>', xml_writer->iostr);         \
60 }
61 
62 
63 /* Define this for far too much output */
64 #undef RAPTOR_DEBUG_CDATA
65 
66 
67 struct raptor_xml_writer_s {
68   raptor_world *world;
69 
70   int canonicalize;
71 
72   int depth;
73 
74   int my_nstack;
75   raptor_namespace_stack *nstack;
76   int nstack_depth;
77 
78   raptor_xml_element* current_element;
79 
80   /* outputting to this iostream */
81   raptor_iostream *iostr;
82 
83   /* Has writing the XML declaration writing been checked? */
84   int xml_declaration_checked;
85 
86   /* An extra newline is wanted */
87   int pending_newline;
88 
89   /* Options (per-object) */
90   raptor_object_options options;
91 };
92 
93 
94 /* 16 spaces */
95 #define SPACES_BUFFER_SIZE sizeof(spaces_buffer)
96 static const unsigned char spaces_buffer[] = {
97   ' ', ' ', ' ', ' ',
98   ' ', ' ', ' ', ' ',
99   ' ', ' ', ' ', ' ',
100   ' ', ' ', ' ', ' '
101 };
102 
103 
104 
105 /* helper functions */
106 
107 /* Handle printing a pending newline OR newline with indenting */
108 static int
raptor_xml_writer_indent(raptor_xml_writer * xml_writer)109 raptor_xml_writer_indent(raptor_xml_writer *xml_writer)
110 {
111   int num_spaces;
112 
113   if(!XML_WRITER_AUTO_INDENT(xml_writer)) {
114     if(xml_writer->pending_newline) {
115       raptor_iostream_write_byte('\n', xml_writer->iostr);
116       xml_writer->pending_newline = 0;
117 
118       if(xml_writer->current_element)
119         xml_writer->current_element->content_cdata_seen = 1;
120     }
121     return 0;
122   }
123 
124   num_spaces = xml_writer->depth * XML_WRITER_INDENT(xml_writer);
125 
126   /* Do not write an extra newline at the start of the document
127    * (after the XML declaration or XMP processing instruction has
128    * been writtten)
129    */
130   if(xml_writer->xml_declaration_checked == 1)
131     xml_writer->xml_declaration_checked++;
132   else {
133     raptor_iostream_write_byte('\n', xml_writer->iostr);
134     xml_writer->pending_newline = 0;
135   }
136 
137   while(num_spaces > 0) {
138 
139     int count = (num_spaces > RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE)) ?
140                  RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE) : num_spaces;
141 
142     raptor_iostream_counted_string_write(spaces_buffer, count,
143                                          xml_writer->iostr);
144 
145     num_spaces -= count;
146   }
147 
148   if(xml_writer->current_element)
149     xml_writer->current_element->content_cdata_seen = 1;
150 
151   return 0;
152 }
153 
154 
155 struct nsd {
156   const raptor_namespace *nspace;
157   unsigned char *declaration;
158   size_t length;
159 };
160 
161 
162 static int
raptor_xml_writer_nsd_compare(const void * a,const void * b)163 raptor_xml_writer_nsd_compare(const void *a, const void *b)
164 {
165   struct nsd* nsd_a = (struct nsd*)a;
166   struct nsd* nsd_b = (struct nsd*)b;
167   return strcmp((const char*)nsd_a->declaration, (const char*)nsd_b->declaration);
168 }
169 
170 
171 static int
raptor_xml_writer_start_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int auto_empty)172 raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer,
173                                        raptor_xml_element* element,
174                                        int auto_empty)
175 {
176   raptor_iostream* iostr = xml_writer->iostr;
177   raptor_namespace_stack *nstack = xml_writer->nstack;
178   int depth = xml_writer->depth;
179   int auto_indent = XML_WRITER_AUTO_INDENT(xml_writer);
180   struct nsd *nspace_declarations = NULL;
181   size_t nspace_declarations_count = 0;
182   unsigned int i;
183 
184   if(nstack) {
185     int nspace_max_count = element->attribute_count * 2; /* attr and value */
186     if(element->name->nspace)
187       nspace_max_count++;
188     if(element->declared_nspaces)
189       nspace_max_count += raptor_sequence_size(element->declared_nspaces);
190     if(element->xml_language)
191       nspace_max_count++;
192 
193     nspace_declarations = RAPTOR_CALLOC(struct nsd*, nspace_max_count,
194                                         sizeof(struct nsd));
195     if(!nspace_declarations)
196       return 1;
197   }
198 
199   if(element->name->nspace) {
200     if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) {
201       nspace_declarations[0].declaration=
202         raptor_namespace_format_as_xml(element->name->nspace,
203                                        &nspace_declarations[0].length);
204       if(!nspace_declarations[0].declaration)
205         goto error;
206       nspace_declarations[0].nspace = element->name->nspace;
207       nspace_declarations_count++;
208     }
209   }
210 
211   if(nstack && element->attributes) {
212     for(i = 0; i < element->attribute_count; i++) {
213       /* qname */
214       if(element->attributes[i]->nspace) {
215         /* Check if we need a namespace declaration attribute */
216         if(nstack &&
217            !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) {
218           /* not in scope and not same as element (so already going to be declared)*/
219           unsigned int j;
220           int declare_me = 1;
221 
222           /* check it wasn't an earlier declaration too */
223           for(j = 0; j < nspace_declarations_count; j++)
224             if(nspace_declarations[j].nspace == element->attributes[i]->nspace) {
225               declare_me = 0;
226               break;
227             }
228 
229           if(declare_me) {
230             nspace_declarations[nspace_declarations_count].declaration=
231               raptor_namespace_format_as_xml(element->attributes[i]->nspace,
232                                              &nspace_declarations[nspace_declarations_count].length);
233             if(!nspace_declarations[nspace_declarations_count].declaration)
234               goto error;
235             nspace_declarations[nspace_declarations_count].nspace = element->attributes[i]->nspace;
236             nspace_declarations_count++;
237           }
238         }
239       }
240 
241       /* Add the attribute's value */
242       nspace_declarations[nspace_declarations_count].declaration=
243         raptor_qname_format_as_xml(element->attributes[i],
244                                    &nspace_declarations[nspace_declarations_count].length);
245       if(!nspace_declarations[nspace_declarations_count].declaration)
246         goto error;
247       nspace_declarations[nspace_declarations_count].nspace = NULL;
248       nspace_declarations_count++;
249 
250     }
251   }
252 
253   if(nstack && element->declared_nspaces &&
254      raptor_sequence_size(element->declared_nspaces) > 0) {
255     for(i = 0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) {
256       raptor_namespace* nspace = (raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i);
257       unsigned int j;
258       int declare_me = 1;
259 
260       /* check it wasn't an earlier declaration too */
261       for(j = 0; j < nspace_declarations_count; j++)
262         if(nspace_declarations[j].nspace == nspace) {
263           declare_me = 0;
264           break;
265         }
266 
267       if(declare_me) {
268         nspace_declarations[nspace_declarations_count].declaration=
269           raptor_namespace_format_as_xml(nspace,
270                                          &nspace_declarations[nspace_declarations_count].length);
271         if(!nspace_declarations[nspace_declarations_count].declaration)
272           goto error;
273         nspace_declarations[nspace_declarations_count].nspace = nspace;
274         nspace_declarations_count++;
275       }
276 
277     }
278   }
279 
280   if(nstack && element->xml_language) {
281     size_t lang_len = strlen(RAPTOR_GOOD_CAST(char*, element->xml_language));
282 #define XML_LANG_PREFIX_LEN 10
283     size_t buf_length = XML_LANG_PREFIX_LEN + lang_len + 1;
284     unsigned char* buffer = RAPTOR_MALLOC(unsigned char*, buf_length + 1);
285     const char quote = '\"';
286     unsigned char* p;
287 
288     memcpy(buffer, "xml:lang=\"", XML_LANG_PREFIX_LEN);
289     p = buffer + XML_LANG_PREFIX_LEN;
290     p += raptor_xml_escape_string(xml_writer->world,
291                                   element->xml_language, lang_len,
292                                   p, buf_length, quote);
293     *p++ = quote;
294     *p = '\0';
295 
296     nspace_declarations[nspace_declarations_count].declaration = buffer;
297     nspace_declarations[nspace_declarations_count].length = buf_length;
298     nspace_declarations[nspace_declarations_count].nspace = NULL;
299     nspace_declarations_count++;
300   }
301 
302 
303   raptor_iostream_write_byte('<', iostr);
304 
305   if(element->name->nspace && element->name->nspace->prefix_length > 0) {
306     raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix,
307                                          element->name->nspace->prefix_length,
308                                          iostr);
309     raptor_iostream_write_byte(':', iostr);
310   }
311   raptor_iostream_counted_string_write((const char*)element->name->local_name,
312                                        element->name->local_name_length,
313                                        iostr);
314 
315   /* declare namespaces and attributes */
316   if(nspace_declarations_count) {
317     int need_indent = 0;
318 
319     /* sort them into the canonical order */
320     qsort((void*)nspace_declarations,
321           nspace_declarations_count, sizeof(struct nsd),
322           raptor_xml_writer_nsd_compare);
323 
324     /* declare namespaces first */
325     for(i = 0; i < nspace_declarations_count; i++) {
326       if(!nspace_declarations[i].nspace)
327         continue;
328 
329       if(auto_indent && need_indent) {
330         /* indent attributes */
331         raptor_xml_writer_newline(xml_writer);
332         xml_writer->depth++;
333         raptor_xml_writer_indent(xml_writer);
334         xml_writer->depth--;
335       }
336       raptor_iostream_write_byte(' ', iostr);
337       raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
338                                            nspace_declarations[i].length,
339                                            iostr);
340       RAPTOR_FREE(char*, nspace_declarations[i].declaration);
341       nspace_declarations[i].declaration = NULL;
342       need_indent = 1;
343 
344       if(raptor_namespace_stack_start_namespace(nstack,
345                                                 (raptor_namespace*)nspace_declarations[i].nspace,
346                                                 depth))
347         goto error;
348     }
349 
350     /* declare attributes */
351     for(i = 0; i < nspace_declarations_count; i++) {
352       if(nspace_declarations[i].nspace)
353         continue;
354 
355       if(auto_indent && need_indent) {
356         /* indent attributes */
357         raptor_xml_writer_newline(xml_writer);
358         xml_writer->depth++;
359         raptor_xml_writer_indent(xml_writer);
360         xml_writer->depth--;
361       }
362       raptor_iostream_write_byte(' ', iostr);
363       raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
364                                            nspace_declarations[i].length,
365                                            iostr);
366       need_indent = 1;
367 
368       RAPTOR_FREE(char*, nspace_declarations[i].declaration);
369       nspace_declarations[i].declaration = NULL;
370     }
371   }
372 
373   if(!auto_empty)
374     raptor_iostream_write_byte('>', iostr);
375 
376   if(nstack)
377     RAPTOR_FREE(stringarray, nspace_declarations);
378 
379   return 0;
380 
381   /* Clean up nspace_declarations on error */
382   error:
383 
384   for(i = 0; i < nspace_declarations_count; i++) {
385     if(nspace_declarations[i].declaration)
386       RAPTOR_FREE(char*, nspace_declarations[i].declaration);
387   }
388 
389   RAPTOR_FREE(stringarray, nspace_declarations);
390 
391   return 1;
392 }
393 
394 
395 static int
raptor_xml_writer_end_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int is_empty)396 raptor_xml_writer_end_element_common(raptor_xml_writer* xml_writer,
397                                      raptor_xml_element *element,
398                                      int is_empty)
399 {
400   raptor_iostream* iostr = xml_writer->iostr;
401 
402   if(is_empty)
403     raptor_iostream_write_byte('/', iostr);
404   else {
405 
406     raptor_iostream_write_byte('<', iostr);
407 
408     raptor_iostream_write_byte('/', iostr);
409 
410     if(element->name->nspace && element->name->nspace->prefix_length > 0) {
411       raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix,
412                                            element->name->nspace->prefix_length,
413                                            iostr);
414       raptor_iostream_write_byte(':', iostr);
415     }
416     raptor_iostream_counted_string_write((const char*)element->name->local_name,
417                                          element->name->local_name_length,
418                                          iostr);
419   }
420 
421   raptor_iostream_write_byte('>', iostr);
422 
423   return 0;
424 
425 }
426 
427 
428 /**
429  * raptor_new_xml_writer:
430  * @world: raptor_world object
431  * @nstack: Namespace stack for the writer to start with (or NULL)
432  * @iostr: I/O stream to write to
433  *
434  * Constructor - Create a new XML Writer writing XML to a raptor_iostream
435  *
436  * Return value: a new #raptor_xml_writer object or NULL on failure
437  **/
438 raptor_xml_writer*
raptor_new_xml_writer(raptor_world * world,raptor_namespace_stack * nstack,raptor_iostream * iostr)439 raptor_new_xml_writer(raptor_world* world,
440                       raptor_namespace_stack *nstack,
441                       raptor_iostream* iostr)
442 {
443   raptor_xml_writer* xml_writer;
444 
445   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
446 
447   if(!iostr)
448     return NULL;
449 
450   raptor_world_open(world);
451 
452   xml_writer = RAPTOR_CALLOC(raptor_xml_writer*, 1, sizeof(*xml_writer));
453   if(!xml_writer)
454     return NULL;
455 
456   xml_writer->world = world;
457 
458   xml_writer->nstack_depth = 0;
459 
460   xml_writer->nstack = nstack;
461   if(!xml_writer->nstack) {
462     xml_writer->nstack = raptor_new_namespaces(world, 1);
463     xml_writer->my_nstack = 1;
464   }
465 
466   xml_writer->iostr = iostr;
467 
468   raptor_object_options_init(&xml_writer->options,
469                              RAPTOR_OPTION_AREA_XML_WRITER);
470 
471   return xml_writer;
472 }
473 
474 
475 /**
476  * raptor_free_xml_writer:
477  * @xml_writer: XML writer object
478  *
479  * Destructor - Free XML Writer
480  *
481  **/
482 void
raptor_free_xml_writer(raptor_xml_writer * xml_writer)483 raptor_free_xml_writer(raptor_xml_writer* xml_writer)
484 {
485   if(!xml_writer)
486     return;
487 
488   if(xml_writer->nstack && xml_writer->my_nstack)
489     raptor_free_namespaces(xml_writer->nstack);
490 
491   raptor_object_options_clear(&xml_writer->options);
492 
493   RAPTOR_FREE(raptor_xml_writer, xml_writer);
494 }
495 
496 
497 static void
raptor_xml_writer_write_xml_declaration(raptor_xml_writer * xml_writer)498 raptor_xml_writer_write_xml_declaration(raptor_xml_writer* xml_writer)
499 {
500   if(!xml_writer->xml_declaration_checked) {
501     /* check that it should be written once only */
502     xml_writer->xml_declaration_checked = 1;
503 
504     if(RAPTOR_OPTIONS_GET_NUMERIC(xml_writer,
505                                   RAPTOR_OPTION_WRITER_XML_DECLARATION)) {
506       raptor_iostream_string_write((const unsigned char*)"<?xml version=\"",
507                                    xml_writer->iostr);
508       raptor_iostream_counted_string_write((XML_WRITER_XML_VERSION(xml_writer) == 10) ?
509                                            (const unsigned char*)"1.0" :
510                                            (const unsigned char*)"1.1",
511                                            3, xml_writer->iostr);
512       raptor_iostream_string_write((const unsigned char*)"\" encoding=\"utf-8\"?>\n",
513                                    xml_writer->iostr);
514     }
515   }
516 
517 }
518 
519 
520 /**
521  * raptor_xml_writer_empty_element:
522  * @xml_writer: XML writer object
523  * @element: XML element object
524  *
525  * Write an empty XML element to the XML writer.
526  *
527  * Closes any previous empty element if XML writer option AUTO_EMPTY
528  * is enabled.
529  **/
530 void
raptor_xml_writer_empty_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)531 raptor_xml_writer_empty_element(raptor_xml_writer* xml_writer,
532                                 raptor_xml_element *element)
533 {
534   raptor_xml_writer_write_xml_declaration(xml_writer);
535 
536   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
537 
538   if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
539     raptor_xml_writer_indent(xml_writer);
540 
541   raptor_xml_writer_start_element_common(xml_writer, element, 1);
542 
543   raptor_xml_writer_end_element_common(xml_writer, element, 1);
544 
545   raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
546 }
547 
548 
549 /**
550  * raptor_xml_writer_start_element:
551  * @xml_writer: XML writer object
552  * @element: XML element object
553  *
554  * Write a start XML element to the XML writer.
555  *
556  * Closes any previous empty element if XML writer option AUTO_EMPTY
557  * is enabled.
558  *
559  * Indents the start element if XML writer option AUTO_INDENT is enabled.
560  **/
561 void
raptor_xml_writer_start_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)562 raptor_xml_writer_start_element(raptor_xml_writer* xml_writer,
563                                 raptor_xml_element *element)
564 {
565   raptor_xml_writer_write_xml_declaration(xml_writer);
566 
567   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
568 
569   if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
570     raptor_xml_writer_indent(xml_writer);
571 
572   raptor_xml_writer_start_element_common(xml_writer, element,
573                                          XML_WRITER_AUTO_EMPTY(xml_writer));
574 
575   xml_writer->depth++;
576 
577   /* SJS Note: This "if" clause is necessary because raptor_rdfxml.c
578    * uses xml_writer for parseType="literal" and passes in elements
579    * whose parent field is already set. The first time this function
580    * is called, it sets element->parent to 0, causing the warn-07.rdf
581    * test to fail. Subsequent calls to this function set
582    * element->parent to its existing value.
583    */
584   if(xml_writer->current_element)
585     element->parent = xml_writer->current_element;
586 
587   xml_writer->current_element = element;
588   if(element->parent)
589     element->parent->content_element_seen = 1;
590 }
591 
592 
593 /**
594  * raptor_xml_writer_end_element:
595  * @xml_writer: XML writer object
596  * @element: XML element object
597  *
598  * Write an end XML element to the XML writer.
599  *
600  * Indents the end element if XML writer option AUTO_INDENT is enabled.
601  **/
602 void
raptor_xml_writer_end_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)603 raptor_xml_writer_end_element(raptor_xml_writer* xml_writer,
604                               raptor_xml_element* element)
605 {
606   int is_empty;
607 
608   xml_writer->depth--;
609 
610   if(xml_writer->pending_newline ||
611      (XML_WRITER_AUTO_INDENT(xml_writer) && element->content_element_seen))
612     raptor_xml_writer_indent(xml_writer);
613 
614   is_empty = XML_WRITER_AUTO_EMPTY(xml_writer) ?
615     !(element->content_cdata_seen || element->content_element_seen) : 0;
616 
617   raptor_xml_writer_end_element_common(xml_writer, element, is_empty);
618 
619   raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
620 
621   if(xml_writer->current_element)
622     xml_writer->current_element = xml_writer->current_element->parent;
623 }
624 
625 
626 /**
627  * raptor_xml_writer_newline:
628  * @xml_writer: XML writer object
629  *
630  * Write a newline to the XML writer.
631  *
632  * Indents the next line if XML writer option AUTO_INDENT is enabled.
633  **/
634 void
raptor_xml_writer_newline(raptor_xml_writer * xml_writer)635 raptor_xml_writer_newline(raptor_xml_writer* xml_writer)
636 {
637   xml_writer->pending_newline = 1;
638 }
639 
640 
641 /**
642  * raptor_xml_writer_cdata:
643  * @xml_writer: XML writer object
644  * @s: string to XML escape and write
645  *
646  * Write CDATA XML-escaped to the XML writer.
647  *
648  * Closes any previous empty element if XML writer option AUTO_EMPTY
649  * is enabled.
650  *
651  **/
652 void
raptor_xml_writer_cdata(raptor_xml_writer * xml_writer,const unsigned char * s)653 raptor_xml_writer_cdata(raptor_xml_writer* xml_writer,
654                         const unsigned char *s)
655 {
656   raptor_xml_writer_write_xml_declaration(xml_writer);
657 
658   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
659 
660   raptor_xml_escape_string_any_write(s, strlen((const char*)s),
661                                       '\0',
662                                       XML_WRITER_XML_VERSION(xml_writer),
663                                       xml_writer->iostr);
664 
665   if(xml_writer->current_element)
666     xml_writer->current_element->content_cdata_seen = 1;
667 }
668 
669 
670 /**
671  * raptor_xml_writer_cdata_counted:
672  * @xml_writer: XML writer object
673  * @s: string to XML escape and write
674  * @len: length of string
675  *
676  * Write counted CDATA XML-escaped to the XML writer.
677  *
678  * Closes any previous empty element if XML writer option AUTO_EMPTY
679  * is enabled.
680  *
681  **/
682 void
raptor_xml_writer_cdata_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)683 raptor_xml_writer_cdata_counted(raptor_xml_writer* xml_writer,
684                                 const unsigned char *s, unsigned int len)
685 {
686   raptor_xml_writer_write_xml_declaration(xml_writer);
687 
688   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
689 
690   raptor_xml_escape_string_any_write(s, len,
691                                       '\0',
692                                       XML_WRITER_XML_VERSION(xml_writer),
693                                       xml_writer->iostr);
694 
695   if(xml_writer->current_element)
696     xml_writer->current_element->content_cdata_seen = 1;
697 }
698 
699 
700 /**
701  * raptor_xml_writer_raw:
702  * @xml_writer: XML writer object
703  * @s: string to write
704  *
705  * Write a string raw to the XML writer.
706  *
707  * Closes any previous empty element if XML writer option AUTO_EMPTY
708  * is enabled.
709  *
710  **/
711 void
raptor_xml_writer_raw(raptor_xml_writer * xml_writer,const unsigned char * s)712 raptor_xml_writer_raw(raptor_xml_writer* xml_writer,
713                       const unsigned char *s)
714 {
715   raptor_xml_writer_write_xml_declaration(xml_writer);
716 
717   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
718 
719   raptor_iostream_string_write(s, xml_writer->iostr);
720 
721   if(xml_writer->current_element)
722     xml_writer->current_element->content_cdata_seen = 1;
723 }
724 
725 
726 /**
727  * raptor_xml_writer_raw_counted:
728  * @xml_writer: XML writer object
729  * @s: string to write
730  * @len: length of string
731  *
732  * Write a counted string raw to the XML writer.
733  *
734  * Closes any previous empty element if XML writer option AUTO_EMPTY
735  * is enabled.
736  *
737  **/
738 void
raptor_xml_writer_raw_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)739 raptor_xml_writer_raw_counted(raptor_xml_writer* xml_writer,
740                               const unsigned char *s, unsigned int len)
741 {
742   raptor_xml_writer_write_xml_declaration(xml_writer);
743 
744   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
745 
746   raptor_iostream_counted_string_write(s, len, xml_writer->iostr);
747 
748   if(xml_writer->current_element)
749     xml_writer->current_element->content_cdata_seen = 1;
750 }
751 
752 
753 /**
754  * raptor_xml_writer_comment:
755  * @xml_writer: XML writer object
756  * @s: comment string to write
757  *
758  * Write an XML comment to the XML writer.
759  *
760  * Closes any previous empty element if XML writer option AUTO_EMPTY
761  * is enabled.
762  *
763  **/
764 void
raptor_xml_writer_comment(raptor_xml_writer * xml_writer,const unsigned char * s)765 raptor_xml_writer_comment(raptor_xml_writer* xml_writer,
766                           const unsigned char *s)
767 {
768   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
769 
770   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
771   raptor_xml_writer_cdata(xml_writer, s);
772   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
773 }
774 
775 
776 /**
777  * raptor_xml_writer_comment_counted:
778  * @xml_writer: XML writer object
779  * @s: comment string to write
780  * @len: length of string
781  *
782  * Write a counted XML comment to the XML writer.
783  *
784  * Closes any previous empty element if XML writer option AUTO_EMPTY
785  * is enabled.
786  *
787  **/
788 void
raptor_xml_writer_comment_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)789 raptor_xml_writer_comment_counted(raptor_xml_writer* xml_writer,
790                                   const unsigned char *s, unsigned int len)
791 {
792   XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
793 
794   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
795   raptor_xml_writer_cdata_counted(xml_writer, s, len);
796   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
797 }
798 
799 
800 /**
801  * raptor_xml_writer_flush:
802  * @xml_writer: XML writer object
803  *
804  * Finish the XML writer.
805  *
806  **/
807 void
raptor_xml_writer_flush(raptor_xml_writer * xml_writer)808 raptor_xml_writer_flush(raptor_xml_writer* xml_writer)
809 {
810   if(xml_writer->pending_newline) {
811     raptor_iostream_write_byte('\n', xml_writer->iostr);
812     xml_writer->pending_newline = 0;
813   }
814 }
815 
816 
817 /**
818  * raptor_xml_writer_set_option:
819  * @xml_writer: #raptor_xml_writer xml_writer object
820  * @option: option to set from enumerated #raptor_option values
821  * @string: string option value (or NULL)
822  * @integer: integer option value
823  *
824  * Set xml_writer option.
825  *
826  * If @string is not NULL and the option type is numeric, the string
827  * value is converted to an integer and used in preference to @integer.
828  *
829  * If @string is NULL and the option type is not numeric, an error is
830  * returned.
831  *
832  * The @string values used are copied.
833  *
834  * The allowed options are available via
835  * raptor_world_get_option_description().
836  *
837  * Return value: non 0 on failure or if the option is unknown
838  **/
839 int
raptor_xml_writer_set_option(raptor_xml_writer * xml_writer,raptor_option option,char * string,int integer)840 raptor_xml_writer_set_option(raptor_xml_writer *xml_writer,
841                              raptor_option option, char* string, int integer)
842 {
843   return raptor_object_options_set_option(&xml_writer->options, option,
844                                           string, integer);
845 }
846 
847 
848 /**
849  * raptor_xml_writer_get_option:
850  * @xml_writer: #raptor_xml_writer xml_writer object
851  * @option: option to get value
852  * @string_p: pointer to where to store string value
853  * @integer_p: pointer to where to store integer value
854  *
855  * Get xml_writer option.
856  *
857  * Any string value returned in *@string_p is shared and must
858  * be copied by the caller.
859  *
860  * The allowed options are available via
861  * raptor_world_get_option_description().
862  *
863  * Return value: option value or < 0 for an illegal option
864  **/
865 int
raptor_xml_writer_get_option(raptor_xml_writer * xml_writer,raptor_option option,char ** string_p,int * integer_p)866 raptor_xml_writer_get_option(raptor_xml_writer *xml_writer,
867                              raptor_option option,
868                              char** string_p, int* integer_p)
869 {
870   return raptor_object_options_get_option(&xml_writer->options, option,
871                                           string_p, integer_p);
872 }
873 
874 
875 /**
876  * raptor_xml_writer_get_depth:
877  * @xml_writer: #raptor_xml_writer xml writer object
878  *
879  * Get the current XML Writer element depth
880  *
881  * Return value: element stack depth
882  */
883 int
raptor_xml_writer_get_depth(raptor_xml_writer * xml_writer)884 raptor_xml_writer_get_depth(raptor_xml_writer *xml_writer)
885 {
886   return xml_writer->depth;
887 }
888 
889 
890 #endif
891 
892 
893 
894 #ifdef STANDALONE
895 
896 /* one more prototype */
897 int main(int argc, char *argv[]);
898 
899 
900 const unsigned char *base_uri_string = (const unsigned char*)"http://example.org/base#";
901 
902 #define OUT_BYTES_COUNT 135
903 
904 int
main(int argc,char * argv[])905 main(int argc, char *argv[])
906 {
907   raptor_world *world;
908   const char *program = raptor_basename(argv[0]);
909   raptor_iostream *iostr;
910   raptor_namespace_stack *nstack;
911   raptor_namespace* foo_ns;
912   raptor_xml_writer* xml_writer;
913   raptor_uri* base_uri;
914   raptor_qname* el_name;
915   raptor_xml_element *element;
916   unsigned long offset;
917   raptor_qname **attrs;
918   raptor_uri* base_uri_copy = NULL;
919 
920   /* for raptor_new_iostream_to_string */
921   void *string = NULL;
922   size_t string_len = 0;
923 
924   world = raptor_new_world();
925   if(!world || raptor_world_open(world))
926     exit(1);
927 
928   iostr = raptor_new_iostream_to_string(world, &string, &string_len, NULL);
929   if(!iostr) {
930     fprintf(stderr, "%s: Failed to create iostream to string\n", program);
931     exit(1);
932   }
933 
934   nstack = raptor_new_namespaces(world, 1);
935 
936   xml_writer = raptor_new_xml_writer(world, nstack, iostr);
937   if(!xml_writer) {
938     fprintf(stderr, "%s: Failed to create xml_writer to iostream\n", program);
939     exit(1);
940   }
941 
942   base_uri = raptor_new_uri(world, base_uri_string);
943 
944   foo_ns = raptor_new_namespace(nstack,
945                               (const unsigned char*)"foo",
946                               (const unsigned char*)"http://example.org/foo-ns#",
947                               0);
948 
949 
950   el_name = raptor_new_qname_from_namespace_local_name(world,
951                                                        foo_ns,
952                                                        (const unsigned char*)"bar",
953                                                        NULL);
954   base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL;
955   element = raptor_new_xml_element(el_name,
956                                   NULL, /* language */
957                                   base_uri_copy);
958 
959   raptor_xml_writer_start_element(xml_writer, element);
960   raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"hello\n", 6);
961   raptor_xml_writer_comment_counted(xml_writer, (const unsigned char*)"comment", 7);
962   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
963   raptor_xml_writer_end_element(xml_writer, element);
964 
965   raptor_free_xml_element(element);
966 
967   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
968 
969   el_name = raptor_new_qname(nstack,
970                              (const unsigned char*)"blah",
971                              NULL /* no attribute value - element */);
972   base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL;
973   element = raptor_new_xml_element(el_name,
974                                    NULL, /* language */
975                                    base_uri_copy);
976 
977   attrs = RAPTOR_CALLOC(raptor_qname**, 1, sizeof(raptor_qname*));
978   attrs[0] = raptor_new_qname(nstack,
979                               (const unsigned char*)"a",
980                               (const unsigned char*)"b" /* attribute value */);
981   raptor_xml_element_set_attributes(element, attrs, 1);
982 
983   raptor_xml_writer_empty_element(xml_writer, element);
984 
985   raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
986 
987   raptor_free_xml_writer(xml_writer);
988 
989   raptor_free_xml_element(element);
990 
991   raptor_free_namespace(foo_ns);
992 
993   raptor_free_namespaces(nstack);
994 
995   raptor_free_uri(base_uri);
996 
997 
998   offset = raptor_iostream_tell(iostr);
999 
1000 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1001   fprintf(stderr, "%s: Freeing iostream\n", program);
1002 #endif
1003   raptor_free_iostream(iostr);
1004 
1005   if(offset != OUT_BYTES_COUNT) {
1006     fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
1007             (int)offset, (int)OUT_BYTES_COUNT);
1008     fputs("[[", stderr);
1009     (void)fwrite(string, 1, string_len, stderr);
1010     fputs("]]\n", stderr);
1011     return 1;
1012   }
1013 
1014   if(!string) {
1015     fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
1016     return 1;
1017   }
1018   string_len = strlen((const char*)string);
1019   if(string_len != offset) {
1020     fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)offset);
1021     return 1;
1022   }
1023 
1024 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1025   fprintf(stderr, "%s: Made XML string of %d bytes\n", program, (int)string_len);
1026   fputs("[[", stderr);
1027   (void)fwrite(string, 1, string_len, stderr);
1028   fputs("]]\n", stderr);
1029 #endif
1030 
1031   raptor_free_memory(string);
1032 
1033   raptor_free_world(world);
1034 
1035   /* keep gcc -Wall happy */
1036   return(0);
1037 }
1038 
1039 #endif
1040