1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * raptor_iostream.c - Raptor I/O-stream class for abstracting I/O
4  *
5  * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2004, 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 #ifdef HAVE_CONFIG_H
26 #include <raptor_config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <stdarg.h>
33 
34 /* Raptor includes */
35 #include "raptor2.h"
36 #include "raptor_internal.h"
37 
38 
39 #ifndef STANDALONE
40 
41 #define RAPTOR_IOSTREAM_MODE_READ  1
42 #define RAPTOR_IOSTREAM_MODE_WRITE 2
43 
44 #define RAPTOR_IOSTREAM_FLAGS_EOF           1
45 #define RAPTOR_IOSTREAM_FLAGS_FREE_HANDLER  2
46 
47 struct raptor_iostream_s
48 {
49   raptor_world *world;
50 
51   void *user_data;
52   const raptor_iostream_handler* handler;
53   size_t offset;
54   unsigned int mode;
55   int flags;
56 };
57 
58 
59 
60 /* prototypes for local functions */
61 
62 
63 static int
raptor_iostream_calculate_modes(const raptor_iostream_handler * const handler)64 raptor_iostream_calculate_modes(const raptor_iostream_handler * const handler)
65 {
66   int mode = 0;
67 
68   /* API V1 checks */
69   if((handler->version >= 1) &&
70      handler->read_bytes)
71     mode |= RAPTOR_IOSTREAM_MODE_READ;
72 
73   /* API V2 checks */
74   if((handler->version >= 2) &&
75      (handler->write_byte || handler->write_bytes))
76     mode |= RAPTOR_IOSTREAM_MODE_WRITE;
77 
78   return mode;
79 }
80 
81 
82 /* Return non-0 if handler is legal and OK for given mode (if not 0 = ANY) */
83 static int
raptor_iostream_check_handler(const raptor_iostream_handler * const handler,unsigned int user_mode)84 raptor_iostream_check_handler(const raptor_iostream_handler * const handler,
85                               unsigned int user_mode)
86 {
87   int mode;
88 
89   if(handler->version < 1 || handler->version > 2)
90     return 0;
91 
92   mode = raptor_iostream_calculate_modes(handler);
93   if(user_mode && !(user_mode & mode))
94     return 0;
95 
96   return (mode != 0);
97 }
98 
99 
100 /**
101  * raptor_new_iostream_from_handler:
102  * @world: raptor_world object
103  * @user_data: pointer to context information to pass in to calls
104  * @handler: pointer to handler methods
105  *
106  * Create a new iostream over a user-defined handler
107  *
108  * Return value: new #raptor_iostream object or NULL on failure
109  **/
110 raptor_iostream*
raptor_new_iostream_from_handler(raptor_world * world,void * user_data,const raptor_iostream_handler * const handler)111 raptor_new_iostream_from_handler(raptor_world *world,
112                                  void *user_data,
113                                  const raptor_iostream_handler* const handler)
114 {
115   raptor_iostream* iostr;
116 
117   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
118   RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(handler, raptor_iostream_handler, NULL);
119 
120   raptor_world_open(world);
121 
122   if(!raptor_iostream_check_handler(handler, 0))
123     return NULL;
124 
125   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
126   if(!iostr)
127     return NULL;
128 
129   iostr->world = world;
130   iostr->handler = handler;
131   iostr->user_data = (void*)user_data;
132   iostr->mode = raptor_iostream_calculate_modes(handler);
133 
134   if(iostr->handler->init &&
135      iostr->handler->init(iostr->user_data)) {
136     RAPTOR_FREE(raptor_iostream, iostr);
137     return NULL;
138   }
139   return iostr;
140 }
141 
142 
143 
144 /* Local handlers for reading/writing to/from a sink */
145 
146 static int
raptor_sink_iostream_write_byte(void * user_data,const int byte)147 raptor_sink_iostream_write_byte(void *user_data, const int byte)
148 {
149   return 0;
150 }
151 
152 static int
raptor_sink_iostream_write_bytes(void * user_data,const void * ptr,size_t size,size_t nmemb)153 raptor_sink_iostream_write_bytes(void *user_data, const void *ptr,
154                                  size_t size, size_t nmemb)
155 {
156   return RAPTOR_BAD_CAST(int, size * nmemb); /* success */
157 }
158 
159 static int
raptor_sink_iostream_read_bytes(void * user_data,void * ptr,size_t size,size_t nmemb)160 raptor_sink_iostream_read_bytes(void *user_data, void *ptr,
161                                 size_t size, size_t nmemb)
162 {
163   return 0;
164 }
165 
166 static int
raptor_sink_iostream_read_eof(void * user_data)167 raptor_sink_iostream_read_eof(void *user_data)
168 {
169   return 1; /* EOF always */
170 }
171 
172 static const raptor_iostream_handler raptor_iostream_sink_handler = {
173   /* .version     = */ 2,
174   /* .init        = */ NULL,
175   /* .finish      = */ NULL,
176   /* .write_byte  = */ raptor_sink_iostream_write_byte,
177   /* .write_bytes = */ raptor_sink_iostream_write_bytes,
178   /* .write_end   = */ NULL,
179   /* .read_bytes  = */ raptor_sink_iostream_read_bytes,
180   /* .read_eof    = */ raptor_sink_iostream_read_eof
181 };
182 
183 
184 /**
185  * raptor_new_iostream_to_sink:
186  * @world: raptor_world object
187  *
188  * Create a new write iostream to a sink, throwing away all data.
189  *
190  * Provides an that throw away all writes and returns end of input
191  * immediately on reads.  Same as raptor_new_iostream_from_sink()
192  *
193  * Return value: new #raptor_iostream object or NULL on failure
194  **/
195 raptor_iostream*
raptor_new_iostream_to_sink(raptor_world * world)196 raptor_new_iostream_to_sink(raptor_world *world)
197 {
198   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
199 
200   raptor_world_open(world);
201 
202   return raptor_new_iostream_from_handler(world,
203                                           NULL, &raptor_iostream_sink_handler);
204 }
205 
206 
207 /* Local handlers for reading/writing from a filename */
208 
209 static void
raptor_filename_iostream_finish(void * user_data)210 raptor_filename_iostream_finish(void *user_data)
211 {
212   FILE* handle = (FILE*)user_data;
213   fclose(handle);
214 }
215 
216 static int
raptor_filename_iostream_write_byte(void * user_data,const int byte)217 raptor_filename_iostream_write_byte(void *user_data, const int byte)
218 {
219   FILE* handle = (FILE*)user_data;
220   return (fputc(byte, handle) == byte);
221 }
222 
223 static int
raptor_filename_iostream_write_bytes(void * user_data,const void * ptr,size_t size,size_t nmemb)224 raptor_filename_iostream_write_bytes(void *user_data,
225                                      const void *ptr, size_t size, size_t nmemb)
226 {
227   FILE* handle = (FILE*)user_data;
228   return RAPTOR_BAD_CAST(int, fwrite(ptr, size, nmemb, handle));
229 }
230 
231 static int
raptor_filename_iostream_write_end(void * user_data)232 raptor_filename_iostream_write_end(void *user_data)
233 {
234   FILE* handle = (FILE*)user_data;
235   return fclose(handle);
236 }
237 
238 static int
raptor_filename_iostream_read_bytes(void * user_data,void * ptr,size_t size,size_t nmemb)239 raptor_filename_iostream_read_bytes(void *user_data,
240                                     void *ptr, size_t size, size_t nmemb)
241 {
242   FILE* handle = (FILE*)user_data;
243   return RAPTOR_BAD_CAST(int, fread(ptr, size, nmemb, handle));
244 }
245 
246 static int
raptor_filename_iostream_read_eof(void * user_data)247 raptor_filename_iostream_read_eof(void *user_data)
248 {
249   FILE* handle = (FILE*)user_data;
250   return feof(handle);
251 }
252 
253 static const raptor_iostream_handler raptor_iostream_write_filename_handler = {
254   /* .version     = */ 2,
255   /* .init        = */ NULL,
256   /* .finish      = */ raptor_filename_iostream_finish,
257   /* .write_byte  = */ raptor_filename_iostream_write_byte,
258   /* .write_bytes = */ raptor_filename_iostream_write_bytes,
259   /* .write_end   = */ raptor_filename_iostream_write_end,
260   /* .read_bytes  = */ NULL,
261   /* .read_eof    = */ NULL
262 };
263 
264 
265 /**
266  * raptor_new_iostream_to_filename:
267  * @world: raptor world
268  * @filename: Output filename to open and write to
269  *
270  * Constructor - create a new iostream writing to a filename.
271  *
272  * Return value: new #raptor_iostream object or NULL on failure
273  **/
274 raptor_iostream*
raptor_new_iostream_to_filename(raptor_world * world,const char * filename)275 raptor_new_iostream_to_filename(raptor_world *world, const char *filename)
276 {
277   FILE *handle;
278   raptor_iostream* iostr;
279   const raptor_iostream_handler* handler;
280   const unsigned int mode = RAPTOR_IOSTREAM_MODE_WRITE;
281 
282   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
283 
284   raptor_world_open(world);
285 
286   if(!filename)
287     return NULL;
288 
289   handler = &raptor_iostream_write_filename_handler;
290   if(!raptor_iostream_check_handler(handler, mode))
291     return NULL;
292 
293   handle = fopen(filename, "wb");
294   if(!handle)
295     return NULL;
296 
297   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
298   if(!iostr) {
299     fclose(handle);
300     return NULL;
301   }
302 
303   iostr->world = world;
304   iostr->handler = handler;
305   iostr->user_data = (void*)handle;
306   iostr->mode = mode;
307 
308   if(iostr->handler->init &&
309      iostr->handler->init(iostr->user_data)) {
310     raptor_free_iostream(iostr);
311     return NULL;
312   }
313   return iostr;
314 }
315 
316 
317 static const raptor_iostream_handler raptor_iostream_write_file_handler = {
318   /* .version     = */ 2,
319   /* .init        = */ NULL,
320   /* .finish      = */ NULL,
321   /* .write_byte  = */ raptor_filename_iostream_write_byte,
322   /* .write_bytes = */ raptor_filename_iostream_write_bytes,
323   /* .write_end   = */ NULL,
324   /* .read_bytes  = */ NULL,
325   /* .read_eof    = */ NULL
326 };
327 
328 
329 /**
330  * raptor_new_iostream_to_file_handle:
331  * @world: raptor world
332  * @handle: FILE* handle to write to
333  *
334  * Constructor - create a new iostream writing to a FILE*.
335  *
336  * The @handle must already be open for writing.
337  * NOTE: This does not fclose the @handle when it is finished.
338  *
339  * Return value: new #raptor_iostream object or NULL on failure
340  **/
341 raptor_iostream*
raptor_new_iostream_to_file_handle(raptor_world * world,FILE * handle)342 raptor_new_iostream_to_file_handle(raptor_world *world, FILE *handle)
343 {
344   raptor_iostream* iostr;
345   const raptor_iostream_handler* handler;
346   const unsigned int mode = RAPTOR_IOSTREAM_MODE_WRITE;
347 
348   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
349 
350   raptor_world_open(world);
351 
352   if(!handle)
353     return NULL;
354 
355   handler = &raptor_iostream_write_file_handler;
356   if(!raptor_iostream_check_handler(handler, mode))
357     return NULL;
358 
359   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
360   if(!iostr)
361     return NULL;
362 
363   iostr->world = world;
364   iostr->handler = handler;
365   iostr->user_data = (void*)handle;
366   iostr->mode = mode;
367 
368   if(iostr->handler->init && iostr->handler->init(iostr->user_data)) {
369     RAPTOR_FREE(raptor_iostream, iostr);
370     return NULL;
371   }
372   return iostr;
373 }
374 
375 
376 
377 struct raptor_write_string_iostream_context {
378   raptor_stringbuffer *sb;
379   void *(*malloc_handler)(size_t size);
380   void **string_p;
381   size_t *length_p;
382 };
383 
384 
385 /* Local handlers for writing to a string */
386 
387 static void
raptor_write_string_iostream_finish(void * user_data)388 raptor_write_string_iostream_finish(void *user_data)
389 {
390   struct raptor_write_string_iostream_context* con;
391   size_t len;
392   void *str = NULL;
393 
394   con = (struct raptor_write_string_iostream_context*)user_data;
395   len = raptor_stringbuffer_length(con->sb);
396 
397   *con->string_p = NULL;
398   if(con->length_p)
399     *con->length_p = len;
400 
401   str = (void*)con->malloc_handler(len+1);
402   if(str) {
403     if(len)
404       raptor_stringbuffer_copy_to_string(con->sb, (unsigned char*)str, len+1);
405     else
406       *(char*)str='\0';
407     *con->string_p = str;
408   }
409 
410   if(!str && con->length_p)
411     *con->length_p = 0;
412 
413   raptor_free_stringbuffer(con->sb);
414   RAPTOR_FREE(raptor_write_string_iostream_context, con);
415   return;
416 }
417 
418 static int
raptor_write_string_iostream_write_byte(void * user_data,const int byte)419 raptor_write_string_iostream_write_byte(void *user_data, const int byte)
420 {
421   struct raptor_write_string_iostream_context* con;
422   unsigned char buf = (unsigned char)byte;
423 
424   con = (struct raptor_write_string_iostream_context*)user_data;
425   return raptor_stringbuffer_append_counted_string(con->sb, &buf, 1, 1);
426 }
427 
428 
429 static int
raptor_write_string_iostream_write_bytes(void * user_data,const void * ptr,size_t size,size_t nmemb)430 raptor_write_string_iostream_write_bytes(void *user_data, const void *ptr,
431                                          size_t size, size_t nmemb)
432 {
433   struct raptor_write_string_iostream_context* con;
434 
435   con = (struct raptor_write_string_iostream_context*)user_data;
436   if(raptor_stringbuffer_append_counted_string(con->sb,
437                                                (const unsigned char*)ptr, size * nmemb, 1))
438     return 0; /* failure */
439   return RAPTOR_BAD_CAST(int, size * nmemb); /* success */
440 }
441 
442 static const raptor_iostream_handler raptor_iostream_write_string_handler = {
443   /* .version     = */ 2,
444   /* .init        = */ NULL,
445   /* .finish      = */ raptor_write_string_iostream_finish,
446   /* .write_byte  = */ raptor_write_string_iostream_write_byte,
447   /* .write_bytes = */ raptor_write_string_iostream_write_bytes,
448   /* .write_end   = */ NULL,
449   /* .read_bytes  = */ NULL,
450   /* .read_eof    = */ NULL
451 };
452 
453 
454 /**
455  * raptor_new_iostream_to_string:
456  * @world: raptor world
457  * @string_p: pointer to location to hold string
458  * @length_p: pointer to location to hold length of string (or NULL)
459  * @malloc_handler: pointer to malloc() to use to make string (or NULL)
460  *
461  * Constructor - create a new iostream writing to a string.
462  *
463  * If @malloc_handler is null, raptor will allocate it using it's
464  * own memory allocator.  *@string_p is set to NULL on failure (and
465  * *@length_p to 0 if @length_p is not NULL).
466  *
467  * Return value: new #raptor_iostream object or NULL on failure
468  **/
469 RAPTOR_EXTERN_C
470 raptor_iostream*
raptor_new_iostream_to_string(raptor_world * world,void ** string_p,size_t * length_p,raptor_data_malloc_handler const malloc_handler)471 raptor_new_iostream_to_string(raptor_world *world,
472                               void **string_p, size_t *length_p,
473                               raptor_data_malloc_handler const malloc_handler)
474 {
475   raptor_iostream* iostr;
476   struct raptor_write_string_iostream_context* con;
477   const raptor_iostream_handler* handler;
478   const unsigned int mode = RAPTOR_IOSTREAM_MODE_WRITE;
479 
480   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
481 
482   if(!string_p)
483     return NULL;
484 
485   raptor_world_open(world);
486 
487   handler = &raptor_iostream_write_string_handler;
488   if(!raptor_iostream_check_handler(handler, mode))
489     return NULL;
490 
491   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
492   if(!iostr)
493     return NULL;
494 
495   con = RAPTOR_CALLOC(struct raptor_write_string_iostream_context*, 1,
496                       sizeof(*con));
497   if(!con) {
498     RAPTOR_FREE(raptor_iostream, iostr);
499     return NULL;
500   }
501 
502   con->sb = raptor_new_stringbuffer();
503   if(!con->sb) {
504     RAPTOR_FREE(raptor_iostream, iostr);
505     RAPTOR_FREE(raptor_write_string_iostream_context, con);
506     return NULL;
507   }
508 
509   con->string_p = string_p;
510   *string_p = NULL;
511 
512   con->length_p = length_p;
513   if(length_p)
514     *length_p = 0;
515 
516   if(malloc_handler)
517     con->malloc_handler = malloc_handler;
518   else
519     con->malloc_handler = raptor_alloc_memory;
520 
521   iostr->world = world;
522   iostr->handler = handler;
523   iostr->user_data = (void*)con;
524   iostr->mode = mode;
525 
526   if(iostr->handler->init && iostr->handler->init(iostr->user_data)) {
527     raptor_free_iostream(iostr);
528     return NULL;
529   }
530   return iostr;
531 }
532 
533 
534 /**
535  * raptor_new_iostream_from_sink:
536  * @world: raptor world
537  *
538  * Create a new read iostream from a sink, returning no data.
539  *
540  * Provides an I/O source that returns end of input immediately on
541  * reads, and throw away all writes. Same as
542  * raptor_new_iostream_to_sink()
543  *
544  * Return value: new #raptor_iostream object or NULL on failure
545  **/
546 raptor_iostream*
raptor_new_iostream_from_sink(raptor_world * world)547 raptor_new_iostream_from_sink(raptor_world *world)
548 {
549   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
550 
551   raptor_world_open(world);
552 
553   return raptor_new_iostream_from_handler(world, NULL,
554                                           &raptor_iostream_sink_handler);
555 }
556 
557 
558 static const raptor_iostream_handler raptor_iostream_read_filename_handler = {
559   /* .version     = */ 2,
560   /* .init        = */ NULL,
561   /* .finish      = */ raptor_filename_iostream_finish,
562   /* .write_byte  = */ NULL,
563   /* .write_bytes = */ NULL,
564   /* .write_end   = */ NULL,
565   /* .read_bytes  = */ raptor_filename_iostream_read_bytes,
566   /* .read_eof    = */ raptor_filename_iostream_read_eof
567 };
568 
569 
570 /**
571  * raptor_new_iostream_from_filename:
572  * @world: raptor world
573  * @filename: Input filename to open and read from
574  *
575  * Constructor - create a new iostream reading from a filename.
576  *
577  * Return value: new #raptor_iostream object or NULL on failure
578  **/
579 raptor_iostream*
raptor_new_iostream_from_filename(raptor_world * world,const char * filename)580 raptor_new_iostream_from_filename(raptor_world *world, const char *filename)
581 {
582   FILE *handle;
583   raptor_iostream* iostr;
584   const raptor_iostream_handler* handler;
585   const unsigned int mode = RAPTOR_IOSTREAM_MODE_READ;
586 
587   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
588 
589   if(!filename)
590     return NULL;
591 
592   raptor_world_open(world);
593 
594   handler = &raptor_iostream_read_filename_handler;
595   if(!raptor_iostream_check_handler(handler, mode))
596     return NULL;
597 
598   handle = fopen(filename, "rb");
599   if(!handle)
600     return NULL;
601 
602   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
603   if(!iostr) {
604     fclose(handle);
605     return NULL;
606   }
607 
608   iostr->world = world;
609   iostr->handler = handler;
610   iostr->user_data = (void*)handle;
611   iostr->mode = mode;
612 
613   if(iostr->handler->init &&
614      iostr->handler->init(iostr->user_data)) {
615     raptor_free_iostream(iostr);
616     return NULL;
617   }
618   return iostr;
619 }
620 
621 
622 static const raptor_iostream_handler raptor_iostream_read_file_handle_handler = {
623   /* .version     = */ 2,
624   /* .init        = */ NULL,
625   /* .finish      = */ NULL,
626   /* .write_byte  = */ NULL,
627   /* .write_bytes = */ NULL,
628   /* .write_end   = */ NULL,
629   /* .read_bytes  = */ raptor_filename_iostream_read_bytes,
630   /* .read_eof    = */ raptor_filename_iostream_read_eof
631 };
632 
633 
634 /**
635  * raptor_new_iostream_from_file_handle:
636  * @world: raptor world
637  * @handle: Input file_handle to open and read from
638  *
639  * Constructor - create a new iostream reading from a file_handle.
640  *
641  * The @handle must already be open for reading.
642  * NOTE: This does not fclose the @handle when it is finished.
643  *
644  * Return value: new #raptor_iostream object or NULL on failure
645  **/
646 raptor_iostream*
raptor_new_iostream_from_file_handle(raptor_world * world,FILE * handle)647 raptor_new_iostream_from_file_handle(raptor_world *world, FILE *handle)
648 {
649   raptor_iostream* iostr;
650   const raptor_iostream_handler* handler;
651   const unsigned int mode = RAPTOR_IOSTREAM_MODE_READ;
652 
653   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
654 
655   if(!handle)
656     return NULL;
657 
658   raptor_world_open(world);
659 
660   handler = &raptor_iostream_read_file_handle_handler;
661   if(!raptor_iostream_check_handler(handler, mode))
662     return NULL;
663 
664   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
665   if(!iostr)
666     return NULL;
667 
668   iostr->world = world;
669   iostr->handler = handler;
670   iostr->user_data = (void*)handle;
671   iostr->mode = mode;
672 
673   if(iostr->handler->init &&
674      iostr->handler->init(iostr->user_data)) {
675     RAPTOR_FREE(raptor_iostream, iostr);
676     return NULL;
677   }
678   return iostr;
679 }
680 
681 
682 /**
683  * raptor_free_iostream:
684  * @iostr: iostream object
685  *
686  * Destructor - destroy an iostream.
687  **/
688 void
raptor_free_iostream(raptor_iostream * iostr)689 raptor_free_iostream(raptor_iostream *iostr)
690 {
691   if(!iostr)
692     return;
693 
694   if(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF)
695     raptor_iostream_write_end(iostr);
696 
697   if(iostr->handler->finish)
698     iostr->handler->finish(iostr->user_data);
699 
700   if((iostr->flags & RAPTOR_IOSTREAM_FLAGS_FREE_HANDLER))
701     RAPTOR_FREE(raptor_iostream_handler, iostr->handler);
702 
703   RAPTOR_FREE(raptor_iostream, iostr);
704 }
705 
706 
707 
708 /**
709  * raptor_iostream_write_byte:
710  * @byte: byte to write
711  * @iostr: raptor iostream
712  *
713  * Write a byte to the iostream.
714  *
715  * Return value: non-0 on failure
716  **/
717 int
raptor_iostream_write_byte(const int byte,raptor_iostream * iostr)718 raptor_iostream_write_byte(const int byte, raptor_iostream *iostr)
719 {
720   iostr->offset++;
721 
722   if(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF)
723     return 1;
724   if(!iostr->handler->write_byte)
725     return 1;
726   if(!(iostr->mode & RAPTOR_IOSTREAM_MODE_WRITE))
727     return 1;
728   return iostr->handler->write_byte(iostr->user_data, byte);
729 }
730 
731 
732 /**
733  * raptor_iostream_write_bytes:
734  * @ptr: start of objects to write
735  * @size: size of object
736  * @nmemb: number of objects
737  * @iostr: raptor iostream
738  *
739  * Write bytes to the iostream.
740  *
741  * Return value: number of objects actually written, which may be less than nmemb. <0 on failure
742  **/
743 int
raptor_iostream_write_bytes(const void * ptr,size_t size,size_t nmemb,raptor_iostream * iostr)744 raptor_iostream_write_bytes(const void *ptr, size_t size, size_t nmemb,
745                             raptor_iostream *iostr)
746 {
747   int nobj;
748 
749   if(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF)
750     return -1;
751   if(!iostr->handler->write_bytes)
752     return -1;
753   if(!(iostr->mode & RAPTOR_IOSTREAM_MODE_WRITE))
754     return -1;
755 
756   nobj = iostr->handler->write_bytes(iostr->user_data, ptr, size, nmemb);
757   if(nobj > 0)
758     iostr->offset += (size * nobj);
759 
760   return nobj;
761 }
762 
763 
764 /**
765  * raptor_iostream_string_write:
766  * @string: string
767  * @iostr: raptor iostream
768  *
769  * Write a NULL-terminated string to the iostream.
770  *
771  * Return value: non-0 on failure
772  **/
773 int
raptor_iostream_string_write(const void * string,raptor_iostream * iostr)774 raptor_iostream_string_write(const void *string, raptor_iostream *iostr)
775 {
776   size_t len = strlen((const char*)string);
777   int nobj = raptor_iostream_write_bytes(string, 1, len, iostr);
778   return (RAPTOR_BAD_CAST(size_t, nobj) != len);
779 }
780 
781 
782 /**
783  * raptor_iostream_counted_string_write:
784  * @string: string
785  * @len: string length
786  * @iostr: raptor iostream
787  *
788  * Write a counted string to the iostream.
789  *
790  * Return value: non-0 on failure
791  **/
792 int
raptor_iostream_counted_string_write(const void * string,size_t len,raptor_iostream * iostr)793 raptor_iostream_counted_string_write(const void *string, size_t len,
794                                      raptor_iostream *iostr)
795 {
796   int nobj = raptor_iostream_write_bytes(string, 1, len, iostr);
797   return (RAPTOR_BAD_CAST(size_t, nobj) != len);
798 }
799 
800 
801 /**
802  * raptor_uri_write:
803  * @uri: URI
804  * @iostr: raptor iostream
805  *
806  * Write a raptor URI to the iostream.
807  *
808  * Return value: non-0 on failure
809  **/
810 int
raptor_uri_write(raptor_uri * uri,raptor_iostream * iostr)811 raptor_uri_write(raptor_uri* uri, raptor_iostream* iostr)
812 {
813   size_t len;
814   const void *string = raptor_uri_as_counted_string(uri, &len);
815   int nobj = raptor_iostream_write_bytes(string, 1, len, iostr);
816   return (RAPTOR_BAD_CAST(size_t, nobj) != len);
817 }
818 
819 
820 /**
821  * raptor_iostream_write_end:
822  * @iostr: raptor iostream
823  *
824  * End writing to the iostream.
825  *
826  * Return value: non-0 on failure
827  **/
828 int
raptor_iostream_write_end(raptor_iostream * iostr)829 raptor_iostream_write_end(raptor_iostream *iostr)
830 {
831   int rc = 0;
832 
833   if(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF)
834     return 1;
835   if(iostr->handler->write_end)
836     rc = iostr->handler->write_end(iostr->user_data);
837   iostr->flags |= RAPTOR_IOSTREAM_FLAGS_EOF;
838 
839   return rc;
840 }
841 
842 
843 /**
844  * raptor_stringbuffer_write:
845  * @sb: #raptor_stringbuffer to write
846  * @iostr: raptor iostream
847  *
848  * Write a stringbuffer to an iostream.
849  *
850  * Return value: non-0 on failure
851  **/
852 int
raptor_stringbuffer_write(raptor_stringbuffer * sb,raptor_iostream * iostr)853 raptor_stringbuffer_write(raptor_stringbuffer *sb, raptor_iostream* iostr)
854 {
855   size_t length;
856   if(!sb)
857     return 1;
858 
859   length = raptor_stringbuffer_length(sb);
860   if(length) {
861     int nobj = raptor_iostream_write_bytes(raptor_stringbuffer_as_string(sb),
862                                             1, length, iostr);
863     return (RAPTOR_BAD_CAST(size_t, nobj) != length);
864   } else
865     return 0;
866 }
867 
868 
869 /**
870  * raptor_iostream_decimal_write:
871  * @integer: integer to format as decimal
872  * @iostr: raptor iostream
873  *
874  * Write an integer in decimal to the iostream.
875  *
876  * Return value: non-0 on failure
877  **/
878 int
raptor_iostream_decimal_write(int integer,raptor_iostream * iostr)879 raptor_iostream_decimal_write(int integer, raptor_iostream* iostr)
880 {
881   /* enough for 64 bit signed integer
882    * INT64_MAX is  9223372036854775807 (19 digits) + 1 for sign
883    */
884   unsigned char buf[20];
885   unsigned char *p;
886   int i = integer;
887   size_t length = 1;
888   int nobj;
889 
890   if(integer < 0) {
891     length++;
892     i= -integer;
893   }
894   while(i /= 10)
895     length++;
896 
897   p = buf+length-1;
898   i = integer;
899   if(i < 0)
900     i= -i;
901   do {
902     *p-- ='0'+(i %10);
903     i /= 10;
904   } while(i);
905   if(integer < 0)
906     *p= '-';
907 
908   nobj = raptor_iostream_write_bytes(buf, 1, length, iostr);
909   return (RAPTOR_BAD_CAST(size_t, nobj) != length);
910 }
911 
912 
913 /**
914  * raptor_iostream_hexadecimal_write:
915  * @integer: unsigned integer to format as hexadecimal
916  * @width: field width
917  * @iostr: raptor iostream
918  *
919  * Write an integer in hexadecimal to the iostream.
920  *
921  * Always 0-fills the entire field and writes in uppercase A-F
922  *
923  * Return value: non-0 on failure
924  **/
925 int
raptor_iostream_hexadecimal_write(unsigned int integer,int width,raptor_iostream * iostr)926 raptor_iostream_hexadecimal_write(unsigned int integer, int width,
927                                   raptor_iostream* iostr)
928 {
929   char *buf;
930   int nobj;
931 
932   if(width < 1)
933     return 1;
934 
935   buf = RAPTOR_MALLOC(char*, width + 1);
936   if(!buf)
937     return 1;
938 
939   (void)raptor_format_integer(buf, width + 1, integer, /* base */ 16,
940                               width, '0');
941 
942   nobj = raptor_iostream_write_bytes(buf, 1, width, iostr);
943   RAPTOR_FREE(char*, buf);
944   return (nobj != width);
945 }
946 
947 
948 
949 /**
950  * raptor_iostream_read_bytes:
951  * @ptr: start of buffer to read objects into
952  * @size: size of object
953  * @nmemb: number of objects to read
954  * @iostr: raptor iostream
955  *
956  * Read bytes to the iostream.
957  *
958  * Return value: number of objects read, 0 or less than nmemb on EOF, <0 on failure
959  **/
960 int
raptor_iostream_read_bytes(void * ptr,size_t size,size_t nmemb,raptor_iostream * iostr)961 raptor_iostream_read_bytes(void *ptr, size_t size, size_t nmemb,
962                            raptor_iostream *iostr)
963 {
964   int count;
965 
966   if(!(iostr->mode & RAPTOR_IOSTREAM_MODE_READ))
967     return -1;
968 
969   if(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF)
970     return 0;
971 
972   if(!iostr->handler->read_bytes)
973     count= -1;
974   else
975     count = iostr->handler->read_bytes(iostr->user_data, ptr, size, nmemb);
976 
977   if(count > 0)
978     iostr->offset += (size*count);
979 
980   if(RAPTOR_BAD_CAST(size_t, count) < nmemb)
981     iostr->flags |= RAPTOR_IOSTREAM_FLAGS_EOF;
982 
983   return count;
984 }
985 
986 
987 /**
988  * raptor_iostream_read_eof:
989  * @iostr: raptor read iostream
990  *
991  * Check if an read iostream has ended
992  *
993  * Return value: non-0 if EOF (or not a read iostream)
994  **/
995 int
raptor_iostream_read_eof(raptor_iostream * iostr)996 raptor_iostream_read_eof(raptor_iostream *iostr)
997 {
998   /* Streams without read are always EOF */
999   if(!(iostr->mode & RAPTOR_IOSTREAM_MODE_READ))
1000     return 1;
1001 
1002   if(!(iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF) &&
1003      iostr->handler->read_eof &&
1004      iostr->handler->read_eof(iostr->user_data))
1005     iostr->flags |= RAPTOR_IOSTREAM_FLAGS_EOF;
1006 
1007   return ((iostr->flags & RAPTOR_IOSTREAM_FLAGS_EOF) != 0);
1008 }
1009 
1010 
1011 struct raptor_read_string_iostream_context {
1012   /* input buffer */
1013   void* string;
1014   size_t length;
1015   /* pointer into buffer */
1016   size_t offset;
1017 };
1018 
1019 
1020 /* Local handlers for reading from a string */
1021 
1022 static void
raptor_read_string_iostream_finish(void * user_data)1023 raptor_read_string_iostream_finish(void *user_data)
1024 {
1025   struct raptor_read_string_iostream_context* con;
1026 
1027   con = (struct raptor_read_string_iostream_context*)user_data;
1028   RAPTOR_FREE(raptor_read_string_iostream_context, con);
1029   return;
1030 }
1031 
1032 static int
raptor_read_string_iostream_read_bytes(void * user_data,void * ptr,size_t size,size_t nmemb)1033 raptor_read_string_iostream_read_bytes(void *user_data, void *ptr,
1034                                        size_t size, size_t nmemb)
1035 {
1036   struct raptor_read_string_iostream_context* con;
1037   size_t avail;
1038   size_t blen;
1039 
1040   if(!ptr || size <= 0 || !nmemb)
1041     return -1;
1042 
1043   con = (struct raptor_read_string_iostream_context*)user_data;
1044   if(con->offset >= con->length)
1045     return 0;
1046 
1047   avail = (con->length - con->offset) / size;
1048   if(avail > nmemb)
1049     avail = nmemb;
1050   blen = (avail * size);
1051   memcpy(ptr, (char*)con->string + con->offset, blen);
1052   con->offset += blen;
1053 
1054   return RAPTOR_BAD_CAST(int, avail);
1055 }
1056 
1057 static int
raptor_read_string_iostream_read_eof(void * user_data)1058 raptor_read_string_iostream_read_eof(void *user_data)
1059 {
1060   struct raptor_read_string_iostream_context* con;
1061 
1062   con = (struct raptor_read_string_iostream_context*)user_data;
1063   return (con->offset >= con->length);
1064 }
1065 
1066 
1067 static const raptor_iostream_handler raptor_iostream_read_string_handler = {
1068   /* .version     = */ 2,
1069   /* .init        = */ NULL,
1070   /* .finish      = */ raptor_read_string_iostream_finish,
1071   /* .write_byte  = */ NULL,
1072   /* .write_bytes = */ NULL,
1073   /* .write_end   = */ NULL,
1074   /* .read_bytes  = */ raptor_read_string_iostream_read_bytes,
1075   /* .read_eof    = */ raptor_read_string_iostream_read_eof
1076 };
1077 
1078 
1079 /**
1080  * raptor_new_iostream_from_string:
1081  * @world: raptor world
1082  * @string: pointer to string
1083  * @length: length of string
1084  *
1085  * Constructor - create a new iostream reading from a string.
1086  *
1087  * Return value: new #raptor_iostream object or NULL on failure
1088  **/
1089 raptor_iostream*
raptor_new_iostream_from_string(raptor_world * world,void * string,size_t length)1090 raptor_new_iostream_from_string(raptor_world *world,
1091                                 void *string, size_t length)
1092 {
1093   raptor_iostream* iostr;
1094   struct raptor_read_string_iostream_context* con;
1095   const raptor_iostream_handler* handler;
1096   const unsigned int mode = RAPTOR_IOSTREAM_MODE_READ;
1097 
1098   RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
1099 
1100   if(!string)
1101     return NULL;
1102 
1103   raptor_world_open(world);
1104 
1105   handler = &raptor_iostream_read_string_handler;
1106   if(!raptor_iostream_check_handler(handler, mode))
1107     return NULL;
1108 
1109   iostr = RAPTOR_CALLOC(raptor_iostream*, 1, sizeof(*iostr));
1110   if(!iostr)
1111     return NULL;
1112 
1113   con = RAPTOR_CALLOC(struct raptor_read_string_iostream_context*, 1,
1114                       sizeof(*con));
1115   if(!con) {
1116     RAPTOR_FREE(raptor_iostream, iostr);
1117     return NULL;
1118   }
1119 
1120   con->string = string;
1121   con->length = length;
1122 
1123   iostr->world = world;
1124   iostr->handler = handler;
1125   iostr->user_data = (void*)con;
1126   iostr->mode = mode;
1127 
1128   if(iostr->handler->init && iostr->handler->init(iostr->user_data)) {
1129     raptor_free_iostream(iostr);
1130     return NULL;
1131   }
1132   return iostr;
1133 }
1134 
1135 
1136 /**
1137  * raptor_iostream_tell:
1138  * @iostr: raptor iostream
1139  *
1140  * Get the offset in the iostream.
1141  *
1142  * Return value: offset in iostream
1143  **/
1144 unsigned long
raptor_iostream_tell(raptor_iostream * iostr)1145 raptor_iostream_tell(raptor_iostream *iostr)
1146 {
1147   return RAPTOR_BAD_CAST(unsigned long, iostr->offset);
1148 }
1149 
1150 
1151 /* internal */
1152 raptor_world*
raptor_iostream_get_world(raptor_iostream * iostr)1153 raptor_iostream_get_world(raptor_iostream *iostr)
1154 {
1155   return iostr->world;
1156 }
1157 
1158 
1159 #endif
1160 
1161 
1162 
1163 #ifdef STANDALONE
1164 
1165 /* one more prototype */
1166 int main(int argc, char *argv[]);
1167 
1168 
1169 static const char *program;
1170 
1171 #define READ_BUFFER_SIZE 256
1172 
1173 
1174 static int
test_write_to_filename(raptor_world * world,const char * filename,const char * test_string,size_t test_string_len,const unsigned int expected_bytes_count)1175 test_write_to_filename(raptor_world *world, const char* filename,
1176                        const char* test_string, size_t test_string_len,
1177                        const unsigned int expected_bytes_count)
1178 {
1179   raptor_iostream *iostr = NULL;
1180   unsigned long count;
1181   int rc = 0;
1182   const char* const label="write iostream to filename";
1183 
1184 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1185   fprintf(stderr, "%s: Testing %s '%s'\n", program, label, filename);
1186 #endif
1187 
1188   iostr = raptor_new_iostream_to_filename(world, filename);
1189   if(!iostr) {
1190     fprintf(stderr, "%s: Failed to create %s '%s'\n", program, label, filename);
1191     rc = 1;
1192     goto tidy;
1193   }
1194 
1195   raptor_iostream_write_bytes(test_string, 1, test_string_len, iostr);
1196   raptor_iostream_write_byte('\n', iostr);
1197 
1198   count = raptor_iostream_tell(iostr);
1199   if(count != expected_bytes_count) {
1200     fprintf(stderr, "%s: %s wrote %d bytes, expected %d\n", program, label,
1201             (int)count, expected_bytes_count);
1202     rc = 1;
1203     goto tidy;
1204   }
1205 
1206   tidy:
1207   if(iostr)
1208     raptor_free_iostream(iostr);
1209   remove(filename);
1210 
1211   if(rc)
1212     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1213 
1214   return rc;
1215 }
1216 
1217 
1218 static int
test_write_to_file_handle(raptor_world * world,FILE * handle,const char * test_string,size_t test_string_len,const unsigned int expected_bytes_count)1219 test_write_to_file_handle(raptor_world *world, FILE* handle,
1220                           const char* test_string, size_t test_string_len,
1221                           const unsigned int expected_bytes_count)
1222 {
1223   raptor_iostream *iostr = NULL;
1224   unsigned long count;
1225   int rc = 0;
1226   const char* const label="write iostream to file handle";
1227 
1228 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1229   fprintf(stderr, "%s: Testing %s\n", program, label);
1230 #endif
1231 
1232   iostr = raptor_new_iostream_to_file_handle(world, handle);
1233   if(!iostr) {
1234     fprintf(stderr, "%s: Failed to create %s\n", program, label);
1235     rc = 1;
1236     goto tidy;
1237   }
1238 
1239   raptor_iostream_write_bytes(test_string, 1, test_string_len, iostr);
1240   raptor_iostream_write_byte('\n', iostr);
1241 
1242   count = raptor_iostream_tell(iostr);
1243   if(count != expected_bytes_count) {
1244     fprintf(stderr, "%s: %s wrote %d bytes, expected %d\n", program, label,
1245             (int)count, expected_bytes_count);
1246     rc = 1;
1247   }
1248 
1249   tidy:
1250   if(iostr)
1251     raptor_free_iostream(iostr);
1252 
1253   if(rc)
1254     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1255 
1256   return rc;
1257 }
1258 
1259 
1260 static int
test_write_to_string(raptor_world * world,const char * test_string,size_t test_string_len,const unsigned int expected_bytes_count)1261 test_write_to_string(raptor_world *world,
1262                      const char* test_string, size_t test_string_len,
1263                      const unsigned int expected_bytes_count)
1264 {
1265   raptor_iostream *iostr = NULL;
1266   unsigned long count;
1267   int rc = 0;
1268   void *string = NULL;
1269   size_t string_len;
1270   const char* const label="write iostream to a string";
1271 
1272 
1273 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1274   fprintf(stderr, "%s: Testing %s\n", program, label);
1275 #endif
1276 
1277   iostr = raptor_new_iostream_to_string(world, &string, &string_len, NULL);
1278   if(!iostr) {
1279     fprintf(stderr, "%s: Failed to create write iostream to string\n",
1280             program);
1281     rc = 1;
1282     goto tidy;
1283   }
1284 
1285   raptor_iostream_write_bytes(test_string, 1, test_string_len, iostr);
1286   raptor_iostream_write_byte('\n', iostr);
1287 
1288   count = raptor_iostream_tell(iostr);
1289   if(count != expected_bytes_count) {
1290     fprintf(stderr, "%s: %s wrote %d bytes, expected %d\n", program, label,
1291             (int)count, expected_bytes_count);
1292     rc = 1;
1293   }
1294 
1295   raptor_free_iostream(iostr); iostr = NULL;
1296 
1297   if(!string) {
1298     fprintf(stderr, "%s: %s failed to create a string\n", program, label);
1299     return 1;
1300   }
1301   if(string_len != count) {
1302     fprintf(stderr, "%s: %s created a string length %d, expected %d\n",
1303             program, label, (int)string_len, (int)count);
1304     return 1;
1305   }
1306 
1307   tidy:
1308   if(string)
1309     raptor_free_memory(string);
1310   if(iostr)
1311     raptor_free_iostream(iostr);
1312 
1313   if(rc)
1314     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1315 
1316   return rc;
1317 }
1318 
1319 
1320 static int
test_write_to_sink(raptor_world * world,const char * test_string,size_t test_string_len,const unsigned int expected_bytes_count)1321 test_write_to_sink(raptor_world *world,
1322                    const char* test_string, size_t test_string_len,
1323                    const unsigned int expected_bytes_count)
1324 {
1325   raptor_iostream *iostr = NULL;
1326   unsigned long count;
1327   int rc = 0;
1328   const char* const label="write iostream to sink";
1329 
1330 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1331   fprintf(stderr, "%s: Testing %s\n", program, label);
1332 #endif
1333 
1334   iostr = raptor_new_iostream_to_sink(world);
1335   if(!iostr) {
1336     fprintf(stderr, "%s: Failed to create %s\n", program, label);
1337     rc = 1;
1338     goto tidy;
1339   }
1340 
1341   raptor_iostream_write_bytes(test_string, 1, test_string_len, iostr);
1342   raptor_iostream_write_byte('\n', iostr);
1343 
1344   count = raptor_iostream_tell(iostr);
1345   if(count != expected_bytes_count) {
1346     fprintf(stderr, "%s: %s wrote %d bytes, expected %d\n", program, label,
1347             (int)count, expected_bytes_count);
1348     rc = 1;
1349   }
1350 
1351   tidy:
1352   if(iostr)
1353     raptor_free_iostream(iostr);
1354 
1355   if(rc)
1356     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1357 
1358   return rc;
1359 }
1360 
1361 
1362 static int
test_read_from_filename(raptor_world * world,const char * filename,const char * test_string,size_t test_string_len,const int expected_len,const int expected_len2)1363 test_read_from_filename(raptor_world *world,
1364                         const char* filename,
1365                         const char* test_string, size_t test_string_len,
1366                         const int expected_len,
1367                         const int expected_len2)
1368 {
1369   raptor_iostream *iostr = NULL;
1370   char buffer[READ_BUFFER_SIZE];
1371   int count;
1372   int rc = 0;
1373   const char* const label="read iostream from filename";
1374 
1375 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1376   fprintf(stderr, "%s: Testing %s '%s'\n", program, label, filename);
1377 #endif
1378 
1379   iostr = raptor_new_iostream_from_filename(world, filename);
1380   if(!iostr) {
1381     fprintf(stderr, "%s: Failed to create %s '%s'\n", program, label, filename);
1382     rc = 1;
1383     goto tidy;
1384   }
1385 
1386   count = raptor_iostream_read_bytes(buffer, 1, test_string_len, iostr);
1387   if(count != expected_len) {
1388     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1389             (int)count, (int)expected_len);
1390     rc = 1;
1391     goto tidy;
1392   }
1393 
1394   count = raptor_iostream_read_bytes(buffer, 1, test_string_len, iostr);
1395   if(count != expected_len2) {
1396     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1397             (int)count, (int)expected_len2);
1398     rc = 1;
1399     goto tidy;
1400   }
1401 
1402   if(!raptor_iostream_read_eof(iostr)) {
1403     fprintf(stderr, "%s: %s not EOF as expected\n", program, label);
1404     rc = 1;
1405     goto tidy;
1406   }
1407 
1408   if(strncmp(buffer, test_string, test_string_len)) {
1409     fprintf(stderr, "%s: %s returned '%s' expected '%s'\n", program, label,
1410             buffer, test_string);
1411     rc = 1;
1412   }
1413 
1414   tidy:
1415   if(iostr)
1416     raptor_free_iostream(iostr);
1417 
1418   if(rc)
1419     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1420 
1421   return rc;
1422 }
1423 
1424 
1425 static int
test_read_from_file_handle(raptor_world * world,FILE * handle,const char * test_string,size_t test_string_len,const unsigned int expected_len,const unsigned int expected_len2)1426 test_read_from_file_handle(raptor_world *world, FILE* handle,
1427                            const char* test_string, size_t test_string_len,
1428                            const unsigned int expected_len,
1429                            const unsigned int expected_len2)
1430 {
1431   raptor_iostream *iostr = NULL;
1432   char buffer[READ_BUFFER_SIZE];
1433   unsigned long count;
1434   int rc = 0;
1435   const char* const label="read iostream from file handle";
1436 
1437 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1438   fprintf(stderr, "%s: Testing %s\n", program, label);
1439 #endif
1440 
1441   iostr = raptor_new_iostream_from_file_handle(world, handle);
1442   if(!iostr) {
1443     fprintf(stderr, "%s: Failed to create %s\n", program, label);
1444     rc = 1;
1445     goto tidy;
1446   }
1447 
1448   count = raptor_iostream_read_bytes(buffer, 1, test_string_len, iostr);
1449   if(count != expected_len) {
1450     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1451             (int)count, (int)expected_len);
1452     rc = 1;
1453   }
1454 
1455   count = raptor_iostream_read_bytes(buffer, 1, test_string_len, iostr);
1456   if(count != expected_len2) {
1457     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1458             (int)count, (int)expected_len2);
1459     rc = 1;
1460     goto tidy;
1461   }
1462 
1463   if(!raptor_iostream_read_eof(iostr)) {
1464     fprintf(stderr, "%s: %s not EOF as expected\n", program, label);
1465     rc = 1;
1466   }
1467 
1468   if(strncmp(buffer, test_string, test_string_len)) {
1469     fprintf(stderr, "%s: %s returned '%s' expected '%s'\n", program, label,
1470             buffer, test_string);
1471     rc = 1;
1472   }
1473 
1474   tidy:
1475   if(iostr)
1476     raptor_free_iostream(iostr);
1477 
1478   if(rc)
1479     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1480 
1481   return rc;
1482 }
1483 
1484 
1485 static int
test_read_from_string(raptor_world * world,const char * test_string,size_t test_string_len,const unsigned int expected_len)1486 test_read_from_string(raptor_world *world,
1487                       const char* test_string, size_t test_string_len,
1488                       const unsigned int expected_len)
1489 {
1490   raptor_iostream *iostr = NULL;
1491   char buffer[READ_BUFFER_SIZE];
1492   unsigned long count;
1493   int rc = 0;
1494   const char* const label="read iostream from a string";
1495 
1496 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1497   fprintf(stderr, "%s: Testing %s\n", program, label);
1498 #endif
1499 
1500   iostr = raptor_new_iostream_from_string(world,
1501                                           (void*)test_string, test_string_len);
1502   if(!iostr) {
1503     fprintf(stderr, "%s: Failed to create %s\n", program, label);
1504     rc = 1;
1505     goto tidy;
1506   }
1507 
1508   count = raptor_iostream_read_bytes(buffer, 1, test_string_len, iostr);
1509   if(count != expected_len) {
1510     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1511             (int)count, (int)expected_len);
1512     rc = 1;
1513   }
1514 
1515   if(!raptor_iostream_read_eof(iostr)) {
1516     fprintf(stderr, "%s: %s not EOF as expected\n", program, label);
1517     rc = 1;
1518   }
1519 
1520   if(strncmp(buffer, test_string, test_string_len)) {
1521     fprintf(stderr, "%s: %s returned '%s' expected '%s'\n", program, label,
1522             buffer, test_string);
1523     rc = 1;
1524   }
1525 
1526   tidy:
1527   if(iostr)
1528     raptor_free_iostream(iostr);
1529 
1530   if(rc)
1531     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1532 
1533   return rc;
1534 }
1535 
1536 
1537 static int
test_read_from_sink(raptor_world * world,size_t read_len,size_t expected_len)1538 test_read_from_sink(raptor_world *world, size_t read_len, size_t expected_len)
1539 {
1540   raptor_iostream *iostr = NULL;
1541   char buffer[READ_BUFFER_SIZE];
1542   unsigned long count;
1543   int rc = 0;
1544   const char* const label="read iostream from sink";
1545 
1546 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1547   fprintf(stderr, "%s: Testing %s\n", program, label);
1548 #endif
1549   expected_len = 0;
1550   iostr = raptor_new_iostream_from_sink(world);
1551   if(!iostr) {
1552     fprintf(stderr, "%s: Failed to create %s\n", program, label);
1553     rc = 1;
1554     goto tidy;
1555   }
1556 
1557   count = raptor_iostream_read_bytes(buffer, 1, read_len, iostr);
1558   if(count != expected_len) {
1559     fprintf(stderr, "%s: %s read %d bytes, expected %d\n", program, label,
1560             (int)count, (int)expected_len);
1561     rc = 1;
1562   }
1563 
1564   if(!raptor_iostream_read_eof(iostr)) {
1565     fprintf(stderr, "%s: %s not EOF as expected\n", program, label);
1566     rc = 1;
1567   }
1568 
1569   tidy:
1570   if(iostr)
1571     raptor_free_iostream(iostr);
1572 
1573   if(rc)
1574     fprintf(stderr, "%s: FAILED Testing %s\n", program, label);
1575 
1576   return rc;
1577 }
1578 
1579 
1580 #define OUT_FILENAME "out.bin"
1581 #define OUT_BYTES_COUNT 14
1582 #define TEST_STRING "Hello, world!"
1583 #define TEST_STRING_LEN 13
1584 #define IN_FILENAME "in.bin"
1585 
1586 
1587 int
main(int argc,char * argv[])1588 main(int argc, char *argv[])
1589 {
1590   raptor_world *world;
1591   FILE *handle = NULL;
1592   int failures = 0;
1593 
1594   program = raptor_basename(argv[0]);
1595 
1596   world = raptor_new_world();
1597   if(!world || raptor_world_open(world))
1598     exit(1);
1599 
1600   /* Write tests */
1601   failures+= test_write_to_filename(world, (const char*)OUT_FILENAME,
1602                          TEST_STRING, TEST_STRING_LEN, (int)OUT_BYTES_COUNT);
1603   handle = fopen((const char*)OUT_FILENAME, "wb");
1604   if(!handle) {
1605     fprintf(stderr, "%s: Failed to create write file handle to file %s\n",
1606             program, OUT_FILENAME);
1607     failures++;
1608   } else {
1609     failures+= test_write_to_file_handle(world,
1610                                          handle, TEST_STRING, TEST_STRING_LEN,
1611                                          (int)OUT_BYTES_COUNT);
1612     fclose(handle);
1613     remove(OUT_FILENAME);
1614   }
1615 
1616   failures+= test_write_to_string(world,
1617                                   TEST_STRING,
1618                                   TEST_STRING_LEN, (int)OUT_BYTES_COUNT);
1619   failures+= test_write_to_sink(world,
1620                                 TEST_STRING,
1621                                 TEST_STRING_LEN, (int)OUT_BYTES_COUNT);
1622 
1623   remove(OUT_FILENAME);
1624 
1625 
1626   /* Read tests */
1627   handle = fopen((const char*)IN_FILENAME, "wb");
1628   if(!handle) {
1629     fprintf(stderr, "%s: Failed to create write handle to file %s\n",
1630             program, IN_FILENAME);
1631     failures++;
1632   } else {
1633     fwrite(TEST_STRING, 1, TEST_STRING_LEN, handle);
1634     fclose(handle);
1635 
1636     failures+= test_read_from_filename(world,
1637                                        (const char*)IN_FILENAME,
1638                                        TEST_STRING, TEST_STRING_LEN,
1639                                        TEST_STRING_LEN, 0);
1640     handle = fopen((const char*)IN_FILENAME, "rb");
1641     if(!handle) {
1642       fprintf(stderr, "%s: Failed to create read file handle to file %s\n",
1643               program, IN_FILENAME);
1644       failures++;
1645     } else {
1646       failures+= test_read_from_file_handle(world,
1647                                             handle,
1648                                             TEST_STRING, TEST_STRING_LEN,
1649                                             TEST_STRING_LEN, 0);
1650       fclose(handle); handle = NULL;
1651     }
1652   }
1653 
1654   failures+= test_read_from_string(world,
1655                                    TEST_STRING, TEST_STRING_LEN,
1656                                    TEST_STRING_LEN);
1657   failures+= test_read_from_sink(world, TEST_STRING_LEN, 0);
1658 
1659   remove(IN_FILENAME);
1660 
1661   raptor_free_world(world);
1662 
1663   return failures;
1664 }
1665 
1666 #endif
1667