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