summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..b8e36da
--- /dev/null
+++ b/main.c
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+if (!argv[1]||!argv[2]){fprintf(stderr,"Usage: %s <binary file> <granulation level (0|1|2|3|4)>\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;
+}