/* * Very simple program to list the names of the PNG/JNG/MNG chunks. * This program does NOT use libpng or libmng. * Author: Cosmin Truta, Jan 2001 * Sorry, ASCII comparisons are used, and the program is not too commented... */ #include #include /** The necessary types: bool, byte, uint32. **/ typedef int bool; typedef unsigned char byte; typedef unsigned long uint32; /** The standard chunks **/ char *std_chunks[] = { /* PNG standard chunks */ "IHDR", "PLTE", "IDAT", "IEND", "cHRM", "gAMA", "iCCP", "sBIT", "sRGB", "bKGD", "hIST", "tRNS", "pHYs", "sPLT", "tIME", "iTXt", "tEXt", "zTXt", /* JNG standard chunks */ "JHDR", "JDAT", "JDAA", "JSEP", /* MNG standard chunks */ "MHDR", "MEND", "TERM", "SAVE", "SEEK", "BASI", "LOOP", "ENDL", "DEFI", "CLON", "PAST", "MAGN", "DISC", "BACK", "FRAM", "MOVE", "CLIP", "SHOW", "DHDR", "PROM", "DROP", "DBYK", "ORDR", "IPNG", "IJNG", "PPLT", "eXPI", "fPRI", "nEED", "pHYg", /* the end of the list */ "" }; /** Opens a PNG, MNG or JNG file. Returns the file pointer. **/ FILE *mng_open(const char *filename, char **errmsg) { static char png_signature[] = {'\211', 'P', 'N', 'G', '\r', '\n', '\32', '\n'}; static char mng_signature[] = {'\212', 'M', 'N', 'G', '\r', '\n', '\32', '\n'}; static char jng_signature[] = {'\213', 'J', 'N', 'G', '\r', '\n', '\32', '\n'}; static char sig_buf[sizeof(mng_signature)]; FILE *fp; int error; if ((fp = fopen(filename, "rb")) == NULL) { *errmsg = "Error opening"; return NULL; } error = 0; *errmsg = "Success opening"; if (fread(sig_buf, sizeof(sig_buf), 1, fp) != 1) { error = 1; *errmsg = "Error reading"; } if (!error) { if (memcmp(sig_buf, png_signature, sizeof(sig_buf)) != 0 && memcmp(sig_buf, mng_signature, sizeof(sig_buf)) != 0 && memcmp(sig_buf, jng_signature, sizeof(sig_buf)) != 0) { error = 1; *errmsg = "Not a PNG/MNG/JNG"; } } if (error) { fclose(fp); return NULL; } else return fp; } /** Reads an uint32. **/ bool mng_read_uint32(uint32 *result, FILE *fp) { byte buffer[4]; if (fread(buffer, 4, 1, fp) != 1) return 0; *result = ((uint32)buffer[0] << 24) | ((uint32)buffer[1] << 16) | ((uint32)buffer[2] << 8) | ((uint32)buffer[3]); return 1; } /** Returns TRUE if the chunk is standard. **/ bool mng_is_standard_chunk(char *signature) { char **p; for (p = std_chunks; **p; p++) { if (memcmp(*p, signature, 4) == 0) return 1; } return 0; } /** List the chunks found in the file. Simplistic. **/ bool mng_list_chunks(FILE *fp, bool concat, bool std) { uint32 chunk_length; char chunk_signature[5]; uint32 chunk_crc32; int i; chunk_signature[4] = '\0'; for ( ;; ) { if (!mng_read_uint32(&chunk_length, fp)) break; if (fread(chunk_signature, 4, 1, fp) != 1) return 0; if (fseek(fp, (long)chunk_length, SEEK_CUR) != 0) return 0; if (!mng_read_uint32(&chunk_crc32, fp)) return 0; if (!std || mng_is_standard_chunk(chunk_signature)) printf((concat ? "%s" : "%s\n"), chunk_signature); } return (memcmp(chunk_signature, "IEND", 4) == 0 || memcmp(chunk_signature, "MEND", 4) == 0) ? 1 : 0; } /** main **/ int main(int argc, char *argv[]) { FILE *fp; char *errmsg; bool concat_chunks = 0; bool std_chunks = 0; bool show_help = 0; while (argc > 1 && argv[1][0] == '-') { switch (argv[1][1]) { case 'c': concat_chunks = 1; break; case 's': std_chunks = 1; break; case 'h': case '?': show_help = 1; break; } --argc; ++argv; } if (argc <= 1) show_help = 1; if (show_help) fprintf(stderr, "Usage: mnglist [-c] [-s] \n" " -c Concatenate the chunk names\n" " -s List the standard chunks only\n" " -h Show this help\n"); if (argc <= 1) return 1; if ((fp = mng_open(argv[1], &errmsg)) == NULL) { fprintf(stderr, "%s %s\n", errmsg, argv[1]); return 2; } if (!mng_list_chunks(fp, concat_chunks, std_chunks)) fprintf(stderr, "Error while listing the chunks.\n"); fclose(fp); return 0; }