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