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