[Debootloaders-devel] r89 - trunk/rsrce
Jeremie Koenig
jkoenig-guest at costa.debian.org
Wed Jul 12 01:40:09 UTC 2006
Author: jkoenig-guest
Date: 2006-07-12 01:40:06 +0000 (Wed, 12 Jul 2006)
New Revision: 89
Added:
trunk/rsrce/rsrc-fmt.h
Modified:
trunk/rsrce/resource.c
trunk/rsrce/resource.h
Log:
- The data structure of in-memory resource forks has been changed to avoid
memory management nightmare. We no longer keep the buffer read from the file
and (unsuccessfully) attempt to keep it sane when changes occur.
- Structure declarations related to the format of resource forks are now in
rsrc-fmt.h; the number of types has been included into 'struct resmaphdr' and
'struct restypelist' has been removed.
- Check the pointers to the end of name and data as well as the beginning.
Modified: trunk/rsrce/resource.c
===================================================================
--- trunk/rsrce/resource.c 2006-07-12 00:52:59 UTC (rev 88)
+++ trunk/rsrce/resource.c 2006-07-12 01:40:06 UTC (rev 89)
@@ -22,16 +22,16 @@
#include <ctype.h>
#include <assert.h>
#include <netinet/in.h>
-#include <endian.h>
#include "resource.h"
+#include "rsrc-fmt.h"
struct resource {
struct res_fork *f;
+ int ti;
struct resource *next;
- restype_t *type;
int16_t id;
uint8_t attr;
char *name, *data;
@@ -39,59 +39,72 @@
};
struct res_fork {
- struct resource *rlist;
-
- char *buf;
- int len;
uint16_t attr;
int rlen; /* Reserved space at beginning */
+ int tn;
+ struct {
+ restype_t type;
+ struct resource *rlist;
+ } *tt;
};
+static int res_lookup_type(struct res_fork *f, restype_t type)
+{
+ int i;
+ for(i=0; (i < f->tn) && memcmp(f->tt[i].type, type, sizeof type); i++);
+ return (i < f->tn) ? i : -1;
+}
+
+static struct resource **res_lookup_rp(struct res_fork *f, int ti, int id)
+{
+ struct resource **rp;
+ for(rp = &f->tt[ti].rlist; *rp && (*rp)->id != id; rp = &(*rp)->next);
+ return rp;
+}
+
struct resource *res_lookup(struct res_fork *f, restype_t type, int16_t id)
{
- struct resource *r;
- for(r=f->rlist ; r ; r=r->next) {
- if(memcmp(*r->type, type, sizeof(type)) == 0 &&
- (id == 0 || r->id == id)) return r;
- }
- return NULL;
+ int ti = res_lookup_type(f, type);
+ return ti >= 0 ? *res_lookup_rp(f, ti, id) : NULL;
}
-static void *res_grab(struct res_fork *f, void *data, int len)
+
+static int res_getti(struct res_fork *f, restype_t type)
{
- if((char *) data >= f->buf && (char *) data < f->buf + f->len) {
- return data;
- } else {
- f->len += len;
- f->buf = realloc(f->buf, f->len);
- memcpy(f->buf + f->len - len, data, len);
- return f->buf + f->len - len;
+ int ti;
+
+ ti = res_lookup_type(f, type);
+ if(ti < 0) {
+ ti = f->tn++;
+ f->tt = realloc(f->tt, f->tn * sizeof *f->tt);
+ memcpy(f->tt[ti].type, type, sizeof type);
+ f->tt[ti].rlist = NULL;
}
+
+ return ti;
}
struct resource *res_new(struct res_fork *f, restype_t type, int16_t id)
{
struct resource *r, **rp;
+ int ti = res_getti(f, type);
+ /* append to the type's resource list's tail */
+ rp = res_lookup_rp(f, ti, -1);
+ if(*rp) {
+ fprintf(stderr, "W: reusing duplicate resource %.4s:%d!\n",
+ type, id);
+ return *rp;
+ }
+
r = malloc(sizeof(*r));
memset(r, 0, sizeof(*r));
r->f = f;
+ r->ti = ti;
r->id = id;
- for(rp = &f->rlist ; *rp && memcmp(*(*rp)->type, type, sizeof(type)) ;
- rp = &(*rp)->next);
- if(*rp) {
- r->type = (*rp)->type;
- while(*rp && ((*rp)->type == r->type))
- rp = &(*rp)->next;
- } else {
- r->type = res_grab(f, type, sizeof(type));
- }
-
- r->next = *rp;
*rp = r;
-
return r;
}
@@ -103,35 +116,29 @@
void res_setdata(struct resource *r, void *p, int len)
{
- if(len > r->datalen) {
- r->data = res_grab(r->f, p, len);
- r->datalen = len;
- } else {
+ if(r->data) free(r->data);
+
+ r->datalen = len;
+ if(len) {
+ r->data = malloc(len);
memcpy(r->data, p, len);
- r->datalen = len;
- }
+ } else
+ r->data = NULL;
}
void res_gettype(struct resource *r, restype_t type)
{
- memcpy(type, r->type, sizeof(type));
+ memcpy(type, r->f->tt[r->ti].type, sizeof type);
}
-/* FIXME: implementer. */
-void res_settype(struct resource *r, restype_t type)
-{
-}
-
void res_rename(struct resource *r, char *name, int nlen)
{
- if(nlen == -1) nlen = strlen(name);
- if(!r->name || nlen > r->namelen) {
- r->name = res_grab(r->f, name, nlen);
- r->namelen = nlen;
- } else {
- memcpy(r->name, name, nlen);
- r->namelen = nlen;
- }
+ if(r->name) free(r->name);
+
+ r->namelen = (nlen >= 0) ? nlen : strlen(name);
+ r->name = malloc(r->namelen + 1);
+ memcpy(r->name, name, r->namelen);
+ r->name[r->namelen] = '\0';
}
const char * const res_attrch = "7spLPlw0";
@@ -163,138 +170,105 @@
}
}
+static void res_deltype(struct res_fork *f, int ti)
+{
+ struct resource *r;
+
+ memmove(f->tt + ti, f->tt + ti + 1, (--f->tn - ti) * sizeof *f->tt);
+ f->tt = realloc(f->tt, f->tn * sizeof *f->tt);
+
+ while(ti < f->tn) {
+ for(r = f->tt[ti].rlist; r; r = r->next)
+ r->ti = ti;
+ ti++;
+ }
+}
+
void res_delete(struct resource *r)
{
struct resource **rp;
-
- for(rp = &r->f->rlist ; *rp && *rp != r ; rp = &(*rp)->next);
+
+ rp = res_lookup_rp(r->f, r->ti, r->id);
assert(*rp);
*rp = r->next;
-
+
+ if(!r->f->tt[r->ti].rlist)
+ res_deltype(r->f, r->ti);
+
free(r);
}
-void res_printinfo(struct resource *r, FILE *s)
+static void res_printinfo(struct resource *r, FILE *s)
{
int i;
-
- fwrite(r->type, 4, 1, s);
- fprintf(s, " %11d ", r->id);
+
+ fprintf(s, "%.4s %11d ", r->f->tt[r->ti].type, r->id);
for(i=0 ; i<8 ; i++)
fprintf(s, "%c", ((r->attr << i) & 0x80) ? res_attrch[i] : '-');
fprintf(s, " %10d", r->datalen);
- if(r->name) {
- fprintf(s, " ");
- fwrite(r->name, 1, r->namelen, s);
- }
+ if(r->name)
+ fprintf(s, " %s", r->name);
fprintf(s, "\n");
}
void res_ls(FILE *s, struct res_fork *f)
{
struct resource *r;
- for(r = f->rlist ; r ; r = r->next)
- res_printinfo(r, s);
+ int ti;
+
+ for(ti = 0; ti < f->tn; ti++)
+ for(r = f->tt[ti].rlist ; r ; r = r->next)
+ res_printinfo(r, s);
}
-/* Resource header */
-struct reshdr {
- uint32_t dofs, mofs, dlen, mlen;
-};
-
struct res_fork *res_newfork()
{
struct res_fork *f;
f = malloc(sizeof(*f));
- f->buf = NULL;
- f->len = 0;
+ memset(f, 0, sizeof *f);
f->rlen = sizeof(struct reshdr);
- f->attr = 0;
- f->rlist = NULL;
return f;
}
void res_delfork(struct res_fork *f)
{
- struct resource *r;
-
- if(f->buf) free(f->buf);
- while(f->rlist) {
- r = f->rlist->next;
- free(f->rlist);
- f->rlist = r;
- }
+ while(f->tn) res_delete(f->tt[0].rlist);
free(f);
}
-/* Resource map header */
-struct resmaphdr {
- uint8_t reserved[22];
- uint16_t attr;
- uint16_t tlistofs;
- uint16_t nlistofs;
-};
+/*** Reading and writing ***/
-/* Resource type list entry */
-struct restype {
- restype_t type;
- uint16_t rnum;
- uint16_t refofs;
-};
-struct restypelist {
- uint16_t tnum;
- struct restype type[0];
+struct res_parsecontext {
+ struct res_fork *f;
+ char *buf, *dbase, *tbase, *nbase;
+ int len;
};
-/* Resource reference list entry */
-struct resref {
- uint16_t id;
- uint16_t nameofs;
- unsigned int attr:8, dataofs:24;
- uint32_t reserved;
-};
+#define CHECKPTR(p, m) \
+if((char *)(p) < c->buf || (char *)(p) + sizeof(*(p)) > c->buf + c->len) { \
+ fprintf(stderr, "Wild " m " offset!\n"); \
+ return -1; \
+}
-/* Used to manipulate the 3-bytes offset */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define ntoh3(a) (ntohl(a) >> 8)
-#define hton3(a) (htonl(a) >> 8)
-#else
-#define ntoh3(a) (a)
-#define hton3(a) (a)
-#endif
-
-/* Resource name list entry */
-struct resname {
- uint8_t len;
- char name[0];
-};
-
-/* Resource data */
-struct resdata {
- uint32_t len;
- uint8_t data[0];
-};
-
-
#define BUFSZ 4096
#define MAXSZ (100*1024*1024)
-static int res_readbuf(struct res_fork *f, FILE *stream)
+static int res_readbuf(struct res_parsecontext *c, FILE *stream)
{
int n;
do {
- f->buf = realloc(f->buf, f->len + BUFSZ);
- n = fread(f->buf + f->len, 1, BUFSZ, stream);
- f->len += n;
- } while(n == BUFSZ && f->len < MAXSZ);
-
- if(f->len >= MAXSZ) {
+ c->buf = realloc(c->buf, c->len + BUFSZ);
+ n = fread(c->buf + c->len, 1, BUFSZ, stream);
+ c->len += n;
+ } while(n == BUFSZ && c->len < MAXSZ);
+
+ if(c->len >= MAXSZ) {
fprintf(stderr, "This resource fork is rather huge !\n");
return -1;
} else if(!feof(stream)) {
@@ -305,14 +279,7 @@
return 0;
}
-#define CHECKPTR(p, m) \
-if((char *)(p) < f->buf || (char *)(p) + sizeof(*(p)) > f->buf + f->len) { \
- fprintf(stderr, "Wild " m " offset!\n"); \
- return -1; \
-}
-
-static int res_parse_reflist(struct res_fork *f, char *dbase, char *tbase,
- char *nbase, struct restype *t)
+static int res_parse_reflist(struct res_parsecontext *c, struct restype *t)
{
struct resource *r;
struct resref *ref;
@@ -320,168 +287,187 @@
struct resdata *data;
int i;
- ref = (struct resref *) (tbase + ntohs(t->refofs));
+ ref = (struct resref *) (c->tbase + ntohs(t->refofs));
for(i=0 ; i < ntohs(t->rnum) + 1 ; i++) {
CHECKPTR(ref+i, "reference");
- r = res_new(f, t->type, ntohs(ref[i].id));
+ r = res_new(c->f, t->type, ntohs(ref[i].id));
r->attr = ref[i].attr;
if(ref[i].nameofs != htons(-1)) {
- name = (struct resname *)(nbase+ntohs(ref[i].nameofs));
+ name = (struct resname *)
+ (c->nbase + ntohs(ref[i].nameofs));
CHECKPTR(name, "name");
+ CHECKPTR(name->name + name->len - 1, "name");
res_rename(r, name->name, name->len);
}
- data = (struct resdata *)(dbase + ntoh3(ref[i].dataofs));
+ data = (struct resdata *)(c->dbase + ntoh3(ref[i].dataofs));
CHECKPTR(data, "data");
+ CHECKPTR(data->data + ntohl(data->len) - 1, "data");
res_setdata(r, data->data, ntohl(data->len));
}
return 0;
}
-static int res_parse_typelist(struct res_fork *f, char *dbase, char *tbase,
- char *nbase)
+static int res_parse_typelist(struct res_parsecontext *c, int tn)
{
- struct restypelist *l = (struct restypelist *) tbase;
+ struct restype *l = (struct restype *) c->tbase;
int i;
- for(i=0 ; i < ntohs(l->tnum) + 1 ; i++) {
- if(res_parse_reflist(f, dbase, tbase, nbase, l->type + i) < 0)
+ for(i=0 ; i < tn ; i++) {
+ if(res_parse_reflist(c, l + i) < 0)
return -1;
}
return 0;
}
-static int res_parsebuf(struct res_fork *f)
+static int res_parsebuf(struct res_parsecontext *c)
{
struct reshdr *rh;
struct resmaphdr *mh;
- rh = (struct reshdr *) f->buf;
- mh = (struct resmaphdr *) (f->buf + ntohl(rh->mofs));
+ rh = (struct reshdr *) c->buf;
+ mh = (struct resmaphdr *) (c->buf + ntohl(rh->mofs));
CHECKPTR(mh, "resource map");
- f->rlen = ntohl(rh->dofs) < ntohl(rh->mofs)
+ c->f->rlen = ntohl(rh->dofs) < ntohl(rh->mofs)
? ntohl(rh->dofs) : ntohl(rh->mofs);
- return res_parse_typelist(f, f->buf + ntohl(rh->dofs),
- (char *) mh + ntohs(mh->tlistofs),
- (char *) mh + ntohs(mh->nlistofs));
+
+ c->dbase = c->buf + ntohl(rh->dofs);
+ c->tbase = (char *) mh + ntohs(mh->tlistofs);
+ c->nbase = (char *) mh + ntohs(mh->nlistofs);
+ return res_parse_typelist(c, ntohs(mh->tnum) + 1);
}
struct res_fork *res_read(FILE *stream)
{
- struct res_fork *f;
+ struct res_parsecontext c;
+ int ok;
- f = res_newfork();
+ memset(&c, 0, sizeof c);
+ c.f = res_newfork();
+ ok = (res_readbuf(&c, stream) >= 0) && (res_parsebuf(&c) >= 0);
+ free(c.buf);
- if(res_readbuf(f, stream) < 0 || res_parsebuf(f) < 0) {
- res_delfork(f);
+ if(!ok) {
+ res_delfork(c.f);
return NULL;
}
-
- return f;
+
+ return c.f;
}
-void res_recreate(struct res_fork *f)
+
+static int res_write_data(struct resource *r, FILE *stream)
{
+ uint32_t len = htonl(r->datalen);
+
+ if(fwrite(&len, sizeof len, 1, stream) != 1)
+ return -1;
+ if(fwrite(r->data, 1, r->datalen, stream) != r->datalen)
+ return -1;
+
+ return 0;
+}
+
+int res_write(struct res_fork *f, FILE *stream)
+{
+ int mlen, dlen, nlen, rlen;
+ int rnum, dofs, nofs, rofs;
+
+ struct reshdr rh;
+ struct resmaphdr mh;
+ struct restype type;
+ struct resref ref;
+
struct resource *r;
- restype_t *t;
- char *buf;
- int tnum, rnum;
- int mlen, dlen, nlen, rlen, len;
+ int ti, i;
- struct reshdr *rh;
- struct resmaphdr *mh;
- struct restypelist *tl;
- struct restype *type;
- struct resref *ref;
- struct resname *name, *name0;
- struct resdata *data, *data0;
-
- t = NULL;
+ /* compute the lenght of parts */
dlen = 0;
- mlen = sizeof(struct resmaphdr) + sizeof(struct restypelist);
+ mlen = sizeof(struct resmaphdr);
rlen = 0;
nlen = 0;
- tnum = 0;
- rnum = 0;
- for(r = f->rlist ; r ; r = r->next) {
- dlen += sizeof(struct resdata) + r->datalen;
- if(r->type != t) {
- mlen += sizeof(struct restype);
- tnum++;
- t = r->type;
- }
- rlen += sizeof(struct resref);
- if(r->name)
+ for(ti = 0; ti < f->tn; ti++) {
+ mlen += sizeof(struct restype);
+ for(r = f->tt[ti].rlist ; r ; r = r->next) {
+ dlen += sizeof(struct resdata) + r->datalen;
+ rlen += sizeof(struct resref);
nlen += sizeof(struct resname) + r->namelen;
- rnum++;
+ }
}
- len = f->rlen + dlen + mlen + rlen + nlen;
- buf = malloc(len);
+ /* write the resource fork header */
+ rh.dofs = htonl(f->rlen);
+ rh.mofs = htonl(f->rlen + dlen);
+ rh.dlen = htonl(dlen);
+ rh.mlen = htonl(mlen + rlen + nlen);
+ if(fwrite(&rh, sizeof rh, 1, stream) != 1)
+ return -1;
- rh = (struct reshdr *) buf;
- data = data0 = (struct resdata *) (buf + f->rlen);
- mh = (struct resmaphdr*) (buf + f->rlen + dlen);
- tl = (struct restypelist *) (mh + 1);
- type = tl->type;
- ref = (struct resref *) (buf + f->rlen + dlen + mlen);
- name = name0 = (struct resname *) (buf + f->rlen + dlen + mlen + rlen);
-
- rh->dofs = htonl(f->rlen);
- rh->dlen = htonl(dlen);
- rh->mofs = htonl(f->rlen + dlen);
- rh->mlen = htonl(mlen + rlen + nlen);
-
- memset(mh->reserved, 0, sizeof(mh->reserved));
- mh->attr = htons(f->attr);
- mh->tlistofs = htons(sizeof(*mh));
- mh->nlistofs = htons(mlen + rlen);
- tl->tnum = htons(tnum - 1);
+ /* pad the reserved zone with zeros */
+ for(i = sizeof rh; i < f->rlen; i++)
+ if(fputc(0, stream) == EOF)
+ return -1;
- t = NULL;
- for(r = f->rlist ; r ; r = r->next) {
- if(r->type != t) {
- if(t) type++;
- type->refofs = htons((char*) ref - (char*) tl);
- memcpy(type->type, r->type, sizeof(restype_t));
- type->rnum = htons(0);
- t = r->type;
- } else {
- type->rnum = htons(ntohs(type->rnum) + 1);
- }
- r->type = &type->type;
-
- ref->id = htons(r->id);
- ref->nameofs = htons(r->name ? (char*)name - (char*)name0 : -1);
- ref->dataofs = hton3((char *) data - (char *) data0);
- ref->attr = r->attr;
- ref->reserved = htonl(0);
- ref++;
+ /* write the resource data */
+ for(ti = 0; ti < f->tn; ti++)
+ for(r = f->tt[ti].rlist; r; r = r->next)
+ if(res_write_data(r, stream))
+ return -1;
- if(r->name) {
- name->len = r->namelen;
- memcpy(name->name, r->name, r->namelen);
- r->name = name->name;
- name = (struct resname *) (name->name + name->len);
- }
+ /* write the resource map header */
+ memset(&mh.reserved, 0, sizeof mh.reserved);
+ mh.attr = htons(f->attr);
+ mh.tlistofs = htons(sizeof mh);
+ mh.nlistofs = htons(mlen + rlen);
+ mh.tnum = htons(f->tn - 1);
+ if(fwrite(&mh, sizeof mh, 1, stream) != 1)
+ return -1;
- data->len = htonl(r->datalen);
- memcpy(data->data, r->data, r->datalen);
- r->data = data->data;
- data = (struct resdata *) (data->data + r->datalen);
+ /* write the type list */
+ rofs = f->tn * sizeof type;
+ for(ti = 0; ti < f->tn; ti++) {
+ /* count resources */
+ for(r = f->tt[ti].rlist, rnum = 0; r; r = r->next, rnum++);
+
+ memcpy(type.type, &f->tt[ti].type, sizeof(restype_t));
+ type.rnum = htons(rnum - 1);
+ type.refofs = htons(rofs);
+ if(fwrite(&type, sizeof type, 1, stream) != 1)
+ return -1;
+
+ rofs += rnum * sizeof ref;
}
- free(f->buf);
- f->buf = buf;
- f->len = len;
-}
+ /* write the reference lists */
+ nofs = dofs = 0;
+ for(ti = 0; ti < f->tn; ti++)
+ for(r = f->tt[ti].rlist; r; r = r->next) {
+ ref.id = htons(r->id);
+ ref.nameofs = htons(r->name ? nofs : -1);
+ ref.dataofs = hton3(dofs);
+ ref.attr = r->attr;
+ ref.reserved = htonl(0);
+ if(fwrite(&ref, sizeof ref, 1, stream) != 1)
+ return -1;
-int res_write(struct res_fork *f, FILE *stream)
-{
- res_recreate(f);
- return fwrite(f->buf, 1, f->len, stream) == f->len ? 0 : -1;
+ nofs += r->name ? sizeof (struct resname) + r->namelen : 0;
+ dofs += sizeof (struct resdata) + r->datalen;
+ }
+
+ /* write the name list */
+ for(ti = 0; ti < f->tn; ti++)
+ for(r = f->tt[ti].rlist; r; r = r->next) {
+ if(!r->name) continue;
+
+ if(fputc(r->namelen, stream) != r->namelen)
+ return -1;
+ if(fwrite(r->name, 1, r->namelen, stream) != r->namelen)
+ return -1;
+ }
+
+ return 0;
}
Modified: trunk/rsrce/resource.h
===================================================================
--- trunk/rsrce/resource.h 2006-07-12 00:52:59 UTC (rev 88)
+++ trunk/rsrce/resource.h 2006-07-12 01:40:06 UTC (rev 89)
@@ -29,7 +29,6 @@
void res_getdata(struct resource *r, void **dp, int *len);
void res_setdata(struct resource *r, void *p, int len);
void res_gettype(struct resource *r, restype_t type);
-void res_settype(struct resource *r, restype_t type);
void res_rename(struct resource *r, char *name, int nlen);
void res_chattr(struct resource *r, const char *spec);
void res_delete(struct resource *r);
Added: trunk/rsrce/rsrc-fmt.h
===================================================================
--- trunk/rsrce/rsrc-fmt.h 2006-07-12 00:52:59 UTC (rev 88)
+++ trunk/rsrce/rsrc-fmt.h 2006-07-12 01:40:06 UTC (rev 89)
@@ -0,0 +1,51 @@
+
+/* Resource header */
+struct reshdr {
+ uint32_t dofs, mofs, dlen, mlen;
+};
+
+/* Resource map header */
+struct resmaphdr {
+ uint8_t reserved[22];
+ uint16_t attr;
+ uint16_t tlistofs;
+ uint16_t nlistofs;
+ uint16_t tnum;
+};
+
+/* Resource type list entry */
+struct restype {
+ restype_t type;
+ uint16_t rnum;
+ uint16_t refofs;
+};
+
+/* Resource reference list entry */
+struct resref {
+ uint16_t id;
+ uint16_t nameofs;
+ unsigned int attr:8, dataofs:24;
+ uint32_t reserved;
+};
+
+/* Resource name list entry */
+struct resname {
+ uint8_t len;
+ char name[0];
+};
+
+/* Resource data */
+struct resdata {
+ uint32_t len;
+ uint8_t data[0];
+};
+
+/* Useful macros for the 3-bytes data offset */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ntoh3(a) (ntohl(a) >> 8)
+#define hton3(a) (htonl(a) >> 8)
+#else
+#define ntoh3(a) (a)
+#define hton3(a) (a)
+#endif
+
More information about the Debootloaders-devel
mailing list