1 #include "u-iff.h"
2 #include <assert.h>
3 #include <limits.h>
4 #include <stdlib.h>
5 #include <string.h>
6
uiff_new_ctx(FILE * f,uiff_ctx_t * ctx)7 uiff_ctx_t *uiff_new_ctx(FILE *f, uiff_ctx_t *ctx) {
8 if(ctx == NULL) ctx = malloc(sizeof(uiff_ctx_t));
9 if(ctx) {
10 memset(ctx, 0, sizeof(uiff_ctx_t));
11 ctx->f = f;
12 //ctx->grbegin = 0;
13 ctx->grend = LONG_MAX;
14 ctx->grsz = INT32_MAX;
15 }
16 return ctx;
17 }
18
19
uiff_from_file(FILE * f,ID grID,ID subID)20 uiff_ctx_t *uiff_from_file(FILE *f, ID grID, ID subID) {
21 uiff_ctx_t *ctx;
22
23 ctx = calloc(sizeof(uiff_ctx_t), 1);
24 if(ctx) {
25 rewind(f);
26 uiff_new_ctx(f, ctx);
27 if(uiff_find_group_ctx(ctx, 0, grID, subID) >= 0) {
28 } else {
29 free(ctx);
30 return NULL;
31 }
32 }
33 return ctx;
34 }
35
36
uiff_close(uiff_ctx_t * ctx)37 int32_t uiff_close(uiff_ctx_t *ctx) {
38 int ret;
39
40 ret = fclose(ctx->f);
41 free(ctx);
42 if(ret != 0) return DOS_ERROR;
43 return IFF_OKAY;
44 }
45
46
read32(FILE * inf)47 uint32_t read32(FILE *inf) {
48 uint32_t u32 = 0;
49 int c, i;
50
51 for(i = 0; i < 4; ++i) {
52 u32 <<= 8;
53 c = fgetc(inf);
54 //if(c == EOF) return SHORT_CHUNK;
55 u32 |= c;
56 }
57 //if(u32 & 0x80808080) return -8;
58 return u32;
59 }
60
read16(FILE * inf)61 uint16_t read16(FILE *inf) {
62 uint16_t u16;
63 int c;
64
65 c = fgetc(inf);
66 u16 = c << 8;
67 c = fgetc(inf);
68 u16 |= c;
69 return u16;
70 }
71
uiff_find_chunk(FILE * inf,long length,ID ckID)72 int32_t uiff_find_chunk(FILE *inf, long length, ID ckID) {
73 ID tmpid;
74 int32_t size;
75 long maxpos;
76
77 maxpos = ftell(inf) + length;
78 while(ftell(inf) < maxpos) {
79 tmpid = read32(inf);
80 if(feof(inf)) return SHORT_CHUNK;
81 size = read32(inf);
82 if(size < 0) return BAD_FORM;
83 if(feof(inf)) return SHORT_CHUNK;
84 if(ckID == 0 || tmpid == ckID) {
85 return size;
86 }
87 fseek(inf, (size + 1) & ~1L, SEEK_CUR);
88 }
89 return NOT_IFF;
90 }
91
uiff_find_chunk_ctx(uiff_ctx_t * ctx,ID ckID)92 int32_t uiff_find_chunk_ctx(uiff_ctx_t *ctx, ID ckID) {
93 int32_t size;
94 long pos;
95
96 pos = ftell(ctx->f);
97 if(pos < ctx->grbgn || pos > ctx->grend) return CLIENT_ERROR; //fseek(ctx->f, ctx->grbgn, SEEK_SET);
98 size = uiff_find_chunk(ctx->f, ctx->grsz, ckID);
99 if(size >= 0) {
100 pos = ftell(ctx->f);
101 ctx->ckID = ckID;
102 ctx->ckbgn = pos;
103 ctx->ckend = pos + size;
104 if(ctx->ckend > ctx->grend) {
105 //Something went wrong! Chunk end is after group end.
106 size = BAD_IFF;
107 }
108 }
109 ctx->cksz = size;
110 return size;
111 }
112
113
uiff_find_chunk_wflags(uiff_ctx_t * ctx,ID ckID,unsigned flags)114 int32_t uiff_find_chunk_wflags(uiff_ctx_t *ctx, ID ckID, unsigned flags) {
115 if(flags & IFF_FIND_REWIND) uiff_rewind_group(ctx);
116 return uiff_find_chunk_ctx(ctx, ckID);
117 }
118
119
uiff_find_group(FILE * inf,long length,ID ckID,ID subID)120 int32_t uiff_find_group(FILE *inf, long length, ID ckID, ID subID) {
121 ID tmpid;
122 int32_t size;
123 long pos, maxpos;
124 int found = 0;
125
126 maxpos = ftell(inf) + length;
127 while((pos = ftell(inf)) < maxpos) {
128 size = uiff_find_chunk(inf, (maxpos - pos), ckID);
129 if(size < 0) return size;
130 if(size < 4) return BAD_FORM;
131 if(ckID != 0) {
132 found = 1;
133 } else { //ckID = 0, find any group type
134 fseek(inf, -8, SEEK_CUR); //Go back to ID
135 tmpid = read32(inf);
136 fseek(inf, 4, SEEK_CUR); //Skip size
137 if(tmpid == FORM || tmpid == PROP || tmpid == LIST || tmpid == CAT) found = 1;
138 }
139 if(found) {
140 tmpid = read32(inf);
141 size -= 4; //Bytes left to read
142 if(feof(inf)) return SHORT_CHUNK;
143 if(tmpid == subID) {
144 return size;
145 } else found = 0;
146 }
147 fseek(inf, size, SEEK_CUR);
148 }
149 return NOT_IFF;
150 }
151
uiff_find_group_ctx(uiff_ctx_t * ctx,unsigned flags,ID ckID,ID subID)152 int32_t uiff_find_group_ctx(uiff_ctx_t *ctx, unsigned flags, ID ckID, ID subID) {
153 int32_t size;
154 long pos;
155
156 if(flags & IFF_FIND_REWIND) uiff_rewind_group(ctx);
157 pos = ftell(ctx->f);
158 //Am I within a group?
159 if(pos < ctx->grbgn || pos > ctx->grend) return CLIENT_ERROR; //fseek(ctx->f, ctx->grbgn, SEEK_SET);
160 size = uiff_find_group(ctx->f, ctx->grsz, ckID, subID);
161 if(size >= 0) {
162 pos = ftell(ctx->f);
163 ctx->grID = ckID;
164 ctx->grsID = subID;
165 ctx->grbgn = pos;
166 ctx->grend = pos + size;
167 ctx->grsz = size;
168 ctx->ckID = 0; //We have no current chunk, set everything to zero/default.
169 ctx->ckbgn = 0;
170 ctx->ckend = 0;
171 ctx->cksz = -1;
172 }
173 ctx->grsz = size;
174 return size;
175 }
176
uiff_reada_chunk_ctx(uiff_ctx_t * ctx)177 void *uiff_reada_chunk_ctx(uiff_ctx_t *ctx) {
178 size_t bytes_read;
179 void *ptr = NULL;
180 long pos = ftell(ctx->f);
181
182 if(pos >= ctx->grbgn && pos < ctx->grend && ctx->cksz > 0) { //We actually have to read something
183 ptr = malloc(ctx->cksz);
184 if(ptr) {
185 bytes_read = fread(ptr, 1, ctx->cksz, ctx->f);
186 if(bytes_read < ctx->cksz) {
187 free(ptr);
188 return NULL; // This is bad
189 }
190 ctx->last_data = ptr;
191 }
192 }
193 return ptr;
194 }
195
uiff_skip(uiff_ctx_t * ctx)196 int32_t uiff_skip(uiff_ctx_t *ctx) {
197 long pos = ftell(ctx->f);
198
199 if(pos < ctx->ckbgn || pos >= ctx->ckend) return CLIENT_ERROR;
200 fseek(ctx->f, ctx->ckend, SEEK_SET);
201 return (int32_t)(ctx->ckend - pos);
202 }
203
uiff_rewind_group(uiff_ctx_t * ctx)204 void uiff_rewind_group(uiff_ctx_t *ctx) {
205 fseek(ctx->f, ctx->grbgn, SEEK_SET);
206 }
207