/* Copyright (C) 2020 Gentoo-libre Install
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
if (!argv[1]||!argv[2]){fprintf(stderr,"Usage: %s \n", argv[0]); exit(1);}
int granulation;
/* For excessively large files, it's useful to skip a number of bytes after a false positive to save time despite the (small) chance of missing some png's */
switch (*argv[2])
{
case '0':
granulation = 8;
break;
case '1':
granulation = 64;
break;
case '2':
granulation = 4096;
break;
case '3':
granulation = 8192;
break;
case '4':
granulation = 10000;
break;
default:
fprintf(stderr,"Valid granulation levels: 0|1|2|3|4\n");
exit(1);
}
FILE *fp = fopen(argv[1],"rb");
if (!fp){fprintf(stderr,"Could not open file!\n"); exit(1);}
fseek(fp, 0L, SEEK_END);
int length = ftell(fp);
/* While we could read the file chunk by chunk, it's easier to just dump it into memory */
char *data = malloc(length);
if (!data){fprintf(stderr,"Malloc failed!\n"); exit(1);}
rewind(fp);
if (fread(data, 1, length, fp) != length){fprintf(stderr, "Bytes read and filesize length do not match!"); exit(1);}
fclose(fp);
if (mkdir("pngs", S_IRWXU | S_IRWXG) == -1 && errno != EEXIST){fprintf(stderr,"Could not create png directory!\n"); exit(1);}
char *header;
int offset = 0;
int size;
int count = 0;
char filename[5+4+4+1];
/* Search for png magic number in file */
while (header=memmem(data+offset, length-offset, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8))
{
/* Check for IHDR header, if this doesn't exist, there was a false positive, so skip ahead by granulation bytes */
if (memcmp(header+8+4,"IHDR",4)){size = granulation; goto skip;}
fprintf(stderr,"Found png at: %d\n", offset);
/* Check for EOF magic number */
char *iend = memmem(header+8, length-offset-8, "IEND", 4);
if (!iend){fprintf(stderr, "Png has no end!\n"); exit(1);}
/* +4 bytes for the IEND and +4 for the crc after IEND */
size = iend-header+8;
fprintf(stderr,"Png size: %d\n", size);
/* Exit if digits no longer fit in filename */
if (count > 9999){fprintf(stderr,"What are you doing?\n"); exit(1);}
snprintf(filename, 14, "pngs/%d.png",count++);
FILE *out = fopen(filename,"wb");
if (!out){fprintf(stderr,"Could not write file: %s!\n", filename); exit(1);}
fprintf(stderr,"Writing png to: %s\n",filename);
fwrite(header, 1, size, out);
fclose(out);
skip:;
if (offset+size >= length){break;}
offset += size;
}
free(data);
return 0;
}