Compare commits

..

9 Commits

Author SHA1 Message Date
cae1791eba Add a9 file submissions 2023-12-05 13:33:01 -04:00
6ff99deff7 Add a8 file submissions 2023-12-05 13:32:04 -04:00
c6dd294bc0 Remove unused import a9 2023-12-05 13:29:57 -04:00
6a6fd9c37c Tests in a9 2023-12-05 13:28:08 -04:00
112535e8e7 Use LF in a9 2023-12-05 13:28:08 -04:00
93635bc1d6 Remove unneeded function 2023-12-05 12:57:16 -04:00
530ab9a135 Add comments and error checking to A9 2023-12-05 12:47:36 -04:00
bea609e01c Use exit define 2023-12-04 20:55:45 -04:00
136a4fe960 Code reformatting 2023-12-04 20:55:07 -04:00
9 changed files with 313 additions and 298 deletions

Binary file not shown.

View File

@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All CTest" type="CTestRunConfiguration" factoryName="CTestRun" PROGRAM_PARAMS="--extra-verbose" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$CMakeCurrentLocalGenerationDir$" PASS_PARENT_ENVS_2="true" CONFIG_NAME="Debug" RUN_PATH="$CTestCurrentExecutableName$" EXPLICIT_BUILD_TARGET_NAME="all" TEST_MODE="PATTERN">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
<option name="BeforeTestRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="images" type="CTestRunConfiguration" factoryName="CTestRun" PROGRAM_PARAMS="--extra-verbose" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$CMakeCurrentLocalGenerationDir$" PASS_PARENT_ENVS_2="true" CONFIG_NAME="Debug" RUN_PATH="$CTestCurrentExecutableName$" EXPLICIT_BUILD_TARGET_NAME="all" TEST_METHOD="images" TEST_MODE="SUITE_TEST">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
<option name="BeforeTestRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="output" type="CTestRunConfiguration" factoryName="CTestRun" PROGRAM_PARAMS="--extra-verbose" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$CMakeCurrentLocalGenerationDir$" PASS_PARENT_ENVS_2="true" CONFIG_NAME="Debug" RUN_PATH="$CTestCurrentExecutableName$" EXPLICIT_BUILD_TARGET_NAME="all" TEST_METHOD="output" TEST_MODE="SUITE_TEST">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
<option name="BeforeTestRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@ -3,4 +3,8 @@ project(Assignment9 C)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
add_executable(Assignment9 src/main.c add_executable(Assignment9 src/main.c
src/png.c src/png.c
src/png.h) src/png.h)
enable_testing()
add_test(NAME output COMMAND test_text.sh WORKING_DIRECTORY ../tests)
add_test(NAME images COMMAND test_images.sh WORKING_DIRECTORY ../tests)

View File

