Mercurial > mm7
comparison lib/libpng/pngtest.c @ 2305:a5e8eecac226
Merge
author | Grumpy7 |
---|---|
date | Sun, 16 Mar 2014 21:04:49 +0100 |
parents | 6e178010fc29 |
children |
comparison
equal
deleted
inserted
replaced
2304:e76b56512abd | 2305:a5e8eecac226 |
---|---|
1 | |
2 /* pngtest.c - a simple test program to test libpng | |
3 * | |
4 * Last changed in libpng 1.6.9 [February 6, 2014] | |
5 * Copyright (c) 1998-2014 Glenn Randers-Pehrson | |
6 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) | |
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) | |
8 * | |
9 * This code is released under the libpng license. | |
10 * For conditions of distribution and use, see the disclaimer | |
11 * and license in png.h | |
12 * | |
13 * This program reads in a PNG image, writes it out again, and then | |
14 * compares the two files. If the files are identical, this shows that | |
15 * the basic chunk handling, filtering, and (de)compression code is working | |
16 * properly. It does not currently test all of the transforms, although | |
17 * it probably should. | |
18 * | |
19 * The program will report "FAIL" in certain legitimate cases: | |
20 * 1) when the compression level or filter selection method is changed. | |
21 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. | |
22 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks | |
23 * exist in the input file. | |
24 * 4) others not listed here... | |
25 * In these cases, it is best to check with another tool such as "pngcheck" | |
26 * to see what the differences between the two files are. | |
27 * | |
28 * If a filename is given on the command-line, then this file is used | |
29 * for the input, rather than the default "pngtest.png". This allows | |
30 * testing a wide variety of files easily. You can also test a number | |
31 * of files at once by typing "pngtest -m file1.png file2.png ..." | |
32 */ | |
33 | |
34 #define _POSIX_SOURCE 1 | |
35 | |
36 #include <stdio.h> | |
37 #include <stdlib.h> | |
38 #include <string.h> | |
39 | |
40 /* Defined so I can write to a file on gui/windowing platforms */ | |
41 /* #define STDERR stderr */ | |
42 #define STDERR stdout /* For DOS */ | |
43 | |
44 #include "png.h" | |
45 | |
46 /* Known chunks that exist in pngtest.png must be supported or pngtest will fail | |
47 * simply as a result of re-ordering them. This may be fixed in 1.7 | |
48 * | |
49 * pngtest allocates a single row buffer for each row and overwrites it, | |
50 * therefore if the write side doesn't support the writing of interlaced images | |
51 * nothing can be done for an interlaced image (and the code below will fail | |
52 * horribly trying to write extra data after writing garbage). | |
53 */ | |
54 #if defined PNG_READ_SUPPORTED && /* else nothing can be done */\ | |
55 defined PNG_READ_bKGD_SUPPORTED &&\ | |
56 defined PNG_READ_cHRM_SUPPORTED &&\ | |
57 defined PNG_READ_gAMA_SUPPORTED &&\ | |
58 defined PNG_READ_oFFs_SUPPORTED &&\ | |
59 defined PNG_READ_pCAL_SUPPORTED &&\ | |
60 defined PNG_READ_pHYs_SUPPORTED &&\ | |
61 defined PNG_READ_sBIT_SUPPORTED &&\ | |
62 defined PNG_READ_sCAL_SUPPORTED &&\ | |
63 defined PNG_READ_sRGB_SUPPORTED &&\ | |
64 defined PNG_READ_tEXt_SUPPORTED &&\ | |
65 defined PNG_READ_tIME_SUPPORTED &&\ | |
66 defined PNG_READ_zTXt_SUPPORTED &&\ | |
67 defined PNG_WRITE_INTERLACING_SUPPORTED | |
68 | |
69 #ifdef PNG_ZLIB_HEADER | |
70 # include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */ | |
71 #else | |
72 # include "../../lib/zlib/zlib.h" | |
73 #endif | |
74 | |
75 /* Copied from pngpriv.h but only used in error messages below. */ | |
76 #ifndef PNG_ZBUF_SIZE | |
77 # define PNG_ZBUF_SIZE 8192 | |
78 #endif | |
79 #define FCLOSE(file) fclose(file) | |
80 | |
81 #ifndef PNG_STDIO_SUPPORTED | |
82 typedef FILE * png_FILE_p; | |
83 #endif | |
84 | |
85 /* Makes pngtest verbose so we can find problems. */ | |
86 #ifndef PNG_DEBUG | |
87 # define PNG_DEBUG 0 | |
88 #endif | |
89 | |
90 #if PNG_DEBUG > 1 | |
91 # define pngtest_debug(m) ((void)fprintf(stderr, m "\n")) | |
92 # define pngtest_debug1(m,p1) ((void)fprintf(stderr, m "\n", p1)) | |
93 # define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2)) | |
94 #else | |
95 # define pngtest_debug(m) ((void)0) | |
96 # define pngtest_debug1(m,p1) ((void)0) | |
97 # define pngtest_debug2(m,p1,p2) ((void)0) | |
98 #endif | |
99 | |
100 #if !PNG_DEBUG | |
101 # define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ | |
102 #endif | |
103 | |
104 /* Turn on CPU timing | |
105 #define PNGTEST_TIMING | |
106 */ | |
107 | |
108 #ifndef PNG_FLOATING_POINT_SUPPORTED | |
109 #undef PNGTEST_TIMING | |
110 #endif | |
111 | |
112 #ifdef PNGTEST_TIMING | |
113 static float t_start, t_stop, t_decode, t_encode, t_misc; | |
114 #include <time.h> | |
115 #endif | |
116 | |
117 #ifdef PNG_TIME_RFC1123_SUPPORTED | |
118 #define PNG_tIME_STRING_LENGTH 29 | |
119 static int tIME_chunk_present = 0; | |
120 static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; | |
121 #endif | |
122 | |
123 static int verbose = 0; | |
124 static int strict = 0; | |
125 static int relaxed = 0; | |
126 static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ | |
127 static int error_count = 0; /* count calls to png_error */ | |
128 static int warning_count = 0; /* count calls to png_warning */ | |
129 | |
130 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ | |
131 #ifndef png_jmpbuf | |
132 # define png_jmpbuf(png_ptr) png_ptr->jmpbuf | |
133 #endif | |
134 | |
135 /* Defines for unknown chunk handling if required. */ | |
136 #ifndef PNG_HANDLE_CHUNK_ALWAYS | |
137 # define PNG_HANDLE_CHUNK_ALWAYS 3 | |
138 #endif | |
139 #ifndef PNG_HANDLE_CHUNK_IF_SAFE | |
140 # define PNG_HANDLE_CHUNK_IF_SAFE 2 | |
141 #endif | |
142 | |
143 /* Utility to save typing/errors, the argument must be a name */ | |
144 #define MEMZERO(var) ((void)memset(&var, 0, sizeof var)) | |
145 | |
146 /* Example of using row callbacks to make a simple progress meter */ | |
147 static int status_pass = 1; | |
148 static int status_dots_requested = 0; | |
149 static int status_dots = 1; | |
150 | |
151 static void PNGCBAPI | |
152 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) | |
153 { | |
154 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) | |
155 return; | |
156 | |
157 if (status_pass != pass) | |
158 { | |
159 fprintf(stdout, "\n Pass %d: ", pass); | |
160 status_pass = pass; | |
161 status_dots = 31; | |
162 } | |
163 | |
164 status_dots--; | |
165 | |
166 if (status_dots == 0) | |
167 { | |
168 fprintf(stdout, "\n "); | |
169 status_dots=30; | |
170 } | |
171 | |
172 fprintf(stdout, "r"); | |
173 } | |
174 | |
175 #ifdef PNG_WRITE_SUPPORTED | |
176 static void PNGCBAPI | |
177 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) | |
178 { | |
179 if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) | |
180 return; | |
181 | |
182 fprintf(stdout, "w"); | |
183 } | |
184 #endif | |
185 | |
186 | |
187 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
188 /* Example of using user transform callback (we don't transform anything, | |
189 * but merely examine the row filters. We set this to 256 rather than | |
190 * 5 in case illegal filter values are present.) | |
191 */ | |
192 static png_uint_32 filters_used[256]; | |
193 static void PNGCBAPI | |
194 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) | |
195 { | |
196 if (png_ptr != NULL && row_info != NULL) | |
197 ++filters_used[*(data - 1)]; | |
198 } | |
199 #endif | |
200 | |
201 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED | |
202 /* Example of using user transform callback (we don't transform anything, | |
203 * but merely count the zero samples) | |
204 */ | |
205 | |
206 static png_uint_32 zero_samples; | |
207 | |
208 static void PNGCBAPI | |
209 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) | |
210 { | |
211 png_bytep dp = data; | |
212 if (png_ptr == NULL) | |
213 return; | |
214 | |
215 /* Contents of row_info: | |
216 * png_uint_32 width width of row | |
217 * png_uint_32 rowbytes number of bytes in row | |
218 * png_byte color_type color type of pixels | |
219 * png_byte bit_depth bit depth of samples | |
220 * png_byte channels number of channels (1-4) | |
221 * png_byte pixel_depth bits per pixel (depth*channels) | |
222 */ | |
223 | |
224 /* Counts the number of zero samples (or zero pixels if color_type is 3 */ | |
225 | |
226 if (row_info->color_type == 0 || row_info->color_type == 3) | |
227 { | |
228 int pos = 0; | |
229 png_uint_32 n, nstop; | |
230 | |
231 for (n = 0, nstop=row_info->width; n<nstop; n++) | |
232 { | |
233 if (row_info->bit_depth == 1) | |
234 { | |
235 if (((*dp << pos++ ) & 0x80) == 0) | |
236 zero_samples++; | |
237 | |
238 if (pos == 8) | |
239 { | |
240 pos = 0; | |
241 dp++; | |
242 } | |
243 } | |
244 | |
245 if (row_info->bit_depth == 2) | |
246 { | |
247 if (((*dp << (pos+=2)) & 0xc0) == 0) | |
248 zero_samples++; | |
249 | |
250 if (pos == 8) | |
251 { | |
252 pos = 0; | |
253 dp++; | |
254 } | |
255 } | |
256 | |
257 if (row_info->bit_depth == 4) | |
258 { | |
259 if (((*dp << (pos+=4)) & 0xf0) == 0) | |
260 zero_samples++; | |
261 | |
262 if (pos == 8) | |
263 { | |
264 pos = 0; | |
265 dp++; | |
266 } | |
267 } | |
268 | |
269 if (row_info->bit_depth == 8) | |
270 if (*dp++ == 0) | |
271 zero_samples++; | |
272 | |
273 if (row_info->bit_depth == 16) | |
274 { | |
275 if ((*dp | *(dp+1)) == 0) | |
276 zero_samples++; | |
277 dp+=2; | |
278 } | |
279 } | |
280 } | |
281 else /* Other color types */ | |
282 { | |
283 png_uint_32 n, nstop; | |
284 int channel; | |
285 int color_channels = row_info->channels; | |
286 if (row_info->color_type > 3)color_channels--; | |
287 | |
288 for (n = 0, nstop=row_info->width; n<nstop; n++) | |
289 { | |
290 for (channel = 0; channel < color_channels; channel++) | |
291 { | |
292 if (row_info->bit_depth == 8) | |
293 if (*dp++ == 0) | |
294 zero_samples++; | |
295 | |
296 if (row_info->bit_depth == 16) | |
297 { | |
298 if ((*dp | *(dp+1)) == 0) | |
299 zero_samples++; | |
300 | |
301 dp+=2; | |
302 } | |
303 } | |
304 if (row_info->color_type > 3) | |
305 { | |
306 dp++; | |
307 if (row_info->bit_depth == 16) | |
308 dp++; | |
309 } | |
310 } | |
311 } | |
312 } | |
313 #endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ | |
314 | |
315 #ifndef PNG_STDIO_SUPPORTED | |
316 /* START of code to validate stdio-free compilation */ | |
317 /* These copies of the default read/write functions come from pngrio.c and | |
318 * pngwio.c. They allow "don't include stdio" testing of the library. | |
319 * This is the function that does the actual reading of data. If you are | |
320 * not reading from a standard C stream, you should create a replacement | |
321 * read_data function and use it at run time with png_set_read_fn(), rather | |
322 * than changing the library. | |
323 */ | |
324 | |
325 #ifdef PNG_IO_STATE_SUPPORTED | |
326 void | |
327 pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, | |
328 png_uint_32 io_op); | |
329 void | |
330 pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, | |
331 png_uint_32 io_op) | |
332 { | |
333 png_uint_32 io_state = png_get_io_state(png_ptr); | |
334 int err = 0; | |
335 | |
336 /* Check if the current operation (reading / writing) is as expected. */ | |
337 if ((io_state & PNG_IO_MASK_OP) != io_op) | |
338 png_error(png_ptr, "Incorrect operation in I/O state"); | |
339 | |
340 /* Check if the buffer size specific to the current location | |
341 * (file signature / header / data / crc) is as expected. | |
342 */ | |
343 switch (io_state & PNG_IO_MASK_LOC) | |
344 { | |
345 case PNG_IO_SIGNATURE: | |
346 if (data_length > 8) | |
347 err = 1; | |
348 break; | |
349 case PNG_IO_CHUNK_HDR: | |
350 if (data_length != 8) | |
351 err = 1; | |
352 break; | |
353 case PNG_IO_CHUNK_DATA: | |
354 break; /* no restrictions here */ | |
355 case PNG_IO_CHUNK_CRC: | |
356 if (data_length != 4) | |
357 err = 1; | |
358 break; | |
359 default: | |
360 err = 1; /* uninitialized */ | |
361 } | |
362 if (err) | |
363 png_error(png_ptr, "Bad I/O state or buffer size"); | |
364 } | |
365 #endif | |
366 | |
367 static void PNGCBAPI | |
368 pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) | |
369 { | |
370 png_size_t check = 0; | |
371 png_voidp io_ptr; | |
372 | |
373 /* fread() returns 0 on error, so it is OK to store this in a png_size_t | |
374 * instead of an int, which is what fread() actually returns. | |
375 */ | |
376 io_ptr = png_get_io_ptr(png_ptr); | |
377 if (io_ptr != NULL) | |
378 { | |
379 check = fread(data, 1, length, (png_FILE_p)io_ptr); | |
380 } | |
381 | |
382 if (check != length) | |
383 { | |
384 png_error(png_ptr, "Read Error"); | |
385 } | |
386 | |
387 #ifdef PNG_IO_STATE_SUPPORTED | |
388 pngtest_check_io_state(png_ptr, length, PNG_IO_READING); | |
389 #endif | |
390 } | |
391 | |
392 #ifdef PNG_WRITE_FLUSH_SUPPORTED | |
393 static void PNGCBAPI | |
394 pngtest_flush(png_structp png_ptr) | |
395 { | |
396 /* Do nothing; fflush() is said to be just a waste of energy. */ | |
397 PNG_UNUSED(png_ptr) /* Stifle compiler warning */ | |
398 } | |
399 #endif | |
400 | |
401 /* This is the function that does the actual writing of data. If you are | |
402 * not writing to a standard C stream, you should create a replacement | |
403 * write_data function and use it at run time with png_set_write_fn(), rather | |
404 * than changing the library. | |
405 */ | |
406 static void PNGCBAPI | |
407 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) | |
408 { | |
409 png_size_t check; | |
410 | |
411 check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr)); | |
412 | |
413 if (check != length) | |
414 { | |
415 png_error(png_ptr, "Write Error"); | |
416 } | |
417 | |
418 #ifdef PNG_IO_STATE_SUPPORTED | |
419 pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING); | |
420 #endif | |
421 } | |
422 #endif /* !PNG_STDIO_SUPPORTED */ | |
423 | |
424 /* This function is called when there is a warning, but the library thinks | |
425 * it can continue anyway. Replacement functions don't have to do anything | |
426 * here if you don't want to. In the default configuration, png_ptr is | |
427 * not used, but it is passed in case it may be useful. | |
428 */ | |
429 typedef struct | |
430 { | |
431 PNG_CONST char *file_name; | |
432 } pngtest_error_parameters; | |
433 | |
434 static void PNGCBAPI | |
435 pngtest_warning(png_structp png_ptr, png_const_charp message) | |
436 { | |
437 PNG_CONST char *name = "UNKNOWN (ERROR!)"; | |
438 pngtest_error_parameters *test = | |
439 (pngtest_error_parameters*)png_get_error_ptr(png_ptr); | |
440 | |
441 ++warning_count; | |
442 | |
443 if (test != NULL && test->file_name != NULL) | |
444 name = test->file_name; | |
445 | |
446 fprintf(STDERR, "%s: libpng warning: %s\n", name, message); | |
447 } | |
448 | |
449 /* This is the default error handling function. Note that replacements for | |
450 * this function MUST NOT RETURN, or the program will likely crash. This | |
451 * function is used by default, or if the program supplies NULL for the | |
452 * error function pointer in png_set_error_fn(). | |
453 */ | |
454 static void PNGCBAPI | |
455 pngtest_error(png_structp png_ptr, png_const_charp message) | |
456 { | |
457 ++error_count; | |
458 | |
459 pngtest_warning(png_ptr, message); | |
460 /* We can return because png_error calls the default handler, which is | |
461 * actually OK in this case. | |
462 */ | |
463 } | |
464 | |
465 /* END of code to validate stdio-free compilation */ | |
466 | |
467 /* START of code to validate memory allocation and deallocation */ | |
468 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
469 | |
470 /* Allocate memory. For reasonable files, size should never exceed | |
471 * 64K. However, zlib may allocate more then 64K if you don't tell | |
472 * it not to. See zconf.h and png.h for more information. zlib does | |
473 * need to allocate exactly 64K, so whatever you call here must | |
474 * have the ability to do that. | |
475 * | |
476 * This piece of code can be compiled to validate max 64K allocations | |
477 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. | |
478 */ | |
479 typedef struct memory_information | |
480 { | |
481 png_alloc_size_t size; | |
482 png_voidp pointer; | |
483 struct memory_information *next; | |
484 } memory_information; | |
485 typedef memory_information *memory_infop; | |
486 | |
487 static memory_infop pinformation = NULL; | |
488 static int current_allocation = 0; | |
489 static int maximum_allocation = 0; | |
490 static int total_allocation = 0; | |
491 static int num_allocations = 0; | |
492 | |
493 png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr, | |
494 png_alloc_size_t size)); | |
495 void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); | |
496 | |
497 png_voidp | |
498 PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t 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 | |
505 if (size == 0) | |
506 return (NULL); | |
507 | |
508 /* This calls the library allocator twice, once to get the requested | |
509 buffer and once to get a new free list entry. */ | |
510 { | |
511 /* Disable malloc_fn and free_fn */ | |
512 memory_infop pinfo; | |
513 png_set_mem_fn(png_ptr, NULL, NULL, NULL); | |
514 pinfo = (memory_infop)png_malloc(png_ptr, | |
515 (sizeof *pinfo)); | |
516 pinfo->size = size; | |
517 current_allocation += size; | |
518 total_allocation += size; | |
519 num_allocations ++; | |
520 | |
521 if (current_allocation > maximum_allocation) | |
522 maximum_allocation = current_allocation; | |
523 | |
524 pinfo->pointer = png_malloc(png_ptr, size); | |
525 /* Restore malloc_fn and free_fn */ | |
526 | |
527 png_set_mem_fn(png_ptr, | |
528 NULL, png_debug_malloc, png_debug_free); | |
529 | |
530 if (size != 0 && pinfo->pointer == NULL) | |
531 { | |
532 current_allocation -= size; | |
533 total_allocation -= size; | |
534 png_error(png_ptr, | |
535 "out of memory in pngtest->png_debug_malloc"); | |
536 } | |
537 | |
538 pinfo->next = pinformation; | |
539 pinformation = pinfo; | |
540 /* Make sure the caller isn't assuming zeroed memory. */ | |
541 memset(pinfo->pointer, 0xdd, pinfo->size); | |
542 | |
543 if (verbose) | |
544 printf("png_malloc %lu bytes at %p\n", (unsigned long)size, | |
545 pinfo->pointer); | |
546 | |
547 return (png_voidp)(pinfo->pointer); | |
548 } | |
549 } | |
550 | |
551 /* Free a pointer. It is removed from the list at the same time. */ | |
552 void PNGCBAPI | |
553 png_debug_free(png_structp png_ptr, png_voidp ptr) | |
554 { | |
555 if (png_ptr == NULL) | |
556 fprintf(STDERR, "NULL pointer to png_debug_free.\n"); | |
557 | |
558 if (ptr == 0) | |
559 { | |
560 #if 0 /* This happens all the time. */ | |
561 fprintf(STDERR, "WARNING: freeing NULL pointer\n"); | |
562 #endif | |
563 return; | |
564 } | |
565 | |
566 /* Unlink the element from the list. */ | |
567 { | |
568 memory_infop *ppinfo = &pinformation; | |
569 | |
570 for (;;) | |
571 { | |
572 memory_infop pinfo = *ppinfo; | |
573 | |
574 if (pinfo->pointer == ptr) | |
575 { | |
576 *ppinfo = pinfo->next; | |
577 current_allocation -= pinfo->size; | |
578 if (current_allocation < 0) | |
579 fprintf(STDERR, "Duplicate free of memory\n"); | |
580 /* We must free the list element too, but first kill | |
581 the memory that is to be freed. */ | |
582 memset(ptr, 0x55, pinfo->size); | |
583 if (pinfo) | |
584 free(pinfo); | |
585 pinfo = NULL; | |
586 break; | |
587 } | |
588 | |
589 if (pinfo->next == NULL) | |
590 { | |
591 fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); | |
592 break; | |
593 } | |
594 | |
595 ppinfo = &pinfo->next; | |
596 } | |
597 } | |
598 | |
599 /* Finally free the data. */ | |
600 if (verbose) | |
601 printf("Freeing %p\n", ptr); | |
602 | |
603 if (ptr) | |
604 free(ptr); | |
605 ptr = NULL; | |
606 } | |
607 #endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ | |
608 /* END of code to test memory allocation/deallocation */ | |
609 | |
610 | |
611 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED | |
612 /* Demonstration of user chunk support of the sTER and vpAg chunks */ | |
613 | |
614 /* (sTER is a public chunk not yet known by libpng. vpAg is a private | |
615 chunk used in ImageMagick to store "virtual page" size). */ | |
616 | |
617 static struct user_chunk_data | |
618 { | |
619 png_const_infop info_ptr; | |
620 png_uint_32 vpAg_width, vpAg_height; | |
621 png_byte vpAg_units; | |
622 png_byte sTER_mode; | |
623 int location[2]; | |
624 } | |
625 user_chunk_data; | |
626 | |
627 /* Used for location and order; zero means nothing. */ | |
628 #define have_sTER 0x01 | |
629 #define have_vpAg 0x02 | |
630 #define before_PLTE 0x10 | |
631 #define before_IDAT 0x20 | |
632 #define after_IDAT 0x40 | |
633 | |
634 static void | |
635 init_callback_info(png_const_infop info_ptr) | |
636 { | |
637 MEMZERO(user_chunk_data); | |
638 user_chunk_data.info_ptr = info_ptr; | |
639 } | |
640 | |
641 static int | |
642 set_location(png_structp png_ptr, struct user_chunk_data *data, int what) | |
643 { | |
644 int location; | |
645 | |
646 if ((data->location[0] & what) || (data->location[1] & what)) | |
647 return 0; /* already have one of these */ | |
648 | |
649 /* Find where we are (the code below zeros info_ptr to indicate that the | |
650 * chunks before the first IDAT have been read.) | |
651 */ | |
652 if (data->info_ptr == NULL) /* after IDAT */ | |
653 location = what | after_IDAT; | |
654 | |
655 else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE)) | |
656 location = what | before_IDAT; | |
657 | |
658 else | |
659 location = what | before_PLTE; | |
660 | |
661 if (data->location[0] == 0) | |
662 data->location[0] = location; | |
663 | |
664 else | |
665 data->location[1] = location; | |
666 | |
667 return 1; /* handled */ | |
668 } | |
669 | |
670 static int PNGCBAPI | |
671 read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) | |
672 { | |
673 struct user_chunk_data *my_user_chunk_data = | |
674 (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr); | |
675 | |
676 if (my_user_chunk_data == NULL) | |
677 png_error(png_ptr, "lost user chunk pointer"); | |
678 | |
679 /* Return one of the following: | |
680 * return (-n); chunk had an error | |
681 * return (0); did not recognize | |
682 * return (n); success | |
683 * | |
684 * The unknown chunk structure contains the chunk data: | |
685 * png_byte name[5]; | |
686 * png_byte *data; | |
687 * png_size_t size; | |
688 * | |
689 * Note that libpng has already taken care of the CRC handling. | |
690 */ | |
691 | |
692 if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ | |
693 chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ | |
694 { | |
695 /* Found sTER chunk */ | |
696 if (chunk->size != 1) | |
697 return (-1); /* Error return */ | |
698 | |
699 if (chunk->data[0] != 0 && chunk->data[0] != 1) | |
700 return (-1); /* Invalid mode */ | |
701 | |
702 if (set_location(png_ptr, my_user_chunk_data, have_sTER)) | |
703 { | |
704 my_user_chunk_data->sTER_mode=chunk->data[0]; | |
705 return (1); | |
706 } | |
707 | |
708 else | |
709 return (0); /* duplicate sTER - give it to libpng */ | |
710 } | |
711 | |
712 if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ | |
713 chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ | |
714 return (0); /* Did not recognize */ | |
715 | |
716 /* Found ImageMagick vpAg chunk */ | |
717 | |
718 if (chunk->size != 9) | |
719 return (-1); /* Error return */ | |
720 | |
721 if (!set_location(png_ptr, my_user_chunk_data, have_vpAg)) | |
722 return (0); /* duplicate vpAg */ | |
723 | |
724 my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data); | |
725 my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4); | |
726 my_user_chunk_data->vpAg_units = chunk->data[8]; | |
727 | |
728 return (1); | |
729 } | |
730 | |
731 #ifdef PNG_WRITE_SUPPORTED | |
732 static void | |
733 write_sTER_chunk(png_structp write_ptr) | |
734 { | |
735 png_byte sTER[5] = {115, 84, 69, 82, '\0'}; | |
736 | |
737 if (verbose) | |
738 fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode); | |
739 | |
740 png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1); | |
741 } | |
742 | |
743 static void | |
744 write_vpAg_chunk(png_structp write_ptr) | |
745 { | |
746 png_byte vpAg[5] = {118, 112, 65, 103, '\0'}; | |
747 | |
748 png_byte vpag_chunk_data[9]; | |
749 | |
750 if (verbose) | |
751 fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n", | |
752 (unsigned long)user_chunk_data.vpAg_width, | |
753 (unsigned long)user_chunk_data.vpAg_height, | |
754 user_chunk_data.vpAg_units); | |
755 | |
756 png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width); | |
757 png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height); | |
758 vpag_chunk_data[8] = user_chunk_data.vpAg_units; | |
759 png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9); | |
760 } | |
761 | |
762 static void | |
763 write_chunks(png_structp write_ptr, int location) | |
764 { | |
765 int i; | |
766 | |
767 /* Notice that this preserves the original chunk order, however chunks | |
768 * intercepted by the callback will be written *after* chunks passed to | |
769 * libpng. This will actually reverse a pair of sTER chunks or a pair of | |
770 * vpAg chunks, resulting in an error later. This is not worth worrying | |
771 * about - the chunks should not be duplicated! | |
772 */ | |
773 for (i=0; i<2; ++i) | |
774 { | |
775 if (user_chunk_data.location[i] == (location | have_sTER)) | |
776 write_sTER_chunk(write_ptr); | |
777 | |
778 else if (user_chunk_data.location[i] == (location | have_vpAg)) | |
779 write_vpAg_chunk(write_ptr); | |
780 } | |
781 } | |
782 #endif /* PNG_WRITE_SUPPORTED */ | |
783 #else /* !PNG_READ_USER_CHUNKS_SUPPORTED */ | |
784 # define write_chunks(pp,loc) ((void)0) | |
785 #endif | |
786 /* END of code to demonstrate user chunk support */ | |
787 | |
788 /* START of code to check that libpng has the required text support; this only | |
789 * checks for the write support because if read support is missing the chunk | |
790 * will simply not be reported back to pngtest. | |
791 */ | |
792 #ifdef PNG_TEXT_SUPPORTED | |
793 static void | |
794 pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr, | |
795 int num_text) | |
796 { | |
797 while (num_text > 0) | |
798 { | |
799 switch (text_ptr[--num_text].compression) | |
800 { | |
801 case PNG_TEXT_COMPRESSION_NONE: | |
802 break; | |
803 | |
804 case PNG_TEXT_COMPRESSION_zTXt: | |
805 # ifndef PNG_WRITE_zTXt_SUPPORTED | |
806 ++unsupported_chunks; | |
807 # endif | |
808 break; | |
809 | |
810 case PNG_ITXT_COMPRESSION_NONE: | |
811 case PNG_ITXT_COMPRESSION_zTXt: | |
812 # ifndef PNG_WRITE_iTXt_SUPPORTED | |
813 ++unsupported_chunks; | |
814 # endif | |
815 break; | |
816 | |
817 default: | |
818 /* This is an error */ | |
819 png_error(png_ptr, "invalid text chunk compression field"); | |
820 break; | |
821 } | |
822 } | |
823 } | |
824 #endif | |
825 /* END of code to check that libpng has the required text support */ | |
826 | |
827 /* Test one file */ | |
828 static int | |
829 test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) | |
830 { | |
831 static png_FILE_p fpin; | |
832 static png_FILE_p fpout; /* "static" prevents setjmp corruption */ | |
833 pngtest_error_parameters error_parameters; | |
834 png_structp read_ptr; | |
835 png_infop read_info_ptr, end_info_ptr; | |
836 #ifdef PNG_WRITE_SUPPORTED | |
837 png_structp write_ptr; | |
838 png_infop write_info_ptr; | |
839 png_infop write_end_info_ptr; | |
840 int interlace_preserved = 1; | |
841 #else | |
842 png_structp write_ptr = NULL; | |
843 png_infop write_info_ptr = NULL; | |
844 png_infop write_end_info_ptr = NULL; | |
845 #endif | |
846 png_bytep row_buf; | |
847 png_uint_32 y; | |
848 png_uint_32 width, height; | |
849 int num_pass = 1, pass; | |
850 int bit_depth, color_type; | |
851 | |
852 row_buf = NULL; | |
853 error_parameters.file_name = inname; | |
854 | |
855 if ((fpin = fopen(inname, "rb")) == NULL) | |
856 { | |
857 fprintf(STDERR, "Could not find input file %s\n", inname); | |
858 return (1); | |
859 } | |
860 | |
861 if ((fpout = fopen(outname, "wb")) == NULL) | |
862 { | |
863 fprintf(STDERR, "Could not open output file %s\n", outname); | |
864 FCLOSE(fpin); | |
865 return (1); | |
866 } | |
867 | |
868 pngtest_debug("Allocating read and write structures"); | |
869 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
870 read_ptr = | |
871 png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, | |
872 NULL, NULL, NULL, png_debug_malloc, png_debug_free); | |
873 #else | |
874 read_ptr = | |
875 png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
876 #endif | |
877 png_set_error_fn(read_ptr, &error_parameters, pngtest_error, | |
878 pngtest_warning); | |
879 | |
880 #ifdef PNG_WRITE_SUPPORTED | |
881 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
882 write_ptr = | |
883 png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, | |
884 NULL, NULL, NULL, png_debug_malloc, png_debug_free); | |
885 #else | |
886 write_ptr = | |
887 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
888 #endif | |
889 png_set_error_fn(write_ptr, &error_parameters, pngtest_error, | |
890 pngtest_warning); | |
891 #endif | |
892 pngtest_debug("Allocating read_info, write_info and end_info structures"); | |
893 read_info_ptr = png_create_info_struct(read_ptr); | |
894 end_info_ptr = png_create_info_struct(read_ptr); | |
895 #ifdef PNG_WRITE_SUPPORTED | |
896 write_info_ptr = png_create_info_struct(write_ptr); | |
897 write_end_info_ptr = png_create_info_struct(write_ptr); | |
898 #endif | |
899 | |
900 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED | |
901 init_callback_info(read_info_ptr); | |
902 png_set_read_user_chunk_fn(read_ptr, &user_chunk_data, | |
903 read_user_chunk_callback); | |
904 #endif | |
905 | |
906 #ifdef PNG_SETJMP_SUPPORTED | |
907 pngtest_debug("Setting jmpbuf for read struct"); | |
908 if (setjmp(png_jmpbuf(read_ptr))) | |
909 { | |
910 fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); | |
911 png_free(read_ptr, row_buf); | |
912 row_buf = NULL; | |
913 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); | |
914 #ifdef PNG_WRITE_SUPPORTED | |
915 png_destroy_info_struct(write_ptr, &write_end_info_ptr); | |
916 png_destroy_write_struct(&write_ptr, &write_info_ptr); | |
917 #endif | |
918 FCLOSE(fpin); | |
919 FCLOSE(fpout); | |
920 return (1); | |
921 } | |
922 | |
923 #ifdef PNG_WRITE_SUPPORTED | |
924 pngtest_debug("Setting jmpbuf for write struct"); | |
925 | |
926 if (setjmp(png_jmpbuf(write_ptr))) | |
927 { | |
928 fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); | |
929 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); | |
930 png_destroy_info_struct(write_ptr, &write_end_info_ptr); | |
931 #ifdef PNG_WRITE_SUPPORTED | |
932 png_destroy_write_struct(&write_ptr, &write_info_ptr); | |
933 #endif | |
934 FCLOSE(fpin); | |
935 FCLOSE(fpout); | |
936 return (1); | |
937 } | |
938 #endif | |
939 #endif | |
940 | |
941 if (strict) | |
942 { | |
943 /* Treat png_benign_error() as errors on read */ | |
944 png_set_benign_errors(read_ptr, 0); | |
945 | |
946 #ifdef PNG_WRITE_SUPPORTED | |
947 /* Treat them as errors on write */ | |
948 png_set_benign_errors(write_ptr, 0); | |
949 #endif | |
950 | |
951 /* if strict is not set, then app warnings and errors are treated as | |
952 * warnings in release builds, but not in unstable builds; this can be | |
953 * changed with '--relaxed'. | |
954 */ | |
955 } | |
956 | |
957 else if (relaxed) | |
958 { | |
959 /* Allow application (pngtest) errors and warnings to pass */ | |
960 png_set_benign_errors(read_ptr, 1); | |
961 | |
962 #ifdef PNG_WRITE_SUPPORTED | |
963 png_set_benign_errors(write_ptr, 1); | |
964 #endif | |
965 } | |
966 | |
967 pngtest_debug("Initializing input and output streams"); | |
968 #ifdef PNG_STDIO_SUPPORTED | |
969 png_init_io(read_ptr, fpin); | |
970 # ifdef PNG_WRITE_SUPPORTED | |
971 png_init_io(write_ptr, fpout); | |
972 # endif | |
973 #else | |
974 png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); | |
975 # ifdef PNG_WRITE_SUPPORTED | |
976 png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, | |
977 # ifdef PNG_WRITE_FLUSH_SUPPORTED | |
978 pngtest_flush); | |
979 # else | |
980 NULL); | |
981 # endif | |
982 # endif | |
983 #endif | |
984 | |
985 if (status_dots_requested == 1) | |
986 { | |
987 #ifdef PNG_WRITE_SUPPORTED | |
988 png_set_write_status_fn(write_ptr, write_row_callback); | |
989 #endif | |
990 png_set_read_status_fn(read_ptr, read_row_callback); | |
991 } | |
992 | |
993 else | |
994 { | |
995 #ifdef PNG_WRITE_SUPPORTED | |
996 png_set_write_status_fn(write_ptr, NULL); | |
997 #endif | |
998 png_set_read_status_fn(read_ptr, NULL); | |
999 } | |
1000 | |
1001 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
1002 { | |
1003 int i; | |
1004 | |
1005 for (i = 0; i<256; i++) | |
1006 filters_used[i] = 0; | |
1007 | |
1008 png_set_read_user_transform_fn(read_ptr, count_filters); | |
1009 } | |
1010 #endif | |
1011 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED | |
1012 zero_samples = 0; | |
1013 png_set_write_user_transform_fn(write_ptr, count_zero_samples); | |
1014 #endif | |
1015 | |
1016 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED | |
1017 /* Preserve all the unknown chunks, if possible. If this is disabled then, | |
1018 * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use | |
1019 * libpng to *save* the unknown chunks on read (because we can't switch the | |
1020 * save option on!) | |
1021 * | |
1022 * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all | |
1023 * unknown chunks and write will write them all. | |
1024 */ | |
1025 #ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED | |
1026 png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, | |
1027 NULL, 0); | |
1028 #endif | |
1029 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED | |
1030 png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, | |
1031 NULL, 0); | |
1032 #endif | |
1033 #endif | |
1034 | |
1035 pngtest_debug("Reading info struct"); | |
1036 png_read_info(read_ptr, read_info_ptr); | |
1037 | |
1038 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED | |
1039 /* This is a bit of a hack; there is no obvious way in the callback function | |
1040 * to determine that the chunks before the first IDAT have been read, so | |
1041 * remove the info_ptr (which is only used to determine position relative to | |
1042 * PLTE) here to indicate that we are after the IDAT. | |
1043 */ | |
1044 user_chunk_data.info_ptr = NULL; | |
1045 #endif | |
1046 | |
1047 pngtest_debug("Transferring info struct"); | |
1048 { | |
1049 int interlace_type, compression_type, filter_type; | |
1050 | |
1051 if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, | |
1052 &color_type, &interlace_type, &compression_type, &filter_type)) | |
1053 { | |
1054 png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, | |
1055 color_type, interlace_type, compression_type, filter_type); | |
1056 #ifndef PNG_READ_INTERLACING_SUPPORTED | |
1057 /* num_pass will not be set below, set it here if the image is | |
1058 * interlaced: what happens is that write interlacing is *not* turned | |
1059 * on an the partial interlaced rows are written directly. | |
1060 */ | |
1061 switch (interlace_type) | |
1062 { | |
1063 case PNG_INTERLACE_NONE: | |
1064 num_pass = 1; | |
1065 break; | |
1066 | |
1067 case PNG_INTERLACE_ADAM7: | |
1068 num_pass = 7; | |
1069 break; | |
1070 | |
1071 default: | |
1072 png_error(read_ptr, "invalid interlace type"); | |
1073 /*NOT REACHED*/ | |
1074 } | |
1075 #endif | |
1076 } | |
1077 } | |
1078 #ifdef PNG_FIXED_POINT_SUPPORTED | |
1079 #ifdef PNG_cHRM_SUPPORTED | |
1080 { | |
1081 png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, | |
1082 blue_y; | |
1083 | |
1084 if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, | |
1085 &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) | |
1086 { | |
1087 png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, | |
1088 red_y, green_x, green_y, blue_x, blue_y); | |
1089 } | |
1090 } | |
1091 #endif | |
1092 #ifdef PNG_gAMA_SUPPORTED | |
1093 { | |
1094 png_fixed_point gamma; | |
1095 | |
1096 if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) | |
1097 png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); | |
1098 } | |
1099 #endif | |
1100 #else /* Use floating point versions */ | |
1101 #ifdef PNG_FLOATING_POINT_SUPPORTED | |
1102 #ifdef PNG_cHRM_SUPPORTED | |
1103 { | |
1104 double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, | |
1105 blue_y; | |
1106 | |
1107 if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, | |
1108 &red_y, &green_x, &green_y, &blue_x, &blue_y)) | |
1109 { | |
1110 png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, | |
1111 red_y, green_x, green_y, blue_x, blue_y); | |
1112 } | |
1113 } | |
1114 #endif | |
1115 #ifdef PNG_gAMA_SUPPORTED | |
1116 { | |
1117 double gamma; | |
1118 | |
1119 if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) | |
1120 png_set_gAMA(write_ptr, write_info_ptr, gamma); | |
1121 } | |
1122 #endif | |
1123 #endif /* Floating point */ | |
1124 #endif /* Fixed point */ | |
1125 #ifdef PNG_iCCP_SUPPORTED | |
1126 { | |
1127 png_charp name; | |
1128 png_bytep profile; | |
1129 png_uint_32 proflen; | |
1130 int compression_type; | |
1131 | |
1132 if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, | |
1133 &profile, &proflen)) | |
1134 { | |
1135 png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, | |
1136 profile, proflen); | |
1137 } | |
1138 } | |
1139 #endif | |
1140 #ifdef PNG_sRGB_SUPPORTED | |
1141 { | |
1142 int intent; | |
1143 | |
1144 if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) | |
1145 png_set_sRGB(write_ptr, write_info_ptr, intent); | |
1146 } | |
1147 #endif | |
1148 { | |
1149 png_colorp palette; | |
1150 int num_palette; | |
1151 | |
1152 if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) | |
1153 png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); | |
1154 } | |
1155 #ifdef PNG_bKGD_SUPPORTED | |
1156 { | |
1157 png_color_16p background; | |
1158 | |
1159 if (png_get_bKGD(read_ptr, read_info_ptr, &background)) | |
1160 { | |
1161 png_set_bKGD(write_ptr, write_info_ptr, background); | |
1162 } | |
1163 } | |
1164 #endif | |
1165 #ifdef PNG_hIST_SUPPORTED | |
1166 { | |
1167 png_uint_16p hist; | |
1168 | |
1169 if (png_get_hIST(read_ptr, read_info_ptr, &hist)) | |
1170 png_set_hIST(write_ptr, write_info_ptr, hist); | |
1171 } | |
1172 #endif | |
1173 #ifdef PNG_oFFs_SUPPORTED | |
1174 { | |
1175 png_int_32 offset_x, offset_y; | |
1176 int unit_type; | |
1177 | |
1178 if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, | |
1179 &unit_type)) | |
1180 { | |
1181 png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); | |
1182 } | |
1183 } | |
1184 #endif | |
1185 #ifdef PNG_pCAL_SUPPORTED | |
1186 { | |
1187 png_charp purpose, units; | |
1188 png_charpp params; | |
1189 png_int_32 X0, X1; | |
1190 int type, nparams; | |
1191 | |
1192 if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, | |
1193 &nparams, &units, ¶ms)) | |
1194 { | |
1195 png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, | |
1196 nparams, units, params); | |
1197 } | |
1198 } | |
1199 #endif | |
1200 #ifdef PNG_pHYs_SUPPORTED | |
1201 { | |
1202 png_uint_32 res_x, res_y; | |
1203 int unit_type; | |
1204 | |
1205 if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) | |
1206 png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); | |
1207 } | |
1208 #endif | |
1209 #ifdef PNG_sBIT_SUPPORTED | |
1210 { | |
1211 png_color_8p sig_bit; | |
1212 | |
1213 if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) | |
1214 png_set_sBIT(write_ptr, write_info_ptr, sig_bit); | |
1215 } | |
1216 #endif | |
1217 #ifdef PNG_sCAL_SUPPORTED | |
1218 #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ | |
1219 defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) | |
1220 { | |
1221 int unit; | |
1222 double scal_width, scal_height; | |
1223 | |
1224 if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, | |
1225 &scal_height)) | |
1226 { | |
1227 png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); | |
1228 } | |
1229 } | |
1230 #else | |
1231 #ifdef PNG_FIXED_POINT_SUPPORTED | |
1232 { | |
1233 int unit; | |
1234 png_charp scal_width, scal_height; | |
1235 | |
1236 if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, | |
1237 &scal_height)) | |
1238 { | |
1239 png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, | |
1240 scal_height); | |
1241 } | |
1242 } | |
1243 #endif | |
1244 #endif | |
1245 #endif | |
1246 #ifdef PNG_TEXT_SUPPORTED | |
1247 { | |
1248 png_textp text_ptr; | |
1249 int num_text; | |
1250 | |
1251 if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) | |
1252 { | |
1253 pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); | |
1254 | |
1255 pngtest_check_text_support(read_ptr, text_ptr, num_text); | |
1256 | |
1257 if (verbose) | |
1258 { | |
1259 int i; | |
1260 | |
1261 printf("\n"); | |
1262 for (i=0; i<num_text; i++) | |
1263 { | |
1264 printf(" Text compression[%d]=%d\n", | |
1265 i, text_ptr[i].compression); | |
1266 } | |
1267 } | |
1268 | |
1269 png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); | |
1270 } | |
1271 } | |
1272 #endif | |
1273 #ifdef PNG_tIME_SUPPORTED | |
1274 { | |
1275 png_timep mod_time; | |
1276 | |
1277 if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) | |
1278 { | |
1279 png_set_tIME(write_ptr, write_info_ptr, mod_time); | |
1280 #ifdef PNG_TIME_RFC1123_SUPPORTED | |
1281 if (png_convert_to_rfc1123_buffer(tIME_string, mod_time)) | |
1282 tIME_string[(sizeof tIME_string) - 1] = '\0'; | |
1283 | |
1284 else | |
1285 { | |
1286 strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string)); | |
1287 tIME_string[(sizeof tIME_string) - 1] = '\0'; | |
1288 } | |
1289 | |
1290 tIME_chunk_present++; | |
1291 #endif /* PNG_TIME_RFC1123_SUPPORTED */ | |
1292 } | |
1293 } | |
1294 #endif | |
1295 #ifdef PNG_tRNS_SUPPORTED | |
1296 { | |
1297 png_bytep trans_alpha; | |
1298 int num_trans; | |
1299 png_color_16p trans_color; | |
1300 | |
1301 if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans, | |
1302 &trans_color)) | |
1303 { | |
1304 int sample_max = (1 << bit_depth); | |
1305 /* libpng doesn't reject a tRNS chunk with out-of-range samples */ | |
1306 if (!((color_type == PNG_COLOR_TYPE_GRAY && | |
1307 (int)trans_color->gray > sample_max) || | |
1308 (color_type == PNG_COLOR_TYPE_RGB && | |
1309 ((int)trans_color->red > sample_max || | |
1310 (int)trans_color->green > sample_max || | |
1311 (int)trans_color->blue > sample_max)))) | |
1312 png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans, | |
1313 trans_color); | |
1314 } | |
1315 } | |
1316 #endif | |
1317 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED | |
1318 { | |
1319 png_unknown_chunkp unknowns; | |
1320 int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr, | |
1321 &unknowns); | |
1322 | |
1323 if (num_unknowns) | |
1324 { | |
1325 png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, | |
1326 num_unknowns); | |
1327 #if PNG_LIBPNG_VER < 10600 | |
1328 /* Copy the locations from the read_info_ptr. The automatically | |
1329 * generated locations in write_end_info_ptr are wrong prior to 1.6.0 | |
1330 * because they are reset from the write pointer (removed in 1.6.0). | |
1331 */ | |
1332 { | |
1333 int i; | |
1334 for (i = 0; i < num_unknowns; i++) | |
1335 png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, | |
1336 unknowns[i].location); | |
1337 } | |
1338 #endif | |
1339 } | |
1340 } | |
1341 #endif | |
1342 | |
1343 #ifdef PNG_WRITE_SUPPORTED | |
1344 pngtest_debug("Writing info struct"); | |
1345 | |
1346 /* Write the info in two steps so that if we write the 'unknown' chunks here | |
1347 * they go to the correct place. | |
1348 */ | |
1349 png_write_info_before_PLTE(write_ptr, write_info_ptr); | |
1350 | |
1351 write_chunks(write_ptr, before_PLTE); /* before PLTE */ | |
1352 | |
1353 png_write_info(write_ptr, write_info_ptr); | |
1354 | |
1355 write_chunks(write_ptr, before_IDAT); /* after PLTE */ | |
1356 #endif | |
1357 | |
1358 #ifdef SINGLE_ROWBUF_ALLOC | |
1359 pngtest_debug("Allocating row buffer..."); | |
1360 row_buf = (png_bytep)png_malloc(read_ptr, | |
1361 png_get_rowbytes(read_ptr, read_info_ptr)); | |
1362 | |
1363 pngtest_debug1("\t0x%08lx", (unsigned long)row_buf); | |
1364 #endif /* SINGLE_ROWBUF_ALLOC */ | |
1365 pngtest_debug("Writing row data"); | |
1366 | |
1367 #ifdef PNG_READ_INTERLACING_SUPPORTED | |
1368 num_pass = png_set_interlace_handling(read_ptr); | |
1369 if (png_set_interlace_handling(write_ptr) != num_pass) | |
1370 png_error(write_ptr, "png_set_interlace_handling: inconsistent num_pass"); | |
1371 #endif | |
1372 | |
1373 #ifdef PNGTEST_TIMING | |
1374 t_stop = (float)clock(); | |
1375 t_misc += (t_stop - t_start); | |
1376 t_start = t_stop; | |
1377 #endif | |
1378 for (pass = 0; pass < num_pass; pass++) | |
1379 { | |
1380 pngtest_debug1("Writing row data for pass %d", pass); | |
1381 for (y = 0; y < height; y++) | |
1382 { | |
1383 #ifndef SINGLE_ROWBUF_ALLOC | |
1384 pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y); | |
1385 row_buf = (png_bytep)png_malloc(read_ptr, | |
1386 png_get_rowbytes(read_ptr, read_info_ptr)); | |
1387 | |
1388 pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf, | |
1389 png_get_rowbytes(read_ptr, read_info_ptr)); | |
1390 | |
1391 #endif /* !SINGLE_ROWBUF_ALLOC */ | |
1392 png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1); | |
1393 | |
1394 #ifdef PNG_WRITE_SUPPORTED | |
1395 #ifdef PNGTEST_TIMING | |
1396 t_stop = (float)clock(); | |
1397 t_decode += (t_stop - t_start); | |
1398 t_start = t_stop; | |
1399 #endif | |
1400 png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); | |
1401 #ifdef PNGTEST_TIMING | |
1402 t_stop = (float)clock(); | |
1403 t_encode += (t_stop - t_start); | |
1404 t_start = t_stop; | |
1405 #endif | |
1406 #endif /* PNG_WRITE_SUPPORTED */ | |
1407 | |
1408 #ifndef SINGLE_ROWBUF_ALLOC | |
1409 pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y); | |
1410 png_free(read_ptr, row_buf); | |
1411 row_buf = NULL; | |
1412 #endif /* !SINGLE_ROWBUF_ALLOC */ | |
1413 } | |
1414 } | |
1415 | |
1416 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED | |
1417 # ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | |
1418 png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); | |
1419 # endif | |
1420 # ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED | |
1421 png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); | |
1422 # endif | |
1423 #endif | |
1424 | |
1425 pngtest_debug("Reading and writing end_info data"); | |
1426 | |
1427 png_read_end(read_ptr, end_info_ptr); | |
1428 #ifdef PNG_TEXT_SUPPORTED | |
1429 { | |
1430 png_textp text_ptr; | |
1431 int num_text; | |
1432 | |
1433 if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) | |
1434 { | |
1435 pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); | |
1436 | |
1437 pngtest_check_text_support(read_ptr, text_ptr, num_text); | |
1438 | |
1439 if (verbose) | |
1440 { | |
1441 int i; | |
1442 | |
1443 printf("\n"); | |
1444 for (i=0; i<num_text; i++) | |
1445 { | |
1446 printf(" Text compression[%d]=%d\n", | |
1447 i, text_ptr[i].compression); | |
1448 } | |
1449 } | |
1450 | |
1451 png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); | |
1452 } | |
1453 } | |
1454 #endif | |
1455 #ifdef PNG_tIME_SUPPORTED | |
1456 { | |
1457 png_timep mod_time; | |
1458 | |
1459 if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) | |
1460 { | |
1461 png_set_tIME(write_ptr, write_end_info_ptr, mod_time); | |
1462 #ifdef PNG_TIME_RFC1123_SUPPORTED | |
1463 if (png_convert_to_rfc1123_buffer(tIME_string, mod_time)) | |
1464 tIME_string[(sizeof tIME_string) - 1] = '\0'; | |
1465 | |
1466 else | |
1467 { | |
1468 strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string); | |
1469 tIME_string[(sizeof tIME_string)-1] = '\0'; | |
1470 } | |
1471 | |
1472 tIME_chunk_present++; | |
1473 #endif /* PNG_TIME_RFC1123_SUPPORTED */ | |
1474 } | |
1475 } | |
1476 #endif | |
1477 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED | |
1478 { | |
1479 png_unknown_chunkp unknowns; | |
1480 int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr, | |
1481 &unknowns); | |
1482 | |
1483 if (num_unknowns) | |
1484 { | |
1485 png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, | |
1486 num_unknowns); | |
1487 #if PNG_LIBPNG_VER < 10600 | |
1488 /* Copy the locations from the read_info_ptr. The automatically | |
1489 * generated locations in write_end_info_ptr are wrong prior to 1.6.0 | |
1490 * because they are reset from the write pointer (removed in 1.6.0). | |
1491 */ | |
1492 { | |
1493 int i; | |
1494 for (i = 0; i < num_unknowns; i++) | |
1495 png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, | |
1496 unknowns[i].location); | |
1497 } | |
1498 #endif | |
1499 } | |
1500 } | |
1501 #endif | |
1502 | |
1503 #ifdef PNG_WRITE_SUPPORTED | |
1504 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED | |
1505 /* Normally one would use Z_DEFAULT_STRATEGY for text compression. | |
1506 * This is here just to make pngtest replicate the results from libpng | |
1507 * versions prior to 1.5.4, and to test this new API. | |
1508 */ | |
1509 png_set_text_compression_strategy(write_ptr, Z_FILTERED); | |
1510 #endif | |
1511 | |
1512 /* When the unknown vpAg/sTER chunks are written by pngtest the only way to | |
1513 * do it is to write them *before* calling png_write_end. When unknown | |
1514 * chunks are written by libpng, however, they are written just before IEND. | |
1515 * There seems to be no way round this, however vpAg/sTER are not expected | |
1516 * after IDAT. | |
1517 */ | |
1518 write_chunks(write_ptr, after_IDAT); | |
1519 | |
1520 png_write_end(write_ptr, write_end_info_ptr); | |
1521 #endif | |
1522 | |
1523 #ifdef PNG_EASY_ACCESS_SUPPORTED | |
1524 if (verbose) | |
1525 { | |
1526 png_uint_32 iwidth, iheight; | |
1527 iwidth = png_get_image_width(write_ptr, write_info_ptr); | |
1528 iheight = png_get_image_height(write_ptr, write_info_ptr); | |
1529 fprintf(STDERR, "\n Image width = %lu, height = %lu\n", | |
1530 (unsigned long)iwidth, (unsigned long)iheight); | |
1531 } | |
1532 #endif | |
1533 | |
1534 pngtest_debug("Destroying data structs"); | |
1535 #ifdef SINGLE_ROWBUF_ALLOC | |
1536 pngtest_debug("destroying row_buf for read_ptr"); | |
1537 png_free(read_ptr, row_buf); | |
1538 row_buf = NULL; | |
1539 #endif /* SINGLE_ROWBUF_ALLOC */ | |
1540 pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr"); | |
1541 png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); | |
1542 #ifdef PNG_WRITE_SUPPORTED | |
1543 pngtest_debug("destroying write_end_info_ptr"); | |
1544 png_destroy_info_struct(write_ptr, &write_end_info_ptr); | |
1545 pngtest_debug("destroying write_ptr, write_info_ptr"); | |
1546 png_destroy_write_struct(&write_ptr, &write_info_ptr); | |
1547 #endif | |
1548 pngtest_debug("Destruction complete."); | |
1549 | |
1550 FCLOSE(fpin); | |
1551 FCLOSE(fpout); | |
1552 | |
1553 /* Summarize any warnings or errors and in 'strict' mode fail the test. | |
1554 * Unsupported chunks can result in warnings, in that case ignore the strict | |
1555 * setting, otherwise fail the test on warnings as well as errors. | |
1556 */ | |
1557 if (error_count > 0) | |
1558 { | |
1559 /* We don't really expect to get here because of the setjmp handling | |
1560 * above, but this is safe. | |
1561 */ | |
1562 fprintf(STDERR, "\n %s: %d libpng errors found (%d warnings)", | |
1563 inname, error_count, warning_count); | |
1564 | |
1565 if (strict != 0) | |
1566 return (1); | |
1567 } | |
1568 | |
1569 # ifdef PNG_WRITE_SUPPORTED | |
1570 /* If there we no write support nothing was written! */ | |
1571 else if (unsupported_chunks > 0) | |
1572 { | |
1573 fprintf(STDERR, "\n %s: unsupported chunks (%d)%s", | |
1574 inname, unsupported_chunks, strict ? ": IGNORED --strict!" : ""); | |
1575 } | |
1576 # endif | |
1577 | |
1578 else if (warning_count > 0) | |
1579 { | |
1580 fprintf(STDERR, "\n %s: %d libpng warnings found", | |
1581 inname, warning_count); | |
1582 | |
1583 if (strict != 0) | |
1584 return (1); | |
1585 } | |
1586 | |
1587 pngtest_debug("Opening files for comparison"); | |
1588 if ((fpin = fopen(inname, "rb")) == NULL) | |
1589 { | |
1590 fprintf(STDERR, "Could not find file %s\n", inname); | |
1591 return (1); | |
1592 } | |
1593 | |
1594 if ((fpout = fopen(outname, "rb")) == NULL) | |
1595 { | |
1596 fprintf(STDERR, "Could not find file %s\n", outname); | |
1597 FCLOSE(fpin); | |
1598 return (1); | |
1599 } | |
1600 | |
1601 #ifdef PNG_WRITE_SUPPORTED /* else nothing was written */ | |
1602 if (interlace_preserved) /* else the files will be changed */ | |
1603 { | |
1604 for (;;) | |
1605 { | |
1606 static int wrote_question = 0; | |
1607 png_size_t num_in, num_out; | |
1608 char inbuf[256], outbuf[256]; | |
1609 | |
1610 num_in = fread(inbuf, 1, sizeof inbuf, fpin); | |
1611 num_out = fread(outbuf, 1, sizeof outbuf, fpout); | |
1612 | |
1613 if (num_in != num_out) | |
1614 { | |
1615 fprintf(STDERR, "\nFiles %s and %s are of a different size\n", | |
1616 inname, outname); | |
1617 | |
1618 if (wrote_question == 0 && unsupported_chunks == 0) | |
1619 { | |
1620 fprintf(STDERR, | |
1621 " Was %s written with the same maximum IDAT chunk size (%d bytes),", | |
1622 inname, PNG_ZBUF_SIZE); | |
1623 fprintf(STDERR, | |
1624 "\n filtering heuristic (libpng default), compression"); | |
1625 fprintf(STDERR, | |
1626 " level (zlib default),\n and zlib version (%s)?\n\n", | |
1627 ZLIB_VERSION); | |
1628 wrote_question = 1; | |
1629 } | |
1630 | |
1631 FCLOSE(fpin); | |
1632 FCLOSE(fpout); | |
1633 | |
1634 if (strict != 0 && unsupported_chunks == 0) | |
1635 return (1); | |
1636 | |
1637 else | |
1638 return (0); | |
1639 } | |
1640 | |
1641 if (!num_in) | |
1642 break; | |
1643 | |
1644 if (memcmp(inbuf, outbuf, num_in)) | |
1645 { | |
1646 fprintf(STDERR, "\nFiles %s and %s are different\n", inname, | |
1647 outname); | |
1648 | |
1649 if (wrote_question == 0 && unsupported_chunks == 0) | |
1650 { | |
1651 fprintf(STDERR, | |
1652 " Was %s written with the same maximum IDAT chunk size (%d bytes),", | |
1653 inname, PNG_ZBUF_SIZE); | |
1654 fprintf(STDERR, | |
1655 "\n filtering heuristic (libpng default), compression"); | |
1656 fprintf(STDERR, | |
1657 " level (zlib default),\n and zlib version (%s)?\n\n", | |
1658 ZLIB_VERSION); | |
1659 wrote_question = 1; | |
1660 } | |
1661 | |
1662 FCLOSE(fpin); | |
1663 FCLOSE(fpout); | |
1664 | |
1665 /* NOTE: the unsupported_chunks escape is permitted here because | |
1666 * unsupported text chunk compression will result in the compression | |
1667 * mode being changed (to NONE) yet, in the test case, the result | |
1668 * can be exactly the same size! | |
1669 */ | |
1670 if (strict != 0 && unsupported_chunks == 0) | |
1671 return (1); | |
1672 | |
1673 else | |
1674 return (0); | |
1675 } | |
1676 } | |
1677 } | |
1678 #endif /* PNG_WRITE_SUPPORTED */ | |
1679 | |
1680 FCLOSE(fpin); | |
1681 FCLOSE(fpout); | |
1682 | |
1683 return (0); | |
1684 } | |
1685 | |
1686 /* Input and output filenames */ | |
1687 #ifdef RISCOS | |
1688 static PNG_CONST char *inname = "pngtest/png"; | |
1689 static PNG_CONST char *outname = "pngout/png"; | |
1690 #else | |
1691 static PNG_CONST char *inname = "pngtest.png"; | |
1692 static PNG_CONST char *outname = "pngout.png"; | |
1693 #endif | |
1694 | |
1695 int | |
1696 main(int argc, char *argv[]) | |
1697 { | |
1698 int multiple = 0; | |
1699 int ierror = 0; | |
1700 | |
1701 fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); | |
1702 fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); | |
1703 fprintf(STDERR, "%s", png_get_copyright(NULL)); | |
1704 /* Show the version of libpng used in building the library */ | |
1705 fprintf(STDERR, " library (%lu):%s", | |
1706 (unsigned long)png_access_version_number(), | |
1707 png_get_header_version(NULL)); | |
1708 | |
1709 /* Show the version of libpng used in building the application */ | |
1710 fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, | |
1711 PNG_HEADER_VERSION_STRING); | |
1712 | |
1713 /* Do some consistency checking on the memory allocation settings, I'm | |
1714 * not sure this matters, but it is nice to know, the first of these | |
1715 * tests should be impossible because of the way the macros are set | |
1716 * in pngconf.h | |
1717 */ | |
1718 #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) | |
1719 fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); | |
1720 #endif | |
1721 /* I think the following can happen. */ | |
1722 #if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) | |
1723 fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); | |
1724 #endif | |
1725 | |
1726 if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) | |
1727 { | |
1728 fprintf(STDERR, | |
1729 "Warning: versions are different between png.h and png.c\n"); | |
1730 fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); | |
1731 fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); | |
1732 ++ierror; | |
1733 } | |
1734 | |
1735 if (argc > 1) | |
1736 { | |
1737 if (strcmp(argv[1], "-m") == 0) | |
1738 { | |
1739 multiple = 1; | |
1740 status_dots_requested = 0; | |
1741 } | |
1742 | |
1743 else if (strcmp(argv[1], "-mv") == 0 || | |
1744 strcmp(argv[1], "-vm") == 0 ) | |
1745 { | |
1746 multiple = 1; | |
1747 verbose = 1; | |
1748 status_dots_requested = 1; | |
1749 } | |
1750 | |
1751 else if (strcmp(argv[1], "-v") == 0) | |
1752 { | |
1753 verbose = 1; | |
1754 status_dots_requested = 1; | |
1755 inname = argv[2]; | |
1756 } | |
1757 | |
1758 else if (strcmp(argv[1], "--strict") == 0) | |
1759 { | |
1760 status_dots_requested = 0; | |
1761 verbose = 1; | |
1762 inname = argv[2]; | |
1763 strict++; | |
1764 relaxed = 0; | |
1765 } | |
1766 | |
1767 else if (strcmp(argv[1], "--relaxed") == 0) | |
1768 { | |
1769 status_dots_requested = 0; | |
1770 verbose = 1; | |
1771 inname = argv[2]; | |
1772 strict = 0; | |
1773 relaxed++; | |
1774 } | |
1775 | |
1776 else | |
1777 { | |
1778 inname = argv[1]; | |
1779 status_dots_requested = 0; | |
1780 } | |
1781 } | |
1782 | |
1783 if (!multiple && argc == 3 + verbose) | |
1784 outname = argv[2 + verbose]; | |
1785 | |
1786 if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) | |
1787 { | |
1788 fprintf(STDERR, | |
1789 "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", | |
1790 argv[0], argv[0]); | |
1791 fprintf(STDERR, | |
1792 " reads/writes one PNG file (without -m) or multiple files (-m)\n"); | |
1793 fprintf(STDERR, | |
1794 " with -m %s is used as a temporary file\n", outname); | |
1795 exit(1); | |
1796 } | |
1797 | |
1798 if (multiple) | |
1799 { | |
1800 int i; | |
1801 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1802 int allocation_now = current_allocation; | |
1803 #endif | |
1804 for (i=2; i<argc; ++i) | |
1805 { | |
1806 int kerror; | |
1807 fprintf(STDERR, "\n Testing %s:", argv[i]); | |
1808 kerror = test_one_file(argv[i], outname); | |
1809 if (kerror == 0) | |
1810 { | |
1811 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
1812 int k; | |
1813 #endif | |
1814 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED | |
1815 fprintf(STDERR, "\n PASS (%lu zero samples)\n", | |
1816 (unsigned long)zero_samples); | |
1817 #else | |
1818 fprintf(STDERR, " PASS\n"); | |
1819 #endif | |
1820 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
1821 for (k = 0; k<256; k++) | |
1822 if (filters_used[k]) | |
1823 fprintf(STDERR, " Filter %d was used %lu times\n", | |
1824 k, (unsigned long)filters_used[k]); | |
1825 #endif | |
1826 #ifdef PNG_TIME_RFC1123_SUPPORTED | |
1827 if (tIME_chunk_present != 0) | |
1828 fprintf(STDERR, " tIME = %s\n", tIME_string); | |
1829 | |
1830 tIME_chunk_present = 0; | |
1831 #endif /* PNG_TIME_RFC1123_SUPPORTED */ | |
1832 } | |
1833 | |
1834 else | |
1835 { | |
1836 fprintf(STDERR, " FAIL\n"); | |
1837 ierror += kerror; | |
1838 } | |
1839 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1840 if (allocation_now != current_allocation) | |
1841 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", | |
1842 current_allocation - allocation_now); | |
1843 | |
1844 if (current_allocation != 0) | |
1845 { | |
1846 memory_infop pinfo = pinformation; | |
1847 | |
1848 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", | |
1849 current_allocation); | |
1850 | |
1851 while (pinfo != NULL) | |
1852 { | |
1853 fprintf(STDERR, " %lu bytes at %x\n", | |
1854 (unsigned long)pinfo->size, | |
1855 (unsigned int)pinfo->pointer); | |
1856 pinfo = pinfo->next; | |
1857 } | |
1858 } | |
1859 #endif | |
1860 } | |
1861 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1862 fprintf(STDERR, " Current memory allocation: %10d bytes\n", | |
1863 current_allocation); | |
1864 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", | |
1865 maximum_allocation); | |
1866 fprintf(STDERR, " Total memory allocation: %10d bytes\n", | |
1867 total_allocation); | |
1868 fprintf(STDERR, " Number of allocations: %10d\n", | |
1869 num_allocations); | |
1870 #endif | |
1871 } | |
1872 | |
1873 else | |
1874 { | |
1875 int i; | |
1876 for (i = 0; i<3; ++i) | |
1877 { | |
1878 int kerror; | |
1879 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1880 int allocation_now = current_allocation; | |
1881 #endif | |
1882 if (i == 1) | |
1883 status_dots_requested = 1; | |
1884 | |
1885 else if (verbose == 0) | |
1886 status_dots_requested = 0; | |
1887 | |
1888 if (i == 0 || verbose == 1 || ierror != 0) | |
1889 fprintf(STDERR, "\n Testing %s:", inname); | |
1890 | |
1891 kerror = test_one_file(inname, outname); | |
1892 | |
1893 if (kerror == 0) | |
1894 { | |
1895 if (verbose == 1 || i == 2) | |
1896 { | |
1897 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
1898 int k; | |
1899 #endif | |
1900 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED | |
1901 fprintf(STDERR, "\n PASS (%lu zero samples)\n", | |
1902 (unsigned long)zero_samples); | |
1903 #else | |
1904 fprintf(STDERR, " PASS\n"); | |
1905 #endif | |
1906 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED | |
1907 for (k = 0; k<256; k++) | |
1908 if (filters_used[k]) | |
1909 fprintf(STDERR, " Filter %d was used %lu times\n", | |
1910 k, (unsigned long)filters_used[k]); | |
1911 #endif | |
1912 #ifdef PNG_TIME_RFC1123_SUPPORTED | |
1913 if (tIME_chunk_present != 0) | |
1914 fprintf(STDERR, " tIME = %s\n", tIME_string); | |
1915 #endif /* PNG_TIME_RFC1123_SUPPORTED */ | |
1916 } | |
1917 } | |
1918 | |
1919 else | |
1920 { | |
1921 if (verbose == 0 && i != 2) | |
1922 fprintf(STDERR, "\n Testing %s:", inname); | |
1923 | |
1924 fprintf(STDERR, " FAIL\n"); | |
1925 ierror += kerror; | |
1926 } | |
1927 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1928 if (allocation_now != current_allocation) | |
1929 fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", | |
1930 current_allocation - allocation_now); | |
1931 | |
1932 if (current_allocation != 0) | |
1933 { | |
1934 memory_infop pinfo = pinformation; | |
1935 | |
1936 fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", | |
1937 current_allocation); | |
1938 | |
1939 while (pinfo != NULL) | |
1940 { | |
1941 fprintf(STDERR, " %lu bytes at %x\n", | |
1942 (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); | |
1943 pinfo = pinfo->next; | |
1944 } | |
1945 } | |
1946 #endif | |
1947 } | |
1948 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG | |
1949 fprintf(STDERR, " Current memory allocation: %10d bytes\n", | |
1950 current_allocation); | |
1951 fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", | |
1952 maximum_allocation); | |
1953 fprintf(STDERR, " Total memory allocation: %10d bytes\n", | |
1954 total_allocation); | |
1955 fprintf(STDERR, " Number of allocations: %10d\n", | |
1956 num_allocations); | |
1957 #endif | |
1958 } | |
1959 | |
1960 #ifdef PNGTEST_TIMING | |
1961 t_stop = (float)clock(); | |
1962 t_misc += (t_stop - t_start); | |
1963 t_start = t_stop; | |
1964 fprintf(STDERR, " CPU time used = %.3f seconds", | |
1965 (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); | |
1966 fprintf(STDERR, " (decoding %.3f,\n", | |
1967 t_decode/(float)CLOCKS_PER_SEC); | |
1968 fprintf(STDERR, " encoding %.3f ,", | |
1969 t_encode/(float)CLOCKS_PER_SEC); | |
1970 fprintf(STDERR, " other %.3f seconds)\n\n", | |
1971 t_misc/(float)CLOCKS_PER_SEC); | |
1972 #endif | |
1973 | |
1974 if (ierror == 0) | |
1975 fprintf(STDERR, " libpng passes test\n"); | |
1976 | |
1977 else | |
1978 fprintf(STDERR, " libpng FAILS test\n"); | |
1979 | |
1980 return (int)(ierror != 0); | |
1981 } | |
1982 #else | |
1983 int | |
1984 main(void) | |
1985 { | |
1986 fprintf(STDERR, | |
1987 " test ignored because libpng was not built with read support\n"); | |
1988 /* And skip this test */ | |
1989 return PNG_LIBPNG_VER < 10600 ? 0 : 77; | |
1990 } | |
1991 #endif | |
1992 | |
1993 /* Generate a compiler error if there is an old png.h in the search path. */ | |
1994 typedef png_libpng_version_1_6_10 Your_png_h_is_not_version_1_6_10; |