NASM 0.94
[nasm.git] / rdoff / rdoff.c
blob96620ecc683dd0e32e6720d1a0d8af18d73a6602
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.
7 */
9 /* TODO: The functions in this module assume they are running
10 * on a little-endian machine. This should be fixed to
11 * make it portable.
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <errno.h>
19 #include "rdoff.h"
21 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
22 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
23 s1),s2)
25 /* ========================================================================
26 * Code for memory buffers (for delayed writing of header until we know
27 * how long it is).
28 * ======================================================================== */
31 memorybuffer * newmembuf(){
32 memorybuffer * t;
34 t = malloc(sizeof(memorybuffer));
36 t->length = 0;
37 t->next = NULL;
38 return t;
41 void membufwrite(memorybuffer *b, void *data, int bytes) {
42 int16 w;
43 long l;
45 if (b->next) { /* memory buffer full - use next buffer */
46 membufwrite(b->next,data,bytes);
47 return;
49 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
50 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) {
52 /* buffer full and no next allocated... allocate and initialise next
53 * buffer */
55 b->next = newmembuf();
56 membufwrite(b->next,data,bytes);
59 switch(bytes) {
60 case -4: /* convert to little-endian */
61 l = * (long *) data ;
62 b->buffer[b->length++] = l & 0xFF;
63 l >>= 8 ;
64 b->buffer[b->length++] = l & 0xFF;
65 l >>= 8 ;
66 b->buffer[b->length++] = l & 0xFF;
67 l >>= 8 ;
68 b->buffer[b->length++] = l & 0xFF;
69 break;
71 case -2:
72 w = * (int16 *) data ;
73 b->buffer[b->length++] = w & 0xFF;
74 w >>= 8 ;
75 b->buffer[b->length++] = w & 0xFF;
76 break;
78 default:
79 while(bytes--) {
80 b->buffer[b->length++] = *(* (unsigned char **) &data);
82 (* (unsigned char **) &data)++ ;
84 break;
88 void membufdump(memorybuffer *b,FILE *fp)
90 if (!b) return;
92 fwrite (b->buffer, 1, b->length, fp);
94 membufdump(b->next,fp);
97 int membuflength(memorybuffer *b)
99 if (!b) return 0;
100 return b->length + membuflength(b->next);
103 void freemembuf(memorybuffer *b)
105 if (!b) return;
106 freemembuf(b->next);
107 free(b);
110 /* =========================================================================
111 General purpose routines and variables used by the library functions
112 ========================================================================= */
114 long translatelong(long in) { /* translate from little endian to
115 local representation */
116 long r;
117 unsigned char *i;
119 i = (unsigned char *)&in;
120 r = i[3];
121 r = (r << 8) + i[2];
122 r = (r << 8) + i[1];
123 r = (r << 8) + *i;
125 return r;
128 const char *RDOFFId = "RDOFF1"; /* written to the start of RDOFF files */
130 const char *rdf_errors[7] = {
131 "no error occurred","could not open file","invalid file format",
132 "error reading file","unknown error","header not read",
133 "out of memory"};
135 int rdf_errno = 0;
137 /* ========================================================================
138 The library functions
139 ======================================================================== */
141 int rdfopen(rdffile *f, const char *name)
143 FILE * fp;
145 fp = fopen(name,"rb");
146 if (!fp) return rdf_errno = 1; /* error 1: file open error */
148 return rdfopenhere(f,fp,NULL,"");
151 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, char *name)
153 char buf[8];
154 long initpos;
156 if (translatelong(0x01020304) != 0x01020304)
157 { /* fix this to be portable! */
158 fputs("*** this program requires a little endian machine\n",stderr);
159 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
160 exit(3);
163 f->fp = fp;
164 initpos = ftell(fp);
166 fread(buf,6,1,f->fp); /* read header */
167 buf[6] = 0;
169 if (strcmp(buf,RDOFFId)) {
170 fclose(f->fp);
171 return rdf_errno = 2; /* error 2: invalid file format */
174 if (fread(&f->header_len,1,4,f->fp) != 4) {
175 fclose(f->fp);
176 return rdf_errno = 3; /* error 3: file read error */
179 f->header_ofs = ftell(f->fp);
181 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
182 fclose(f->fp);
183 return rdf_errno = 2; /* seek past end of file...? */
186 if (fread(&f->code_len,1,4,f->fp) != 4) {
187 fclose(f->fp);
188 return rdf_errno = 3;
191 f->code_ofs = ftell(f->fp);
192 if (fseek(f->fp,f->code_len,SEEK_CUR)) {
193 fclose(f->fp);
194 return rdf_errno = 2;
197 if (fread(&f->data_len,1,4,f->fp) != 4) {
198 fclose(f->fp);
199 return rdf_errno = 3;
202 f->data_ofs = ftell(f->fp);
203 fseek(f->fp,initpos,SEEK_SET);
204 f->header_loc = NULL;
206 f->name = newstr(name);
207 f->refcount = refcount;
208 if (refcount) (*refcount)++;
209 return 0;
212 int rdfclose(rdffile *f)
214 if (! f->refcount || ! *--f->refcount)
215 fclose(f->fp);
216 free(f->name);
218 return 0;
221 void rdfperror(const char *app,const char *name)
223 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
224 if (rdf_errno == 1 || rdf_errno == 3)
226 perror(app);
231 int rdfloadseg(rdffile *f,int segment,void *buffer)
233 long fpos;
234 long slen;
236 switch(segment) {
237 case RDOFF_HEADER:
238 fpos = f->header_ofs;
239 slen = f->header_len;
240 f->header_loc = (char *)buffer;
241 f->header_fp = 0;
242 break;
243 case RDOFF_CODE:
244 fpos = f->code_ofs;
245 slen = f->code_len;
246 break;
247 case RDOFF_DATA:
248 fpos = f->data_ofs;
249 slen = f->data_len;
250 break;
251 default:
252 fpos = 0;
253 slen = 0;
256 if (fseek(f->fp,fpos,SEEK_SET))
257 return rdf_errno = 4;
259 if (fread(buffer,1,slen,f->fp) != slen)
260 return rdf_errno = 3;
262 return 0;
265 /* Macros for reading integers from header in memory */
267 #define RI8(v) v = f->header_loc[f->header_fp++]
268 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
269 (f->header_loc[f->header_fp+1] << 8)); \
270 f->header_fp += 2; }
272 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
273 (f->header_loc[f->header_fp+1] << 8) + \
274 (f->header_loc[f->header_fp+2] << 16) + \
275 (f->header_loc[f->header_fp+3] << 24)); \
276 f->header_fp += 4; }
278 #define RS(str,max) { for(i=0;i<max;i++){\
279 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
281 rdfheaderrec *rdfgetheaderrec(rdffile *f)
283 static rdfheaderrec r;
284 int i;
286 if (!f->header_loc) {
287 rdf_errno = 5;
288 return NULL;
291 if (f->header_fp >= f->header_len) return 0;
293 RI8(r.type);
294 switch(r.type) {
295 case 1: /* Relocation record */
296 RI8(r.r.segment);
297 RI32(r.r.offset);
298 RI8(r.r.length);
299 RI16(r.r.refseg);
300 break;
302 case 2: /* Imported symbol record */
303 RI16(r.i.segment);
304 RS(r.i.label,32);
305 break;
307 case 3: /* Exported symbol record */
308 RI8(r.e.segment);
309 RI32(r.e.offset);
310 RS(r.e.label,32);
311 break;
313 case 4: /* DLL record */
314 RS(r.d.libname,127);
315 break;
317 case 5: /* BSS reservation record */
318 RI32(r.b.amount);
319 break;
321 default:
322 rdf_errno = 2; /* invalid file */
323 return NULL;
325 return &r;
328 void rdfheaderrewind(rdffile *f)
330 f->header_fp = 0;
334 rdf_headerbuf * rdfnewheader(void)
336 return newmembuf();
339 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
341 switch (r->type)
343 case 1:
344 membufwrite(h,&r->type,1);
345 membufwrite(h,&r->r.segment,1);
346 membufwrite(h,&r->r.offset,-4);
347 membufwrite(h,&r->r.length,1);
348 membufwrite(h,&r->r.refseg,-2); /* 9 bytes written */
349 break;
351 case 2: /* import */
352 membufwrite(h,&r->type,1);
353 membufwrite(h,&r->i.segment,-2);
354 membufwrite(h,&r->i.label,strlen(r->i.label) + 1);
355 break ;
357 case 3: /* export */
358 membufwrite(h,&r->type,1);
359 membufwrite(h,&r->e.segment,1);
360 membufwrite(h,&r->e.offset,-4);
361 membufwrite(h,&r->e.label,strlen(r->e.label) + 1);
362 break ;
364 case 4: /* DLL */
365 membufwrite(h,&r->type,1);
366 membufwrite(h,&r->d.libname,strlen(r->d.libname) + 1);
367 break ;
369 case 5: /* BSS */
370 membufwrite(h,&r->type,1);
371 membufwrite(h,&r->b.amount,-4);
372 break ;
374 default:
375 return (rdf_errno = 2);
377 return 0;
380 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
382 long l;
384 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
386 l = translatelong ( membuflength (h) );
387 fwrite (&l, 4, 1, fp);
389 membufdump(h, fp);
391 return 0; /* no error handling in here... CHANGE THIS! */
394 void rdfdoneheader(rdf_headerbuf * h)
396 freemembuf(h);