Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / iff.c
1 /*-
2  * Copyright 2010-2012 Chris Spiegel.
3  *
4  * This file is part of Bocfel.
5  *
6  * Bocfel is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version
8  * 2 or 3, as published by the Free Software Foundation.
9  *
10  * Bocfel is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Bocfel.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
22
23 #include "iff.h"
24 #include "io.h"
25
26 struct zterp_iff
27 {
28   zterp_io *io;
29   uint32_t tag;
30   long offset;
31   uint32_t size;
32
33   struct zterp_iff *next;
34 };
35
36 void zterp_iff_free(zterp_iff *iff)
37 {
38   while(iff != NULL)
39   {
40     zterp_iff *tmp = iff->next;
41     free(iff);
42     iff = tmp;
43   }
44 }
45
46 zterp_iff *zterp_iff_parse(zterp_io *io, const char type[4])
47 {
48   uint32_t tag;
49
50   zterp_iff *iff = NULL, *tail = NULL;
51
52   if(zterp_io_seek(io, 0, SEEK_SET) == -1) goto err;
53
54   if(!zterp_io_read32(io, &tag) || tag != STRID("FORM")) goto err;
55
56   if(zterp_io_seek(io, 4, SEEK_CUR) == -1) goto err;
57
58   if(!zterp_io_read32(io, &tag) || tag != STRID(type)) goto err;
59
60   while(zterp_io_read32(io, &tag))
61   {
62     uint32_t size;
63     zterp_iff *new;
64
65     if(!zterp_io_read32(io, &size)) goto err;
66
67     new = malloc(sizeof *new);
68     if(new == NULL) goto err;
69
70     new->tag = tag;
71     new->io = io;
72     new->offset = zterp_io_tell(io);
73     new->size = size;
74     new->next = NULL;
75
76     if(iff == NULL) iff = new;
77     else            tail->next = new;
78
79     tail = new;
80
81     if(new->offset == -1) goto err;
82
83     if(size & 1) size++;
84
85     if(zterp_io_seek(io, size, SEEK_CUR) == -1) goto err;
86   }
87
88   return iff;
89
90 err:
91   zterp_iff_free(iff);
92
93   return NULL;
94 }
95
96 int zterp_iff_find(zterp_iff *iff, const char tag[4], uint32_t *size)
97 {
98   while(iff != NULL)
99   {
100     if(iff->tag == STRID(tag))
101     {
102       if(zterp_io_seek(iff->io, iff->offset, SEEK_SET) == -1) return 0;
103       *size = iff->size;
104
105       return 1;
106     }
107
108     iff = iff->next;
109   }
110
111   return 0;
112 }