Skip to content

Commit

Permalink
add option to read png from stdin
Browse files Browse the repository at this point in the history
  • Loading branch information
FRex committed Sep 18, 2021
1 parent 77ad14b commit afe8a15
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 19 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
85 changes: 67 additions & 18 deletions analyzepng.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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 '<stdin>'\n");
else
printf("File '%s'\n", fname);

return parse_and_close_png_file(f, skipidat, showpalette, showpalettecolors);
}

Expand Down

0 comments on commit afe8a15

Please sign in to comment.