#include <stdlib.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include <assert.h> #include "lz77.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, 8); /* 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 */ size_t compressed_size_loc = ftell(output_file); write_u32(output_file, 0); /* 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 */ uint32_t compressed_size = write_lz77_stream(input_file, output_file); /* printf("Compressed size = %d\n", compressed_size); */ size_t central_directory_start = ftell(output_file); /* save location */ fseek(output_file, compressed_size_loc, SEEK_SET); /* move back */ write_u32(output_file, compressed_size); /* write compressed size */ fseek(output_file, central_directory_start, SEEK_SET); /* return to writing */ /* (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, 8); /* 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, compressed_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; }