NASM 0.98.22
[nasm.git] / rdoff / rdoff.c
blob80b96cc2cf3d5a8c1379c716fb87e89794bb4b9b
1 /* rdoff.c library of routines for manipulating rdoff files
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * Permission to use this file in your own projects is granted, as long
9 * as acknowledgement is given in an appropriate manner to its authors,
10 * with instructions of how to obtain a copy via ftp.
13 /* TODO: The functions in this module assume they are running
14 * on a little-endian machine. This should be fixed to
15 * make it portable.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
23 #include "multboot.h"
24 #include "rdoff.h"
26 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
27 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
28 s1),s2)
31 * Comment this out to allow the module to read & write header record types
32 * that it isn't aware of. With this defined, unrecognised header records
33 * will generate error number 8, reported as 'unknown extended header record'.
36 #define STRICT_ERRORS
38 /* ========================================================================
39 * Code for memory buffers (for delayed writing of header until we know
40 * how long it is).
41 * ======================================================================== */
44 memorybuffer * newmembuf()
46 memorybuffer * t;
48 t = malloc(sizeof(memorybuffer));
49 if (!t) return NULL;
51 t->length = 0;
52 t->next = NULL;
53 return t;
56 void membufwrite(memorybuffer *const b, void *data, int bytes)
58 int16 w;
59 long l;
61 if (b->next) { /* memory buffer full - use next buffer */
62 membufwrite(b->next,data,bytes);
63 return;
66 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
67 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN))
70 /* buffer full and no next allocated... allocate and initialise next
71 * buffer */
72 b->next = newmembuf();
73 membufwrite(b->next,data,bytes);
74 return;
77 switch(bytes) {
78 case -4: /* convert to little-endian */
79 l = * (long *) data ;
80 b->buffer[b->length++] = l & 0xFF;
81 l >>= 8 ;
82 b->buffer[b->length++] = l & 0xFF;
83 l >>= 8 ;
84 b->buffer[b->length++] = l & 0xFF;
85 l >>= 8 ;
86 b->buffer[b->length++] = l & 0xFF;
87 break;
89 case -2:
90 w = * (int16 *) data ;
91 b->buffer[b->length++] = w & 0xFF;
92 w >>= 8 ;
93 b->buffer[b->length++] = w & 0xFF;
94 break;
96 default:
97 while(bytes--) {
98 b->buffer[b->length++] = *(* (unsigned char **) &data);
100 (* (unsigned char **) &data)++ ;
102 break;
106 void membufdump(memorybuffer *b,FILE *fp)
108 if (!b) return;
110 fwrite (b->buffer, 1, b->length, fp);
112 membufdump(b->next,fp);
115 int membuflength(memorybuffer *b)
117 if (!b) return 0;
118 return b->length + membuflength(b->next);
121 void freemembuf(memorybuffer *b)
123 if (!b) return;
124 freemembuf(b->next);
125 free(b);
128 /* =========================================================================
129 General purpose routines and variables used by the library functions
130 ========================================================================= */
133 * translatelong() and translateshort()
135 * translate from little endian to local representation
137 long translatelong(long in)
139 long r;
140 unsigned char *i;
142 i = (unsigned char *)&in;
143 r = i[3];
144 r = (r << 8) + i[2];
145 r = (r << 8) + i[1];
146 r = (r << 8) + *i;
148 return r;
151 int16 translateshort(int16 in)
153 int16 r;
154 unsigned char * i;
156 i = (unsigned char *)&in;
157 r = (i[1] << 8) + i[0];
159 return r;
162 const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */
164 const char *rdf_errors[11] = {
165 "no error occurred","could not open file","invalid file format",
166 "error reading file","unknown error","header not read",
167 "out of memory", "RDOFF v1 not supported",
168 "unknown extended header record",
169 "header record of known type but unknown length",
170 "no such segment"};
172 int rdf_errno = 0;
174 /* ========================================================================
175 The library functions
176 ======================================================================== */
178 int rdfopen(rdffile *f, const char *name)
180 FILE * fp;
182 fp = fopen(name,"rb");
183 if (!fp) return rdf_errno = 1; /* error 1: file open error */
185 return rdfopenhere(f,fp,NULL,name);
188 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
190 char buf[8];
191 long initpos;
192 long l;
193 int16 s;
195 if (translatelong(0x01020304) != 0x01020304)
196 { /* fix this to be portable! */
197 fputs("*** this program requires a little endian machine\n",stderr);
198 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
199 exit(3);
202 f->fp = fp;
203 initpos = ftell(fp);
205 fread(buf,6,1,f->fp); /* read header */
206 buf[6] = 0;
208 if (strcmp(buf,RDOFFId)) {
209 fclose(f->fp);
210 if (!strcmp(buf,"RDOFF1"))
211 return rdf_errno = 7; /* error 7: RDOFF 1 not supported */
212 return rdf_errno = 2; /* error 2: invalid file format */
215 if (fread(&l,1,4,f->fp) != 4 ||
216 fread(&f->header_len,1,4,f->fp) != 4) {
217 fclose(f->fp);
218 return rdf_errno = 3; /* error 3: file read error */
221 f->header_ofs = ftell(f->fp);
222 f->eof_offset = f->header_ofs + translatelong(l) - 4;
224 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
225 fclose(f->fp);
226 return rdf_errno = 2; /* seek past end of file...? */
229 if (fread(&s,1,2,f->fp) != 2) {
230 fclose(f->fp);
231 return rdf_errno = 3;
234 f->nsegs = 0;
236 while (s != 0)
238 f->seg[f->nsegs].type = s;
239 if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
240 fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
241 fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4)
243 fclose(f->fp);
244 return rdf_errno = 3;
247 f->seg[f->nsegs].offset = ftell(f->fp);
248 if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
249 fclose(f->fp);
250 return rdf_errno = 2;
252 f->nsegs++;
254 if (fread(&s,1,2,f->fp) != 2) {
255 fclose(f->fp);
256 return rdf_errno = 3;
260 if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */
262 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
263 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
265 fseek(f->fp,initpos,SEEK_SET);
266 f->header_loc = NULL;
268 f->name = newstr(name);
269 f->refcount = refcount;
270 if (refcount) (*refcount)++;
271 return 0;
274 int rdfclose(rdffile *f)
276 if (! f->refcount || ! --(*f->refcount))
278 fclose(f->fp);
279 f->fp = NULL;
281 free(f->name);
283 return 0;
286 void rdfperror(const char *app,const char *name)
288 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
289 if (rdf_errno == 1 || rdf_errno == 3)
291 perror(app);
296 int rdffindsegment(rdffile * f, int segno)
298 int i;
299 for (i = 0; i < f->nsegs; i++)
300 if (f->seg[i].number == segno) return i;
301 return -1;
304 int rdfloadseg(rdffile *f,int segment,void *buffer)
306 long fpos;
307 long slen;
309 switch(segment) {
310 case RDOFF_HEADER:
311 fpos = f->header_ofs;
312 slen = f->header_len;
313 f->header_loc = (byte *)buffer;
314 f->header_fp = 0;
315 break;
316 default:
317 if (segment < f->nsegs) {
318 fpos = f->seg[segment].offset;
319 slen = f->seg[segment].length;
320 f->seg[segment].data = (byte *)buffer;
322 else {
323 return rdf_errno = 10; /* no such segment */
327 if (fseek(f->fp,fpos,SEEK_SET))
328 return rdf_errno = 4;
330 if (fread(buffer,1,slen,f->fp) != slen)
331 return rdf_errno = 3;
333 return 0;
336 /* Macros for reading integers from header in memory */
338 #define RI8(v) v = f->header_loc[f->header_fp++]
339 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
340 (f->header_loc[f->header_fp+1] << 8)); \
341 f->header_fp += 2; }
343 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
344 (f->header_loc[f->header_fp+1] << 8) + \
345 (f->header_loc[f->header_fp+2] << 16) + \
346 (f->header_loc[f->header_fp+3] << 24)); \
347 f->header_fp += 4; }
349 #define RS(str,max) { for(i=0;i<max;i++){\
350 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
352 rdfheaderrec *rdfgetheaderrec(rdffile *f)
354 static rdfheaderrec r;
355 int i;
357 if (!f->header_loc) {
358 rdf_errno = 5;
359 return NULL;
362 if (f->header_fp >= f->header_len) return 0;
364 RI8(r.type);
365 RI8(r.g.reclen);
367 switch(r.type) {
368 case 1: /* Relocation record */
369 case 6:
370 if (r.r.reclen != 8) {
371 rdf_errno = 9;
372 return NULL;
374 RI8(r.r.segment);
375 RI32(r.r.offset);
376 RI8(r.r.length);
377 RI16(r.r.refseg);
378 break;
380 case 2: /* Imported symbol record */
381 case 7:
382 RI16(r.i.segment);
383 RS(r.i.label,32);
384 break;
386 case 3: /* Exported symbol record */
387 RI8(r.e.flags);
388 RI8(r.e.segment);
389 RI32(r.e.offset);
390 RS(r.e.label,32);
391 break;
393 case 4: /* DLL record */
394 RS(r.d.libname,127);
395 break;
397 case 5: /* BSS reservation record */
398 if (r.r.reclen != 4) {
399 rdf_errno = 9;
400 return NULL;
402 RI32(r.b.amount);
403 break;
405 case 8: /* Module name record */
406 RS(r.m.modname,127);
407 break;
409 default:
410 #ifdef STRICT_ERRORS
411 rdf_errno = 8; /* unknown header record */
412 return NULL;
413 #else
414 for (i = 0; i < r.g.reclen; i++)
415 RI8(r.g.data[i]);
416 #endif
418 return &r;
421 void rdfheaderrewind(rdffile *f)
423 f->header_fp = 0;
427 rdf_headerbuf * rdfnewheader(void)
429 rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf));
430 if (hb == NULL) return NULL;
432 hb->buf = newmembuf();
433 hb->nsegments = 0;
434 hb->seglength = 0;
436 return hb;
439 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
441 #ifndef STRICT_ERRORS
442 int i;
443 #endif
444 membufwrite(h->buf,&r->type,1);
445 membufwrite(h->buf,&r->g.reclen,1);
447 switch (r->type)
449 case 1:
450 case 6:
451 membufwrite(h->buf,&r->r.segment,1);
452 membufwrite(h->buf,&r->r.offset,-4);
453 membufwrite(h->buf,&r->r.length,1);
454 membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
455 break;
457 case 2: /* import */
458 case 7:
459 membufwrite(h->buf,&r->i.segment,-2);
460 membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
461 break ;
463 case 3: /* export */
464 membufwrite(h->buf,&r->e.flags,1);
465 membufwrite(h->buf,&r->e.segment,1);
466 membufwrite(h->buf,&r->e.offset,-4);
467 membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
468 break ;
470 case 4: /* DLL */
471 membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
472 break ;
474 case 5: /* BSS */
475 membufwrite(h->buf,&r->b.amount,-4);
476 break ;
478 case 8: /* Module name */
479 membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1);
480 break ;
482 #ifdef _MULTBOOT_H
483 case 9: /* MultiBoot header */
484 membufwrite(h->buf,&r->mbh.mb,sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE);
485 break ;
486 #endif
488 default:
489 #ifdef STRICT_ERRORS
490 return (rdf_errno = 8);
491 #else
492 for (i = 0; i < r->g.reclen; i++)
493 membufwrite(h->buf, r->g.data[i], 1);
494 #endif
496 return 0;
499 int rdfaddsegment(rdf_headerbuf *h, long seglength)
501 h->nsegments ++;
502 h->seglength += seglength;
503 return 0;
506 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
508 long l, l2;
510 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
512 l = membuflength (h->buf);
513 l2 = l + 14 + 10*h->nsegments + h->seglength;
514 l = translatelong(l);
515 l2 = translatelong(l2);
516 fwrite (&l2, 4, 1, fp); /* object length */
517 fwrite (&l, 4, 1, fp); /* header length */
519 membufdump(h->buf, fp);
521 return 0; /* no error handling in here... CHANGE THIS! */
524 void rdfdoneheader(rdf_headerbuf * h)
526 freemembuf(h->buf);
527 free(h);