aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/mimesh/libg3d-0.0.8/src/iff.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/src/iff.c')
-rw-r--r--src/others/mimesh/libg3d-0.0.8/src/iff.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/src/iff.c b/src/others/mimesh/libg3d-0.0.8/src/iff.c
new file mode 100644
index 0000000..763d0c5
--- /dev/null
+++ b/src/others/mimesh/libg3d-0.0.8/src/iff.c
@@ -0,0 +1,459 @@
1/* $Id$ */
2
3/*
4 libg3d - 3D object loading library
5
6 Copyright (C) 2005-2009 Markus Dahms <mad@automagically.de>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
23#include <g3d/config.h>
24
25#include <stdio.h>
26#include <string.h>
27#include <g3d/stream.h>
28#include <g3d/read.h>
29#include <g3d/iff.h>
30#include <g3d/context.h>
31#include <g3d/debug.h>
32
33EAPI
34gboolean g3d_iff_check(G3DStream *stream, guint32 *id, gsize *len)
35{
36 guint32 magic, form_bytes;
37
38 magic = g3d_stream_read_int32_be(stream);
39 if((magic != G3D_IFF_MKID('F','O','R','M')) &&
40 (magic != G3D_IFF_MKID('F','O','R','4'))) {
41 g_warning("IFF: %s is not a valid IFF stream", stream->uri);
42 return FALSE;
43 }
44 form_bytes = g3d_stream_read_int32_be(stream);
45 *id = g3d_stream_read_int32_be(stream);
46 *len = form_bytes - 4;
47 return TRUE;
48}
49
50#ifndef G3D_DISABLE_DEPRECATED
51FILE *g3d_iff_open(const gchar *filename, guint32 *id, guint32 *len)
52{
53 FILE *f;
54 guint32 form_bytes, magic;
55
56 f = fopen(filename, "r");
57 if(f == NULL)
58 {
59 g_critical("can't open file '%s'", filename);
60 return NULL;
61 }
62
63 magic = g3d_read_int32_be(f);
64 if((magic != G3D_IFF_MKID('F','O','R','M')) &&
65 (magic != G3D_IFF_MKID('F','O','R','4')))
66 {
67 g_critical("file %s is not an IFF file", filename);
68 fclose(f);
69 return NULL;
70 }
71
72 form_bytes = g3d_read_int32_be(f);
73 *id = g3d_read_int32_be(f);
74 form_bytes -= 4;
75 *len = form_bytes;
76
77 return f;
78}
79#endif /* !G3D_DISABLE_DEPRECATED */
80
81EAPI
82gsize g3d_iff_read_chunk(G3DStream *stream, guint32 *id, gsize *len,
83 guint32 flags)
84{
85 *id = g3d_stream_read_int32_be(stream);
86 if(flags & G3D_IFF_LEN16) {
87 *len = (flags & G3D_IFF_LE) ?
88 g3d_stream_read_int16_le(stream) :
89 g3d_stream_read_int16_be(stream);
90 return 6 + *len + (*len % 2);
91 } else {
92 *len = (flags & G3D_IFF_LE) ?
93 g3d_stream_read_int32_le(stream) :
94 g3d_stream_read_int32_be(stream);
95 return 8 + *len + (*len % 2);
96 }
97}
98
99#ifndef G3D_DISABLE_DEPRECATED
100int g3d_iff_readchunk(FILE *f, guint32 *id, guint32 *len, guint32 flags)
101{
102 *id = g3d_read_int32_be(f);
103 if(flags & G3D_IFF_LEN16)
104 {
105 *len = (flags & G3D_IFF_LE) ?
106 g3d_read_int16_le(f) : g3d_read_int16_be(f);
107 return 6 + *len + (*len % 2);
108 }
109 else
110 {
111 *len = (flags & G3D_IFF_LE) ?
112 g3d_read_int32_le(f) : g3d_read_int32_be(f);
113 return 8 + *len + (*len % 2);
114 }
115}
116#endif /* G3D_DISABLE_DEPRECATED */
117
118EAPI
119gchar *g3d_iff_id_to_text(guint32 id)
120{
121 gchar *tid;
122
123 tid = g_new0(gchar, 5);
124
125 tid[0] = (id >> 24) & 0xFF;
126 tid[1] = (id >> 16) & 0xFF;
127 tid[2] = (id >> 8) & 0xFF;
128 tid[3] = id & 0xFF;
129
130 return tid;
131}
132
133EAPI
134gboolean g3d_iff_chunk_matches(guint32 id, gchar *tid)
135{
136 if(((id >> 24) & 0xFF) != tid[0]) return FALSE;
137 if(((id >> 16) & 0xFF) != tid[1]) return FALSE;
138 if(((id >> 8) & 0xFF) != tid[2]) return FALSE;
139 return (id & 0xFF) == tid[3];
140}
141
142EAPI
143G3DIffChunkInfo *g3d_iff_get_chunk_info(G3DIffChunkInfo *chunks,
144 guint32 chunk_id)
145{
146 guint32 i = 0;
147
148 while(chunks[i].id && !g3d_iff_chunk_matches(chunk_id, chunks[i].id))
149 i ++;
150
151 if(chunks[i].id)
152 return &(chunks[i]);
153
154 return NULL;
155}
156
157EAPI
158void g3d_iff_debug_chunk(G3DIffChunkInfo *info, guint32 chunk_id,
159 guint32 chunk_len, gchar chunk_type, guint32 pos, guint32 level)
160{
161 gchar *tid;
162 gchar *padding = " ";
163
164 tid = g3d_iff_id_to_text(chunk_id);
165 g_debug("\\%s(%d)[%s][%c%c%c] %s (%d) @ 0x%08x - %d bytes left",
166 padding + (strlen(padding) - level), level,
167 tid,
168 chunk_type,
169 info->container ? 'c' : ' ',
170 info->callback ? 'f' : ' ',
171 info->description,
172 chunk_len,
173 pos,
174 chunk_len);
175 g_free(tid);
176}
177
178static goffset g3d_iff_pos(G3DIffGlobal *global)
179{
180 if(global->stream)
181 return g3d_stream_tell(global->stream);
182 else
183#ifndef G_DISABLE_DEPRECATED
184 return ftell(global->f);
185#else
186 return -1;
187#endif
188}
189
190EAPI
191gpointer g3d_iff_handle_chunk(G3DIffGlobal *global, G3DIffLocal *plocal,
192 G3DIffChunkInfo *chunks, guint32 flags)
193{
194 gpointer object = NULL;
195 guint32 chunk_id;
196 gsize chunk_len;
197 G3DIffLocal *sublocal;
198 G3DIffChunkInfo *info;
199
200 /* read info for one chunk */
201 if(global->stream)
202 g3d_iff_read_chunk(global->stream, &chunk_id, &chunk_len, 0);
203 else
204#ifndef G3D_DISABLE_DEPRECATED
205 {
206 guint32 chunk_len32;
207 g3d_iff_readchunk(global->f, &chunk_id, &chunk_len32, 0);
208 chunk_len = chunk_len32;
209 }
210#else
211 return NULL;
212#endif
213
214 plocal->nb -= 8;
215
216 sublocal = g_new0(G3DIffLocal, 1);
217 sublocal->parent_id = plocal->id;
218 sublocal->id = chunk_id;
219 sublocal->object = plocal->object;
220 sublocal->level = plocal->level + 1;
221 sublocal->nb = ((guint32)chunk_len);
222 plocal->nb -= sublocal->nb;
223
224 /* call function */
225 info = g3d_iff_get_chunk_info(chunks, chunk_id);
226 if(info)
227 {
228 g3d_iff_debug_chunk(info, chunk_id, chunk_len, 'X',
229 (guint32)g3d_iff_pos(global) - 8, plocal->level);
230
231 if(info->callback)
232 info->callback(global, sublocal);
233
234 if(sublocal->nb > 0) {
235 if(global->stream) {
236 g3d_stream_skip(global->stream, sublocal->nb);
237 } else {
238#ifndef G_DISABLE_DEPRECATED
239 fseek(global->f, sublocal->nb, SEEK_CUR);
240#else
241 return NULL;
242#endif
243 }
244 }
245 }
246
247 object = sublocal->level_object;
248 g_free(sublocal);
249
250 return object;
251}
252
253EAPI
254gboolean g3d_iff_read_ctnr(G3DIffGlobal *global, G3DIffLocal *local,
255 G3DIffChunkInfo *chunks, guint32 flags)
256{
257 G3DIffLocal *sublocal;
258 G3DIffChunkInfo *info;
259 guint32 chunk_id, chunk_mod, chunk_type;
260 gsize chunk_len;
261 gchar *tid;
262 gpointer level_object;
263#ifndef G3D_DISABLE_DEPRECATED
264 long int fpos;
265#endif
266
267 level_object = NULL;
268
269#ifndef G3D_DISABLE_DEPRECATED
270 if(global->max_fpos == 0)
271 global->max_fpos = local->nb + 12;
272#endif
273 while(local->nb >= ((flags & G3D_IFF_LEN16) ? 6 : 8))
274 {
275 chunk_id = 0;
276
277 if(global->stream)
278 g3d_iff_read_chunk(global->stream, &chunk_id, &chunk_len, flags);
279 else
280#ifndef G3D_DISABLE_DEPRECATED
281 {
282 guint32 chunk_len32 = ((guint32)chunk_len);
283 g3d_iff_readchunk(global->f, &chunk_id, &chunk_len32, flags);
284 chunk_len = chunk_len32;
285 }
286#else
287 return FALSE;
288#endif
289 local->nb -= ((flags & G3D_IFF_LEN16) ? 6 : 8);
290
291 chunk_mod = flags & 0x0F;
292 if(chunk_mod == 0) {
293 g_warning("[IFF] mod = 0 (flags: 0x%02X\n)", flags);
294 chunk_mod = 2;
295 }
296 chunk_type = ' ';
297
298 /* handle special chunks */
299 switch(chunk_id)
300 {
301 case 0:
302 case 0xFFFFFFFF:
303 g_warning(
304 "[IFF] got invalid ID, skipping %d bytes @ 0x%08x",
305 local->nb, (guint32)g3d_iff_pos(global));
306
307 /* skip rest of parent chunk */
308 if(local->nb > 0)
309 {
310 fseek(global->f, local->nb, SEEK_CUR);
311 local->nb = 0;
312 }
313 return FALSE;
314 break;
315
316 case G3D_IFF_MKID('F','O','R','4'):
317 if(global->stream)
318 chunk_id = g3d_stream_read_int32_be(global->stream);
319 else
320#ifndef G3D_DISABLE_DEPRECATED
321 chunk_id = g3d_read_int32_be(global->f);
322#else
323 return FALSE;
324#endif
325 chunk_len -= 4;
326 chunk_mod = 4;
327 chunk_type = 'F';
328 local->nb -= 4;
329 break;
330
331 case G3D_IFF_MKID('L','I','S','4'):
332 if(global->stream)
333 chunk_id = g3d_stream_read_int32_be(global->stream);
334 else
335#ifndef G3D_DISABLE_DEPRECATED
336 chunk_id = g3d_read_int32_be(global->f);
337#else
338 return FALSE;
339#endif
340 chunk_len -= 4;
341 chunk_mod = 4;
342 chunk_type = 'L';
343 local->nb -= 4;
344 break;
345
346 default:
347 break;
348 }
349
350 info = g3d_iff_get_chunk_info(chunks, chunk_id);
351
352 if(info) {
353 g3d_iff_debug_chunk(info, chunk_id, chunk_len, chunk_type,
354 (guint32)g3d_iff_pos(global) - ((chunk_type == ' ') ? 8 : 12),
355 local->level);
356
357 sublocal = g_new0(G3DIffLocal, 1);
358 sublocal->parent_id = local->id;
359 sublocal->id = chunk_id;
360 sublocal->object = local->object;
361 sublocal->level = local->level + 1;
362 sublocal->level_object = level_object;
363 sublocal->nb = ((guint32)chunk_len);
364
365 if(info->callback)
366 info->callback(global, sublocal);
367
368 if(info->container) {
369 /* LWO has 16 bit length in subchunks */
370 if(flags & G3D_IFF_SUBCHUNK_LEN16)
371 g3d_iff_read_ctnr(global, sublocal, chunks,
372 flags | G3D_IFF_LEN16);
373 else
374 g3d_iff_read_ctnr(global, sublocal, chunks, flags);
375 }
376
377 if(info->container && info->callback) {
378 sublocal->finalize = TRUE;
379 info->callback(global, sublocal);
380 }
381
382 if(sublocal->nb > 0) {
383 if(global->stream) {
384 g3d_stream_skip(global->stream, sublocal->nb);
385 } else {
386#ifndef G3D_DISABLE_DEPRECATED
387 fseek(global->f, sublocal->nb, SEEK_CUR);
388#else
389 return FALSE;
390#endif
391 }
392 }
393 level_object = sublocal->level_object;
394
395 g_free(sublocal);
396 } else {
397 tid = g3d_iff_id_to_text(chunk_id);
398 g_warning("[IFF] unknown chunk type \"%s\" (%d) @ 0x%08x",
399 tid, (guint32)chunk_len, (guint32)g3d_iff_pos(global) - 8);
400 g_free(tid);
401 if(global->stream)
402 g3d_stream_skip(global->stream, chunk_len);
403 else
404#ifndef G3D_DISABLE_DEPRECATED
405 fseek(global->f, chunk_len, SEEK_CUR);
406#else
407 return FALSE;
408#endif
409 }
410
411 local->nb -= chunk_len;
412
413 if(chunk_len % chunk_mod) {
414 if(global->stream)
415 g3d_stream_skip(global->stream,
416 chunk_mod - (chunk_len % chunk_mod));
417 else
418#ifndef G3D_DISABLE_DEPRECATED
419 fseek(global->f,
420 chunk_mod - (chunk_len % chunk_mod), SEEK_CUR);
421#else
422 return FALSE;
423#endif
424 local->nb -= (chunk_mod - (chunk_len % chunk_mod));
425 }
426
427 if(global->stream) {
428 g3d_context_update_progress_bar(global->context,
429 (G3DFloat)g3d_stream_tell(global->stream) /
430 (G3DFloat)g3d_stream_size(global->stream), TRUE);
431 }
432#ifndef G3D_DISABLE_DEPRECATED
433 else {
434 fpos = ftell(global->f);
435 g3d_context_update_progress_bar(global->context,
436 ((G3DFloat)fpos / (G3DFloat)global->max_fpos), TRUE);
437 }
438#endif
439 } /* nb >= 8/6 */
440
441 if(local->nb > 0)
442 {
443 g_warning("[IFF] skipping %d bytes at the end of chunk",
444 local->nb);
445 if(global->stream) {
446 g3d_stream_skip(global->stream, local->nb);
447 } else {
448#ifndef G3D_DISABLE_DEPRECATED
449 fseek(global->f, local->nb, SEEK_CUR);
450#else
451 return FALSE;
452#endif
453 }
454 local->nb = 0;
455 }
456
457 return TRUE;
458}
459