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