167 lines
4.6 KiB
C
167 lines
4.6 KiB
C
/*
|
|
* 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 <arpa/inet.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include "png.h"
|
|
|
|
int get_fd(char *path) {
|
|
FILE *fp = fopen(path, "rb");
|
|
if (fp == NULL) {
|
|
perror("fopen");
|
|
exit(1);
|
|
}
|
|
int fd = fileno(fp);
|
|
if (fd == -1) {
|
|
perror("fileno");
|
|
exit(1);
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
FILE *get_fp(int fd) {
|
|
FILE *fp = fdopen(fd, "rb");
|
|
if (fp == NULL) {
|
|
perror("fdopen");
|
|
exit(1);
|
|
}
|
|
return fp;
|
|
}
|
|
|
|
char *load_file(int fd) {
|
|
FILE *fp = get_fp(fd);
|
|
fseek(fp, 0, SEEK_END);
|
|
long size = ftell(fp);
|
|
rewind(fp);
|
|
char *buffer = malloc(size);
|
|
if (buffer == NULL) {
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
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(1);
|
|
}
|
|
memcpy(&chunk->length, buffer + offset + 0, 4);
|
|
chunk->length = ntohl(chunk->length);
|
|
memcpy(&chunk->type, buffer + offset + 4, 4);
|
|
chunk->data = malloc(chunk->length);
|
|
if (chunk->data == NULL) {
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
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(1);
|
|
}
|
|
unsigned int offset = PNG_SIGNATURE_SIZE;
|
|
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++;
|
|
chunks = realloc(chunks, sizeof(png_chunk *) * (i + 1));
|
|
if (chunks == NULL) {
|
|
perror("realloc");
|
|
exit(1);
|
|
}
|
|
}
|
|
return chunks;
|
|
}
|
|
|
|
int get_number_of_chunks(png_chunk **chunks) {
|
|
int i = 0;
|
|
while (memcmp(chunks[i]->type, "IEND", 4) != 0) {
|
|
i++;
|
|
}
|
|
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(1);
|
|
}
|
|
fwrite(PNG_SIGNATURE, PNG_SIGNATURE_SIZE, 1, fp);
|
|
unsigned int size = get_number_of_chunks(chunks);
|
|
for (int i = 0; i < size; i++) {
|
|
chunks[i]->length = htonl(chunks[i]->length);
|
|
fwrite(&chunks[i]->length, 4, 1, fp);
|
|
fwrite(chunks[i]->type, 4, 1, fp);
|
|
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);
|
|
}
|