/* * Copyright Notice * ---------------- * Copyright © 1998, 1999 by: Glenn Randers-Pehrson * This specification is a modification of the PNG 1.0 specification. It is being * provided by the copyright holder under the provisions of the 1996 MIT copyright and license: * Copyright © 1996 by: Massachusetts Institute of Technology (MIT) * This W3C specification is being provided by the copyright holders under * the following license. By obtaining, using and/or copying this specification, you * agree that you have read, understood, and will comply with the following terms * and conditions: * Permission to use, copy, and distribute this specification for any purpose * and without fee or royalty is hereby granted, provided that the full text of * this NOTICE appears on ALL copies of the specification or portions thereof, * including modifications, that you make. * THIS SPECIFICATION IS PROVIDED ”AS IS,” AND COPYRIGHT HOLD-ERS * MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR * IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, COPYRIGHT * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY * OR FITNESS FOR ANY PARTICULAR PURPOSE OR * THAT THE USE OF THE SPECIFICATION WILL NOT INFRINGE ANY * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER * RIGHTS. COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY * USE OF THIS SPECIFICATION. * The name and trademarks of copyright holders may NOT be used in * advertising or publicity pertaining to the specification without specific, written * prior permission. Title to copyright in this specification and any associated * documentation will at all times remain with copyright holders. */ #include #include #include #include #include #include "png.h" FILE *get_file(char *path) { FILE *fp = fopen(path, "rb"); if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } return fp; } char *load_file(char *path) { FILE *fp = get_file(path); fseek(fp, 0, SEEK_END); long size = ftell(fp); rewind(fp); char *buffer = malloc(size); if (buffer == NULL) { perror("malloc"); exit(EXIT_FAILURE); } fread(buffer, 1, size, fp); fclose(fp); return buffer; } int is_png(char *buffer) { return memcmp(buffer, PNG_SIGNATURE, PNG_SIGNATURE_SIZE) == 0; } png_chunk *get_png_chunk(char *buffer, unsigned int offset) { png_chunk *chunk = malloc(sizeof(png_chunk)); if (chunk == NULL) { perror("malloc"); exit(EXIT_FAILURE); } memcpy(&chunk->length, buffer + offset + 0, 4); // Convert length to host byte order because PNG lengths is in network byte order/Big Endian chunk->length = ntohl(chunk->length); memcpy(&chunk->type, buffer + offset + 4, 4); chunk->data = malloc(chunk->length); if (chunk->data == NULL) { perror("malloc"); exit(EXIT_FAILURE); } memcpy(chunk->data, buffer + offset + 8, chunk->length); memcpy(&chunk->crc, buffer + offset + 8 + chunk->length, 4); return chunk; } png_chunk **get_png_chunks(char *buffer) { png_chunk **chunks = malloc(sizeof(png_chunk *)); if (chunks == NULL) { perror("malloc"); exit(EXIT_FAILURE); } // Running offset of the buffer unsigned int offset = PNG_SIGNATURE_SIZE; // Index of the current chunk int i = 0; while (true) { chunks[i] = get_png_chunk(buffer, offset); // 12 = 4 (length) + 4 (type) + 4 (crc) offset += 12 + chunks[i]->length; if (memcmp(chunks[i]->type, "IEND", 4) == 0) { break; } i++; // Add one because realloc is 1-indexed when multiplying by sizeof png_chunk **err_check = realloc(chunks, sizeof(png_chunk *) * (i + 1)); if (err_check == NULL) { destroy_chunks(chunks); perror("realloc"); exit(EXIT_FAILURE); } chunks = err_check; } return chunks; } int get_number_of_chunks(png_chunk **chunks) { int i = 0; while (memcmp(chunks[i]->type, "IEND", 4) != 0) { i++; } // Add one for the IEND chunk return ++i; } void xor_data(png_chunk *chunk) { for (int i = 0; i < chunk->length; i++) { chunk->data[i] ^= KEY; } } void destroy_chunks(png_chunk **chunks) { unsigned int size = get_number_of_chunks(chunks); for (int i = 0; i < size; i++) { free(chunks[i]->data); free(chunks[i]); } free(chunks); } void write_png_chunks(char *path, png_chunk **chunks) { FILE *fp = fopen(path, "wb"); if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } fwrite(PNG_SIGNATURE, PNG_SIGNATURE_SIZE, 1, fp); unsigned int size = get_number_of_chunks(chunks); for (int i = 0; i < size; i++) { // Convert length to network byte order for writing chunks[i]->length = htonl(chunks[i]->length); fwrite(&chunks[i]->length, 4, 1, fp); fwrite(chunks[i]->type, 4, 1, fp); // Convert back so we can accurately use it to write the length of the data chunks[i]->length = ntohl(chunks[i]->length); fwrite(chunks[i]->data, chunks[i]->length, 1, fp); fwrite(&chunks[i]->crc, 4, 1, fp); } fclose(fp); }