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