1
2/* pngmem.c - stub functions for memory allocation
3 *
4 * libpng version 1.2.7 - September 12, 2004
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2004 Glenn Randers-Pehrson
7 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9 *
10 * This file provides a location for all memory allocation.  Users who
11 * need special memory handling are expected to supply replacement
12 * functions for png_malloc() and png_free(), and to use
13 * png_create_read_struct_2() and png_create_write_struct_2() to
14 * identify the replacement functions.
15 */
16
17#define PNG_INTERNAL
18#include "png.h"
19
20/* Borland DOS special memory handler */
21#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
22/* if you change this, be sure to change the one in png.h also */
23
24/* Allocate memory for a png_struct.  The malloc and memset can be replaced
25   by a single call to calloc() if this is thought to improve performance. */
26png_voidp /* PRIVATE */
27png_create_struct(int type)
28{
29#ifdef PNG_USER_MEM_SUPPORTED
30   return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
31}
32
33/* Alternate version of png_create_struct, for use with user-defined malloc. */
34png_voidp /* PRIVATE */
35png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
36{
37#endif /* PNG_USER_MEM_SUPPORTED */
38   png_size_t size;
39   png_voidp struct_ptr;
40
41   if (type == PNG_STRUCT_INFO)
42     size = png_sizeof(png_info);
43   else if (type == PNG_STRUCT_PNG)
44     size = png_sizeof(png_struct);
45   else
46     return (png_get_copyright(NULL));
47
48#ifdef PNG_USER_MEM_SUPPORTED
49   if(malloc_fn != NULL)
50   {
51      png_struct dummy_struct;
52      png_structp png_ptr = &dummy_struct;
53      png_ptr->mem_ptr=mem_ptr;
54      struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size);
55   }
56   else
57#endif /* PNG_USER_MEM_SUPPORTED */
58      struct_ptr = (png_voidp)farmalloc(size);
59   if (struct_ptr != NULL)
60      png_memset(struct_ptr, 0, size);
61   return (struct_ptr);
62}
63
64/* Free memory allocated by a png_create_struct() call */
65void /* PRIVATE */
66png_destroy_struct(png_voidp struct_ptr)
67{
68#ifdef PNG_USER_MEM_SUPPORTED
69   png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
70}
71
72/* Free memory allocated by a png_create_struct() call */
73void /* PRIVATE */
74png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
75    png_voidp mem_ptr)
76{
77#endif
78   if (struct_ptr != NULL)
79   {
80#ifdef PNG_USER_MEM_SUPPORTED
81      if(free_fn != NULL)
82      {
83         png_struct dummy_struct;
84         png_structp png_ptr = &dummy_struct;
85         png_ptr->mem_ptr=mem_ptr;
86         (*(free_fn))(png_ptr, struct_ptr);
87         return;
88      }
89#endif /* PNG_USER_MEM_SUPPORTED */
90      farfree (struct_ptr);
91   }
92}
93
94/* Allocate memory.  For reasonable files, size should never exceed
95 * 64K.  However, zlib may allocate more then 64K if you don't tell
96 * it not to.  See zconf.h and png.h for more information. zlib does
97 * need to allocate exactly 64K, so whatever you call here must
98 * have the ability to do that.
99 *
100 * Borland seems to have a problem in DOS mode for exactly 64K.
101 * It gives you a segment with an offset of 8 (perhaps to store its
102 * memory stuff).  zlib doesn't like this at all, so we have to
103 * detect and deal with it.  This code should not be needed in
104 * Windows or OS/2 modes, and only in 16 bit mode.  This code has
105 * been updated by Alexander Lehmann for version 0.89 to waste less
106 * memory.
107 *
108 * Note that we can't use png_size_t for the "size" declaration,
109 * since on some systems a png_size_t is a 16-bit quantity, and as a
110 * result, we would be truncating potentially larger memory requests
111 * (which should cause a fatal error) and introducing major problems.
112 */
113
114png_voidp PNGAPI
115png_malloc(png_structp png_ptr, png_uint_32 size)
116{
117   png_voidp ret;
118
119   if (png_ptr == NULL || size == 0)
120      return (NULL);
121
122#ifdef PNG_USER_MEM_SUPPORTED
123   if(png_ptr->malloc_fn != NULL)
124       ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
125   else
126       ret = (png_malloc_default(png_ptr, size));
127   if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
128       png_error(png_ptr, "Out of memory!");
129   return (ret);
130}
131
132png_voidp PNGAPI
133png_malloc_default(png_structp png_ptr, png_uint_32 size)
134{
135   png_voidp ret;
136#endif /* PNG_USER_MEM_SUPPORTED */
137
138#ifdef PNG_MAX_MALLOC_64K
139   if (size > (png_uint_32)65536L)
140   {
141      png_warning(png_ptr, "Cannot Allocate > 64K");
142      ret = NULL;
143   }
144   else
145#endif
146
147   if (size != (size_t)size)
148     ret = NULL;
149   else if (size == (png_uint_32)65536L)
150   {
151      if (png_ptr->offset_table == NULL)
152      {
153         /* try to see if we need to do any of this fancy stuff */
154         ret = farmalloc(size);
155         if (ret == NULL || ((png_size_t)ret & 0xffff))
156         {
157            int num_blocks;
158            png_uint_32 total_size;
159            png_bytep table;
160            int i;
161            png_byte huge * hptr;
162
163            if (ret != NULL)
164            {
165               farfree(ret);
166               ret = NULL;
167            }
168
169            if(png_ptr->zlib_window_bits > 14)
170               num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
171            else
172               num_blocks = 1;
173            if (png_ptr->zlib_mem_level >= 7)
174               num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
175            else
176               num_blocks++;
177
178            total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
179
180            table = farmalloc(total_size);
181
182            if (table == NULL)
183            {
184#ifndef PNG_USER_MEM_SUPPORTED
185               if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
186                  png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
187               else
188                  png_warning(png_ptr, "Out Of Memory.");
189#endif
190               return (NULL);
191            }
192
193            if ((png_size_t)table & 0xfff0)
194            {
195#ifndef PNG_USER_MEM_SUPPORTED
196               if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
197                  png_error(png_ptr,
198                    "Farmalloc didn't return normalized pointer");
199               else
200                  png_warning(png_ptr,
201                    "Farmalloc didn't return normalized pointer");
202#endif
203               return (NULL);
204            }
205
206            png_ptr->offset_table = table;
207            png_ptr->offset_table_ptr = farmalloc(num_blocks *
208               png_sizeof (png_bytep));
209
210            if (png_ptr->offset_table_ptr == NULL)
211            {
212#ifndef PNG_USER_MEM_SUPPORTED
213               if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
214                  png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */
215               else
216                  png_warning(png_ptr, "Out Of memory.");
217#endif
218               return (NULL);
219            }
220
221            hptr = (png_byte huge *)table;
222            if ((png_size_t)hptr & 0xf)
223            {
224               hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
225               hptr = hptr + 16L;  /* "hptr += 16L" fails on Turbo C++ 3.0 */
226            }
227            for (i = 0; i < num_blocks; i++)
228            {
229               png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
230               hptr = hptr + (png_uint_32)65536L;  /* "+=" fails on TC++3.0 */
231            }
232
233            png_ptr->offset_table_number = num_blocks;
234            png_ptr->offset_table_count = 0;
235            png_ptr->offset_table_count_free = 0;
236         }
237      }
238
239      if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
240      {
241#ifndef PNG_USER_MEM_SUPPORTED
242         if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
243            png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */
244         else
245            png_warning(png_ptr, "Out of Memory.");
246#endif
247         return (NULL);
248      }
249
250      ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
251   }
252   else
253      ret = farmalloc(size);
254
255#ifndef PNG_USER_MEM_SUPPORTED
256   if (ret == NULL)
257   {
258      if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
259         png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
260      else
261         png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */
262   }
263#endif
264
265   return (ret);
266}
267
268/* free a pointer allocated by png_malloc().  In the default
269   configuration, png_ptr is not used, but is passed in case it
270   is needed.  If ptr is NULL, return without taking any action. */
271void PNGAPI
272png_free(png_structp png_ptr, png_voidp ptr)
273{
274   if (png_ptr == NULL || ptr == NULL)
275      return;
276
277#ifdef PNG_USER_MEM_SUPPORTED
278   if (png_ptr->free_fn != NULL)
279   {
280      (*(png_ptr->free_fn))(png_ptr, ptr);
281      return;
282   }
283   else png_free_default(png_ptr, ptr);
284}
285
286void PNGAPI
287png_free_default(png_structp png_ptr, png_voidp ptr)
288{
289#endif /* PNG_USER_MEM_SUPPORTED */
290
291   if (png_ptr->offset_table != NULL)
292   {
293      int i;
294
295      for (i = 0; i < png_ptr->offset_table_count; i++)
296      {
297         if (ptr == png_ptr->offset_table_ptr[i])
298         {
299            ptr = NULL;
300            png_ptr->offset_table_count_free++;
301            break;
302         }
303      }
304      if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
305      {
306         farfree(png_ptr->offset_table);
307         farfree(png_ptr->offset_table_ptr);
308         png_ptr->offset_table = NULL;
309         png_ptr->offset_table_ptr = NULL;
310      }
311   }
312
313   if (ptr != NULL)
314   {
315      farfree(ptr);
316   }
317}
318
319#else /* Not the Borland DOS special memory handler */
320
321/* Allocate memory for a png_struct or a png_info.  The malloc and
322   memset can be replaced by a single call to calloc() if this is thought
323   to improve performance noticably. */
324png_voidp /* PRIVATE */
325png_create_struct(int type)
326{
327#ifdef PNG_USER_MEM_SUPPORTED
328   return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
329}
330
331/* Allocate memory for a png_struct or a png_info.  The malloc and
332   memset can be replaced by a single call to calloc() if this is thought
333   to improve performance noticably. */
334png_voidp /* PRIVATE */
335png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
336{
337#endif /* PNG_USER_MEM_SUPPORTED */
338   png_size_t size;
339   png_voidp struct_ptr;
340
341   if (type == PNG_STRUCT_INFO)
342      size = png_sizeof(png_info);
343   else if (type == PNG_STRUCT_PNG)
344      size = png_sizeof(png_struct);
345   else
346      return (NULL);
347
348#ifdef PNG_USER_MEM_SUPPORTED
349   if(malloc_fn != NULL)
350   {
351      png_struct dummy_struct;
352      png_structp png_ptr = &dummy_struct;
353      png_ptr->mem_ptr=mem_ptr;
354      struct_ptr = (*(malloc_fn))(png_ptr, size);
355      if (struct_ptr != NULL)
356         png_memset(struct_ptr, 0, size);
357      return (struct_ptr);
358   }
359#endif /* PNG_USER_MEM_SUPPORTED */
360
361#if defined(__TURBOC__) && !defined(__FLAT__)
362   struct_ptr = (png_voidp)farmalloc(size);
363#else
364# if defined(_MSC_VER) && defined(MAXSEG_64K)
365   struct_ptr = (png_voidp)halloc(size,1);
366# else
367   struct_ptr = (png_voidp)malloc(size);
368# endif
369#endif
370   if (struct_ptr != NULL)
371      png_memset(struct_ptr, 0, size);
372
373   return (struct_ptr);
374}
375
376
377/* Free memory allocated by a png_create_struct() call */
378void /* PRIVATE */
379png_destroy_struct(png_voidp struct_ptr)
380{
381#ifdef PNG_USER_MEM_SUPPORTED
382   png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
383}
384
385/* Free memory allocated by a png_create_struct() call */
386void /* PRIVATE */
387png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
388    png_voidp mem_ptr)
389{
390#endif /* PNG_USER_MEM_SUPPORTED */
391   if (struct_ptr != NULL)
392   {
393#ifdef PNG_USER_MEM_SUPPORTED
394      if(free_fn != NULL)
395      {
396         png_struct dummy_struct;
397         png_structp png_ptr = &dummy_struct;
398         png_ptr->mem_ptr=mem_ptr;
399         (*(free_fn))(png_ptr, struct_ptr);
400         return;
401      }
402#endif /* PNG_USER_MEM_SUPPORTED */
403#if defined(__TURBOC__) && !defined(__FLAT__)
404      farfree(struct_ptr);
405#else
406# if defined(_MSC_VER) && defined(MAXSEG_64K)
407      hfree(struct_ptr);
408# else
409      free(struct_ptr);
410# endif
411#endif
412   }
413}
414
415/* Allocate memory.  For reasonable files, size should never exceed
416   64K.  However, zlib may allocate more then 64K if you don't tell
417   it not to.  See zconf.h and png.h for more information.  zlib does
418   need to allocate exactly 64K, so whatever you call here must
419   have the ability to do that. */
420
421png_voidp PNGAPI
422png_malloc(png_structp png_ptr, png_uint_32 size)
423{
424   png_voidp ret;
425
426#ifdef PNG_USER_MEM_SUPPORTED
427   if (png_ptr == NULL || size == 0)
428      return (NULL);
429
430   if(png_ptr->malloc_fn != NULL)
431       ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
432   else
433       ret = (png_malloc_default(png_ptr, size));
434   if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
435       png_error(png_ptr, "Out of Memory!");
436   return (ret);
437}
438
439png_voidp PNGAPI
440png_malloc_default(png_structp png_ptr, png_uint_32 size)
441{
442   png_voidp ret;
443#endif /* PNG_USER_MEM_SUPPORTED */
444
445   if (png_ptr == NULL || size == 0)
446      return (NULL);
447
448#ifdef PNG_MAX_MALLOC_64K
449   if (size > (png_uint_32)65536L)
450   {
451#ifndef PNG_USER_MEM_SUPPORTED
452      if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
453         png_error(png_ptr, "Cannot Allocate > 64K");
454      else
455#endif
456         return NULL;
457   }
458#endif
459
460 /* Check for overflow */
461#if defined(__TURBOC__) && !defined(__FLAT__)
462 if (size != (unsigned long)size)
463   ret = NULL;
464 else
465   ret = farmalloc(size);
466#else
467# if defined(_MSC_VER) && defined(MAXSEG_64K)
468 if (size != (unsigned long)size)
469   ret = NULL;
470 else
471   ret = halloc(size, 1);
472# else
473 if (size != (size_t)size)
474   ret = NULL;
475 else
476   ret = malloc((size_t)size);
477# endif
478#endif
479
480#ifndef PNG_USER_MEM_SUPPORTED
481   if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
482      png_error(png_ptr, "Out of Memory");
483#endif
484
485   return (ret);
486}
487
488/* Free a pointer allocated by png_malloc().  If ptr is NULL, return
489   without taking any action. */
490void PNGAPI
491png_free(png_structp png_ptr, png_voidp ptr)
492{
493   if (png_ptr == NULL || ptr == NULL)
494      return;
495
496#ifdef PNG_USER_MEM_SUPPORTED
497   if (png_ptr->free_fn != NULL)
498   {
499      (*(png_ptr->free_fn))(png_ptr, ptr);
500      return;
501   }
502   else png_free_default(png_ptr, ptr);
503}
504void PNGAPI
505png_free_default(png_structp png_ptr, png_voidp ptr)
506{
507   if (png_ptr == NULL || ptr == NULL)
508      return;
509
510#endif /* PNG_USER_MEM_SUPPORTED */
511
512#if defined(__TURBOC__) && !defined(__FLAT__)
513   farfree(ptr);
514#else
515# if defined(_MSC_VER) && defined(MAXSEG_64K)
516   hfree(ptr);
517# else
518   free(ptr);
519# endif
520#endif
521}
522
523#endif /* Not Borland DOS special memory handler */
524
525#if defined(PNG_1_0_X)
526#  define png_malloc_warn png_malloc
527#else
528/* This function was added at libpng version 1.2.3.  The png_malloc_warn()
529 * function will set up png_malloc() to issue a png_warning and return NULL
530 * instead of issuing a png_error, if it fails to allocate the requested
531 * memory.
532 */
533png_voidp PNGAPI
534png_malloc_warn(png_structp png_ptr, png_uint_32 size)
535{
536   png_voidp ptr;
537   png_uint_32 save_flags=png_ptr->flags;
538
539   png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
540   ptr = (png_voidp)png_malloc((png_structp)png_ptr, size);
541   png_ptr->flags=save_flags;
542   return(ptr);
543}
544#endif
545
546png_voidp PNGAPI
547png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
548   png_uint_32 length)
549{
550   png_size_t size;
551
552   size = (png_size_t)length;
553   if ((png_uint_32)size != length)
554      png_error(png_ptr,"Overflow in png_memcpy_check.");
555
556   return(png_memcpy (s1, s2, size));
557}
558
559png_voidp PNGAPI
560png_memset_check (png_structp png_ptr, png_voidp s1, int value,
561   png_uint_32 length)
562{
563   png_size_t size;
564
565   size = (png_size_t)length;
566   if ((png_uint_32)size != length)
567      png_error(png_ptr,"Overflow in png_memset_check.");
568
569   return (png_memset (s1, value, size));
570
571}
572
573#ifdef PNG_USER_MEM_SUPPORTED
574/* This function is called when the application wants to use another method
575 * of allocating and freeing memory.
576 */
577void PNGAPI
578png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
579  malloc_fn, png_free_ptr free_fn)
580{
581   png_ptr->mem_ptr = mem_ptr;
582   png_ptr->malloc_fn = malloc_fn;
583   png_ptr->free_fn = free_fn;
584}
585
586/* This function returns a pointer to the mem_ptr associated with the user
587 * functions.  The application should free any memory associated with this
588 * pointer before png_write_destroy and png_read_destroy are called.
589 */
590png_voidp PNGAPI
591png_get_mem_ptr(png_structp png_ptr)
592{
593   return ((png_voidp)png_ptr->mem_ptr);
594}
595#endif /* PNG_USER_MEM_SUPPORTED */
596