merged libpng 1.2.34 into the trunk (see #10043)
[wxWidgets.git] / src / png / pngtest.c
1
2 /* pngtest.c - a simple test program to test libpng
3 *
4 * Last changed in libpng 1.2.32 [September 18, 2008]
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
7 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9 *
10 * This 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) \
40 if (ReadFile(file, data, length, &check, NULL)) check = 0
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) \
48 check=(png_size_t)fread(data, (png_size_t)1, length, file)
49 # define WRITEFILE(file, data, length, check) \
50 check=(png_size_t)fwrite(data, (png_size_t)1, length, file)
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
80 static 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)
85 #define PNG_tIME_STRING_LENGTH 29
86 static int tIME_chunk_present = 0;
87 static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
88 #endif
89
90 static int verbose = 0;
91
92 int 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
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
112 /* example of using row callbacks to make a simple progress meter */
113 static int status_pass = 1;
114 static int status_dots_requested = 0;
115 static int status_dots = 1;
116
117 void
118 #ifdef PNG_1_0_X
119 PNGAPI
120 #endif
121 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
122 void
123 #ifdef PNG_1_0_X
124 PNGAPI
125 #endif
126 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
127 {
128 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) return;
129 if (status_pass != pass)
130 {
131 fprintf(stdout, "\n Pass %d: ", pass);
132 status_pass = pass;
133 status_dots = 31;
134 }
135 status_dots--;
136 if (status_dots == 0)
137 {
138 fprintf(stdout, "\n ");
139 status_dots=30;
140 }
141 fprintf(stdout, "r");
142 }
143
144 void
145 #ifdef PNG_1_0_X
146 PNGAPI
147 #endif
148 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
149 void
150 #ifdef PNG_1_0_X
151 PNGAPI
152 #endif
153 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
154 {
155 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return;
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.) */
164 static png_uint_32 filters_used[256];
165 void
166 #ifdef PNG_1_0_X
167 PNGAPI
168 #endif
169 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
170 void
171 #ifdef PNG_1_0_X
172 PNGAPI
173 #endif
174 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
175 {
176 if (png_ptr != NULL && row_info != NULL)
177 ++filters_used[*(data - 1)];
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
185 static png_uint_32 zero_samples;
186
187 void
188 #ifdef PNG_1_0_X
189 PNGAPI
190 #endif
191 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
192 void
193 #ifdef PNG_1_0_X
194 PNGAPI
195 #endif
196 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
197 {
198 png_bytep dp = data;
199 if (png_ptr == NULL)return;
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
213 if (row_info->color_type == 0 || row_info->color_type == 3)
214 {
215 int pos = 0;
216 png_uint_32 n, nstop;
217 for (n = 0, nstop=row_info->width; n<nstop; n++)
218 {
219 if (row_info->bit_depth == 1)
220 {
221 if (((*dp << pos++ ) & 0x80) == 0) zero_samples++;
222 if (pos == 8)
223 {
224 pos = 0;
225 dp++;
226 }
227 }
228 if (row_info->bit_depth == 2)
229 {
230 if (((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
231 if (pos == 8)
232 {
233 pos = 0;
234 dp++;
235 }
236 }
237 if (row_info->bit_depth == 4)
238 {
239 if (((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
240 if (pos == 8)
241 {
242 pos = 0;
243 dp++;
244 }
245 }
246 if (row_info->bit_depth == 8)
247 if (*dp++ == 0) zero_samples++;
248 if (row_info->bit_depth == 16)
249 {
250 if ((*dp | *(dp+1)) == 0) zero_samples++;
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;
260 if (row_info->color_type > 3)color_channels--;
261
262 for (n = 0, nstop=row_info->width; n<nstop; n++)
263 {
264 for (channel = 0; channel < color_channels; channel++)
265 {
266 if (row_info->bit_depth == 8)
267 if (*dp++ == 0) zero_samples++;
268 if (row_info->bit_depth == 16)
269 {
270 if ((*dp | *(dp+1)) == 0) zero_samples++;
271 dp+=2;
272 }
273 }
274 if (row_info->color_type > 3)
275 {
276 dp++;
277 if (row_info->bit_depth == 16)dp++;
278 }
279 }
280 }
281 }
282 #endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
283
284 static 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
296 static void
297 pngtest_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
320 static void
321 pngtest_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 */
345 if (err != read)
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)
362 static void
363 pngtest_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
379 static void
380 pngtest_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
399 static void
400 pngtest_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 */
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 */
445 static void
446 pngtest_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 */
459 static void
460 pngtest_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 }
466 #endif /* PNG_NO_STDIO */
467 /* END of code to validate stdio-free compilation */
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. */
480 typedef struct memory_information
481 {
482 png_uint_32 size;
483 png_voidp pointer;
484 struct memory_information FAR *next;
485 } memory_information;
486 typedef memory_information FAR *memory_infop;
487
488 static memory_infop pinformation = NULL;
489 static int current_allocation = 0;
490 static int maximum_allocation = 0;
491 static int total_allocation = 0;
492 static int num_allocations = 0;
493
494 png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
495 void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
496
497 png_voidp
498 png_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,
514 (png_uint_32)png_sizeof(*pinfo));
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 */
523 png_set_mem_fn(png_ptr,
524 png_voidp_NULL, (png_malloc_ptr)png_debug_malloc,
525 (png_free_ptr)png_debug_free);
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);
537 if (verbose)
538 printf("png_malloc %lu bytes at %x\n", (unsigned long)size,
539 pinfo->pointer);
540 return (png_voidp)(pinfo->pointer);
541 }
542 }
543
544 /* Free a pointer. It is removed from the list at the same time. */
545 void
546 png_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);
574 pinfo = NULL;
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. */
587 if (verbose)
588 printf("Freeing %x\n", ptr);
589 png_free_default(png_ptr, ptr);
590 ptr = NULL;
591 }
592 #endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
593 /* END of code to test memory allocation/deallocation */
594
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
600 chunk used in ImageMagick to store "virtual page" size). */
601
602 static 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
610 static 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
662 /* Test one file */
663 int
664 test_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
720 png_debug(0, "Allocating read and write structures");
721 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
722 read_ptr =
723 png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
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
727 read_ptr =
728 png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
729 png_error_ptr_NULL, png_error_ptr_NULL);
730 #endif
731 #if defined(PNG_NO_STDIO)
732 png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
733 pngtest_warning);
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
745 #ifdef PNG_WRITE_SUPPORTED
746 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
747 write_ptr =
748 png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
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
752 write_ptr =
753 png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
754 png_error_ptr_NULL, png_error_ptr_NULL);
755 #endif
756 #if defined(PNG_NO_STDIO)
757 png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
758 pngtest_warning);
759 #endif
760 #endif
761 png_debug(0, "Allocating read_info, write_info and end_info structures");
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
770 png_debug(0, "Setting jmpbuf for read struct");
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);
778 png_free(read_ptr, row_buf);
779 row_buf = NULL;
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
790 png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf));
791 #endif
792
793 #ifdef PNG_WRITE_SUPPORTED
794 png_debug(0, "Setting jmpbuf for write struct");
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
812 png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf));
813 #endif
814 #endif
815 #endif
816
817 png_debug(0, "Initializing input and output streams");
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
834 if (status_dots_requested == 1)
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;
852 for (i = 0; i<256; i++)
853 filters_used[i] = 0;
854 png_set_read_user_transform_fn(read_ptr, count_filters);
855 }
856 #endif
857 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
858 zero_samples = 0;
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
877 png_debug(0, "Reading info struct");
878 png_read_info(read_ptr, read_info_ptr);
879
880 png_debug(0, "Transferring info struct");
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
1003 if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1004 &unit_type))
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 {
1080 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
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)
1093 /* we have to use png_memcpy instead of "=" because the string
1094 pointed to by png_convert_to_rfc1123() gets free'ed before
1095 we use it */
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';
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 {
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);
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
1148 png_debug(0, "Writing info struct");
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);
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
1188 #endif
1189
1190 #ifdef SINGLE_ROWBUF_ALLOC
1191 png_debug(0, "Allocating row buffer...");
1192 row_buf = (png_bytep)png_malloc(read_ptr,
1193 png_get_rowbytes(read_ptr, read_info_ptr));
1194 png_debug1(0, "0x%08lx", (unsigned long)row_buf);
1195 #endif /* SINGLE_ROWBUF_ALLOC */
1196 png_debug(0, "Writing row data");
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
1205 num_pass = 1;
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 {
1215 png_debug1(0, "Writing row data for pass %d", pass);
1216 for (y = 0; y < height; y++)
1217 {
1218 #ifndef SINGLE_ROWBUF_ALLOC
1219 png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass, y);
1220 row_buf = (png_bytep)png_malloc(read_ptr,
1221 png_get_rowbytes(read_ptr, read_info_ptr));
1222 png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf,
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
1242 png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y);
1243 png_free(read_ptr, row_buf);
1244 row_buf = NULL;
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
1256 png_debug(0, "Reading and writing end_info data");
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 {
1266 png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
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)
1279 /* we have to use png_memcpy instead of "=" because the string
1280 pointed to by png_convert_to_rfc1123() gets free'ed before
1281 we use it */
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';
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
1316 if (verbose)
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
1326 png_debug(0, "Destroying data structs");
1327 #ifdef SINGLE_ROWBUF_ALLOC
1328 png_debug(1, "destroying row_buf for read_ptr");
1329 png_free(read_ptr, row_buf);
1330 row_buf = NULL;
1331 #endif /* SINGLE_ROWBUF_ALLOC */
1332 png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr");
1333 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1334 #ifdef PNG_WRITE_SUPPORTED
1335 png_debug(1, "destroying write_end_info_ptr");
1336 png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1337 png_debug(1, "destroying write_ptr, write_info_ptr");
1338 png_destroy_write_struct(&write_ptr, &write_info_ptr);
1339 #endif
1340 png_debug(0, "Destruction complete.");
1341
1342 FCLOSE(fpin);
1343 FCLOSE(fpout);
1344
1345 png_debug(0, "Opening files for comparison");
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
1369 for (;;)
1370 {
1371 png_size_t num_in, num_out;
1372
1373 READFILE(fpin, inbuf, 1, num_in);
1374 READFILE(fpout, outbuf, 1, num_out);
1375
1376 if (num_in != num_out)
1377 {
1378 fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1379 inname, outname);
1380 if (wrote_question == 0)
1381 {
1382 fprintf(STDERR,
1383 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
1384 inname, PNG_ZBUF_SIZE);
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);
1390 wrote_question = 1;
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);
1403 if (wrote_question == 0)
1404 {
1405 fprintf(STDERR,
1406 " Was %s written with the same maximum IDAT chunk size (%d bytes),",
1407 inname, PNG_ZBUF_SIZE);
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);
1413 wrote_question = 1;
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
1429 static PNG_CONST char *inname = "pngtest/png";
1430 static PNG_CONST char *outname = "pngout/png";
1431 #else
1432 static PNG_CONST char *inname = "pngtest.png";
1433 static PNG_CONST char *outname = "pngout.png";
1434 #endif
1435
1436 int
1437 main(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);
1444 fprintf(STDERR, "%s", png_get_copyright(NULL));
1445 /* Show the version of libpng used in building the library */
1446 fprintf(STDERR, " library (%lu):%s",
1447 (unsigned long)png_access_version_number(),
1448 png_get_header_version(NULL));
1449 /* Show the version of libpng used in building the application */
1450 fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1451 PNG_HEADER_VERSION_STRING);
1452 fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
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
1503 if (!multiple && argc == 3 + verbose)
1504 outname = argv[2 + verbose];
1505
1506 if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
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;
1530 fprintf(STDERR, "Testing %s:", argv[i]);
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)
1541 for (k = 0; k<256; k++)
1542 if (filters_used[k])
1543 fprintf(STDERR, " Filter %d was used %lu times\n",
1544 k, (unsigned long)filters_used[k]);
1545 #endif
1546 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1547 if (tIME_chunk_present != 0)
1548 fprintf(STDERR, " tIME = %s\n", tIME_string);
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",
1560 current_allocation - allocation_now);
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 {
1569 fprintf(STDERR, " %lu bytes at %x\n",
1570 (unsigned long)pinfo->size,
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;
1591 for (i = 0; i<3; ++i)
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;
1598 else if (verbose == 0)status_dots_requested = 0;
1599 if (i == 0 || verbose == 1 || ierror != 0)
1600 fprintf(STDERR, "Testing %s:", inname);
1601 kerror = test_one_file(inname, outname);
1602 if (kerror == 0)
1603 {
1604 if (verbose == 1 || i == 2)
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)
1616 for (k = 0; k<256; k++)
1617 if (filters_used[k])
1618 fprintf(STDERR, " Filter %d was used %lu times\n",
1619 k,
1620 (unsigned long)filters_used[k]);
1621 #endif
1622 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1623 if (tIME_chunk_present != 0)
1624 fprintf(STDERR, " tIME = %s\n", tIME_string);
1625 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1626 }
1627 }
1628 else
1629 {
1630 if (verbose == 0 && i != 2)
1631 fprintf(STDERR, "Testing %s:", inname);
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",
1638 current_allocation - allocation_now);
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 {
1647 fprintf(STDERR, " %lu bytes at %x\n",
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;
1670 fprintf(STDERR, " CPU time used = %.3f seconds",
1671 (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1672 fprintf(STDERR, " (decoding %.3f,\n",
1673 t_decode/(float)CLOCKS_PER_SEC);
1674 fprintf(STDERR, " encoding %.3f ,",
1675 t_encode/(float)CLOCKS_PER_SEC);
1676 fprintf(STDERR, " other %.3f seconds)\n\n",
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. */
1688 typedef version_1_2_34 your_png_h_is_not_version_1_2_34;