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