0.84 release
[imager.git] / io.c
CommitLineData
e310e5f9 1#include "imager.h"
50c75381 2#include "imageri.h"
02d1d628
AMH
3#include <stdlib.h>
4#ifndef _MSC_VER
5#include <unistd.h>
6#endif
7
8
9/* FIXME: make allocation dynamic */
10
11
12#ifdef IMAGER_DEBUG_MALLOC
13
2ff8ed30 14#define MAXMAL 102400
02d1d628
AMH
15#define MAXDESC 65
16
a743c0a6
AMH
17#define UNDRRNVAL 10
18#define OVERRNVAL 10
02d1d628
AMH
19
20#define PADBYTE 0xaa
21
22
23static int malloc_need_init = 1;
24
25typedef struct {
fe6163bf 26 void* ptr;
02d1d628 27 size_t size;
fe6163bf 28 char comm[MAXDESC];
02d1d628
AMH
29} malloc_entry;
30
31malloc_entry malloc_pointers[MAXMAL];
32
fe6163bf
AMH
33
34
35
36/* Utility functions */
37
38
39static
40void
aea697ad 41malloc_init(void) {
fe6163bf
AMH
42 int i;
43 for(i=0; i<MAXMAL; i++) malloc_pointers[i].ptr = NULL;
44 malloc_need_init = 0;
45 atexit(malloc_state);
46}
47
48
49static
50int
51find_ptr(void *p) {
52 int i;
53 for(i=0;i<MAXMAL;i++)
54 if (malloc_pointers[i].ptr == p)
55 return i;
56 return -1;
57}
58
59
60/* Takes a pointer to real start of array,
61 * sets the entries in the table, returns
62 * the offset corrected pointer */
63
64static
65void *
66set_entry(int i, char *buf, size_t size, char *file, int line) {
67 memset( buf, PADBYTE, UNDRRNVAL );
68 memset( &buf[UNDRRNVAL+size], PADBYTE, OVERRNVAL );
69 buf += UNDRRNVAL;
70 malloc_pointers[i].ptr = buf;
71 malloc_pointers[i].size = size;
72 sprintf(malloc_pointers[i].comm,"%s (%d)", file, line);
73 return buf;
74}
75
02d1d628 76void
aea697ad 77malloc_state(void) {
fe6163bf
AMH
78 int i, total = 0;
79
cd4b0b20 80 i_clear_error();
02d1d628
AMH
81 mm_log((0,"malloc_state()\n"));
82 bndcheck_all();
fe6163bf
AMH
83 for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr != NULL) {
84 mm_log((0,"%d: %d (0x%x) : %s\n", i, malloc_pointers[i].size, malloc_pointers[i].ptr, malloc_pointers[i].comm));
85 total += malloc_pointers[i].size;
02d1d628 86 }
fe6163bf
AMH
87 if (total == 0) mm_log((0,"No memory currently used!\n"))
88 else mm_log((0,"total: %d\n",total));
02d1d628
AMH
89}
90
91
fe6163bf 92
02d1d628 93void*
fe6163bf 94mymalloc_file_line(size_t size, char* file, int line) {
02d1d628
AMH
95 char *buf;
96 int i;
fe6163bf
AMH
97 if (malloc_need_init) malloc_init();
98
99 /* bndcheck_all(); Uncomment for LOTS OF THRASHING */
100
101 if ( (i = find_ptr(NULL)) < 0 ) {
102 mm_log((0,"more than %d segments allocated at %s (%d)\n", MAXMAL, file, line));
103 exit(3);
02d1d628
AMH
104 }
105
fe6163bf
AMH
106 if ( (buf = malloc(size+UNDRRNVAL+OVERRNVAL)) == NULL ) {
107 mm_log((1,"Unable to allocate %i for %s (%i)\n", size, file, line));
108 exit(3);
02d1d628
AMH
109 }
110
fe6163bf
AMH
111 buf = set_entry(i, buf, size, file, line);
112 mm_log((1,"mymalloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, size, buf, file, line));
113 return buf;
02d1d628
AMH
114}
115
e310e5f9
TC
116void *
117(mymalloc)(int size) {
118 return mymalloc_file_line(size, "unknown", 0);
119}
120
02d1d628 121void*
fe6163bf
AMH
122myrealloc_file_line(void *ptr, size_t newsize, char* file, int line) {
123 char *buf;
02d1d628 124 int i;
fe6163bf
AMH
125
126 if (malloc_need_init) malloc_init();
127 /* bndcheck_all(); ACTIVATE FOR LOTS OF THRASHING */
128
129 if (!ptr) {
130 mm_log((1, "realloc called with ptr = NULL, sending request to malloc\n"));
131 return mymalloc_file_line(newsize, file, line);
02d1d628
AMH
132 }
133
fe6163bf
AMH
134 if (!newsize) {
135 mm_log((1, "newsize = 0, sending request to free\n"));
136 myfree_file_line(ptr, file, line);
137 return NULL;
138 }
02d1d628 139
fe6163bf
AMH
140 if ( (i = find_ptr(ptr)) == -1) {
141 mm_log((0, "Unable to find %p in realloc for %s (%i)\n", ptr, file, line));
142 exit(3);
143 }
144
aea697ad 145 if ( (buf = realloc(((char *)ptr)-UNDRRNVAL, UNDRRNVAL+OVERRNVAL+newsize)) == NULL ) {
fe6163bf
AMH
146 mm_log((1,"Unable to reallocate %i bytes at %p for %s (%i)\n", newsize, ptr, file, line));
147 exit(3);
02d1d628 148 }
fe6163bf
AMH
149
150 buf = set_entry(i, buf, newsize, file, line);
151 mm_log((1,"realloc_file_line: slot <%d> %d bytes allocated at %p for %s (%d)\n", i, newsize, buf, file, line));
152 return buf;
02d1d628 153}
fe6163bf 154
e310e5f9
TC
155void *
156(myrealloc)(void *ptr, size_t newsize) {
157 return myrealloc_file_line(ptr, newsize, "unknown", 0);
158}
159
02d1d628
AMH
160static
161void
162bndcheck(int idx) {
163 int i;
164 size_t s = malloc_pointers[idx].size;
fe6163bf 165 unsigned char *pp = malloc_pointers[idx].ptr;
02d1d628
AMH
166 if (!pp) {
167 mm_log((1, "bndcheck: No pointer in slot %d\n", idx));
168 return;
169 }
170
171 for(i=0;i<UNDRRNVAL;i++)
fe6163bf
AMH
172 if (pp[-(1+i)] != PADBYTE)
173 mm_log((1,"bndcheck: UNDERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s ));
02d1d628 174
fe6163bf 175 for(i=0;i<OVERRNVAL;i++)
02d1d628
AMH
176 if (pp[s+i] != PADBYTE)
177 mm_log((1,"bndcheck: OVERRUN OF %d bytes detected: slot = %d, point = %p, size = %d\n", i+1, idx, pp, s ));
178}
179
180void
181bndcheck_all() {
182 int idx;
183 mm_log((1, "bndcheck_all()\n"));
76ff75b8 184 for(idx=0; idx<MAXMAL; idx++)
fe6163bf 185 if (malloc_pointers[idx].ptr)
02d1d628
AMH
186 bndcheck(idx);
187}
188
02d1d628
AMH
189void
190myfree_file_line(void *p, char *file, int line) {
191 char *pp = p;
192 int match = 0;
193 int i;
e2f09cf1
TC
194
195 if (p == NULL)
196 return;
02d1d628 197
fe6163bf 198 for(i=0; i<MAXMAL; i++) if (malloc_pointers[i].ptr == p) {
02d1d628
AMH
199 mm_log((1,"myfree_file_line: pointer %i (%s) freed at %s (%i)\n", i, malloc_pointers[i].comm, file, line));
200 bndcheck(i);
fe6163bf 201 malloc_pointers[i].ptr = NULL;
02d1d628
AMH
202 match++;
203 }
97c4effc
TC
204
205 mm_log((1, "myfree_file_line: freeing address %p (real %p)\n", pp, pp-UNDRRNVAL));
02d1d628
AMH
206
207 if (match != 1) {
f1ac5027 208 mm_log((1, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line));
aea697ad 209 fprintf(stderr, "myfree_file_line: INCONSISTENT REFCOUNT %d at %s (%i)\n", match, file, line);
a73aeb5f 210 exit(255);
02d1d628
AMH
211 }
212
02d1d628
AMH
213
214 free(pp-UNDRRNVAL);
215}
216
e310e5f9
TC
217void
218(myfree)(void *block) {
219 myfree_file_line(block, "unknown", 0);
220}
221
02d1d628
AMH
222#else
223
224#define malloc_comm(a,b) (mymalloc(a))
225
226void
227malloc_state() {
02d1d628
AMH
228}
229
230void*
231mymalloc(int size) {
232 void *buf;
233
a659442a
TC
234 if (size < 0) {
235 fprintf(stderr, "Attempt to allocate size %d\n", size);
236 exit(3);
237 }
238
a743c0a6 239 if ( (buf = malloc(size)) == NULL ) {
faa9b3e7 240 mm_log((1, "mymalloc: unable to malloc %d\n", size));
cc6483e0 241 fprintf(stderr,"Unable to malloc %d.\n", size); exit(3);
02d1d628 242 }
f1ac5027 243 mm_log((1, "mymalloc(size %d) -> %p\n", size, buf));
02d1d628
AMH
244 return buf;
245}
246
e310e5f9
TC
247void *
248mymalloc_file_line(size_t size, char *file, int line) {
249 return mymalloc(size);
250}
251
02d1d628
AMH
252void
253myfree(void *p) {
dd55acc8 254 mm_log((1, "myfree(p %p)\n", p));
02d1d628
AMH
255 free(p);
256}
257
e310e5f9
TC
258void
259myfree_file_line(void *p, char *file, int line) {
260 myfree(p);
261}
262
faa9b3e7
TC
263void *
264myrealloc(void *block, size_t size) {
265 void *result;
266
267 mm_log((1, "myrealloc(block %p, size %u)\n", block, size));
268 if ((result = realloc(block, size)) == NULL) {
269 mm_log((1, "myrealloc: out of memory\n"));
270 fprintf(stderr, "Out of memory.\n");
271 exit(3);
272 }
273 return result;
274}
275
e310e5f9
TC
276void *
277myrealloc_file_line(void *block, size_t newsize, char *file, int size) {
278 return myrealloc(block, newsize);
279}
280
02d1d628
AMH
281#endif /* IMAGER_MALLOC_DEBUG */
282
283
284
285
8047cbb5
AMH
286/* memory pool implementation */
287
288void
289i_mempool_init(i_mempool *mp) {
290 mp->alloc = 10;
291 mp->used = 0;
292 mp->p = mymalloc(sizeof(void*)*mp->alloc);
293}
294
295void
296i_mempool_extend(i_mempool *mp) {
297 mp->p = myrealloc(mp->p, mp->alloc * 2);
298 mp->alloc *=2;
299}
300
301void *
302i_mempool_alloc(i_mempool *mp, size_t size) {
303 if (mp->used == mp->alloc) i_mempool_extend(mp);
304 mp->p[mp->used] = mymalloc(size);
305 mp->used++;
306 return mp->p[mp->used-1];
307}
308
309
310void
311i_mempool_destroy(i_mempool *mp) {
312 unsigned int i;
313 for(i=0; i<mp->used; i++) myfree(mp->p[i]);
314 myfree(mp->p);
315}
316
02d1d628
AMH
317
318
5473b91d 319/* Should these really be here? */
02d1d628
AMH
320
321#undef min
322#undef max
323
50c75381
TC
324i_img_dim
325i_minx(i_img_dim a, i_img_dim b) {
02d1d628
AMH
326 if (a<b) return a; else return b;
327}
328
50c75381
TC
329i_img_dim
330i_maxx(i_img_dim a, i_img_dim b) {
02d1d628
AMH
331 if (a>b) return a; else return b;
332}
333
4f68b48f
TC
334
335struct utf8_size {
336 int mask, expect;
337 int size;
338};
339
340struct utf8_size utf8_sizes[] =
341{
342 { 0x80, 0x00, 1 },
343 { 0xE0, 0xC0, 2 },
344 { 0xF0, 0xE0, 3 },
345 { 0xF8, 0xF0, 4 },
346};
347
348/*
50c75381 349=item i_utf8_advance(char **p, size_t *len)
4f68b48f 350
50c75381 351Retrieve a C<UTF-8> character from the stream.
4f68b48f
TC
352
353Modifies *p and *len to indicate the consumed characters.
354
50c75381
TC
355This doesn't support the extended C<UTF-8> encoding used by later
356versions of Perl.
4f68b48f 357
50c75381 358This doesn't check that the C<UTF-8> character is using the shortest
855fe4d7
TC
359possible representation.
360
4f68b48f
TC
361=cut
362*/
363
855fe4d7 364unsigned long
718b8c97 365i_utf8_advance(char const **p, size_t *len) {
4f68b48f
TC
366 unsigned char c;
367 int i, ci, clen = 0;
368 unsigned char codes[3];
369 if (*len == 0)
370 return ~0UL;
371 c = *(*p)++; --*len;
372
373 for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) {
374 if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) {
375 clen = utf8_sizes[i].size;
855fe4d7 376 break;
4f68b48f
TC
377 }
378 }
379 if (clen == 0 || *len < clen-1) {
380 --*p; ++*len;
381 return ~0UL;
382 }
383
384 /* check that each character is well formed */
385 i = 1;
386 ci = 0;
387 while (i < clen) {
388 if (((*p)[ci] & 0xC0) != 0x80) {
389 --*p; ++*len;
390 return ~0UL;
391 }
392 codes[ci] = (*p)[ci];
393 ++ci; ++i;
394 }
395 *p += clen-1; *len -= clen-1;
396 if (c & 0x80) {
397 if ((c & 0xE0) == 0xC0) {
398 return ((c & 0x1F) << 6) + (codes[0] & 0x3F);
399 }
400 else if ((c & 0xF0) == 0xE0) {
401 return ((c & 0x0F) << 12) | ((codes[0] & 0x3F) << 6) | (codes[1] & 0x3f);
402 }
403 else if ((c & 0xF8) == 0xF0) {
404 return ((c & 0x07) << 18) | ((codes[0] & 0x3F) << 12)
405 | ((codes[1] & 0x3F) << 6) | (codes[2] & 0x3F);
406 }
407 else {
408 *p -= clen; *len += clen;
409 return ~0UL;
410 }
411 }
412 else {
413 return c;
414 }
415}
416