]> git.saurik.com Git - wxWidgets.git/blame - src/png/pngtest.c
non PCH compilation
[wxWidgets.git] / src / png / pngtest.c
CommitLineData
0272a10d
VZ
1
2/* pngtest.c - a simple test program to test libpng
3 *
970f6abe 4 * Last changed in libpng 1.2.32 [September 18, 2008]
0272a10d 5 * For conditions of distribution and use, see copyright notice in png.h
970f6abe 6 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
0272a10d
VZ
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 program reads in a PNG image, writes it out again, and then
11 * compares the two files. If the files are identical, this shows that
12 * the basic chunk handling, filtering, and (de)compression code is working
13 * properly. It does not currently test all of the transforms, although
14 * it probably should.
15 *
16 * The program will report "FAIL" in certain legitimate cases:
17 * 1) when the compression level or filter selection method is changed.
18 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
19 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
20 * exist in the input file.
21 * 4) others not listed here...
22 * In these cases, it is best to check with another tool such as "pngcheck"
23 * to see what the differences between the two files are.
24 *
25 * If a filename is given on the command-line, then this file is used
26 * for the input, rather than the default "pngtest.png". This allows
27 * testing a wide variety of files easily. You can also test a number
28 * of files at once by typing "pngtest -m file1.png file2.png ..."
29 */
30
31#include "png.h"
32
33#if defined(_WIN32_WCE)
34# if _WIN32_WCE < 211
35 __error__ (f|w)printf functions are not supported on old WindowsCE.;
36# endif
37# include <windows.h>
38# include <stdlib.h>
39# define READFILE(file, data, length, check) \
970f6abe 40 if (ReadFile(file, data, length, &check, NULL)) check = 0
0272a10d
VZ
41# define WRITEFILE(file, data, length, check)) \
42 if (WriteFile(file, data, length, &check, NULL)) check = 0
43# define FCLOSE(file) CloseHandle(file)
44#else
45# include <stdio.h>
46# include <stdlib.h>
47# define READFILE(file, data, length, check) \
970f6abe 48 check=(png_size_t)fread(data, (png_size_t)1, length, file)
0272a10d 49# define WRITEFILE(file, data, length, check) \
970f6abe 50 check=(png_size_t)fwrite(data, (png_size_t)1, length, file)
0272a10d
VZ
51# define FCLOSE(file) fclose(file)
52#endif
53
54#if defined(PNG_NO_STDIO)
55# if defined(_WIN32_WCE)
56 typedef HANDLE png_FILE_p;
57# else
58 typedef FILE * png_FILE_p;
59# endif
60#endif
61
62/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
63#ifndef PNG_DEBUG
64# define PNG_DEBUG 0
65#endif
66
67#if !PNG_DEBUG
68# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */
69#endif
70
71/* Turn on CPU timing
72#define PNGTEST_TIMING
73*/
74
75#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
76#undef PNGTEST_TIMING
77#endif
78
79#ifdef PNGTEST_TIMING
80static float t_start, t_stop, t_decode, t_encode, t_misc;
81#include <time.h>
82#endif
83
84#if defined(PNG_TIME_RFC1123_SUPPORTED)
970f6abe
VZ
85#define PNG_tIME_STRING_LENGTH 29
86static int tIME_chunk_present = 0;
87static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
0272a10d
VZ
88#endif
89
90static int verbose = 0;
91
92int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
93
94#ifdef __TURBOC__
95#include <mem.h>
96#endif
97
98/* defined so I can write to a file on gui/windowing platforms */
99/* #define STDERR stderr */
100#define STDERR stdout /* for DOS */
101
0272a10d
VZ
102/* In case a system header (e.g., on AIX) defined jmpbuf */
103#ifdef jmpbuf
104# undef jmpbuf
105#endif
106
107/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
108#ifndef png_jmpbuf
109# define png_jmpbuf(png_ptr) png_ptr->jmpbuf
110#endif
111
970f6abe
VZ
112/* example of using row callbacks to make a simple progress meter */
113static int status_pass = 1;
114static int status_dots_requested = 0;
115static int status_dots = 1;
116
0272a10d
VZ
117void
118#ifdef PNG_1_0_X
119PNGAPI
120#endif
121read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
122void
123#ifdef PNG_1_0_X
124PNGAPI
125#endif
126read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
127{
970f6abe
VZ
128 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) return;
129 if (status_pass != pass)
0272a10d 130 {
970f6abe 131 fprintf(stdout, "\n Pass %d: ", pass);
0272a10d
VZ
132 status_pass = pass;
133 status_dots = 31;
134 }
135 status_dots--;
970f6abe 136 if (status_dots == 0)
0272a10d
VZ
137 {
138 fprintf(stdout, "\n ");
139 status_dots=30;
140 }
141 fprintf(stdout, "r");
142}
143
144void
145#ifdef PNG_1_0_X
146PNGAPI
147#endif
148write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
149void
150#ifdef PNG_1_0_X
151PNGAPI
152#endif
153write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
154{
970f6abe 155 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return;
0272a10d
VZ
156 fprintf(stdout, "w");
157}
158
159
160#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
161/* Example of using user transform callback (we don't transform anything,
162 but merely examine the row filters. We set this to 256 rather than
163 5 in case illegal filter values are present.) */
164static png_uint_32 filters_used[256];
165void
166#ifdef PNG_1_0_X
167PNGAPI
168#endif
169count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
170void
171#ifdef PNG_1_0_X
172PNGAPI
173#endif
174count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
175{
970f6abe
VZ
176 if (png_ptr != NULL && row_info != NULL)
177 ++filters_used[*(data - 1)];
0272a10d
VZ
178}
179#endif
180
181#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
182/* example of using user transform callback (we don't transform anything,
183 but merely count the zero samples) */
184
185static png_uint_32 zero_samples;
186
187void
188#ifdef PNG_1_0_X
189PNGAPI
190#endif
191count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
192void
193#ifdef PNG_1_0_X
194PNGAPI
195#endif
196count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
197{
198 png_bytep dp = data;
970f6abe 199 if (png_ptr == NULL)return;
0272a10d
VZ
200
201 /* contents of row_info:
202 * png_uint_32 width width of row
203 * png_uint_32 rowbytes number of bytes in row
204 * png_byte color_type color type of pixels
205 * png_byte bit_depth bit depth of samples
206 * png_byte channels number of channels (1-4)
207 * png_byte pixel_depth bits per pixel (depth*channels)
208 */
209
210
211 /* counts the number of zero samples (or zero pixels if color_type is 3 */
212
970f6abe 213 if (row_info->color_type == 0 || row_info->color_type == 3)
0272a10d 214 {
970f6abe 215 int pos = 0;
0272a10d 216 png_uint_32 n, nstop;
970f6abe 217 for (n = 0, nstop=row_info->width; n<nstop; n++)
0272a10d 218 {
970f6abe 219 if (row_info->bit_depth == 1)
0272a10d 220 {
970f6abe
VZ
221 if (((*dp << pos++ ) & 0x80) == 0) zero_samples++;
222 if (pos == 8)
0272a10d
VZ
223 {
224 pos = 0;
225 dp++;
226 }
227 }
970f6abe 228 if (row_info->bit_depth == 2)
0272a10d 229 {
970f6abe
VZ
230 if (((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
231 if (pos == 8)
0272a10d
VZ
232 {
233 pos = 0;
234 dp++;
235 }
236 }
970f6abe 237 if (row_info->bit_depth == 4)
0272a10d 238 {
970f6abe
VZ
239 if (((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
240 if (pos == 8)
0272a10d
VZ
241 {
242 pos = 0;
243 dp++;
244 }
245 }
970f6abe
VZ
246 if (row_info->bit_depth == 8)
247 if (*dp++ == 0) zero_samples++;
248 if (row_info->bit_depth == 16)
0272a10d 249 {
970f6abe 250 if ((*dp | *(dp+1)) == 0) zero_samples++;
0272a10d
VZ
251 dp+=2;
252 }
253 }
254 }
255 else /* other color types */
256 {
257 png_uint_32 n, nstop;
258 int channel;
259 int color_channels = row_info->channels;
970f6abe 260 if (row_info->color_type > 3)color_channels--;
0272a10d 261
970f6abe 262 for (n = 0, nstop=row_info->width; n<nstop; n++)
0272a10d
VZ
263 {
264 for (channel = 0; channel < color_channels; channel++)
265 {
970f6abe
VZ
266 if (row_info->bit_depth == 8)
267 if (*dp++ == 0) zero_samples++;
268 if (row_info->bit_depth == 16)
0272a10d 269 {
970f6abe 270 if ((*dp | *(dp+1)) == 0) zero_samples++;
0272a10d
VZ
271 dp+=2;
272 }
273 }
970f6abe 274 if (row_info->color_type > 3)
0272a10d
VZ
275 {
276 dp++;
970f6abe 277 if (row_info->bit_depth == 16)dp++;
0272a10d
VZ
278 }
279 }
280 }
281}
282#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
283
284static int wrote_question = 0;
285
286#if defined(PNG_NO_STDIO)
287/* START of code to validate stdio-free compilation */
288/* These copies of the default read/write functions come from pngrio.c and */
289/* pngwio.c. They allow "don't include stdio" testing of the library. */
290/* This is the function that does the actual reading of data. If you are
291 not reading from a standard C stream, you should create a replacement
292 read_data function and use it at run time with png_set_read_fn(), rather
293 than changing the library. */
294
295#ifndef USE_FAR_KEYWORD
296static void
297pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
298{
299 png_size_t check;
300
301 /* fread() returns 0 on error, so it is OK to store this in a png_size_t
302 * instead of an int, which is what fread() actually returns.
303 */
304 READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
305
306 if (check != length)
307 {
308 png_error(png_ptr, "Read Error!");
309 }
310}
311#else
312/* this is the model-independent version. Since the standard I/O library
313 can't handle far buffers in the medium and small models, we have to copy
314 the data.
315*/
316
317#define NEAR_BUF_SIZE 1024
318#define MIN(a,b) (a <= b ? a : b)
319
320static void
321pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
322{
323 int check;
324 png_byte *n_data;
325 png_FILE_p io_ptr;
326
327 /* Check if data really is near. If so, use usual code. */
328 n_data = (png_byte *)CVT_PTR_NOCHECK(data);
329 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
330 if ((png_bytep)n_data == data)
331 {
332 READFILE(io_ptr, n_data, length, check);
333 }
334 else
335 {
336 png_byte buf[NEAR_BUF_SIZE];
337 png_size_t read, remaining, err;
338 check = 0;
339 remaining = length;
340 do
341 {
342 read = MIN(NEAR_BUF_SIZE, remaining);
343 READFILE(io_ptr, buf, 1, err);
344 png_memcpy(data, buf, read); /* copy far buffer to near buffer */
970f6abe 345 if (err != read)
0272a10d
VZ
346 break;
347 else
348 check += err;
349 data += read;
350 remaining -= read;
351 }
352 while (remaining != 0);
353 }
354 if (check != length)
355 {
356 png_error(png_ptr, "read Error");
357 }
358}
359#endif /* USE_FAR_KEYWORD */
360
361#if defined(PNG_WRITE_FLUSH_SUPPORTED)
362static void
363pngtest_flush(png_structp png_ptr)
364{
365#if !defined(_WIN32_WCE)
366 png_FILE_p io_ptr;
367 io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
368 if (io_ptr != NULL)
369 fflush(io_ptr);
370#endif
371}
372#endif
373
374/* This is the function that does the actual writing of data. If you are
375 not writing to a standard C stream, you should create a replacement
376 write_data function and use it at run time with png_set_write_fn(), rather
377 than changing the library. */
378#ifndef USE_FAR_KEYWORD
379static void
380pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
381{
382 png_uint_32 check;
383
384 WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
385 if (check != length)
386 {
387 png_error(png_ptr, "Write Error");
388 }
389}
390#else
391/* this is the model-independent version. Since the standard I/O library
392 can't handle far buffers in the medium and small models, we have to copy
393 the data.
394*/
395
396#define NEAR_BUF_SIZE 1024
397#define MIN(a,b) (a <= b ? a : b)
398
399static void
400pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
401{
402 png_uint_32 check;
403 png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
404 png_FILE_p io_ptr;
405
406 /* Check if data really is near. If so, use usual code. */
407 near_data = (png_byte *)CVT_PTR_NOCHECK(data);
408 io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
409 if ((png_bytep)near_data == data)
410 {
411 WRITEFILE(io_ptr, near_data, length, check);
412 }
413 else
414 {
415 png_byte buf[NEAR_BUF_SIZE];
416 png_size_t written, remaining, err;
417 check = 0;
418 remaining = length;
419 do
420 {
421 written = MIN(NEAR_BUF_SIZE, remaining);
422 png_memcpy(buf, data, written); /* copy far buffer to near buffer */
423 WRITEFILE(io_ptr, buf, written, err);
424 if (err != written)
425 break;
426 else
427 check += err;
428 data += written;
429 remaining -= written;
430 }
431 while (remaining != 0);
432 }
433 if (check != length)
434 {
435 png_error(png_ptr, "Write Error");
436 }
437}
438#endif /* USE_FAR_KEYWORD */
0272a10d
VZ
439
440/* This function is called when there is a warning, but the library thinks
441 * it can continue anyway. Replacement functions don't have to do anything
442 * here if you don't want to. In the default configuration, png_ptr is
443 * not used, but it is passed in case it may be useful.
444 */
445static void
446pngtest_warning(png_structp png_ptr, png_const_charp message)
447{
448 PNG_CONST char *name = "UNKNOWN (ERROR!)";
449 if (png_ptr != NULL && png_ptr->error_ptr != NULL)
450 name = png_ptr->error_ptr;
451 fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
452}
453
454/* This is the default error handling function. Note that replacements for
455 * this function MUST NOT RETURN, or the program will likely crash. This
456 * function is used by default, or if the program supplies NULL for the
457 * error function pointer in png_set_error_fn().
458 */
459static void
460pngtest_error(png_structp png_ptr, png_const_charp message)
461{
462 pngtest_warning(png_ptr, message);
463 /* We can return because png_error calls the default handler, which is
464 * actually OK in this case. */
465}
970f6abe
VZ
466#endif /* PNG_NO_STDIO */
467/* END of code to validate stdio-free compilation */
0272a10d
VZ
468
469/* START of code to validate memory allocation and deallocation */
470#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
471
472/* Allocate memory. For reasonable files, size should never exceed
473 64K. However, zlib may allocate more then 64K if you don't tell
474 it not to. See zconf.h and png.h for more information. zlib does
475 need to allocate exactly 64K, so whatever you call here must
476 have the ability to do that.
477
478 This piece of code can be compiled to validate max 64K allocations
479 by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
480typedef struct memory_information
481{
482 png_uint_32 size;
483 png_voidp pointer;
484 struct memory_information FAR *next;
485} memory_information;
486typedef memory_information FAR *memory_infop;
487
488static memory_infop pinformation = NULL;
489static int current_allocation = 0;
490static int maximum_allocation = 0;
491static int total_allocation = 0;
492static int num_allocations = 0;
493
494png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
495void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
496
497png_voidp
498png_debug_malloc(png_structp png_ptr, png_uint_32 size)
499{
500
501 /* png_malloc has already tested for NULL; png_create_struct calls
502 png_debug_malloc directly, with png_ptr == NULL which is OK */
503
504 if (size == 0)
505 return (NULL);
506
507 /* This calls the library allocator twice, once to get the requested
508 buffer and once to get a new free list entry. */
509 {
510 /* Disable malloc_fn and free_fn */
511 memory_infop pinfo;
512 png_set_mem_fn(png_ptr, NULL, NULL, NULL);
513 pinfo = (memory_infop)png_malloc(png_ptr,
970f6abe 514 (png_uint_32)png_sizeof(*pinfo));
0272a10d
VZ
515 pinfo->size = size;
516 current_allocation += size;
517 total_allocation += size;
518 num_allocations ++;
519 if (current_allocation > maximum_allocation)
520 maximum_allocation = current_allocation;
521 pinfo->pointer = (png_voidp)png_malloc(png_ptr, size);
522 /* Restore malloc_fn and free_fn */
970f6abe
VZ
523 png_set_mem_fn(png_ptr,
524 png_voidp_NULL, (png_malloc_ptr)png_debug_malloc,
525 (png_free_ptr)png_debug_free);
0272a10d
VZ
526 if (size != 0 && pinfo->pointer == NULL)
527 {
528 current_allocation -= size;
529 total_allocation -= size;
530 png_error(png_ptr,
531 "out of memory in pngtest->png_debug_malloc.");
532 }
533 pinfo->next = pinformation;
534 pinformation = pinfo;
535 /* Make sure the caller isn't assuming zeroed memory. */
536 png_memset(pinfo->pointer, 0xdd, pinfo->size);
970f6abe
VZ
537 if (verbose)
538 printf("png_malloc %lu bytes at %x\n", (unsigned long)size,
539 pinfo->pointer);
0272a10d
VZ
540 return (png_voidp)(pinfo->pointer);
541 }
542}
543
544/* Free a pointer. It is removed from the list at the same time. */
545void
546png_debug_free(png_structp png_ptr, png_voidp ptr)
547{
548 if (png_ptr == NULL)
549 fprintf(STDERR, "NULL pointer to png_debug_free.\n");
550 if (ptr == 0)
551 {
552#if 0 /* This happens all the time. */
553 fprintf(STDERR, "WARNING: freeing NULL pointer\n");
554#endif
555 return;
556 }
557
558 /* Unlink the element from the list. */
559 {
560 memory_infop FAR *ppinfo = &pinformation;
561 for (;;)
562 {
563 memory_infop pinfo = *ppinfo;
564 if (pinfo->pointer == ptr)
565 {
566 *ppinfo = pinfo->next;
567 current_allocation -= pinfo->size;
568 if (current_allocation < 0)
569 fprintf(STDERR, "Duplicate free of memory\n");
570 /* We must free the list element too, but first kill
571 the memory that is to be freed. */
572 png_memset(ptr, 0x55, pinfo->size);
573 png_free_default(png_ptr, pinfo);
970f6abe 574 pinfo = NULL;
0272a10d
VZ
575 break;
576 }
577 if (pinfo->next == NULL)
578 {
579 fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
580 break;
581 }
582 ppinfo = &pinfo->next;
583 }
584 }
585
586 /* Finally free the data. */
970f6abe
VZ
587 if (verbose)
588 printf("Freeing %x\n", ptr);
0272a10d 589 png_free_default(png_ptr, ptr);
970f6abe 590 ptr = NULL;
0272a10d
VZ
591}
592#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
593/* END of code to test memory allocation/deallocation */
594
970f6abe
VZ
595
596/* Demonstration of user chunk support of the sTER and vpAg chunks */
597#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
598
599/* (sTER is a public chunk not yet understood by libpng. vpAg is a private
600chunk used in ImageMagick to store "virtual page" size). */
601
602static png_uint_32 user_chunk_data[4];
603
604 /* 0: sTER mode + 1
605 * 1: vpAg width
606 * 2: vpAg height
607 * 3: vpAg units
608 */
609
610static int read_user_chunk_callback(png_struct *png_ptr,
611 png_unknown_chunkp chunk)
612{
613 png_uint_32
614 *user_chunk_data;
615
616 /* Return one of the following: */
617 /* return (-n); chunk had an error */
618 /* return (0); did not recognize */
619 /* return (n); success */
620
621 /* The unknown chunk structure contains the chunk data:
622 * png_byte name[5];
623 * png_byte *data;
624 * png_size_t size;
625 *
626 * Note that libpng has already taken care of the CRC handling.
627 */
628
629 if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */
630 chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */
631 {
632 /* Found sTER chunk */
633 if (chunk->size != 1)
634 return (-1); /* Error return */
635 if (chunk->data[0] != 0 && chunk->data[0] != 1)
636 return (-1); /* Invalid mode */
637 user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
638 user_chunk_data[0]=chunk->data[0]+1;
639 return (1);
640 }
641 if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */
642 chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */
643 return (0); /* Did not recognize */
644
645 /* Found ImageMagick vpAg chunk */
646
647 if (chunk->size != 9)
648 return (-1); /* Error return */
649
650 user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
651
652 user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data);
653 user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4);
654 user_chunk_data[3]=(png_uint_32)chunk->data[8];
655
656 return (1);
657
658}
659#endif
660/* END of code to demonstrate user chunk support */
661
0272a10d
VZ
662/* Test one file */
663int
664test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
665{
666 static png_FILE_p fpin;
667 static png_FILE_p fpout; /* "static" prevents setjmp corruption */
668 png_structp read_ptr;
669 png_infop read_info_ptr, end_info_ptr;
670#ifdef PNG_WRITE_SUPPORTED
671 png_structp write_ptr;
672 png_infop write_info_ptr;
673 png_infop write_end_info_ptr;
674#else
675 png_structp write_ptr = NULL;
676 png_infop write_info_ptr = NULL;
677 png_infop write_end_info_ptr = NULL;
678#endif
679 png_bytep row_buf;
680 png_uint_32 y;
681 png_uint_32 width, height;
682 int num_pass, pass;
683 int bit_depth, color_type;
684#ifdef PNG_SETJMP_SUPPORTED
685#ifdef USE_FAR_KEYWORD
686 jmp_buf jmpbuf;
687#endif
688#endif
689
690#if defined(_WIN32_WCE)
691 TCHAR path[MAX_PATH];
692#endif
693 char inbuf[256], outbuf[256];
694
695 row_buf = NULL;
696
697#if defined(_WIN32_WCE)
698 MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
699 if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
700#else
701 if ((fpin = fopen(inname, "rb")) == NULL)
702#endif
703 {
704 fprintf(STDERR, "Could not find input file %s\n", inname);
705 return (1);
706 }
707
708#if defined(_WIN32_WCE)
709 MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
710 if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
711#else
712 if ((fpout = fopen(outname, "wb")) == NULL)
713#endif
714 {
715 fprintf(STDERR, "Could not open output file %s\n", outname);
716 FCLOSE(fpin);
717 return (1);
718 }
719
970f6abe 720 png_debug(0, "Allocating read and write structures");
0272a10d 721#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
970f6abe
VZ
722 read_ptr =
723 png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
0272a10d
VZ
724 png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
725 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
726#else
970f6abe
VZ
727 read_ptr =
728 png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
0272a10d
VZ
729 png_error_ptr_NULL, png_error_ptr_NULL);
730#endif
970f6abe 731#if defined(PNG_NO_STDIO)
0272a10d
VZ
732 png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
733 pngtest_warning);
970f6abe
VZ
734#endif
735
736#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
737 user_chunk_data[0] = 0;
738 user_chunk_data[1] = 0;
739 user_chunk_data[2] = 0;
740 user_chunk_data[3] = 0;
741 png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
742 read_user_chunk_callback);
743
744#endif
0272a10d
VZ
745#ifdef PNG_WRITE_SUPPORTED
746#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
970f6abe
VZ
747 write_ptr =
748 png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
0272a10d
VZ
749 png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
750 (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
751#else
970f6abe
VZ
752 write_ptr =
753 png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
0272a10d
VZ
754 png_error_ptr_NULL, png_error_ptr_NULL);
755#endif
970f6abe 756#if defined(PNG_NO_STDIO)
0272a10d
VZ
757 png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
758 pngtest_warning);
759#endif
970f6abe
VZ
760#endif
761 png_debug(0, "Allocating read_info, write_info and end_info structures");
0272a10d
VZ
762 read_info_ptr = png_create_info_struct(read_ptr);
763 end_info_ptr = png_create_info_struct(read_ptr);
764#ifdef PNG_WRITE_SUPPORTED
765 write_info_ptr = png_create_info_struct(write_ptr);
766 write_end_info_ptr = png_create_info_struct(write_ptr);
767#endif
768
769#ifdef PNG_SETJMP_SUPPORTED
970f6abe 770 png_debug(0, "Setting jmpbuf for read struct");
0272a10d
VZ
771#ifdef USE_FAR_KEYWORD
772 if (setjmp(jmpbuf))
773#else
774 if (setjmp(png_jmpbuf(read_ptr)))
775#endif
776 {
777 fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
970f6abe
VZ
778 png_free(read_ptr, row_buf);
779 row_buf = NULL;
0272a10d
VZ
780 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
781#ifdef PNG_WRITE_SUPPORTED
782 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
783 png_destroy_write_struct(&write_ptr, &write_info_ptr);
784#endif
785 FCLOSE(fpin);
786 FCLOSE(fpout);
787 return (1);
788 }
789#ifdef USE_FAR_KEYWORD
970f6abe 790 png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf));
0272a10d
VZ
791#endif
792
793#ifdef PNG_WRITE_SUPPORTED
970f6abe 794 png_debug(0, "Setting jmpbuf for write struct");
0272a10d
VZ
795#ifdef USE_FAR_KEYWORD
796 if (setjmp(jmpbuf))
797#else
798 if (setjmp(png_jmpbuf(write_ptr)))
799#endif
800 {
801 fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
802 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
803 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
804#ifdef PNG_WRITE_SUPPORTED
805 png_destroy_write_struct(&write_ptr, &write_info_ptr);
806#endif
807 FCLOSE(fpin);
808 FCLOSE(fpout);
809 return (1);
810 }
811#ifdef USE_FAR_KEYWORD
970f6abe 812 png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf));
0272a10d
VZ
813#endif
814#endif
815#endif
816
970f6abe 817 png_debug(0, "Initializing input and output streams");
0272a10d
VZ
818#if !defined(PNG_NO_STDIO)
819 png_init_io(read_ptr, fpin);
820# ifdef PNG_WRITE_SUPPORTED
821 png_init_io(write_ptr, fpout);
822# endif
823#else
824 png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
825# ifdef PNG_WRITE_SUPPORTED
826 png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data,
827# if defined(PNG_WRITE_FLUSH_SUPPORTED)
828 pngtest_flush);
829# else
830 NULL);
831# endif
832# endif
833#endif
970f6abe 834 if (status_dots_requested == 1)
0272a10d
VZ
835 {
836#ifdef PNG_WRITE_SUPPORTED
837 png_set_write_status_fn(write_ptr, write_row_callback);
838#endif
839 png_set_read_status_fn(read_ptr, read_row_callback);
840 }
841 else
842 {
843#ifdef PNG_WRITE_SUPPORTED
844 png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL);
845#endif
846 png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL);
847 }
848
849#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
850 {
851 int i;
970f6abe
VZ
852 for (i = 0; i<256; i++)
853 filters_used[i] = 0;
0272a10d
VZ
854 png_set_read_user_transform_fn(read_ptr, count_filters);
855 }
856#endif
857#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
970f6abe 858 zero_samples = 0;
0272a10d
VZ
859 png_set_write_user_transform_fn(write_ptr, count_zero_samples);
860#endif
861
862#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
863# ifndef PNG_HANDLE_CHUNK_ALWAYS
864# define PNG_HANDLE_CHUNK_ALWAYS 3
865# endif
866 png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
867 png_bytep_NULL, 0);
868#endif
869#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
870# ifndef PNG_HANDLE_CHUNK_IF_SAFE
871# define PNG_HANDLE_CHUNK_IF_SAFE 2
872# endif
873 png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
874 png_bytep_NULL, 0);
875#endif
876
970f6abe 877 png_debug(0, "Reading info struct");
0272a10d
VZ
878 png_read_info(read_ptr, read_info_ptr);
879
970f6abe 880 png_debug(0, "Transferring info struct");
0272a10d
VZ
881 {
882 int interlace_type, compression_type, filter_type;
883
884 if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
885 &color_type, &interlace_type, &compression_type, &filter_type))
886 {
887 png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
888#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
889 color_type, interlace_type, compression_type, filter_type);
890#else
891 color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
892#endif
893 }
894 }
895#if defined(PNG_FIXED_POINT_SUPPORTED)
896#if defined(PNG_cHRM_SUPPORTED)
897 {
898 png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
899 blue_y;
900 if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
901 &red_y, &green_x, &green_y, &blue_x, &blue_y))
902 {
903 png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
904 red_y, green_x, green_y, blue_x, blue_y);
905 }
906 }
907#endif
908#if defined(PNG_gAMA_SUPPORTED)
909 {
910 png_fixed_point gamma;
911
912 if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
913 {
914 png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
915 }
916 }
917#endif
918#else /* Use floating point versions */
919#if defined(PNG_FLOATING_POINT_SUPPORTED)
920#if defined(PNG_cHRM_SUPPORTED)
921 {
922 double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
923 blue_y;
924 if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
925 &red_y, &green_x, &green_y, &blue_x, &blue_y))
926 {
927 png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
928 red_y, green_x, green_y, blue_x, blue_y);
929 }
930 }
931#endif
932#if defined(PNG_gAMA_SUPPORTED)
933 {
934 double gamma;
935
936 if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
937 {
938 png_set_gAMA(write_ptr, write_info_ptr, gamma);
939 }
940 }
941#endif
942#endif /* floating point */
943#endif /* fixed point */
944#if defined(PNG_iCCP_SUPPORTED)
945 {
946 png_charp name;
947 png_charp profile;
948 png_uint_32 proflen;
949 int compression_type;
950
951 if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
952 &profile, &proflen))
953 {
954 png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
955 profile, proflen);
956 }
957 }
958#endif
959#if defined(PNG_sRGB_SUPPORTED)
960 {
961 int intent;
962
963 if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
964 {
965 png_set_sRGB(write_ptr, write_info_ptr, intent);
966 }
967 }
968#endif
969 {
970 png_colorp palette;
971 int num_palette;
972
973 if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
974 {
975 png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
976 }
977 }
978#if defined(PNG_bKGD_SUPPORTED)
979 {
980 png_color_16p background;
981
982 if (png_get_bKGD(read_ptr, read_info_ptr, &background))
983 {
984 png_set_bKGD(write_ptr, write_info_ptr, background);
985 }
986 }
987#endif
988#if defined(PNG_hIST_SUPPORTED)
989 {
990 png_uint_16p hist;
991
992 if (png_get_hIST(read_ptr, read_info_ptr, &hist))
993 {
994 png_set_hIST(write_ptr, write_info_ptr, hist);
995 }
996 }
997#endif
998#if defined(PNG_oFFs_SUPPORTED)
999 {
1000 png_int_32 offset_x, offset_y;
1001 int unit_type;
1002
970f6abe
VZ
1003 if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1004 &unit_type))
0272a10d
VZ
1005 {
1006 png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
1007 }
1008 }
1009#endif
1010#if defined(PNG_pCAL_SUPPORTED)
1011 {
1012 png_charp purpose, units;
1013 png_charpp params;
1014 png_int_32 X0, X1;
1015 int type, nparams;
1016
1017 if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
1018 &nparams, &units, &params))
1019 {
1020 png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
1021 nparams, units, params);
1022 }
1023 }
1024#endif
1025#if defined(PNG_pHYs_SUPPORTED)
1026 {
1027 png_uint_32 res_x, res_y;
1028 int unit_type;
1029
1030 if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
1031 {
1032 png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
1033 }
1034 }
1035#endif
1036#if defined(PNG_sBIT_SUPPORTED)
1037 {
1038 png_color_8p sig_bit;
1039
1040 if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
1041 {
1042 png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
1043 }
1044 }
1045#endif
1046#if defined(PNG_sCAL_SUPPORTED)
1047#ifdef PNG_FLOATING_POINT_SUPPORTED
1048 {
1049 int unit;
1050 double scal_width, scal_height;
1051
1052 if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1053 &scal_height))
1054 {
1055 png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1056 }
1057 }
1058#else
1059#ifdef PNG_FIXED_POINT_SUPPORTED
1060 {
1061 int unit;
1062 png_charp scal_width, scal_height;
1063
1064 if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1065 &scal_height))
1066 {
1067 png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1068 }
1069 }
1070#endif
1071#endif
1072#endif
1073#if defined(PNG_TEXT_SUPPORTED)
1074 {
1075 png_textp text_ptr;
1076 int num_text;
1077
1078 if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
1079 {
970f6abe 1080 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
0272a10d
VZ
1081 png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
1082 }
1083 }
1084#endif
1085#if defined(PNG_tIME_SUPPORTED)
1086 {
1087 png_timep mod_time;
1088
1089 if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
1090 {
1091 png_set_tIME(write_ptr, write_info_ptr, mod_time);
1092#if defined(PNG_TIME_RFC1123_SUPPORTED)
970f6abe 1093 /* we have to use png_memcpy instead of "=" because the string
0272a10d
VZ
1094 pointed to by png_convert_to_rfc1123() gets free'ed before
1095 we use it */
970f6abe
VZ
1096 png_memcpy(tIME_string,
1097 png_convert_to_rfc1123(read_ptr, mod_time),
1098 png_sizeof(tIME_string));
1099 tIME_string[png_sizeof(tIME_string) - 1] = '\0';
0272a10d
VZ
1100 tIME_chunk_present++;
1101#endif /* PNG_TIME_RFC1123_SUPPORTED */
1102 }
1103 }
1104#endif
1105#if defined(PNG_tRNS_SUPPORTED)
1106 {
1107 png_bytep trans;
1108 int num_trans;
1109 png_color_16p trans_values;
1110
1111 if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
1112 &trans_values))
1113 {
970f6abe
VZ
1114 int sample_max = (1 << read_info_ptr->bit_depth);
1115 /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1116 if (!((read_info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1117 (int)trans_values->gray > sample_max) ||
1118 (read_info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1119 ((int)trans_values->red > sample_max ||
1120 (int)trans_values->green > sample_max ||
1121 (int)trans_values->blue > sample_max))))
1122 png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
1123 trans_values);
0272a10d
VZ
1124 }
1125 }
1126#endif
1127#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1128 {
1129 png_unknown_chunkp unknowns;
1130 int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
1131 &unknowns);
1132 if (num_unknowns)
1133 {
1134 png_size_t i;
1135 png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1136 num_unknowns);
1137 /* copy the locations from the read_info_ptr. The automatically
1138 generated locations in write_info_ptr are wrong because we
1139 haven't written anything yet */
1140 for (i = 0; i < (png_size_t)num_unknowns; i++)
1141 png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1142 unknowns[i].location);
1143 }
1144 }
1145#endif
1146
1147#ifdef PNG_WRITE_SUPPORTED
970f6abe 1148 png_debug(0, "Writing info struct");
0272a10d
VZ
1149
1150/* If we wanted, we could write info in two steps:
1151 png_write_info_before_PLTE(write_ptr, write_info_ptr);
1152 */
1153 png_write_info(write_ptr, write_info_ptr);
970f6abe
VZ
1154
1155#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
1156 if (user_chunk_data[0] != 0)
1157 {
1158 png_byte png_sTER[5] = {115, 84, 69, 82, '\0'};
1159
1160 unsigned char
1161 ster_chunk_data[1];
1162
1163 if (verbose)
1164 fprintf(STDERR, "stereo mode = %lu\n",
1165 (unsigned long)(user_chunk_data[0] - 1));
1166 ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
1167 png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1168 }
1169 if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
1170 {
1171 png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'};
1172
1173 unsigned char
1174 vpag_chunk_data[9];
1175
1176 if (verbose)
1177 fprintf(STDERR, "vpAg = %lu x %lu, units=%lu\n",
1178 (unsigned long)user_chunk_data[1],
1179 (unsigned long)user_chunk_data[2],
1180 (unsigned long)user_chunk_data[3]);
1181 png_save_uint_32(vpag_chunk_data, user_chunk_data[1]);
1182 png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]);
1183 vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff);
1184 png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
1185 }
1186
1187#endif
0272a10d
VZ
1188#endif
1189
1190#ifdef SINGLE_ROWBUF_ALLOC
970f6abe 1191 png_debug(0, "Allocating row buffer...");
0272a10d
VZ
1192 row_buf = (png_bytep)png_malloc(read_ptr,
1193 png_get_rowbytes(read_ptr, read_info_ptr));
970f6abe 1194 png_debug1(0, "0x%08lx", (unsigned long)row_buf);
0272a10d 1195#endif /* SINGLE_ROWBUF_ALLOC */
970f6abe 1196 png_debug(0, "Writing row data");
0272a10d
VZ
1197
1198#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
1199 defined(PNG_WRITE_INTERLACING_SUPPORTED)
1200 num_pass = png_set_interlace_handling(read_ptr);
1201# ifdef PNG_WRITE_SUPPORTED
1202 png_set_interlace_handling(write_ptr);
1203# endif
1204#else
970f6abe 1205 num_pass = 1;
0272a10d
VZ
1206#endif
1207
1208#ifdef PNGTEST_TIMING
1209 t_stop = (float)clock();
1210 t_misc += (t_stop - t_start);
1211 t_start = t_stop;
1212#endif
1213 for (pass = 0; pass < num_pass; pass++)
1214 {
970f6abe 1215 png_debug1(0, "Writing row data for pass %d", pass);
0272a10d
VZ
1216 for (y = 0; y < height; y++)
1217 {
1218#ifndef SINGLE_ROWBUF_ALLOC
970f6abe 1219 png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass, y);
0272a10d
VZ
1220 row_buf = (png_bytep)png_malloc(read_ptr,
1221 png_get_rowbytes(read_ptr, read_info_ptr));
970f6abe 1222 png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf,
0272a10d
VZ
1223 png_get_rowbytes(read_ptr, read_info_ptr));
1224#endif /* !SINGLE_ROWBUF_ALLOC */
1225 png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1);
1226
1227#ifdef PNG_WRITE_SUPPORTED
1228#ifdef PNGTEST_TIMING
1229 t_stop = (float)clock();
1230 t_decode += (t_stop - t_start);
1231 t_start = t_stop;
1232#endif
1233 png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1234#ifdef PNGTEST_TIMING
1235 t_stop = (float)clock();
1236 t_encode += (t_stop - t_start);
1237 t_start = t_stop;
1238#endif
1239#endif /* PNG_WRITE_SUPPORTED */
1240
1241#ifndef SINGLE_ROWBUF_ALLOC
970f6abe 1242 png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y);
0272a10d 1243 png_free(read_ptr, row_buf);
970f6abe 1244 row_buf = NULL;
0272a10d
VZ
1245#endif /* !SINGLE_ROWBUF_ALLOC */
1246 }
1247 }
1248
1249#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1250 png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1251#endif
1252#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1253 png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1254#endif
1255
970f6abe 1256 png_debug(0, "Reading and writing end_info data");
0272a10d
VZ
1257
1258 png_read_end(read_ptr, end_info_ptr);
1259#if defined(PNG_TEXT_SUPPORTED)
1260 {
1261 png_textp text_ptr;
1262 int num_text;
1263
1264 if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
1265 {
970f6abe 1266 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
0272a10d
VZ
1267 png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
1268 }
1269 }
1270#endif
1271#if defined(PNG_tIME_SUPPORTED)
1272 {
1273 png_timep mod_time;
1274
1275 if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
1276 {
1277 png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1278#if defined(PNG_TIME_RFC1123_SUPPORTED)
970f6abe 1279 /* we have to use png_memcpy instead of "=" because the string
0272a10d
VZ
1280 pointed to by png_convert_to_rfc1123() gets free'ed before
1281 we use it */
970f6abe
VZ
1282 png_memcpy(tIME_string,
1283 png_convert_to_rfc1123(read_ptr, mod_time),
1284 png_sizeof(tIME_string));
1285 tIME_string[png_sizeof(tIME_string) - 1] = '\0';
0272a10d
VZ
1286 tIME_chunk_present++;
1287#endif /* PNG_TIME_RFC1123_SUPPORTED */
1288 }
1289 }
1290#endif
1291#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1292 {
1293 png_unknown_chunkp unknowns;
1294 int num_unknowns;
1295 num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
1296 &unknowns);
1297 if (num_unknowns)
1298 {
1299 png_size_t i;
1300 png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1301 num_unknowns);
1302 /* copy the locations from the read_info_ptr. The automatically
1303 generated locations in write_end_info_ptr are wrong because we
1304 haven't written the end_info yet */
1305 for (i = 0; i < (png_size_t)num_unknowns; i++)
1306 png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1307 unknowns[i].location);
1308 }
1309 }
1310#endif
1311#ifdef PNG_WRITE_SUPPORTED
1312 png_write_end(write_ptr, write_end_info_ptr);
1313#endif
1314
1315#ifdef PNG_EASY_ACCESS_SUPPORTED
970f6abe 1316 if (verbose)
0272a10d
VZ
1317 {
1318 png_uint_32 iwidth, iheight;
1319 iwidth = png_get_image_width(write_ptr, write_info_ptr);
1320 iheight = png_get_image_height(write_ptr, write_info_ptr);
1321 fprintf(STDERR, "Image width = %lu, height = %lu\n",
1322 (unsigned long)iwidth, (unsigned long)iheight);
1323 }
1324#endif
1325
970f6abe 1326 png_debug(0, "Destroying data structs");
0272a10d 1327#ifdef SINGLE_ROWBUF_ALLOC
970f6abe 1328 png_debug(1, "destroying row_buf for read_ptr");
0272a10d 1329 png_free(read_ptr, row_buf);
970f6abe 1330 row_buf = NULL;
0272a10d 1331#endif /* SINGLE_ROWBUF_ALLOC */
970f6abe 1332 png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr");
0272a10d
VZ
1333 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1334#ifdef PNG_WRITE_SUPPORTED
970f6abe 1335 png_debug(1, "destroying write_end_info_ptr");
0272a10d 1336 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
970f6abe 1337 png_debug(1, "destroying write_ptr, write_info_ptr");
0272a10d
VZ
1338 png_destroy_write_struct(&write_ptr, &write_info_ptr);
1339#endif
970f6abe 1340 png_debug(0, "Destruction complete.");
0272a10d
VZ
1341
1342 FCLOSE(fpin);
1343 FCLOSE(fpout);
1344
970f6abe 1345 png_debug(0, "Opening files for comparison");
0272a10d
VZ
1346#if defined(_WIN32_WCE)
1347 MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
1348 if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1349#else
1350 if ((fpin = fopen(inname, "rb")) == NULL)
1351#endif
1352 {
1353 fprintf(STDERR, "Could not find file %s\n", inname);
1354 return (1);
1355 }
1356
1357#if defined(_WIN32_WCE)
1358 MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
1359 if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1360#else
1361 if ((fpout = fopen(outname, "rb")) == NULL)
1362#endif
1363 {
1364 fprintf(STDERR, "Could not find file %s\n", outname);
1365 FCLOSE(fpin);
1366 return (1);
1367 }
1368
970f6abe 1369 for (;;)
0272a10d
VZ
1370 {
1371 png_size_t num_in, num_out;
1372
970f6abe
VZ
1373 READFILE(fpin, inbuf, 1, num_in);
1374 READFILE(fpout, outbuf, 1, num_out);
0272a10d
VZ
1375
1376 if (num_in != num_out)
1377 {
1378 fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1379 inname, outname);
970f6abe 1380 if (wrote_question == 0)
0272a10d
VZ
1381 {
1382 fprintf(STDERR,
1383 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
970f6abe 1384 inname, PNG_ZBUF_SIZE);
0272a10d
VZ
1385 fprintf(STDERR,
1386 "\n filtering heuristic (libpng default), compression");
1387 fprintf(STDERR,
1388 " level (zlib default),\n and zlib version (%s)?\n\n",
1389 ZLIB_VERSION);
970f6abe 1390 wrote_question = 1;
0272a10d
VZ
1391 }
1392 FCLOSE(fpin);
1393 FCLOSE(fpout);
1394 return (0);
1395 }
1396
1397 if (!num_in)
1398 break;
1399
1400 if (png_memcmp(inbuf, outbuf, num_in))
1401 {
1402 fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
970f6abe 1403 if (wrote_question == 0)
0272a10d
VZ
1404 {
1405 fprintf(STDERR,
1406 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
970f6abe 1407 inname, PNG_ZBUF_SIZE);
0272a10d
VZ
1408 fprintf(STDERR,
1409 "\n filtering heuristic (libpng default), compression");
1410 fprintf(STDERR,
1411 " level (zlib default),\n and zlib version (%s)?\n\n",
1412 ZLIB_VERSION);
970f6abe 1413 wrote_question = 1;
0272a10d
VZ
1414 }
1415 FCLOSE(fpin);
1416 FCLOSE(fpout);
1417 return (0);
1418 }
1419 }
1420
1421 FCLOSE(fpin);
1422 FCLOSE(fpout);
1423
1424 return (0);
1425}
1426
1427/* input and output filenames */
1428#ifdef RISCOS
1429static PNG_CONST char *inname = "pngtest/png";
1430static PNG_CONST char *outname = "pngout/png";
1431#else
1432static PNG_CONST char *inname = "pngtest.png";
1433static PNG_CONST char *outname = "pngout.png";
1434#endif
1435
1436int
1437main(int argc, char *argv[])
1438{
1439 int multiple = 0;
1440 int ierror = 0;
1441
1442 fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1443 fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
970f6abe 1444 fprintf(STDERR, "%s", png_get_copyright(NULL));
0272a10d 1445 /* Show the version of libpng used in building the library */
970f6abe 1446 fprintf(STDERR, " library (%lu):%s",
0272a10d
VZ
1447 (unsigned long)png_access_version_number(),
1448 png_get_header_version(NULL));
1449 /* Show the version of libpng used in building the application */
970f6abe 1450 fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
0272a10d 1451 PNG_HEADER_VERSION_STRING);
970f6abe 1452 fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
0272a10d
VZ
1453 (long)png_sizeof(png_struct), (long)png_sizeof(png_info));
1454
1455 /* Do some consistency checking on the memory allocation settings, I'm
1456 not sure this matters, but it is nice to know, the first of these
1457 tests should be impossible because of the way the macros are set
1458 in pngconf.h */
1459#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1460 fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1461#endif
1462 /* I think the following can happen. */
1463#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1464 fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1465#endif
1466
1467 if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
1468 {
1469 fprintf(STDERR,
1470 "Warning: versions are different between png.h and png.c\n");
1471 fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
1472 fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
1473 ++ierror;
1474 }
1475
1476 if (argc > 1)
1477 {
1478 if (strcmp(argv[1], "-m") == 0)
1479 {
1480 multiple = 1;
1481 status_dots_requested = 0;
1482 }
1483 else if (strcmp(argv[1], "-mv") == 0 ||
1484 strcmp(argv[1], "-vm") == 0 )
1485 {
1486 multiple = 1;
1487 verbose = 1;
1488 status_dots_requested = 1;
1489 }
1490 else if (strcmp(argv[1], "-v") == 0)
1491 {
1492 verbose = 1;
1493 status_dots_requested = 1;
1494 inname = argv[2];
1495 }
1496 else
1497 {
1498 inname = argv[1];
1499 status_dots_requested = 0;
1500 }
1501 }
1502
970f6abe
VZ
1503 if (!multiple && argc == 3 + verbose)
1504 outname = argv[2 + verbose];
0272a10d 1505
970f6abe 1506 if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
0272a10d
VZ
1507 {
1508 fprintf(STDERR,
1509 "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1510 argv[0], argv[0]);
1511 fprintf(STDERR,
1512 " reads/writes one PNG file (without -m) or multiple files (-m)\n");
1513 fprintf(STDERR,
1514 " with -m %s is used as a temporary file\n", outname);
1515 exit(1);
1516 }
1517
1518 if (multiple)
1519 {
1520 int i;
1521#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1522 int allocation_now = current_allocation;
1523#endif
1524 for (i=2; i<argc; ++i)
1525 {
1526#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1527 int k;
1528#endif
1529 int kerror;
970f6abe 1530 fprintf(STDERR, "Testing %s:", argv[i]);
0272a10d
VZ
1531 kerror = test_one_file(argv[i], outname);
1532 if (kerror == 0)
1533 {
1534#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1535 fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1536 (unsigned long)zero_samples);
1537#else
1538 fprintf(STDERR, " PASS\n");
1539#endif
1540#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
970f6abe
VZ
1541 for (k = 0; k<256; k++)
1542 if (filters_used[k])
0272a10d 1543 fprintf(STDERR, " Filter %d was used %lu times\n",
970f6abe 1544 k, (unsigned long)filters_used[k]);
0272a10d
VZ
1545#endif
1546#if defined(PNG_TIME_RFC1123_SUPPORTED)
970f6abe
VZ
1547 if (tIME_chunk_present != 0)
1548 fprintf(STDERR, " tIME = %s\n", tIME_string);
0272a10d
VZ
1549 tIME_chunk_present = 0;
1550#endif /* PNG_TIME_RFC1123_SUPPORTED */
1551 }
1552 else
1553 {
1554 fprintf(STDERR, " FAIL\n");
1555 ierror += kerror;
1556 }
1557#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1558 if (allocation_now != current_allocation)
1559 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
970f6abe 1560 current_allocation - allocation_now);
0272a10d
VZ
1561 if (current_allocation != 0)
1562 {
1563 memory_infop pinfo = pinformation;
1564
1565 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1566 current_allocation);
1567 while (pinfo != NULL)
1568 {
970f6abe
VZ
1569 fprintf(STDERR, " %lu bytes at %x\n",
1570 (unsigned long)pinfo->size,
0272a10d
VZ
1571 (unsigned int) pinfo->pointer);
1572 pinfo = pinfo->next;
1573 }
1574 }
1575#endif
1576 }
1577#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1578 fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1579 current_allocation);
1580 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1581 maximum_allocation);
1582 fprintf(STDERR, " Total memory allocation: %10d bytes\n",
1583 total_allocation);
1584 fprintf(STDERR, " Number of allocations: %10d\n",
1585 num_allocations);
1586#endif
1587 }
1588 else
1589 {
1590 int i;
970f6abe 1591 for (i = 0; i<3; ++i)
0272a10d
VZ
1592 {
1593 int kerror;
1594#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1595 int allocation_now = current_allocation;
1596#endif
1597 if (i == 1) status_dots_requested = 1;
970f6abe 1598 else if (verbose == 0)status_dots_requested = 0;
0272a10d 1599 if (i == 0 || verbose == 1 || ierror != 0)
970f6abe 1600 fprintf(STDERR, "Testing %s:", inname);
0272a10d 1601 kerror = test_one_file(inname, outname);
970f6abe 1602 if (kerror == 0)
0272a10d 1603 {
970f6abe 1604 if (verbose == 1 || i == 2)
0272a10d
VZ
1605 {
1606#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1607 int k;
1608#endif
1609#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1610 fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1611 (unsigned long)zero_samples);
1612#else
1613 fprintf(STDERR, " PASS\n");
1614#endif
1615#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
970f6abe
VZ
1616 for (k = 0; k<256; k++)
1617 if (filters_used[k])
0272a10d 1618 fprintf(STDERR, " Filter %d was used %lu times\n",
970f6abe
VZ
1619 k,
1620 (unsigned long)filters_used[k]);
0272a10d
VZ
1621#endif
1622#if defined(PNG_TIME_RFC1123_SUPPORTED)
970f6abe
VZ
1623 if (tIME_chunk_present != 0)
1624 fprintf(STDERR, " tIME = %s\n", tIME_string);
0272a10d
VZ
1625#endif /* PNG_TIME_RFC1123_SUPPORTED */
1626 }
1627 }
1628 else
1629 {
970f6abe
VZ
1630 if (verbose == 0 && i != 2)
1631 fprintf(STDERR, "Testing %s:", inname);
0272a10d
VZ
1632 fprintf(STDERR, " FAIL\n");
1633 ierror += kerror;
1634 }
1635#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1636 if (allocation_now != current_allocation)
1637 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
970f6abe 1638 current_allocation - allocation_now);
0272a10d
VZ
1639 if (current_allocation != 0)
1640 {
1641 memory_infop pinfo = pinformation;
1642
1643 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1644 current_allocation);
1645 while (pinfo != NULL)
1646 {
970f6abe 1647 fprintf(STDERR, " %lu bytes at %x\n",
0272a10d
VZ
1648 (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1649 pinfo = pinfo->next;
1650 }
1651 }
1652#endif
1653 }
1654#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1655 fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1656 current_allocation);
1657 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1658 maximum_allocation);
1659 fprintf(STDERR, " Total memory allocation: %10d bytes\n",
1660 total_allocation);
1661 fprintf(STDERR, " Number of allocations: %10d\n",
1662 num_allocations);
1663#endif
1664 }
1665
1666#ifdef PNGTEST_TIMING
1667 t_stop = (float)clock();
1668 t_misc += (t_stop - t_start);
1669 t_start = t_stop;
970f6abe 1670 fprintf(STDERR, " CPU time used = %.3f seconds",
0272a10d 1671 (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
970f6abe 1672 fprintf(STDERR, " (decoding %.3f,\n",
0272a10d 1673 t_decode/(float)CLOCKS_PER_SEC);
970f6abe 1674 fprintf(STDERR, " encoding %.3f ,",
0272a10d 1675 t_encode/(float)CLOCKS_PER_SEC);
970f6abe 1676 fprintf(STDERR, " other %.3f seconds)\n\n",
0272a10d
VZ
1677 t_misc/(float)CLOCKS_PER_SEC);
1678#endif
1679
1680 if (ierror == 0)
1681 fprintf(STDERR, "libpng passes test\n");
1682 else
1683 fprintf(STDERR, "libpng FAILS test\n");
1684 return (int)(ierror != 0);
1685}
1686
1687/* Generate a compiler error if there is an old png.h in the search path. */
970f6abe 1688typedef version_1_2_34 your_png_h_is_not_version_1_2_34;