Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / blorb.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 <string.h>
21 #include <stdint.h>
22
23 #include "blorb.h"
24 #include "iff.h"
25 #include "io.h"
26
27 struct zterp_blorb
28 {
29   struct zterp_io *io;
30   struct zterp_iff *iff;
31
32   size_t nchunks;
33   zterp_blorb_chunk *chunks;
34 };
35
36 struct zterp_blorb *zterp_blorb_parse(zterp_io *io)
37 {
38   uint32_t size;
39   uint32_t nresources;
40   zterp_iff *iff;
41   struct zterp_blorb *blorb = NULL;
42
43   iff = zterp_iff_parse(io, "IFRS");
44   if(!zterp_iff_find(iff, "RIdx", &size)) goto err;
45   zterp_iff_free(iff);
46
47   if(!zterp_io_read32(io, &nresources)) goto err;
48
49   if((nresources * 12) + 4 != size) goto err;
50
51   blorb = malloc(sizeof *blorb);
52   if(blorb == NULL) goto err;
53
54   blorb->io = io;
55   blorb->nchunks = 0;
56   blorb->chunks = NULL;
57
58   for(uint32_t i = 0; i < nresources; i++)
59   {
60     uint32_t usage, number, start, type;
61     zterp_blorb_chunk *new;
62     long saved;
63     uint32_t idx;
64
65     if(!zterp_io_read32(io, &usage) || !zterp_io_read32(io, &number) || !zterp_io_read32(io, &start)) goto err;
66
67     if(usage != BLORB_PICT && usage != BLORB_SND && usage != BLORB_EXEC) goto err;
68
69     saved = zterp_io_tell(io);
70     if(saved == -1) goto err;
71
72     if(zterp_io_seek(io, start, SEEK_SET) == -1) goto err;
73
74     if(!zterp_io_read32(io, &type) || !zterp_io_read32(io, &size)) goto err;
75
76     if(zterp_io_seek(io, saved, SEEK_SET) == -1) goto err;
77
78     if(type == STRID("FORM"))
79     {
80       start -= 8;
81       size += 8;
82     }
83
84     /* Not really efficient, but does it matter? */
85     new = realloc(blorb->chunks, sizeof *new * ++blorb->nchunks);
86     if(new == NULL) goto err;
87     blorb->chunks = new;
88
89     idx = blorb->nchunks - 1;
90
91     new[idx].usage = usage;
92     new[idx].number = number;
93     new[idx].type = type;
94     memcpy(new[idx].name, IDSTR(type), 5);
95     new[idx].offset = start + 8;
96     new[idx].size = size;
97   }
98
99   return blorb;
100
101 err:
102   zterp_blorb_free(blorb);
103
104   return NULL;
105 }
106
107 void zterp_blorb_free(struct zterp_blorb *blorb)
108 {
109   if(blorb != NULL) free(blorb->chunks);
110   free(blorb);
111 }
112
113 const zterp_blorb_chunk *zterp_blorb_find(struct zterp_blorb *blorb, uint32_t usage, int number)
114 {
115   for(size_t i = 0; i < blorb->nchunks; i++)
116   {
117     if(blorb->chunks[i].usage == usage && blorb->chunks[i].number == number) return &blorb->chunks[i];
118   }
119
120   return NULL;
121 }