diff --git a/README.md b/README.md index 7e52681..b528904 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ in the help/usage message. The UTF-16 filenames in the command output (`File ''` they will be printed as UTF-8. On other OSes this line is not present and they are assumed to be using UTF-8 filenames and have color enabled terminals by default. +If `-` is used as fileame it will read from stdin. This allows not using a +temporary file on disk when using `curl` or some program that generates a png +on its stdout, but for a file already on disk it will be slower because piping +data in requires reading it all and discarding the majority of it, while a disk +file can seek and read only the parts that are needed. + On OpenBSD it also uses [pledge(2)](https://man.openbsd.org/pledge.2) and [unveil(2)](https://man.openbsd.org/unveil.2) to allow only read only access of only the files passed in as arguments, to improve security. @@ -31,7 +37,7 @@ are always up to date). $ analyzepng.exe -h analyzepng.exe - print information about chunks of given png files Windows build capable of colors and UTF-16 filenames -Usage: analyzepng.exe [--no-idat] file.png... +Usage: analyzepng.exe [--no-idat] file.png... # a single - means read from stdin --h OR --help #print this help to stdout --no-idat #don't print IDAT chunk locations and sizes, can be anywhere --plte #print RGB values from the PLTE chunk diff --git a/analyzepng.c b/analyzepng.c index bf0df44..74cc9ce 100644 --- a/analyzepng.c +++ b/analyzepng.c @@ -29,17 +29,32 @@ static int isoption(const char * arg) #define OPENBSD_PLEDGE_AND_UNVEIL_USED 1 static void applyOpenBsdRestrictions(int argc, char ** argv) { - int i; + int i, unveiled; - /* hide all files except the filename arguments */ + /* hide all files except the filename arguments, skip "-" too, because it means stdin */ + unveiled = 0; for(i = 1; i < argc; ++i) - if(!isoption(argv[i])) - if(unveil(argv[i], "r") == -1) - err(1, "unveil"); + { + if(isoption(argv[i]) || samestring(argv[i], "-")) + continue; - /* only allow stdio and reading files, this also takes away ability to unveil */ - if(pledge("stdio rpath", NULL) == -1) - err(1, "pledge"); + ++unveiled; + if(unveil(argv[i], "r") == -1) + err(1, "unveil"); + } + + if(unveiled == 0) + { + /* only allow stdio and no disk access, since we have 0 files on disk to process */ + if(pledge("stdio", NULL) == -1) + err(1, "pledge"); + } + else + { + /* only allow stdio and reading files, this also takes away ability to unveil */ + if(pledge("stdio rpath", NULL) == -1) + err(1, "pledge"); + } } #else #define OPENBSD_PLEDGE_AND_UNVEIL_USED 0 @@ -114,7 +129,7 @@ static int print_usage(const char * argv0, FILE * f) if(OPENBSD_PLEDGE_AND_UNVEIL_USED) fprintf(f, "OpenBSD build using pledge(2) and unveil(2) for extra safety\n"); - fprintf(f, "Usage: %s [--no-idat] file.png...\n", argv0); + fprintf(f, "Usage: %s [--no-idat] file.png... # a single - means read from stdin\n", argv0); fprintf(f, " --h OR --help #print this help to stdout\n"); fprintf(f, " --no-idat #don't print IDAT chunk locations and sizes, can be anywhere\n"); fprintf(f, " --plte #print RGB values from the PLTE chunk\n"); @@ -165,8 +180,35 @@ static void skip_step_int(struct myruntime * runtime, int amount) runtime->bytes += amount; } +static void error(struct myruntime * runtime, const char * errmsg) +{ + fprintf(stderr, "Error: %s\n", errmsg); + longjmp(runtime->jumper, 1); +} + +#define SKIP_THROWAWAY_BUFF_SIZE (32 * 1024 * 1024) +static char skipThrowawayBuff[SKIP_THROWAWAY_BUFF_SIZE]; + static void skip(struct myruntime * runtime, unsigned amount) { + /* if it's stdin then read to skip since fseek doesn't work */ + if(runtime->f == stdin) + { + while(amount > 0) + { + unsigned toread = SKIP_THROWAWAY_BUFF_SIZE; + if(amount < toread) + toread = amount; + + if(toread != fread(skipThrowawayBuff, 1, toread, runtime->f)) + error(runtime, "fread on stdin failed or truncated"); + + amount -= toread; + } /* while amount > 0 */ + + return; + } + const int step = 1900000000; while(amount >= (unsigned)step) { @@ -176,12 +218,6 @@ static void skip(struct myruntime * runtime, unsigned amount) skip_step_int(runtime, (int)amount); } -static void error(struct myruntime * runtime, const char * errmsg) -{ - fprintf(stderr, "Error: %s\n", errmsg); - longjmp(runtime->jumper, 1); -} - /* ensures b - does nothing if its true, prints Errr: errmsg and longjmps if its false */ static void ensure(struct myruntime * runtime, int b, const char * errmsg) { @@ -797,16 +833,29 @@ static int parse_and_close_png_file(FILE * f, int skipidat, int showpalette, int runtime.showpalette = showpalette; runtime.showpalettecolors = showpalettecolors; ret = setjmp_and_doit(&runtime); - fclose(f); + + /* if it was stdin then don't close it */ + if(f != stdin) + fclose(f); + return ret; } static int handle_file(const char * fname, int skipidat, int showpalette, int showpalettecolors) { - FILE * f = my_utf8_fopen_rb(fname); + FILE * f; + if(samestring(fname, "-")) + f = stdin; + else + f = my_utf8_fopen_rb(fname); + if(f) { - printf("File '%s'\n", fname); + if(samestring(fname, "-")) + printf("File ''\n"); + else + printf("File '%s'\n", fname); + return parse_and_close_png_file(f, skipidat, showpalette, showpalettecolors); }