NASM: relicense under the 2-clause BSD license
[platform/upstream/nasm.git] / saa.c
1 /* ----------------------------------------------------------------------- *
2  *   
3  *   Copyright 1996-2009 The NASM Authors - All Rights Reserved
4  *   See the file AUTHORS included with the NASM distribution for
5  *   the specific copyright holders.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following
9  *   conditions are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *     
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * ----------------------------------------------------------------------- */
33
34 #include "compiler.h"
35 #include "nasmlib.h"
36 #include "saa.h"
37
38 /* Aggregate SAA components smaller than this */
39 #define SAA_BLKSHIFT    16
40 #define SAA_BLKLEN      ((size_t)1 << SAA_BLKSHIFT)
41
42 struct SAA *saa_init(size_t elem_len)
43 {
44     struct SAA *s;
45     char *data;
46
47     s = nasm_zalloc(sizeof(struct SAA));
48
49     if (elem_len >= SAA_BLKLEN)
50         s->blk_len = elem_len;
51     else
52         s->blk_len = SAA_BLKLEN - (SAA_BLKLEN % elem_len);
53
54     s->elem_len = elem_len;
55     s->length = s->blk_len;
56     data = nasm_malloc(s->blk_len);
57     s->nblkptrs = s->nblks = 1;
58     s->blk_ptrs = nasm_malloc(sizeof(char *));
59     s->blk_ptrs[0] = data;
60     s->wblk = s->rblk = &s->blk_ptrs[0];
61
62     return s;
63 }
64
65 void saa_free(struct SAA *s)
66 {
67     char **p;
68     size_t n;
69
70     for (p = s->blk_ptrs, n = s->nblks; n; p++, n--)
71         nasm_free(*p);
72
73     nasm_free(s->blk_ptrs);
74     nasm_free(s);
75 }
76
77 /* Add one allocation block to an SAA */
78 static void saa_extend(struct SAA *s)
79 {
80     size_t blkn = s->nblks++;
81
82     if (blkn >= s->nblkptrs) {
83         size_t rindex = s->rblk - s->blk_ptrs;
84         size_t windex = s->wblk - s->blk_ptrs;
85
86         s->nblkptrs <<= 1;
87         s->blk_ptrs =
88             nasm_realloc(s->blk_ptrs, s->nblkptrs * sizeof(char *));
89
90         s->rblk = s->blk_ptrs + rindex;
91         s->wblk = s->blk_ptrs + windex;
92     }
93
94     s->blk_ptrs[blkn] = nasm_malloc(s->blk_len);
95     s->length += s->blk_len;
96 }
97
98 void *saa_wstruct(struct SAA *s)
99 {
100     void *p;
101
102     if (s->wpos % s->elem_len)
103         nasm_malloc_error(ERR_PANIC | ERR_NOFILE,
104                           "misaligned wpos in saa_wstruct");
105
106     if (s->wpos + s->elem_len > s->blk_len) {
107         if (s->wpos != s->blk_len)
108             nasm_malloc_error(ERR_PANIC | ERR_NOFILE,
109                               "unfilled block in saa_wstruct");
110
111         if (s->wptr + s->elem_len > s->length)
112             saa_extend(s);
113         s->wblk++;
114         s->wpos = 0;
115     }
116
117     p = *s->wblk + s->wpos;
118     s->wpos += s->elem_len;
119     s->wptr += s->elem_len;
120
121     if (s->wptr > s->datalen)
122         s->datalen = s->wptr;
123
124     return p;
125 }
126
127 void saa_wbytes(struct SAA *s, const void *data, size_t len)
128 {
129     const char *d = data;
130
131     while (len) {
132         size_t l = s->blk_len - s->wpos;
133         if (l > len)
134             l = len;
135         if (l) {
136             if (d) {
137                 memcpy(*s->wblk + s->wpos, d, l);
138                 d += l;
139             } else
140                 memset(*s->wblk + s->wpos, 0, l);
141             s->wpos += l;
142             s->wptr += l;
143             len -= l;
144
145             if (s->datalen < s->wptr)
146                 s->datalen = s->wptr;
147         }
148         if (len) {
149             if (s->wptr >= s->length)
150                 saa_extend(s);
151             s->wblk++;
152             s->wpos = 0;
153         }
154     }
155 }
156
157 void saa_rewind(struct SAA *s)
158 {
159     s->rblk = s->blk_ptrs;
160     s->rpos = s->rptr = 0;
161 }
162
163 void *saa_rstruct(struct SAA *s)
164 {
165     void *p;
166
167     if (s->rptr + s->elem_len > s->datalen)
168         return NULL;
169
170     if (s->rpos % s->elem_len)
171         nasm_malloc_error(ERR_PANIC | ERR_NOFILE,
172                           "misaligned rpos in saa_rstruct");
173
174     if (s->rpos + s->elem_len > s->blk_len) {
175         s->rblk++;
176         s->rpos = 0;
177     }
178
179     p = *s->rblk + s->rpos;
180     s->rpos += s->elem_len;
181     s->rptr += s->elem_len;
182
183     return p;
184 }
185
186 const void *saa_rbytes(struct SAA *s, size_t * lenp)
187 {
188     const void *p;
189     size_t len;
190
191     if (s->rptr >= s->datalen) {
192         *lenp = 0;
193         return NULL;
194     }
195
196     if (s->rpos >= s->blk_len) {
197         s->rblk++;
198         s->rpos = 0;
199     }
200
201     len = *lenp;
202     if (len > s->datalen - s->rptr)
203         len = s->datalen - s->rptr;
204     if (len > s->blk_len - s->rpos)
205         len = s->blk_len - s->rpos;
206
207     *lenp = len;
208     p = *s->rblk + s->rpos;
209
210     s->rpos += len;
211     s->rptr += len;
212
213     return p;
214 }
215
216 void saa_rnbytes(struct SAA *s, void *data, size_t len)
217 {
218     char *d = data;
219
220     if (s->rptr + len > s->datalen) {
221         nasm_malloc_error(ERR_PANIC | ERR_NOFILE,
222                           "overrun in saa_rnbytes");
223         return;
224     }
225
226     while (len) {
227         size_t l;
228         const void *p;
229
230         l = len;
231         p = saa_rbytes(s, &l);
232
233         memcpy(d, p, l);
234         d += l;
235         len -= l;
236     }
237 }
238
239 /* Same as saa_rnbytes, except position the counter first */
240 void saa_fread(struct SAA *s, size_t posn, void *data, size_t len)
241 {
242     size_t ix;
243
244     if (posn + len > s->datalen) {
245         nasm_malloc_error(ERR_PANIC | ERR_NOFILE, "overrun in saa_fread");
246         return;
247     }
248
249     if (likely(s->blk_len == SAA_BLKLEN)) {
250         ix = posn >> SAA_BLKSHIFT;
251         s->rpos = posn & (SAA_BLKLEN - 1);
252     } else {
253         ix = posn / s->blk_len;
254         s->rpos = posn % s->blk_len;
255     }
256     s->rptr = posn;
257     s->rblk = &s->blk_ptrs[ix];
258
259     saa_rnbytes(s, data, len);
260 }
261
262 /* Same as saa_wbytes, except position the counter first */
263 void saa_fwrite(struct SAA *s, size_t posn, const void *data, size_t len)
264 {
265     size_t ix;
266
267     if (posn > s->datalen) {
268         /* Seek beyond the end of the existing array not supported */
269         nasm_malloc_error(ERR_PANIC | ERR_NOFILE, "overrun in saa_fwrite");
270         return;
271     }
272
273     if (likely(s->blk_len == SAA_BLKLEN)) {
274         ix = posn >> SAA_BLKSHIFT;
275         s->wpos = posn & (SAA_BLKLEN - 1);
276     } else {
277         ix = posn / s->blk_len;
278         s->wpos = posn % s->blk_len;
279     }
280     s->wptr = posn;
281     s->wblk = &s->blk_ptrs[ix];
282
283     if (!s->wpos) {
284         s->wpos = s->blk_len;
285         s->wblk--;
286     }
287
288     saa_wbytes(s, data, len);
289 }
290
291 void saa_fpwrite(struct SAA *s, FILE * fp)
292 {
293     const char *data;
294     size_t len;
295
296     saa_rewind(s);
297     while (len = s->datalen, (data = saa_rbytes(s, &len)) != NULL)
298         fwrite(data, 1, len, fp);
299 }
300
301 void saa_write8(struct SAA *s, uint8_t v)
302 {
303     saa_wbytes(s, &v, 1);
304 }
305
306 #ifdef WORDS_LITTEENDIAN
307
308 void saa_write16(struct SAA *s, uint16_t v)
309 {
310     saa_wbytes(s, &v, 2);
311 }
312
313 void saa_write32(struct SAA *s, uint32_t v)
314 {
315     saa_wbytes(s, &v, 4);
316 }
317
318 void saa_write64(struct SAA *s, uint64_t v)
319 {
320     saa_wbytes(s, &v, 8);
321 }
322
323 void saa_writeaddr(struct SAA *s, uint64_t v, size_t len)
324 {
325     saa_wbytes(s, &v, len);
326 }
327
328 #else                           /* not WORDS_LITTLEENDIAN */
329
330 void saa_write16(struct SAA *s, uint16_t v)
331 {
332     uint8_t b[2];
333
334     b[0] = v;
335     b[1] = v >> 8;
336     saa_wbytes(s, b, 2);
337 }
338
339 void saa_write32(struct SAA *s, uint32_t v)
340 {
341     uint8_t b[4];
342
343     b[0] = v;
344     b[1] = v >> 8;
345     b[2] = v >> 16;
346     b[3] = v >> 24;
347     saa_wbytes(s, b, 4);
348 }
349
350 void saa_write64(struct SAA *s, uint64_t v)
351 {
352     uint8_t b[8];
353
354     b[0] = v;
355     b[1] = v >> 8;
356     b[2] = v >> 16;
357     b[3] = v >> 24;
358     b[4] = v >> 32;
359     b[5] = v >> 40;
360     b[6] = v >> 48;
361     b[7] = v >> 56;
362     saa_wbytes(s, b, 8);
363 }
364
365 void saa_writeaddr(struct SAA *s, uint64_t v, size_t len)
366 {
367     uint8_t b[8];
368
369     b[0] = v;
370     b[1] = v >> 8;
371     b[2] = v >> 16;
372     b[3] = v >> 24;
373     b[4] = v >> 32;
374     b[5] = v >> 40;
375     b[6] = v >> 48;
376     b[7] = v >> 56;
377
378     saa_wbytes(s, &v, len);
379 }
380
381 #endif                          /* WORDS_LITTLEENDIAN */
382
383 /* write unsigned LEB128 value to SAA */
384 void saa_wleb128u(struct SAA *psaa, int value)
385 {
386     char temp[64], *ptemp;
387     uint8_t byte;
388     int len;
389
390     ptemp = temp;
391     len = 0;
392     do {
393         byte = value & 127;
394         value >>= 7;
395         if (value != 0)         /* more bytes to come */
396             byte |= 0x80;
397         *ptemp = byte;
398         ptemp++;
399         len++;
400     } while (value != 0);
401     saa_wbytes(psaa, temp, len);
402 }
403
404 /* write signed LEB128 value to SAA */
405 void saa_wleb128s(struct SAA *psaa, int value)
406 {
407     char temp[64], *ptemp;
408     uint8_t byte;
409     bool more, negative;
410     int size, len;
411
412     ptemp = temp;
413     more = 1;
414     negative = (value < 0);
415     size = sizeof(int) * 8;
416     len = 0;
417     while (more) {
418         byte = value & 0x7f;
419         value >>= 7;
420         if (negative)
421             /* sign extend */
422             value |= -(1 << (size - 7));
423         /* sign bit of byte is second high order bit (0x40) */
424         if ((value == 0 && !(byte & 0x40)) ||
425             ((value == -1) && (byte & 0x40)))
426             more = 0;
427         else
428             byte |= 0x80;
429         *ptemp = byte;
430         ptemp++;
431         len++;
432     }
433     saa_wbytes(psaa, temp, len);
434 }