Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: third_party/libpng/contrib/libtests/timepng.c

Issue 2033063003: Check libpng directly into third_party/ (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: public.bzl Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* timepng.c
2 *
3 * Copyright (c) 2013,2016 John Cunningham Bowler
4 *
5 * Last changed in libpng 1.6.22 [(PENDING RELEASE)]
6 *
7 * This code is released under the libpng license.
8 * For conditions of distribution and use, see the disclaimer
9 * and license in png.h
10 *
11 * Load an arbitrary number of PNG files (from the command line, or, if there
12 * are no arguments on the command line, from stdin) then run a time test by
13 * reading each file by row or by image (possibly with transforms in the latter
14 * case). The only output is a time as a floating point number of seconds with
15 * 9 decimal digits.
16 */
17 #define _POSIX_C_SOURCE 199309L /* for clock_gettime */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <limits.h>
24
25 #include <time.h>
26
27 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
28 # include <config.h>
29 #endif
30
31 /* Define the following to use this test against your installed libpng, rather
32 * than the one being built here:
33 */
34 #ifdef PNG_FREESTANDING_TESTS
35 # include <png.h>
36 #else
37 # include "../../png.h"
38 #endif
39
40 /* The following is to support direct compilation of this file as C++ */
41 #ifdef __cplusplus
42 # define voidcast(type, value) static_cast<type>(value)
43 #else
44 # define voidcast(type, value) (value)
45 #endif /* __cplusplus */
46
47 #if ((defined(PNG_SEQUENTIAL_READ_SUPPORTED)) && defined(PNG_STDIO_SUPPORTED)\
48 && defined(PNG_EASY_ACCESS_SUPPORTED) && defined(PNG_INFO_IMAGE_SUPPORTED))
49 typedef struct
50 {
51 FILE *input;
52 FILE *output;
53 } io_data;
54
55 static PNG_CALLBACK(void, read_and_copy,
56 (png_structp png_ptr, png_bytep buffer, png_size_t cb))
57 {
58 io_data *io = (io_data*)png_get_io_ptr(png_ptr);
59
60 if (fread(buffer, cb, 1, io->input) != 1)
61 png_error(png_ptr, strerror(errno));
62
63 if (fwrite(buffer, cb, 1, io->output) != 1)
64 {
65 perror("temporary file");
66 fprintf(stderr, "temporary file PNG write failed\n");
67 exit(1);
68 }
69 }
70
71 static void read_by_row(png_structp png_ptr, png_infop info_ptr,
72 FILE *write_ptr, FILE *read_ptr)
73 {
74 /* These don't get freed on error, this is fine; the program immediately
75 * exits.
76 */
77 png_bytep row = NULL, display = NULL;
78 io_data io_copy;
79
80 if (write_ptr != NULL)
81 {
82 /* Set up for a copy to the temporary file: */
83 io_copy.input = read_ptr;
84 io_copy.output = write_ptr;
85 png_set_read_fn(png_ptr, &io_copy, read_and_copy);
86 }
87
88 png_read_info(png_ptr, info_ptr);
89
90 {
91 png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
92
93 row = voidcast(png_bytep,malloc(rowbytes));
94 display = voidcast(png_bytep,malloc(rowbytes));
95
96 if (row == NULL || display == NULL)
97 png_error(png_ptr, "OOM allocating row buffers");
98
99 {
100 png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
101 int passes = png_set_interlace_handling(png_ptr);
102 int pass;
103
104 png_start_read_image(png_ptr);
105
106 for (pass = 0; pass < passes; ++pass)
107 {
108 png_uint_32 y = height;
109
110 /* NOTE: this trashes the row each time; interlace handling won't
111 * work, but this avoids memory thrashing for speed testing and is
112 * somewhat representative of an application that works row-by-row.
113 */
114 while (y-- > 0)
115 png_read_row(png_ptr, row, display);
116 }
117 }
118 }
119
120 /* Make sure to read to the end of the file: */
121 png_read_end(png_ptr, info_ptr);
122
123 /* Free this up: */
124 free(row);
125 free(display);
126 }
127
128 static PNG_CALLBACK(void, no_warnings, (png_structp png_ptr,
129 png_const_charp warning))
130 {
131 (void)png_ptr;
132 (void)warning;
133 }
134
135 static int read_png(FILE *fp, png_int_32 transforms, FILE *write_file)
136 {
137 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,
138 no_warnings);
139 png_infop info_ptr = NULL;
140
141 if (png_ptr == NULL)
142 return 0;
143
144 if (setjmp(png_jmpbuf(png_ptr)))
145 {
146 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
147 return 0;
148 }
149
150 # ifdef PNG_BENIGN_ERRORS_SUPPORTED
151 png_set_benign_errors(png_ptr, 1/*allowed*/);
152 # endif
153 png_init_io(png_ptr, fp);
154
155 info_ptr = png_create_info_struct(png_ptr);
156
157 if (info_ptr == NULL)
158 png_error(png_ptr, "OOM allocating info structure");
159
160 if (transforms < 0)
161 read_by_row(png_ptr, info_ptr, write_file, fp);
162
163 else
164 png_read_png(png_ptr, info_ptr, transforms, NULL/*params*/);
165
166 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
167 return 1;
168 }
169
170 static int mytime(struct timespec *t)
171 {
172 /* Do the timing using clock_gettime and the per-process timer. */
173 if (!clock_gettime(CLOCK_PROCESS_CPUTIME_ID, t))
174 return 1;
175
176 perror("CLOCK_PROCESS_CPUTIME_ID");
177 fprintf(stderr, "timepng: could not get the time\n");
178 return 0;
179 }
180
181 static int perform_one_test(FILE *fp, int nfiles, png_int_32 transforms)
182 {
183 int i;
184 struct timespec before, after;
185
186 /* Clear out all errors: */
187 rewind(fp);
188
189 if (mytime(&before))
190 {
191 for (i=0; i<nfiles; ++i)
192 {
193 if (read_png(fp, transforms, NULL/*write*/))
194 {
195 if (ferror(fp))
196 {
197 perror("temporary file");
198 fprintf(stderr, "file %d: error reading PNG data\n", i);
199 return 0;
200 }
201 }
202
203 else
204 {
205 perror("temporary file");
206 fprintf(stderr, "file %d: error from libpng\n", i);
207 return 0;
208 }
209 }
210 }
211
212 else
213 return 0;
214
215 if (mytime(&after))
216 {
217 /* Work out the time difference and print it - this is the only output,
218 * so flush it immediately.
219 */
220 unsigned long s = after.tv_sec - before.tv_sec;
221 long ns = after.tv_nsec - before.tv_nsec;
222
223 if (ns < 0)
224 {
225 --s;
226 ns += 1000000000;
227
228 if (ns < 0)
229 {
230 fprintf(stderr, "timepng: bad clock from kernel\n");
231 return 0;
232 }
233 }
234
235 printf("%lu.%.9ld\n", s, ns);
236 fflush(stdout);
237 if (ferror(stdout))
238 {
239 fprintf(stderr, "timepng: error writing output\n");
240 return 0;
241 }
242
243 /* Successful return */
244 return 1;
245 }
246
247 else
248 return 0;
249 }
250
251 static int add_one_file(FILE *fp, char *name)
252 {
253 FILE *ip = fopen(name, "rb");
254
255 if (ip != NULL)
256 {
257 /* Read the file using libpng; this detects errors and also deals with
258 * files which contain data beyond the end of the file.
259 */
260 int ok = 0;
261 fpos_t pos;
262
263 if (fgetpos(fp, &pos))
264 {
265 /* Fatal error reading the start: */
266 perror("temporary file");
267 fprintf(stderr, "temporary file fgetpos error\n");
268 exit(1);
269 }
270
271 if (read_png(ip, -1/*by row*/, fp/*output*/))
272 {
273 if (ferror(ip))
274 {
275 perror(name);
276 fprintf(stderr, "%s: read error\n", name);
277 }
278
279 else
280 ok = 1; /* read ok */
281 }
282
283 else
284 fprintf(stderr, "%s: file not added\n", name);
285
286 (void)fclose(ip);
287
288 /* An error in the output is fatal; exit immediately: */
289 if (ferror(fp))
290 {
291 perror("temporary file");
292 fprintf(stderr, "temporary file write error\n");
293 exit(1);
294 }
295
296 if (ok)
297 return 1;
298
299 /* Did not read the file successfully, simply rewind the temporary
300 * file. This must happen after the ferror check above to avoid clearing
301 * the error.
302 */
303 if (fsetpos(fp, &pos))
304 {
305 perror("temporary file");
306 fprintf(stderr, "temporary file fsetpos error\n");
307 exit(1);
308 }
309 }
310
311 else
312 {
313 /* file open error: */
314 perror(name);
315 fprintf(stderr, "%s: open failed\n", name);
316 }
317
318 return 0; /* file not added */
319 }
320
321 static void
322 usage(FILE *fp)
323 {
324 if (fp != NULL) fclose(fp);
325
326 fprintf(stderr,
327 "Usage:\n"
328 " timepng --assemble <assembly> {files}\n"
329 " Read the files into <assembly>, output the count. Options are ignored.\n"
330 " timepng --dissemble <assembly> <count> [options]\n"
331 " Time <count> files from <assembly>, additional files may not be given.\n"
332 " Otherwise:\n"
333 " Read the files into a temporary file and time the decode\n"
334 "Transforms:\n"
335 " --by-image: read by image with png_read_png\n"
336 " --<transform>: implies by-image, use PNG_TRANSFORM_<transform>\n"
337 " Otherwise: read by row using png_read_row (to a single row buffer)\n"
338 /* ISO C90 string length max 509 */);fprintf(stderr,
339 "{files}:\n"
340 " PNG files to copy into the assembly and time. Invalid files are skipped\n"
341 " with appropriate error messages. If no files are given the list of files\n"
342 " is read from stdin with each file name terminated by a newline\n"
343 "Output:\n"
344 " For --assemble the output is the name of the assembly file followed by the\n"
345 " count of the files it contains; the arguments for --dissemble. Otherwise\n"
346 " the output is the total decode time in seconds.\n");
347
348 exit(99);
349 }
350
351 int main(int argc, char **argv)
352 {
353 int ok = 0;
354 int err = 0;
355 int nfiles = 0;
356 int transforms = -1; /* by row */
357 const char *assembly = NULL;
358 FILE *fp;
359
360 if (argc > 2 && strcmp(argv[1], "--assemble") == 0)
361 {
362 /* Just build the test file, argv[2] is the file name. */
363 assembly = argv[2];
364 fp = fopen(assembly, "wb");
365 if (fp == NULL)
366 {
367 perror(assembly);
368 fprintf(stderr, "timepng --assemble %s: could not open for write\n",
369 assembly);
370 usage(NULL);
371 }
372
373 argv += 2;
374 argc -= 2;
375 }
376
377 else if (argc > 3 && strcmp(argv[1], "--dissemble") == 0)
378 {
379 fp = fopen(argv[2], "rb");
380
381 if (fp == NULL)
382 {
383 perror(argv[2]);
384 fprintf(stderr, "timepng --dissemble %s: could not open for read\n",
385 argv[2]);
386 usage(NULL);
387 }
388
389 nfiles = atoi(argv[3]);
390 if (nfiles <= 0)
391 {
392 fprintf(stderr,
393 "timepng --dissemble <file> <count>: %s is not a count\n",
394 argv[3]);
395 exit(99);
396 }
397 #ifdef __COVERITY__
398 else
399 {
400 nfiles &= PNG_UINT_31_MAX;
401 }
402 #endif
403
404 argv += 3;
405 argc -= 3;
406 }
407
408 else /* Else use a temporary file */
409 {
410 #ifndef __COVERITY__
411 fp = tmpfile();
412 #else
413 /* Experimental. Coverity says tmpfile() is insecure because it
414 * generates predictable names.
415 *
416 * It is possible to satisfy Coverity by using mkstemp(); however,
417 * any platform supporting mkstemp() undoubtedly has a secure tmpfile()
418 * implementation as well, and doesn't need the fix. Note that
419 * the fix won't work on platforms that don't support mkstemp().
420 *
421 * https://www.securecoding.cert.org/confluence/display/c/
422 * FIO21-C.+Do+not+create+temporary+files+in+shared+directories
423 * says that most historic implementations of tmpfile() provide
424 * only a limited number of possible temporary file names
425 * (usually 26) before file names are recycled. That article also
426 * provides a secure solution that unfortunately depends upon mkstemp().
427 */
428 char tmpfile[] = "timepng-XXXXXX";
429 int filedes;
430 umask(0177);
431 filedes = mkstemp(tmpfile);
432 if (filedes < 0)
433 fp = NULL;
434 else
435 {
436 fp = fdopen(filedes,"w+");
437 /* Hide the filename immediately and ensure that the file does
438 * not exist after the program ends
439 */
440 (void) unlink(tmpfile);
441 }
442 #endif
443
444 if (fp == NULL)
445 {
446 perror("tmpfile");
447 fprintf(stderr, "timepng: could not open the temporary file\n");
448 exit(1); /* not a user error */
449 }
450 }
451
452 /* Handle the transforms: */
453 while (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-')
454 {
455 const char *opt = *++argv + 2;
456
457 --argc;
458
459 /* Transforms turn on the by-image processing and maybe set some
460 * transforms:
461 */
462 if (transforms == -1)
463 transforms = PNG_TRANSFORM_IDENTITY;
464
465 if (strcmp(opt, "by-image") == 0)
466 {
467 /* handled above */
468 }
469
470 # define OPT(name) else if (strcmp(opt, #name) == 0)\
471 transforms |= PNG_TRANSFORM_ ## name
472
473 OPT(STRIP_16);
474 OPT(STRIP_ALPHA);
475 OPT(PACKING);
476 OPT(PACKSWAP);
477 OPT(EXPAND);
478 OPT(INVERT_MONO);
479 OPT(SHIFT);
480 OPT(BGR);
481 OPT(SWAP_ALPHA);
482 OPT(SWAP_ENDIAN);
483 OPT(INVERT_ALPHA);
484 OPT(STRIP_FILLER);
485 OPT(STRIP_FILLER_BEFORE);
486 OPT(STRIP_FILLER_AFTER);
487 OPT(GRAY_TO_RGB);
488 OPT(EXPAND_16);
489 OPT(SCALE_16);
490
491 else
492 {
493 fprintf(stderr, "timepng %s: unrecognized transform\n", opt);
494 usage(fp);
495 }
496 }
497
498 /* Handle the files: */
499 if (argc > 1 && nfiles > 0)
500 usage(fp); /* Additional files not valid with --dissemble */
501
502 else if (argc > 1)
503 {
504 int i;
505
506 for (i=1; i<argc; ++i)
507 {
508 if (nfiles == INT_MAX)
509 {
510 fprintf(stderr, "%s: skipped, too many files\n", argv[i]);
511 break;
512 }
513
514 else if (add_one_file(fp, argv[i]))
515 ++nfiles;
516 }
517 }
518
519 else if (nfiles == 0) /* Read from stdin withoout --dissemble */
520 {
521 char filename[FILENAME_MAX+1];
522
523 while (fgets(filename, FILENAME_MAX+1, stdin))
524 {
525 size_t len = strlen(filename);
526
527 if (filename[len-1] == '\n')
528 {
529 filename[len-1] = 0;
530 if (nfiles == INT_MAX)
531 {
532 fprintf(stderr, "%s: skipped, too many files\n", filename);
533 break;
534 }
535
536 else if (add_one_file(fp, filename))
537 ++nfiles;
538 }
539
540 else
541 {
542 fprintf(stderr, "timepng: file name too long: ...%s\n",
543 filename+len-32);
544 err = 1;
545 break;
546 }
547 }
548
549 if (ferror(stdin))
550 {
551 fprintf(stderr, "timepng: stdin: read error\n");
552 err = 1;
553 }
554 }
555
556 /* Perform the test, or produce the --assemble output: */
557 if (!err)
558 {
559 if (nfiles > 0)
560 {
561 if (assembly != NULL)
562 {
563 if (fflush(fp) && !ferror(fp) && fclose(fp))
564 {
565 perror(assembly);
566 fprintf(stderr, "%s: close failed\n", assembly);
567 }
568
569 else
570 {
571 printf("%s %d\n", assembly, nfiles);
572 fflush(stdout);
573 ok = !ferror(stdout);
574 }
575 }
576
577 else
578 {
579 ok = perform_one_test(fp, nfiles, transforms);
580 (void)fclose(fp);
581 }
582 }
583
584 else
585 usage(fp);
586 }
587
588 else
589 (void)fclose(fp);
590
591 /* Exit code 0 on success. */
592 return ok == 0;
593 }
594 #else /* !sufficient support */
595 int main(void) { return 77; }
596 #endif /* !sufficient support */
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698