@ -1,52 +1,50 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include "png.h"
#include "png.h"
int main(int argc, char *argv[]) {
int main(int argc, char *argv[]) { // Error handling
if (argc != 2) { if (argc != 2) {
printf("Usage: %s <png file>\n", argv[0]); printf("Usage: %s <png file>\n", argv[0]);
exit(1); exit(EXIT_FAILURE);
} }
if (strlen(argv[1]) > PATH_MAX) { if (strlen(argv[1]) > PATH_MAX) {
printf("Path too long\n"); printf("Path too long\n");
exit(1); exit(EXIT_FAILURE);
} }
char *path = argv[1]; // Read file
char *path = argv[1];
char* png_buffer = load_file(get_fd(path)); char *png_buffer = load_file(path);
if (!is_png(png_buffer)) { if (!is_png(png_buffer)) {
printf("It's not a PNG file\n"); printf("It's not a PNG file\n");
exit(1); exit(EXIT_FAILURE);
} else { } else {
printf("It's a PNG file\n"); printf("It's a PNG file\n");
} }
png_chunk **chunks = get_png_chunks(png_buffer); png_chunk **chunks = get_png_chunks(png_buffer);
free(png_buffer); free(png_buffer);
int size = get_number_of_chunks(chunks); // Done with buffer, as chunks are a structured way to access the data
for (int i = 0; i < size; i++) { // Iterate over chunks to display info and "decrypt" IDAT chunks
// Check if header is IDAT or IEND int size = get_number_of_chunks(chunks);
bool is_idat = memcmp(chunks[i]->type, "IDAT", 4) == 0; for (int i = 0; i < size; i++) {
bool is_iend = memcmp(chunks[i]->type, "IEND", 4) == 0; // Check if header is IDAT or IEND
if (is_idat || is_iend) { bool is_idat = memcmp(chunks[i]->type, "IDAT", 4) == 0;
printf("Found %.4s\n", chunks[i]->type); bool is_iend = memcmp(chunks[i]->type, "IEND", 4) == 0;
if (is_idat) { if (is_idat || is_iend) {
xor_data(chunks[i]); printf("Found %.4s\n", chunks[i]->type);
} if (is_idat) {
} else { xor_data(chunks[i]);
printf("Found unknown: %.4s\n", chunks[i]->type); }
} } else {
printf("Chunk size is:%d\n", chunks[i]->length); printf("Found unknown: %.4s\n", chunks[i]->type);
} }
// Uncomment to not overwrite original file printf("Chunk size is:%d\n", chunks[i]->length);
//char new_path[PATH_MAX]; }
//getcwd(new_path, sizeof(new_path)); // Write file and free memory
//strcat(new_path, "/output.png"); write_png_chunks(path, chunks);
//write_png_chunks(new_path, chunks); destroy_chunks(chunks);
write_png_chunks(path, chunks); return EXIT_SUCCESS;
destroy_chunks(chunks); }
return EXIT_SUCCESS;
}

View File

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

View File

@ -1,79 +1,75 @@
/* /*
* Copyright Notice * Copyright Notice
* ---------------- * ----------------
* Copyright © 1998, 1999 by: Glenn Randers-Pehrson * Copyright © 1998, 1999 by: Glenn Randers-Pehrson
* This specification is a modification of the PNG 1.0 specification. It is being * 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: * provided by the copyright holder under the provisions of the 1996 MIT copyright and license:
* Copyright © 1996 by: Massachusetts Institute of Technology (MIT) * Copyright © 1996 by: Massachusetts Institute of Technology (MIT)
* This W3C specification is being provided by the copyright holders under * This W3C specification is being provided by the copyright holders under
* the following license. By obtaining, using and/or copying this specification, you * 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 * agree that you have read, understood, and will comply with the following terms
* and conditions: * and conditions:
* Permission to use, copy, and distribute this specification for any purpose * 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 * 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, * this NOTICE appears on ALL copies of the specification or portions thereof,
* including modifications, that you make. * including modifications, that you make.
* THIS SPECIFICATION IS PROVIDED ”AS IS,” AND COPYRIGHT HOLD-ERS * THIS SPECIFICATION IS PROVIDED ”AS IS,” AND COPYRIGHT HOLD-ERS
* MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR * MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
* IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, COPYRIGHT * IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, COPYRIGHT
* HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY
* OR FITNESS FOR ANY PARTICULAR PURPOSE OR * OR FITNESS FOR ANY PARTICULAR PURPOSE OR
* THAT THE USE OF THE SPECIFICATION WILL NOT INFRINGE ANY * THAT THE USE OF THE SPECIFICATION WILL NOT INFRINGE ANY
* THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER
* RIGHTS. COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY * RIGHTS. COPYRIGHT HOLDERS WILL BEAR NO LIABILITY FOR ANY
* USE OF THIS SPECIFICATION. * USE OF THIS SPECIFICATION.
* The name and trademarks of copyright holders may NOT be used in * The name and trademarks of copyright holders may NOT be used in
* advertising or publicity pertaining to the specification without specific, written * advertising or publicity pertaining to the specification without specific, written
* prior permission. Title to copyright in this specification and any associated * prior permission. Title to copyright in this specification and any associated
* documentation will at all times remain with copyright holders. * documentation will at all times remain with copyright holders.
*/ */
#pragma once #pragma once
#include <arpa/inet.h> // Needed for uint types
#include <stdio.h> #include <arpa/inet.h>
#include <stdlib.h>
#include <string.h> // http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature
#define PNG_SIGNATURE "\211PNG\r\n\032\n"
// http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature #define PNG_SIGNATURE_SIZE 8
#define PNG_SIGNATURE "\211PNG\r\n\032\n"
#define PNG_SIGNATURE_SIZE 8 // The key used to "encrypt/decrypt" the PNG chunks
#define KEY 42
#define KEY 42
typedef struct png_chunk {
typedef struct png_chunk { uint32_t length;
uint32_t length; char type[4];
char type[4]; char *data;
char *data; uint32_t crc;
uint32_t crc; } png_chunk;
} png_chunk;
// Get FILE from path
// Get file descriptor from path int get_fd(char *path);
int get_fd(char *path);
// Store file in heap memory
// Get FILE* from file descriptor char *load_file(char *path);
FILE *get_fp(int fd);
// Check if file is a PNG
// Store file in heap memory int is_png(char *buffer);
char *load_file(int fd);
// Get PNG chunk
// Check if file is a PNG png_chunk *get_png_chunk(char *buffer, unsigned int offset);
int is_png(char *buffer);
// Get all PNG chunks
// Get PNG chunk png_chunk **get_png_chunks(char *buffer);
png_chunk *get_png_chunk(char *buffer, unsigned int offset);
// Get number of chunks
// Get all PNG chunks int get_number_of_chunks(png_chunk **chunks);
png_chunk **get_png_chunks(char *buffer);
// XOR chunk with key
// Get number of chunks void xor_data(png_chunk *chunk);
int get_number_of_chunks(png_chunk **chunks);
// Destroy all chunks
// XOR chunk with key void destroy_chunks(png_chunk **chunks);
void xor_data(png_chunk *chunk);
// Write PNG chunks to file
// Destroy all chunks void write_png_chunks(char *path, png_chunk **chunks);
void destroy_chunks(png_chunk **chunks);
// Write PNG chunks to file
void write_png_chunks(char *path, png_chunk **chunks);

Binary file not shown.