diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..822895d828941cf6cc60f68aaac31b7dfd40462b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +myzip0 +myunzip0 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f1e3ca95a2c8efeeceae703a15d25fb8fef20608 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +all : myzip0 myunzip0 + +myzip0 : myzip0.c + cc myzip0.c -o myzip0 + +myunzip0 : myunzip0.c + cc myunzip0.c -o myunzip0 \ No newline at end of file diff --git a/myzip0.c b/myzip0.c new file mode 100644 index 0000000000000000000000000000000000000000..4c2bd23877f10177dfbea0cc7fe26f366bff7798 --- /dev/null +++ b/myzip0.c @@ -0,0 +1,131 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +const uint32_t BUFFER_SIZE = 1024; + +int write_u8(FILE *file, const uint8_t v) +{ + return fwrite(&v, sizeof(uint8_t), 1, file); +} + +int write_u16(FILE *file, const uint16_t v) +{ + return fwrite(&v, sizeof(uint16_t), 1, file); +} + +int write_u32(FILE *file, const uint32_t v) +{ + return fwrite(&v, sizeof(uint32_t), 1, file); +} + +int copy_file_to_file(FILE *input, FILE *output, uint32_t bytes) +{ + uint8_t buffer[BUFFER_SIZE]; + uint32_t bytes_written = 0; + + for (uint32_t start = 0; start < bytes; start += BUFFER_SIZE) + { + uint32_t remaining_bytes = bytes - start; + uint32_t copy_this_iter = (remaining_bytes < BUFFER_SIZE) ? + remaining_bytes : BUFFER_SIZE; + + fread(buffer, 1, copy_this_iter, input); + bytes_written += fwrite(buffer, 1, copy_this_iter, output); + } + + return bytes_written; +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + fprintf(stderr, "Usage: %s <output zip filename> <input file filename>\n", argv[0]); + return 1; + } + + const char *output_file_name = argv[1]; + const char *input_file_name = argv[2]; + FILE *input_file = fopen(input_file_name, "r"); + FILE *output_file = fopen(output_file_name, "w"); + + if (input_file == NULL) + { + fprintf(stderr, "Could not open \"%s\"\n", input_file_name); + return 1; + } + + if (output_file == NULL) + { + fprintf(stderr, "Could not open \"%s\"\n", output_file_name); + return 2; + } + + + + fseek(input_file, 0, SEEK_END); + uint32_t input_file_size = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + /* (1) LOCAL FILE RECORD */ + write_u32(output_file, 0x04034b50); /* local file signature */ + write_u16(output_file, 20); /* extract version */ + write_u16(output_file, 0); /* general purpose flag */ + write_u16(output_file, 0); /* compression method */ + write_u16(output_file, 0); /* last mod file time */ + write_u16(output_file, 0); /* last mod file date */ + write_u32(output_file, 0xDEADBEEF); /* crc */ + write_u32(output_file, input_file_size); /* compressed file size */ + write_u32(output_file, input_file_size); /* uncompressed file size */ + write_u16(output_file, strlen(input_file_name)); /* file name len */ + write_u16(output_file, 0); /* extra field length */ + fputs(input_file_name, output_file); /* file name */ + /* extra field */ + /* copy input file to output */ + copy_file_to_file(input_file, output_file, input_file_size); + + uint32_t central_directory_start = ftell(output_file); + + /* (2) CENTRAL DIRECTORY RECORD */ + write_u32(output_file, 0x02014b50); /* central directory signature */ + write_u8 (output_file, 30); /* specification version */ + write_u8 (output_file, 65); /* made by */ + write_u16(output_file, 20); /* extract version */ + write_u16(output_file, 0); /* general purpose bit flag */ + write_u16(output_file, 0); /* compression method */ + write_u16(output_file, 0); /* last mod file time */ + write_u16(output_file, 0); /* last mod file date */ + write_u32(output_file, 0xdeadbeef); /* crc */ + write_u32(output_file, input_file_size); /* compressed file size */ + write_u32(output_file, input_file_size); /* uncompressed file size */ + write_u16(output_file, strlen(input_file_name)); /* file name length */ + write_u16(output_file, 0); /* extra field length */ + write_u16(output_file, 0); /* file comment length */ + write_u16(output_file, 0); /* disk number start */ + write_u16(output_file, 1); /* internal file attributes */ + write_u32(output_file, 1); /* external file attributes */ + write_u32(output_file, 0); /* offset of local header */ + fputs(input_file_name, output_file); /* file name */ + /* extra field */ + /* file comment */ + + uint32_t end_record_start = ftell(output_file); + + /* (3) END OF CENTRAL DIRECTORY RECORD */ + write_u32(output_file, 0x06054b50); /* end of central dir signature */ + write_u16(output_file, 0); /* number of this disk */ + write_u16(output_file, 0); /* number of the start disk */ + write_u16(output_file, 1); /* total number of entries on this disk */ + write_u16(output_file, 1); /* total number of entries */ + write_u32(output_file, end_record_start - central_directory_start); /* size of central directory record */ + write_u32(output_file, central_directory_start); /* offset of start of central directory */ + write_u16(output_file, 0); /* .zip file comment length */ + /* .zip file comment */ + + fclose(input_file); + fclose(output_file); + return 0; +} \ No newline at end of file