Commit a2f22dc5 authored by Mike Iovine's avatar Mike Iovine
Browse files

Implement myunzip

parent ea230a0f
No related merge requests found
Pipeline #30575 failed with stage
in 0 seconds
Showing with 128 additions and 31 deletions
+128 -31
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
/myunzip0 /myunzip0
/inflate /inflate
/huffman /huffman
/myunzip
all : myzip0 myunzip0 huffman inflate test_inflate all : myzip0 myunzip0 huffman inflate test_inflate myunzip
myzip0 : myzip0.c myzip0 : myzip0.c
cc myzip0.c -o myzip0 cc myzip0.c -o myzip0
...@@ -12,9 +12,12 @@ huffman : huffman.c ...@@ -12,9 +12,12 @@ huffman : huffman.c
inflate : include/inflate.h src/inflate/main.c src/inflate/inflate.c inflate : include/inflate.h src/inflate/main.c src/inflate/inflate.c
gcc -I include src/inflate/main.c src/inflate/inflate.c -o inflate gcc -I include src/inflate/main.c src/inflate/inflate.c -o inflate
myunzip : include/inflate.h src/inflate/inflate.c src/myunzip/myunzip.c
gcc -I include src/inflate/inflate.c src/myunzip/myunzip.c -o myunzip
test_inflate : src/inflate/inflate.c tests/inflate_test.cpp test_inflate : src/inflate/inflate.c tests/inflate_test.cpp
g++ -I include src/inflate/inflate.c tests/inflate_test.cpp -o test_inflate -l gtest g++ -I include src/inflate/inflate.c tests/inflate_test.cpp -o test_inflate -l gtest
./test_inflate ./test_inflate
clean : clean :
rm myzip0 myunzip0 huffman inflate test_inflate rm myzip0 myunzip0 huffman inflate test_inflate myunzip
#include <stdbool.h>
#ifndef _INFLATE_H_ #ifndef _INFLATE_H_
#define _INFLATE_H_ #define _INFLATE_H_
...@@ -67,11 +69,11 @@ int *read_lens(char *buf, huffman_t *hf_codes, ...@@ -67,11 +69,11 @@ int *read_lens(char *buf, huffman_t *hf_codes,
* Read a single block from the buffer, and write the deflated * Read a single block from the buffer, and write the deflated
* results to "out". * results to "out".
*/ */
void read_block(char *buf, FILE *out); bool read_block(char *buf, FILE *out);
/* /*
* Inflate the file fp. * Inflate the file fp.
*/ */
void inflate(FILE *fp, char *fname); void inflate(FILE *fp, long size, char *fname);
#endif #endif
...@@ -283,7 +283,7 @@ int *read_lens(char *buf, huffman_t *hf_codes, int num_symbols, int num_codes) { ...@@ -283,7 +283,7 @@ int *read_lens(char *buf, huffman_t *hf_codes, int num_symbols, int num_codes) {
return lens; return lens;
} }
void read_block(char *buf, FILE *out) { bool read_block(char *buf, FILE *out) {
/* First bit is the BFINAL flag */ /* First bit is the BFINAL flag */
bool bfinal = get_next_bit(buf); bool bfinal = get_next_bit(buf);
...@@ -346,7 +346,6 @@ void read_block(char *buf, FILE *out) { ...@@ -346,7 +346,6 @@ void read_block(char *buf, FILE *out) {
{ {
/* Match a huffman code */ /* Match a huffman code */
chunk_val = read_chunk(buf, *hf); chunk_val = read_chunk(buf, *hf);
printf("%d\n", chunk_val);
/* Literal, just write to output buffer */ /* Literal, just write to output buffer */
if (chunk_val < 256) { if (chunk_val < 256) {
fwrite(&chunk_val, 1, sizeof(char), out); fwrite(&chunk_val, 1, sizeof(char), out);
...@@ -381,32 +380,15 @@ void read_block(char *buf, FILE *out) { ...@@ -381,32 +380,15 @@ void read_block(char *buf, FILE *out) {
destroy_huffman(hf); destroy_huffman(hf);
destroy_huffman(hf_dist); destroy_huffman(hf_dist);
} }
}
void truncate_suffix(char *fname) {
char *dot = strrchr(fname, '.');
const char *suffix = ".deflate"; return bfinal;
for (int i = 0; i < 8; i++) {
if (dot == NULL || *(dot + i) != suffix[i]) {
fprintf(stderr, "error: must be a .deflate file");
exit(1);
}
}
*dot = '\0';
} }
void inflate(FILE *fp, char *fname) { void inflate(FILE *fp, long size, char *fname) {
truncate_suffix(fname);
/* Create output file */ /* Create output file */
FILE *out = fopen(fname, "wb+"); FILE *out = fopen(fname, "wb+");
/* Read the file into a buffer */ /* Read the file into a buffer */
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
char *buf = (char *) malloc(size); char *buf = (char *) malloc(size);
if (!buf) { if (!buf) {
fprintf(stderr, "error: memory error\n"); fprintf(stderr, "error: memory error\n");
...@@ -414,9 +396,8 @@ void inflate(FILE *fp, char *fname) { ...@@ -414,9 +396,8 @@ void inflate(FILE *fp, char *fname) {
} }
fread(buf, 1, size, fp); fread(buf, 1, size, fp);
while (_CUR_BIT < 8 * size) { /* Read until last block */
read_block(buf, out); while (!read_block(buf, out)) {}
}
fclose(out); fclose(out);
free(buf); free(buf);
......
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <inflate.h> #include <inflate.h>
void truncate_suffix(char *fname) {
char *dot = strrchr(fname, '.');
const char *suffix = ".deflate";
for (int i = 0; i < 8; i++) {
if (dot == NULL || *(dot + i) != suffix[i]) {
fprintf(stderr, "error: must be a .deflate file\n");
exit(1);
}
}
*dot = '\0';
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "usage: inflate [file]\n"); fprintf(stderr, "usage: inflate [file]\n");
...@@ -18,7 +34,12 @@ int main(int argc, char *argv[]) { ...@@ -18,7 +34,12 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
inflate(fp, fname); fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
truncate_suffix(fname);
inflate(fp, size, fname);
fclose(fp); fclose(fp);
return 0; return 0;
......
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <inflate.h>
struct file_record {
uint32_t signature;
uint16_t version;
uint16_t flag;
uint16_t compression;
uint16_t mod_time;
uint16_t mod_date;
uint32_t crc32;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint16_t file_name_len;
uint16_t extra_len;
}
/* Don't pad this struct, i.e. guaranteed that sizeof(struct file_record) =
* sum of the sizes of its elements. This makes the code a bit nicer;
* we can just fread() the first sizeof(struct file_record) bytes in the
* file directly into the struct.
*/
__attribute__((packed));
typedef struct file_record file_record_t;
const int UNCOMPRESSED = 0;
const int DEFLATE = 8;
void unzip(FILE *fp) {
file_record_t *record = (file_record_t *) malloc(sizeof(file_record_t));
if (!record) {
fprintf(stderr, "error: memory error\n");
exit(1);
}
/* Read metadata */
fread(record, 1, sizeof(file_record_t), fp);
char *fname = (char *) malloc(record->file_name_len);
fread(fname, 1, record->file_name_len, fp);
/* Move pointer to start of file data */
fseek(fp, record->extra_len, SEEK_CUR);
int size;
if (record->compression == UNCOMPRESSED) {
FILE *out = fopen(fname, "wb");
size = record->uncompressed_size;
char *buf = (char *) malloc(size * sizeof(char));
fread(buf, 1, size, fp);
fwrite(buf, 1, size, out);
fclose(out);
} else if (record->compression == DEFLATE) {
inflate(fp, record->compressed_size, fname);
} else {
fprintf(stderr, "error: invalid compression\n");
exit(1);
}
free(record);
}
int main(int argc, char *argv[]) {
FILE *fp;
if (argc != 2) {
fprintf(stderr, "usage: myunzip0 [filename]\n");
return 1;
}
fp = fopen(argv[1], "rb");
if (!fp) {
fprintf(stderr, "error: no such file\n");
return 1;
}
unzip(fp);
fclose(fp);
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment