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