/* 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; }