1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgsistream.c 343 2006-08-18 16:48:09Z 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 implementations of input streams.                               *
31 *                                                                     *
32 ***********************************************************************/
33
34#include <hpgs.h>
35#include <math.h>
36#include <string.h>
37#include <errno.h>
38
39static int file_seek (FILE *file, size_t pos)
40{
41  return fseek(file,pos,SEEK_SET);
42}
43
44static int file_seekend (FILE *file, size_t pos)
45{
46  return fseek(file,-(long)pos,SEEK_END);
47}
48
49static int file_tell (FILE *file, size_t *pos)
50{
51  long pp=ftell(file);
52
53  if (pp<0) return -1;
54
55  *pos = pp;
56  return 0;
57}
58
59/*! \defgroup base Basic facilities.
60
61  This module contains structures for operating on abstract input streams
62  as well as color structures and a 2D point.
63*/
64
65static hpgs_istream_vtable file_vtable =
66  {
67    (hpgs_istream_getc_func_t)    getc,
68    (hpgs_istream_ungetc_func_t)  ungetc,
69    (hpgs_istream_close_func_t)   fclose,
70    (hpgs_istream_iseof_func_t)   feof,
71    (hpgs_istream_iserror_func_t) ferror,
72    (hpgs_istream_seek_func_t)    file_seek,
73    (hpgs_istream_tell_func_t)    file_tell,
74    (hpgs_istream_read_func_t)    fread,
75    (hpgs_istream_seekend_func_t) file_seekend
76  };
77
78/*! Returns a new \c hpgs_istream created on the heap,
79    which operates on a file, which is opened by this call
80    in read-only mode.
81
82    Returns a null pointer, when an I/O error occurrs.
83    In this case, details about the the error can be retrieved
84    using \c errno.
85  */
86hpgs_istream *hpgs_new_file_istream(const char *fn)
87{
88  FILE *in = fopen (fn,"rb");
89  hpgs_istream *ret = 0;
90
91  if (!in) return 0;
92
93  ret = (hpgs_istream *)malloc(sizeof(hpgs_istream));
94
95  if (!ret)
96    {
97      fclose(in);
98      return 0;
99    }
100
101  ret->stream = in;
102  ret->vtable = &file_vtable;
103
104  return ret;
105}
106
107/* memory stream implementation functions. */
108typedef struct hpgs_mem_istream_stream_st hpgs_mem_istream_stream;
109
110struct hpgs_mem_istream_stream_st
111{
112  const unsigned char *data;
113  const unsigned char *gptr;
114  const unsigned char *eptr;
115  int errflg;
116};
117
118static int mem_getc   (hpgs_mem_istream_stream *stream)
119{
120  int ret;
121
122  if (stream->errflg)
123    ret=EOF;
124  else
125    {
126      if (stream->gptr >= stream->eptr)
127        ret = EOF;
128      else
129        {
130          ret = *stream->gptr;
131          ++stream->gptr;
132        }
133    }
134
135  return ret;
136}
137
138static int mem_ungetc (int c, hpgs_mem_istream_stream *stream)
139{
140  if (stream->errflg) return -1;
141  if (stream->gptr <= stream->data) { stream->errflg = 1; return -1; }
142  --stream->gptr;
143  return 0;
144}
145
146static int mem_close  (hpgs_mem_istream_stream *stream)
147{
148  return 0;
149}
150
151static int mem_iseof  (hpgs_mem_istream_stream *stream)
152{
153  return stream->gptr >= stream->eptr;
154}
155
156static int mem_iserror  (hpgs_mem_istream_stream *stream)
157{
158  return stream->errflg;
159}
160
161static int mem_tell (hpgs_mem_istream_stream *stream, size_t *pos)
162{
163  if (stream->errflg) return -1;
164  *pos = stream->gptr - stream->data;
165  return 0;
166}
167
168static int mem_seek (hpgs_mem_istream_stream *stream, size_t pos)
169{
170  if (stream->data + pos > stream->eptr)
171    {
172      stream->errflg = 1;
173      return -1;
174    }
175
176  stream->gptr = stream->data+pos;
177  stream->errflg = 0;
178  return 0;
179}
180
181static int mem_seekend (hpgs_mem_istream_stream *stream, size_t pos)
182{
183  if (stream->data + pos > stream->eptr)
184    {
185      stream->errflg = 1;
186      return -1;
187    }
188
189  stream->gptr = stream->eptr-pos;
190  stream->errflg = 0;
191  return 0;
192}
193
194static size_t mem_read (void *ptr, size_t size, size_t nmemb, hpgs_mem_istream_stream *stream)
195{
196  size_t ret = 0;
197
198  if (!stream->errflg)
199    {
200      if (stream->gptr < stream->eptr)
201        {
202          ret = (stream->eptr - stream->gptr)/size;
203          if (ret > nmemb) ret = nmemb;
204
205          memcpy(ptr,stream->gptr,size * ret);
206          stream->gptr += size * ret;
207        }
208    }
209
210  return ret;
211}
212
213static hpgs_istream_vtable mem_vtable =
214  {
215    (hpgs_istream_getc_func_t)    mem_getc,
216    (hpgs_istream_ungetc_func_t)  mem_ungetc,
217    (hpgs_istream_close_func_t)   mem_close,
218    (hpgs_istream_iseof_func_t)   mem_iseof,
219    (hpgs_istream_iserror_func_t) mem_iserror,
220    (hpgs_istream_seek_func_t)    mem_seek,
221    (hpgs_istream_tell_func_t)    mem_tell,
222    (hpgs_istream_read_func_t)    mem_read,
223    (hpgs_istream_seekend_func_t) mem_seekend
224  };
225
226/*! Returns a new \c hpgs_istream created on the heap,
227    which operates on a chunk of memory in the given
228    location with the given size.
229
230    Returns a null pointer, when the system is out of memory.
231  */
232hpgs_istream *hpgs_new_mem_istream(const unsigned char *data,
233				   size_t data_size,
234                                   hpgs_bool dup)
235{
236#define HPGS_ISTREAM_PAD_SZ (8*((sizeof(hpgs_istream)+7)/8))
237#define HPGS_ISTREAM_STREAM_PAD_SZ (8*((sizeof(hpgs_mem_istream_stream)+7)/8))
238
239  hpgs_mem_istream_stream *stream;
240  hpgs_istream *ret;
241  size_t sz = HPGS_ISTREAM_PAD_SZ + HPGS_ISTREAM_STREAM_PAD_SZ;
242  void *ptr;
243
244  if (dup) sz += data_size;
245
246  ptr = malloc(sz);
247  ret = (hpgs_istream *)ptr;
248
249  if (!ret)
250    return 0;
251
252  stream = (hpgs_mem_istream_stream *)(ptr+HPGS_ISTREAM_PAD_SZ);
253
254  if (dup)
255    {
256      unsigned char *ddata =
257        (unsigned char *)ptr + HPGS_ISTREAM_PAD_SZ + HPGS_ISTREAM_STREAM_PAD_SZ;
258
259      stream->data = ddata;
260      stream->gptr = ddata;
261      stream->eptr = ddata+data_size;
262
263      memcpy(ddata,data,data_size);
264    }
265  else
266    {
267      stream->data = data;
268      stream->gptr = data;
269      stream->eptr = data+data_size;
270    }
271
272  stream->errflg = 0;
273
274  ret->stream = stream;
275  ret->vtable = &mem_vtable;
276
277  return ret;
278}
279