1 /*
2 * The 3D Studio File Format Library
3 * Copyright (C) 1996-2007 by Jan Eric Kyprianidis <www.kyprianidis.com>
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 * License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * $Id: io.c,v 1.9 2007/06/20 17:04:08 jeh Exp $
21 */
22 #include <lib3ds/io.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26
27 /*!
28 * \defgroup io Binary Input/Ouput Abstraction Layer
29 */
30
31 typedef union {
32 Lib3dsDword dword_value;
33 Lib3dsFloat float_value;
34 } Lib3dsDwordFloat;
35
36
37 struct Lib3dsIo {
38 void *self;
39 Lib3dsIoErrorFunc error_func;
40 Lib3dsIoSeekFunc seek_func;
41 Lib3dsIoTellFunc tell_func;
42 Lib3dsIoReadFunc read_func;
43 Lib3dsIoWriteFunc write_func;
44 };
45
46
47 Lib3dsIo*
lib3ds_io_new(void * self,Lib3dsIoErrorFunc error_func,Lib3dsIoSeekFunc seek_func,Lib3dsIoTellFunc tell_func,Lib3dsIoReadFunc read_func,Lib3dsIoWriteFunc write_func)48 lib3ds_io_new(void *self, Lib3dsIoErrorFunc error_func, Lib3dsIoSeekFunc seek_func,
49 Lib3dsIoTellFunc tell_func, Lib3dsIoReadFunc read_func, Lib3dsIoWriteFunc write_func)
50 {
51 Lib3dsIo *io = calloc(sizeof(Lib3dsIo),1);
52 ASSERT(io);
53 if (!io) {
54 return 0;
55 }
56
57 io->self = self;
58 io->error_func = error_func;
59 io->seek_func = seek_func;
60 io->tell_func = tell_func;
61 io->read_func = read_func;
62 io->write_func = write_func;
63
64 return io;
65 }
66
67
68 void
lib3ds_io_free(Lib3dsIo * io)69 lib3ds_io_free(Lib3dsIo *io)
70 {
71 ASSERT(io);
72 if (!io) {
73 return;
74 }
75 free(io);
76 }
77
78
79 Lib3dsBool
lib3ds_io_error(Lib3dsIo * io)80 lib3ds_io_error(Lib3dsIo *io)
81 {
82 ASSERT(io);
83 if (!io || !io->error_func) {
84 return 0;
85 }
86 return (*io->error_func)(io->self);
87 }
88
89
90 long
lib3ds_io_seek(Lib3dsIo * io,long offset,Lib3dsIoSeek origin)91 lib3ds_io_seek(Lib3dsIo *io, long offset, Lib3dsIoSeek origin)
92 {
93 ASSERT(io);
94 if (!io || !io->seek_func) {
95 return 0;
96 }
97 return (*io->seek_func)(io->self, offset, origin);
98 }
99
100
101 long
lib3ds_io_tell(Lib3dsIo * io)102 lib3ds_io_tell(Lib3dsIo *io)
103 {
104 ASSERT(io);
105 if (!io || !io->tell_func) {
106 return 0;
107 }
108 return (*io->tell_func)(io->self);
109 }
110
111
112 size_t
lib3ds_io_read(Lib3dsIo * io,void * buffer,size_t size)113 lib3ds_io_read(Lib3dsIo *io, void *buffer, size_t size)
114 {
115 ASSERT(io);
116 if (!io || !io->read_func) {
117 return 0;
118 }
119 return (*io->read_func)(io->self, buffer, size);
120 }
121
122
123 size_t
lib3ds_io_write(Lib3dsIo * io,const void * buffer,size_t size)124 lib3ds_io_write(Lib3dsIo *io, const void *buffer, size_t size)
125 {
126 ASSERT(io);
127 if (!io || !io->write_func) {
128 return 0;
129 }
130 return (*io->write_func)(io->self, buffer, size);
131 }
132
133
134 /*!
135 * \ingroup io
136 *
137 * Read a byte from a file stream.
138 */
139 Lib3dsByte
lib3ds_io_read_byte(Lib3dsIo * io)140 lib3ds_io_read_byte(Lib3dsIo *io)
141 {
142 Lib3dsByte b;
143
144 ASSERT(io);
145 lib3ds_io_read(io, &b, 1);
146 return(b);
147 }
148
149
150 /**
151 * Read a word from a file stream in little endian format.
152 */
153 Lib3dsWord
lib3ds_io_read_word(Lib3dsIo * io)154 lib3ds_io_read_word(Lib3dsIo *io)
155 {
156 Lib3dsByte b[2];
157 Lib3dsWord w;
158
159 ASSERT(io);
160 lib3ds_io_read(io, b, 2);
161 w=((Lib3dsWord)b[1] << 8) |
162 ((Lib3dsWord)b[0]);
163 return(w);
164 }
165
166
167 /*!
168 * \ingroup io
169 *
170 * Read a dword from file a stream in little endian format.
171 */
172 Lib3dsDword
lib3ds_io_read_dword(Lib3dsIo * io)173 lib3ds_io_read_dword(Lib3dsIo *io)
174 {
175 Lib3dsByte b[4];
176 Lib3dsDword d;
177
178 ASSERT(io);
179 lib3ds_io_read(io, b, 4);
180 d=((Lib3dsDword)b[3] << 24) |
181 ((Lib3dsDword)b[2] << 16) |
182 ((Lib3dsDword)b[1] << 8) |
183 ((Lib3dsDword)b[0]);
184 return(d);
185 }
186
187
188 /*!
189 * \ingroup io
190 *
191 * Read a signed byte from a file stream.
192 */
193 Lib3dsIntb
lib3ds_io_read_intb(Lib3dsIo * io)194 lib3ds_io_read_intb(Lib3dsIo *io)
195 {
196 Lib3dsIntb b;
197
198 ASSERT(io);
199 lib3ds_io_read(io, &b, 1);
200 return(b);
201 }
202
203
204 /*!
205 * \ingroup io
206 *
207 * Read a signed word from a file stream in little endian format.
208 */
209 Lib3dsIntw
lib3ds_io_read_intw(Lib3dsIo * io)210 lib3ds_io_read_intw(Lib3dsIo *io)
211 {
212 Lib3dsByte b[2];
213 Lib3dsWord w;
214
215 ASSERT(io);
216 lib3ds_io_read(io, b, 2);
217 w=((Lib3dsWord)b[1] << 8) |
218 ((Lib3dsWord)b[0]);
219 return((Lib3dsIntw)w);
220 }
221
222
223 /*!
224 * \ingroup io
225 *
226 * Read a signed dword a from file stream in little endian format.
227 */
228 Lib3dsIntd
lib3ds_io_read_intd(Lib3dsIo * io)229 lib3ds_io_read_intd(Lib3dsIo *io)
230 {
231 Lib3dsByte b[4];
232 Lib3dsDword d;
233
234 ASSERT(io);
235 lib3ds_io_read(io, b, 4);
236 d=((Lib3dsDword)b[3] << 24) |
237 ((Lib3dsDword)b[2] << 16) |
238 ((Lib3dsDword)b[1] << 8) |
239 ((Lib3dsDword)b[0]);
240 return((Lib3dsIntd)d);
241 }
242
243
244 /*!
245 * \ingroup io
246 *
247 * Read a float from a file stream in little endian format.
248 */
249 Lib3dsFloat
lib3ds_io_read_float(Lib3dsIo * io)250 lib3ds_io_read_float(Lib3dsIo *io)
251 {
252 Lib3dsByte b[4];
253 Lib3dsDwordFloat d;
254
255 ASSERT(io);
256 lib3ds_io_read(io, b, 4);
257 d.dword_value=((Lib3dsDword)b[3] << 24) |
258 ((Lib3dsDword)b[2] << 16) |
259 ((Lib3dsDword)b[1] << 8) |
260 ((Lib3dsDword)b[0]);
261 return d.float_value;
262 }
263
264
265 /*!
266 * \ingroup io
267 *
268 * Read a vector from a file stream in little endian format.
269 *
270 * \param io IO input handle.
271 * \param v The vector to store the data.
272 */
273 Lib3dsBool
lib3ds_io_read_vector(Lib3dsIo * io,Lib3dsVector v)274 lib3ds_io_read_vector(Lib3dsIo *io, Lib3dsVector v)
275 {
276 ASSERT(io);
277
278 v[0]=lib3ds_io_read_float(io);
279 v[1]=lib3ds_io_read_float(io);
280 v[2]=lib3ds_io_read_float(io);
281
282 return(!lib3ds_io_error(io));
283 }
284
285
286 /*!
287 * \ingroup io
288 */
289 Lib3dsBool
lib3ds_io_read_rgb(Lib3dsIo * io,Lib3dsRgb rgb)290 lib3ds_io_read_rgb(Lib3dsIo *io, Lib3dsRgb rgb)
291 {
292 ASSERT(io);
293
294 rgb[0]=lib3ds_io_read_float(io);
295 rgb[1]=lib3ds_io_read_float(io);
296 rgb[2]=lib3ds_io_read_float(io);
297
298 return(!lib3ds_io_error(io));
299 }
300
301
302 /*!
303 * \ingroup io
304 *
305 * Read a zero-terminated string from a file stream.
306 *
307 * \param io IO input handle.
308 * \param s The buffer to store the read string.
309 * \param buflen Buffer length.
310 *
311 * \return True on success, False otherwise.
312 */
313 Lib3dsBool
lib3ds_io_read_string(Lib3dsIo * io,char * s,int buflen)314 lib3ds_io_read_string(Lib3dsIo *io, char *s, int buflen)
315 {
316 char c;
317 int k=0;
318
319 ASSERT(io);
320 for (;;) {
321 if (lib3ds_io_read(io, &c, 1)!=1) {
322 return LIB3DS_FALSE;
323 }
324 *s++ = c;
325 if (!c) {
326 break;
327 }
328 ++k;
329 if (k>=buflen) {
330 return(LIB3DS_FALSE);
331 }
332 }
333
334 return(!lib3ds_io_error(io));
335 }
336
337
338 /*!
339 * \ingroup io
340 *
341 * Writes a byte into a file stream.
342 */
343 Lib3dsBool
lib3ds_io_write_byte(Lib3dsIo * io,Lib3dsByte b)344 lib3ds_io_write_byte(Lib3dsIo *io, Lib3dsByte b)
345 {
346 ASSERT(io);
347 if (lib3ds_io_write(io, &b, 1)!=1) {
348 return(LIB3DS_FALSE);
349 }
350 return(LIB3DS_TRUE);
351 }
352
353
354 /*!
355 * \ingroup io
356 *
357 * Writes a word into a little endian file stream.
358 */
359 Lib3dsBool
lib3ds_io_write_word(Lib3dsIo * io,Lib3dsWord w)360 lib3ds_io_write_word(Lib3dsIo *io, Lib3dsWord w)
361 {
362 Lib3dsByte b[2];
363
364 ASSERT(io);
365 b[1]=((Lib3dsWord)w & 0xFF00) >> 8;
366 b[0]=((Lib3dsWord)w & 0x00FF);
367 if (lib3ds_io_write(io, b, 2)!=2) {
368 return(LIB3DS_FALSE);
369 }
370 return(LIB3DS_TRUE);
371 }
372
373
374 /*!
375 * \ingroup io
376 *
377 * Writes a dword into a little endian file stream.
378 */
379 Lib3dsBool
lib3ds_io_write_dword(Lib3dsIo * io,Lib3dsDword d)380 lib3ds_io_write_dword(Lib3dsIo *io, Lib3dsDword d)
381 {
382 Lib3dsByte b[4];
383
384 ASSERT(io);
385 b[3]=(Lib3dsByte)(((Lib3dsDword)d & 0xFF000000) >> 24);
386 b[2]=(Lib3dsByte)(((Lib3dsDword)d & 0x00FF0000) >> 16);
387 b[1]=(Lib3dsByte)(((Lib3dsDword)d & 0x0000FF00) >> 8);
388 b[0]=(Lib3dsByte)(((Lib3dsDword)d & 0x000000FF));
389 if (lib3ds_io_write(io, b, 4)!=4) {
390 return(LIB3DS_FALSE);
391 }
392 return(LIB3DS_TRUE);
393 }
394
395
396 /*!
397 * \ingroup io
398 *
399 * Writes a signed byte in a file stream.
400 */
401 Lib3dsBool
lib3ds_io_write_intb(Lib3dsIo * io,Lib3dsIntb b)402 lib3ds_io_write_intb(Lib3dsIo *io, Lib3dsIntb b)
403 {
404 ASSERT(io);
405 if (lib3ds_io_write(io, &b, 1)!=1) {
406 return(LIB3DS_FALSE);
407 }
408 return(LIB3DS_TRUE);
409 }
410
411
412 /*!
413 * \ingroup io
414 *
415 * Writes a signed word into a little endian file stream.
416 */
417 Lib3dsBool
lib3ds_io_write_intw(Lib3dsIo * io,Lib3dsIntw w)418 lib3ds_io_write_intw(Lib3dsIo *io, Lib3dsIntw w)
419 {
420 Lib3dsByte b[2];
421
422 ASSERT(io);
423 b[1]=((Lib3dsWord)w & 0xFF00) >> 8;
424 b[0]=((Lib3dsWord)w & 0x00FF);
425 if (lib3ds_io_write(io, b, 2)!=2) {
426 return(LIB3DS_FALSE);
427 }
428 return(LIB3DS_TRUE);
429 }
430
431
432 /*!
433 * \ingroup io
434 *
435 * Writes a signed dword into a little endian file stream.
436 */
437 Lib3dsBool
lib3ds_io_write_intd(Lib3dsIo * io,Lib3dsIntd d)438 lib3ds_io_write_intd(Lib3dsIo *io, Lib3dsIntd d)
439 {
440 Lib3dsByte b[4];
441
442 ASSERT(io);
443 b[3]=(Lib3dsByte)(((Lib3dsDword)d & 0xFF000000) >> 24);
444 b[2]=(Lib3dsByte)(((Lib3dsDword)d & 0x00FF0000) >> 16);
445 b[1]=(Lib3dsByte)(((Lib3dsDword)d & 0x0000FF00) >> 8);
446 b[0]=(Lib3dsByte)(((Lib3dsDword)d & 0x000000FF));
447 if (lib3ds_io_write(io, b, 4)!=4) {
448 return(LIB3DS_FALSE);
449 }
450 return(LIB3DS_TRUE);
451 }
452
453
454 /*!
455 * \ingroup io
456 *
457 * Writes a float into a little endian file stream.
458 */
459 Lib3dsBool
lib3ds_io_write_float(Lib3dsIo * io,Lib3dsFloat l)460 lib3ds_io_write_float(Lib3dsIo *io, Lib3dsFloat l)
461 {
462 Lib3dsByte b[4];
463 Lib3dsDwordFloat d;
464
465 ASSERT(io);
466 d.float_value=l;
467 b[3]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0xFF000000) >> 24);
468 b[2]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x00FF0000) >> 16);
469 b[1]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x0000FF00) >> 8);
470 b[0]=(Lib3dsByte)(((Lib3dsDword)d.dword_value & 0x000000FF));
471 if (lib3ds_io_write(io, b, 4)!=4) {
472 return(LIB3DS_FALSE);
473 }
474 return(LIB3DS_TRUE);
475 }
476
477
478 /*!
479 * \ingroup io
480 *
481 * Writes a vector into a file stream in little endian format.
482 */
483 Lib3dsBool
lib3ds_io_write_vector(Lib3dsIo * io,Lib3dsVector v)484 lib3ds_io_write_vector(Lib3dsIo *io, Lib3dsVector v)
485 {
486 int i;
487 for (i=0; i<3; ++i) {
488 if (!lib3ds_io_write_float(io, v[i])) {
489 return(LIB3DS_FALSE);
490 }
491 }
492 return(LIB3DS_TRUE);
493 }
494
495
496 /*!
497 * \ingroup io
498 */
499 Lib3dsBool
lib3ds_io_write_rgb(Lib3dsIo * io,Lib3dsRgb rgb)500 lib3ds_io_write_rgb(Lib3dsIo *io, Lib3dsRgb rgb)
501 {
502 int i;
503 for (i=0; i<3; ++i) {
504 if (!lib3ds_io_write_float(io, rgb[i])) {
505 return(LIB3DS_FALSE);
506 }
507 }
508 return(LIB3DS_TRUE);
509 }
510
511
512 /*!
513 * \ingroup io
514 *
515 * Writes a zero-terminated string into a file stream.
516 */
517 Lib3dsBool
lib3ds_io_write_string(Lib3dsIo * io,const char * s)518 lib3ds_io_write_string(Lib3dsIo *io, const char *s)
519 {
520 ASSERT(s);
521 ASSERT(io);
522 lib3ds_io_write(io, s, strlen(s)+1);
523 return(!lib3ds_io_error(io));
524 }
525