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