1/*********************************************************************** 2 * * 3 * $Id: hpgsostream.c 368 2006-12-31 15:18:08Z softadm $ 4 * * 5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript * 6 * API for rendering a scene and thus renders to a variety of * 7 * devices and fileformats. * 8 * * 9 * (C) 2004-2006 ev-i Informationstechnologie GmbH http://www.ev-i.at * 10 * * 11 * Author: Wolfgang Glas * 12 * * 13 * hpgs is free software; you can redistribute it and/or * 14 * modify it under the terms of the GNU Lesser General Public * 15 * License as published by the Free Software Foundation; either * 16 * version 2.1 of the License, or (at your option) any later version. * 17 * * 18 * hpgs is distributed in the hope that it will be useful, * 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 21 * Lesser General Public License for more details. * 22 * * 23 * You should have received a copy of the GNU Lesser General Public * 24 * License along with this library; if not, write to the * 25 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 26 * Boston, MA 02111-1307 USA * 27 * * 28 *********************************************************************** 29 * * 30 * The implementation of basic output streams. * 31 * * 32 ***********************************************************************/ 33 34#include<hpgs.h> 35#include<string.h> 36#include<stdarg.h> 37 38/*! The counterpart of ANSI fprintf for \c hpgs_ostream. */ 39int hpgs_ostream_printf (hpgs_ostream *_this, const char *msg, ...) 40{ 41 int ret; 42 va_list ap; 43 va_start(ap,msg); 44 ret=_this->vtable->vprintf_func(_this->stream,msg,ap); 45 va_end(ap); 46 return ret; 47} 48 49/*! The counterpart of ANSI fvprintf for \c hpgs_ostream. */ 50int hpgs_ostream_vprintf (hpgs_ostream *_this, const char *msg, va_list ap) 51{ 52 int ret; 53 va_list aq; 54 va_copy(aq, ap); 55 ret = _this->vtable->vprintf_func(_this->stream,msg,aq); 56 va_end(aq); 57 return ret; 58} 59 60 61static int file_seek (FILE *file, size_t pos) 62{ 63 return fseek(file,pos,SEEK_SET); 64} 65 66static int file_tell (FILE *file, int layer, size_t *pos) 67{ 68 if (layer) return -1; 69 70 long pp=ftell(file); 71 72 if (pp<0) return -1; 73 74 *pos = pp; 75 return 0; 76} 77 78static hpgs_ostream_vtable stdfile_vtable = 79 { 80 (hpgs_ostream_putc_func_t) putc, 81 (hpgs_ostream_write_func_t) fwrite, 82 (hpgs_ostream_vprintf_func_t) vfprintf, 83 (hpgs_ostream_flush_func_t) fflush, 84 (hpgs_ostream_close_func_t) fflush, 85 (hpgs_ostream_iserror_func_t) ferror, 86 (hpgs_ostream_getbuf_func_t) 0, 87 (hpgs_ostream_tell_func_t) file_tell, 88 (hpgs_ostream_seek_func_t) 0 89 }; 90 91static hpgs_ostream_vtable file_vtable = 92 { 93 (hpgs_ostream_putc_func_t) putc, 94 (hpgs_ostream_write_func_t) fwrite, 95 (hpgs_ostream_vprintf_func_t) vfprintf, 96 (hpgs_ostream_flush_func_t) fflush, 97 (hpgs_ostream_close_func_t) fclose, 98 (hpgs_ostream_iserror_func_t) ferror, 99 (hpgs_ostream_getbuf_func_t) 0, 100 (hpgs_ostream_tell_func_t) file_tell, 101 (hpgs_ostream_seek_func_t) file_seek 102 }; 103 104/*! Returns a new \c hpgs_ostream created on the heap, 105 which operates on a file, which is opened by this call 106 in write-only mode. 107 108 Returns a null pointer, when an I/O error occurrs. 109 In this case, details about the the error can be retrieved 110 using \c errno. 111 */ 112hpgs_ostream *hpgs_new_file_ostream (const char *fn) 113{ 114 FILE *out = fn ? fopen (fn,"wb") : stdout; 115 hpgs_ostream *ret = 0; 116 117 if (!out) return 0; 118 119 ret = (hpgs_ostream *)malloc(sizeof(hpgs_ostream)); 120 121 if (!ret) 122 { 123 fclose(out); 124 return 0; 125 } 126 127 ret->stream = out; 128 129 if (fn) 130 ret->vtable = &file_vtable; 131 else 132 ret->vtable = &stdfile_vtable; 133 134 return ret; 135} 136 137typedef struct hpgs_mem_ostream_stream_st hpgs_mem_ostream_stream; 138 139struct hpgs_mem_ostream_stream_st 140{ 141 unsigned char *data; 142 unsigned char *pptr; 143 unsigned char *eptr; 144 int errflg; 145}; 146 147static int mem_grow (hpgs_mem_ostream_stream *stream, size_t hint) 148{ 149 if (stream->errflg) 150 return EOF; 151 152 size_t pos = stream->pptr-stream->data; 153 size_t sz = stream->eptr-stream->data; 154 size_t sz2 = (hint > sz) ? sz+hint : 2*sz; 155 156 // check for overflow. 157 if (sz2 < sz) 158 { 159 stream->errflg = 1; 160 return EOF; 161 } 162 163 unsigned char *ndata=(unsigned char *)realloc(stream->data,sz2); 164 165 if (ndata) 166 { 167 stream->data=ndata; 168 stream->pptr=stream->data+pos; 169 stream->eptr=stream->data+sz2; 170 return 0; 171 } 172 else 173 { 174 stream->errflg = 1; 175 return EOF; 176 } 177} 178 179static int mem_putc (int c, hpgs_mem_ostream_stream *stream) 180{ 181 if (stream->pptr >= stream->eptr) 182 mem_grow(stream,0); 183 184 if (stream->errflg) 185 return EOF; 186 187 *stream->pptr = c; 188 ++stream->pptr; 189 190 return c & 0xff; 191} 192 193static size_t mem_write (void *ptr, size_t size, size_t nmemb, hpgs_mem_ostream_stream *stream) 194{ 195 if (stream->pptr + size*nmemb > stream->eptr) 196 mem_grow(stream,size*nmemb); 197 198 if (stream->errflg) 199 return 0; 200 201 memcpy(stream->pptr,ptr,size*nmemb); 202 stream->pptr += size*nmemb; 203 204 return nmemb; 205} 206 207static int mem_vprintf (hpgs_mem_ostream_stream *stream, const char *fmt, va_list ap) 208{ 209 int n; 210 size_t size; 211 212 while (1) 213 { 214 if (stream->errflg) 215 return EOF; 216 217 size = stream->eptr - stream->pptr; 218 /* Try to print in the allocated space. */ 219 va_list aq; 220 va_copy(aq, ap); 221#ifdef WIN32 222 n = _vsnprintf (stream->pptr, size, fmt, aq); 223#else 224 n = vsnprintf ((char*)stream->pptr, size, fmt, aq); 225#endif 226 va_end(aq); 227 /* If that worked, return the string. */ 228 if (n > -1 && n < size) 229 { 230 stream->pptr += n; 231 return n; 232 } 233 234 /* Else try again with more space. */ 235 mem_grow(stream,0); 236 } 237 238 return 0; 239} 240 241static int mem_close (hpgs_mem_ostream_stream *stream) 242{ 243 if (stream->data) free(stream->data); 244 free(stream); 245 return 0; 246} 247 248static int mem_iserror (hpgs_mem_ostream_stream *stream) 249{ 250 return stream->errflg; 251} 252 253static hpgs_istream *mem_getbuf (hpgs_mem_ostream_stream *stream) 254{ 255 if (stream->errflg || !stream->data) 256 return 0; 257 258 return hpgs_new_mem_istream (stream->data,stream->pptr-stream->data,HPGS_FALSE); 259} 260 261static int mem_tell (hpgs_mem_ostream_stream *stream, int layer, size_t *pos) 262{ 263 if (layer || stream->errflg) return -1; 264 265 *pos = stream->pptr-stream->data; 266 return 0; 267} 268 269static int mem_seek (hpgs_mem_ostream_stream *stream, size_t pos) 270{ 271 if (stream->errflg) return -1; 272 273 if (stream->data + pos > stream->pptr) 274 { 275 stream->errflg = 1; 276 return -1; 277 } 278 279 stream->pptr = stream->data + pos; 280 return 0; 281} 282 283static hpgs_ostream_vtable mem_vtable = 284 { 285 (hpgs_ostream_putc_func_t) mem_putc, 286 (hpgs_ostream_write_func_t) mem_write, 287 (hpgs_ostream_vprintf_func_t) mem_vprintf, 288 (hpgs_ostream_flush_func_t) 0, 289 (hpgs_ostream_close_func_t) mem_close, 290 (hpgs_ostream_iserror_func_t) mem_iserror, 291 (hpgs_ostream_getbuf_func_t) mem_getbuf, 292 (hpgs_ostream_tell_func_t) mem_tell, 293 (hpgs_ostream_seek_func_t) mem_seek 294 }; 295 296/*! Returns a new \c hpgs_ostream created on the heap, 297 which operates on a malloced chunk of memory with 298 the preallocated given size. 299 300 The memory buffer is realloced when the data grows over the 301 given preallocated size. 302 303 Returns a null pointer, when the system is out of memory. 304 */ 305hpgs_ostream *hpgs_new_mem_ostream (size_t data_reserve) 306{ 307 hpgs_mem_ostream_stream *stream; 308 hpgs_ostream *ret = (hpgs_ostream *)malloc(sizeof(hpgs_ostream)); 309 310 if (!ret) 311 return 0; 312 313 stream = 314 (hpgs_mem_ostream_stream *)malloc(sizeof(hpgs_mem_ostream_stream)); 315 316 if (!stream) 317 { 318 free (ret); 319 return 0; 320 } 321 322 stream->data = (unsigned char *)malloc(data_reserve); 323 stream->pptr = stream->data; 324 stream->eptr = stream->data ? stream->data+data_reserve : 0; 325 stream->errflg = stream->data ? 0 : 1; 326 327 ret->stream = stream; 328 ret->vtable = &mem_vtable; 329 330 return ret; 331} 332 333int hpgs_copy_streams (hpgs_ostream *out, hpgs_istream *in) 334{ 335 unsigned char buf[16384]; 336 size_t sz; 337 338 while ((sz = hpgs_istream_read(buf,1,sizeof(buf),in)) > 0) 339 if (hpgs_ostream_write(buf,1,sz,out) == 0) 340 return -1; 341 342 return hpgs_istream_iserror(in); 343} 344