forked from andrewcb/iffdigest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iffdigest.cc
140 lines (121 loc) · 2.94 KB
/
iffdigest.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "iffdigest.h"
#include <algorithm>
static IFFChunkList
parseChunks(const char* mem, enum IFFFormat fmt, unsigned int len);
static inline unsigned int
swap_u32(unsigned int i)
{
return ((i&0xff)<<24) | ((i&0xff00) <<8) | ((i&0xff0000)>>8) | (i>>24);
}
static inline unsigned int
u32_be(unsigned int i)
{
#ifdef __BIG_ENDIAN__
return i;
#else
return swap_u32(i);
#endif
}
static inline unsigned int
u32_le(unsigned int i)
{
#ifdef __BIG_ENDIAN__
return swap_u32(i);
#else
return i;
#endif
}
static inline unsigned int
u32(unsigned int i, enum IFFFormat fmt)
{
if(fmt==IFF_FMT_RIFF) return u32_le(i);
else return u32_be(i);
}
// utility function for casting the first 4 chars of a string to an unsigned int
// compare a chunk ID (unsigned int) to a (4-letter) string.
static inline bool
ckid_cmp(iff_ckid_t id, const char* tag)
{
return (id == iff_ckid(tag));
}
// ----- IFFChunkList methods
IFFChunkIterator
IFFChunkList::findNextChunk(IFFChunkIterator from, iff_ckid_t ckid)
{
return find(++from, end(), ckid);
}
IFFChunkIterator
IFFChunkList::findChunk(iff_ckid_t ckid)
{
return find(begin(), end(), ckid);
}
// ----- IFFChunk methods
// ----- IFFChunk methods
IFFChunk::IFFChunk(const IFFChunk& ck)
: ckid(ck.ckid), tnull('\0'), ctype(ck.ctype), data(0), length(0) {
if(ctype == IFF_CHUNK_DATA) {
length=ck.length; data=ck.data;
} else {
subchunks = ck.subchunks;
}
}
void
IFFChunk::operator=(const IFFChunk& ck)
{
ckid = ck.ckid;
tnull = '\0';
ctype = ck.ctype;
switch(ctype) {
case IFF_CHUNK_DATA:
data = ck.data; length = ck.length; break;
case IFF_CHUNK_LIST:
subchunks = ck.subchunks; data = 0; length = 0;
}
}
static IFFChunk
parseChunk(const char* mem, enum IFFFormat fmt, unsigned int *clen)
{
unsigned int len;
len = u32(((unsigned int*)mem)[1], fmt);
*clen = ((len+8)+1)&0xfffffffe;
if(ckid_cmp(((unsigned int*)mem)[0], "LIST")) {
IFFChunkList sc = parseChunks(mem+12, fmt, len-4);
return IFFChunk( ((unsigned int*)mem)[2], sc);
} else {
return IFFChunk(*((unsigned int*)mem), mem+8, len);
}
}
static IFFChunkList
parseChunks(const char* mem, enum IFFFormat fmt, unsigned int len)
{
IFFChunkList result;
while(len>0) {
unsigned int cl;
IFFChunk c = parseChunk(mem, fmt, &cl);
mem+=cl; len -= cl;
result.push_back(c);
}
return result;
}
IFFDigest::IFFDigest(const char* data, unsigned int dlen)
: tnull('\0'), contents(data)
{
if(ckid_cmp(((unsigned int*)data)[0], "FORM")) {
ftype = IFF_FMT_IFF85;
}
else if(ckid_cmp(((unsigned int*)data)[0], "RIFF")) {
ftype = IFF_FMT_RIFF;
} else {
// maybe throw an exception here?
ftype = IFF_FMT_ERROR;
return;
}
unsigned int len = u32(((unsigned int*)data)[1], ftype)-4;
if(len>dlen-12) {
// illegal length in top level; maybe throw an exception here?
ftype = IFF_FMT_ERROR;
return;
}
fid = ((unsigned int*)data)[2];
chunks = parseChunks(data+12, ftype, len);
}