1 /*
2    Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3    Organisation (CSIRO) Australia
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 
16    - Neither the name of CSIRO Australia nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19 
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 /*
34  * oggz_io.c
35  *
36  * Conrad Parker <conrad@annodex.net>
37  */
38 
39 #include "config.h"
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <errno.h>
45 
46 #include "oggz_compat.h"
47 #include "oggz_private.h"
48 
49 /*#define DEBUG*/
50 
51 size_t
oggz_io_read(OGGZ * oggz,void * buf,size_t n)52 oggz_io_read (OGGZ * oggz, void * buf, size_t n)
53 {
54   OggzIO * io;
55   size_t bytes;
56 
57   if (oggz->file != NULL) {
58     if ((bytes = fread (buf, 1, n, oggz->file)) == 0) {
59       if (ferror (oggz->file)) {
60         return (size_t) OGGZ_ERR_SYSTEM;
61       }
62     }
63   }
64 
65   else if ((io = oggz->io) != NULL) {
66     if (io->read == NULL) return (size_t) -1;
67     bytes = io->read (io->read_user_handle, buf, n);
68   }
69 
70   else return (size_t) OGGZ_ERR_INVALID;
71 
72   return bytes;
73 }
74 
75 size_t
oggz_io_write(OGGZ * oggz,void * buf,size_t n)76 oggz_io_write (OGGZ * oggz, void * buf, size_t n)
77 {
78   OggzIO * io;
79   size_t bytes;
80 
81   if (oggz->file != NULL) {
82     bytes = fwrite (buf, 1, n, oggz->file);
83   }
84 
85   else if ((io = oggz->io) != NULL) {
86     if (io->write == NULL) return (size_t) -1;
87     bytes = io->write (io->write_user_handle, buf, n);
88   }
89 
90   else {
91     return (size_t) OGGZ_ERR_INVALID;
92   }
93 
94   return bytes;
95 }
96 
97 int
oggz_io_seek(OGGZ * oggz,long offset,int whence)98 oggz_io_seek (OGGZ * oggz, long offset, int whence)
99 {
100   OggzIO * io;
101 
102   if (oggz->file != NULL) {
103     if (fseek (oggz->file, offset, whence) == -1) {
104       if (errno == ESPIPE) {
105 	/*oggz_set_error (oggz, OGGZ_ERR_NOSEEK);*/
106       } else {
107 	/*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
108       }
109       return OGGZ_ERR_SYSTEM;
110     }
111   }
112 
113   else if ((io = oggz->io) != NULL) {
114     if (io->seek == NULL) return -1;
115     if (io->seek (io->seek_user_handle, offset, whence) == -1)
116       return -1;
117   }
118 
119   else return OGGZ_ERR_INVALID;
120 
121   return 0;
122 }
123 
124 long
oggz_io_tell(OGGZ * oggz)125 oggz_io_tell (OGGZ * oggz)
126 {
127   OggzIO * io;
128   long offset;
129 
130   if (oggz->file != NULL) {
131     if ((offset = ftell (oggz->file)) == -1) {
132       if (errno == ESPIPE) {
133 	/*oggz_set_error (oggz, OGGZ_ERR_NOSEEK);*/
134       } else {
135 	/*oggz_set_error (oggz, OGGZ_ERR_SYSTEM);*/
136       }
137       return -1;
138     }
139   }
140 
141   else if ((io = oggz->io) != NULL) {
142     if (io->tell == NULL) return -1;
143     if ((offset = io->tell (io->tell_user_handle)) == -1)
144       return -1;
145   }
146 
147   else return OGGZ_ERR_INVALID;
148 
149   return offset;
150 }
151 
152 int
oggz_io_flush(OGGZ * oggz)153 oggz_io_flush (OGGZ * oggz)
154 {
155   OggzIO * io;
156 
157   if (oggz->file != NULL) {
158     if (fflush (oggz->file) == EOF) {
159       /* check errno for write-related errors */
160       return OGGZ_ERR_SYSTEM;
161     }
162   }
163 
164   else if ((io = oggz->io) != NULL) {
165     if (io->flush == NULL) return OGGZ_ERR_INVALID;
166 
167     if (io->flush (io->flush_user_handle) == -1) {
168       return -1;
169     }
170   }
171 
172   else return OGGZ_ERR_INVALID;
173 
174   return 0;
175 }
176 
177 /* get/set functions */
178 
179 static int
oggz_io_init(OGGZ * oggz)180 oggz_io_init (OGGZ * oggz)
181 {
182   oggz->io = (OggzIO *) oggz_malloc (sizeof (OggzIO));
183   if (oggz->io == NULL) return -1;
184 
185   memset (oggz->io, 0, sizeof (OggzIO));
186 
187   return 0;
188 }
189 
190 int
oggz_io_set_read(OGGZ * oggz,OggzIORead read,void * user_handle)191 oggz_io_set_read (OGGZ * oggz, OggzIORead read, void * user_handle)
192 {
193   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
194   if (oggz->file != NULL) return OGGZ_ERR_INVALID;
195 
196   if (oggz->io == NULL) {
197     if (oggz_io_init (oggz) == -1)
198       return OGGZ_ERR_OUT_OF_MEMORY;
199   }
200 
201   oggz->io->read = read;
202   oggz->io->read_user_handle = user_handle;
203 
204   return 0;
205 }
206 
207 void *
oggz_io_get_read_user_handle(OGGZ * oggz)208 oggz_io_get_read_user_handle (OGGZ * oggz)
209 {
210   if (oggz == NULL) return NULL;
211   if (oggz->file != NULL) return NULL;
212 
213   if (oggz->io == NULL) return NULL;
214 
215   return oggz->io->read_user_handle;
216 }
217 
218 int
oggz_io_set_write(OGGZ * oggz,OggzIOWrite write,void * user_handle)219 oggz_io_set_write (OGGZ * oggz, OggzIOWrite write, void * user_handle)
220 {
221   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
222   if (oggz->file != NULL) return OGGZ_ERR_INVALID;
223 
224   if (oggz->io == NULL) {
225     if (oggz_io_init (oggz) == -1)
226       return OGGZ_ERR_OUT_OF_MEMORY;
227   }
228 
229   oggz->io->write = write;
230   oggz->io->write_user_handle = user_handle;
231 
232   return 0;
233 }
234 
235 void *
oggz_io_get_write_user_handle(OGGZ * oggz)236 oggz_io_get_write_user_handle (OGGZ * oggz)
237 {
238   if (oggz == NULL) return NULL;
239   if (oggz->file != NULL) return NULL;
240 
241   if (oggz->io == NULL) return NULL;
242 
243   return oggz->io->write_user_handle;
244 }
245 
246 int
oggz_io_set_seek(OGGZ * oggz,OggzIOSeek seek,void * user_handle)247 oggz_io_set_seek (OGGZ * oggz, OggzIOSeek seek, void * user_handle)
248 {
249   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
250   if (oggz->file != NULL) return OGGZ_ERR_INVALID;
251 
252   if (oggz->io == NULL) {
253     if (oggz_io_init (oggz) == -1)
254       return OGGZ_ERR_OUT_OF_MEMORY;
255   }
256 
257   oggz->io->seek = seek;
258   oggz->io->seek_user_handle = user_handle;
259 
260   return 0;
261 }
262 
263 void *
oggz_io_get_seek_user_handle(OGGZ * oggz)264 oggz_io_get_seek_user_handle (OGGZ * oggz)
265 {
266   if (oggz == NULL) return NULL;
267   if (oggz->file != NULL) return NULL;
268 
269   if (oggz->io == NULL) return NULL;
270 
271   return oggz->io->seek_user_handle;
272 }
273 
274 int
oggz_io_set_tell(OGGZ * oggz,OggzIOTell tell,void * user_handle)275 oggz_io_set_tell (OGGZ * oggz, OggzIOTell tell, void * user_handle)
276 {
277   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
278   if (oggz->file != NULL) return OGGZ_ERR_INVALID;
279 
280   if (oggz->io == NULL) {
281     if (oggz_io_init (oggz) == -1)
282       return OGGZ_ERR_OUT_OF_MEMORY;
283   }
284 
285   oggz->io->tell = tell;
286   oggz->io->tell_user_handle = user_handle;
287 
288   return 0;
289 }
290 
291 void *
oggz_io_get_tell_user_handle(OGGZ * oggz)292 oggz_io_get_tell_user_handle (OGGZ * oggz)
293 {
294   if (oggz == NULL) return NULL;
295   if (oggz->file != NULL) return NULL;
296 
297   if (oggz->io == NULL) return NULL;
298 
299   return oggz->io->tell_user_handle;
300 }
301 
302 int
oggz_io_set_flush(OGGZ * oggz,OggzIOFlush flush,void * user_handle)303 oggz_io_set_flush (OGGZ * oggz, OggzIOFlush flush, void * user_handle)
304 {
305   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
306   if (oggz->file != NULL) return OGGZ_ERR_INVALID;
307 
308   if (oggz->io == NULL) {
309     if (oggz_io_init (oggz) == -1)
310       return OGGZ_ERR_OUT_OF_MEMORY;
311   }
312 
313   oggz->io->flush = flush;
314   oggz->io->flush_user_handle = user_handle;
315 
316   return 0;
317 }
318 
319 void *
oggz_io_get_flush_user_handle(OGGZ * oggz)320 oggz_io_get_flush_user_handle (OGGZ * oggz)
321 {
322   if (oggz == NULL) return NULL;
323   if (oggz->file != NULL) return NULL;
324 
325   if (oggz->io == NULL) return NULL;
326 
327   return oggz->io->flush_user_handle;
328 }
329