1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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;
}