1 | #include "mupdf/fitz.h" |
2 | #include "fitz-imp.h" |
3 | |
4 | #include <string.h> |
5 | |
6 | #include <zlib.h> |
7 | |
8 | #if !defined (INT32_MAX) |
9 | #define INT32_MAX 2147483647L |
10 | #endif |
11 | |
12 | #define ZIP_LOCAL_FILE_SIG 0x04034b50 |
13 | #define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50 |
14 | #define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50 |
15 | |
16 | struct fz_zip_writer_s |
17 | { |
18 | fz_output *output; |
19 | fz_buffer *central; |
20 | int count; |
21 | int closed; |
22 | }; |
23 | |
24 | void |
25 | fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress) |
26 | { |
27 | int offset = fz_tell_output(ctx, zip->output); |
28 | int sum; |
29 | |
30 | sum = crc32(0, NULL, 0); |
31 | sum = crc32(sum, buf->data, (uInt)buf->len); |
32 | |
33 | fz_append_int32_le(ctx, zip->central, ZIP_CENTRAL_DIRECTORY_SIG); |
34 | fz_append_int16_le(ctx, zip->central, 0); /* version made by: MS-DOS */ |
35 | fz_append_int16_le(ctx, zip->central, 20); /* version to extract: 2.0 */ |
36 | fz_append_int16_le(ctx, zip->central, 0); /* general purpose bit flag */ |
37 | fz_append_int16_le(ctx, zip->central, 0); /* compression method: store */ |
38 | fz_append_int16_le(ctx, zip->central, 0); /* TODO: last mod file time */ |
39 | fz_append_int16_le(ctx, zip->central, 0); /* TODO: last mod file date */ |
40 | fz_append_int32_le(ctx, zip->central, sum); /* crc-32 */ |
41 | fz_append_int32_le(ctx, zip->central, (int)buf->len); /* csize */ |
42 | fz_append_int32_le(ctx, zip->central, (int)buf->len); /* usize */ |
43 | fz_append_int16_le(ctx, zip->central, (int)strlen(name)); /* file name length */ |
44 | fz_append_int16_le(ctx, zip->central, 0); /* extra field length */ |
45 | fz_append_int16_le(ctx, zip->central, 0); /* file comment length */ |
46 | fz_append_int16_le(ctx, zip->central, 0); /* disk number start */ |
47 | fz_append_int16_le(ctx, zip->central, 0); /* internal file attributes */ |
48 | fz_append_int32_le(ctx, zip->central, 0); /* external file attributes */ |
49 | fz_append_int32_le(ctx, zip->central, offset); /* relative offset of local header */ |
50 | fz_append_string(ctx, zip->central, name); |
51 | |
52 | fz_write_int32_le(ctx, zip->output, ZIP_LOCAL_FILE_SIG); |
53 | fz_write_int16_le(ctx, zip->output, 20); /* version to extract: 2.0 */ |
54 | fz_write_int16_le(ctx, zip->output, 0); /* general purpose bit flag */ |
55 | fz_write_int16_le(ctx, zip->output, 0); /* compression method: store */ |
56 | fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file time */ |
57 | fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file date */ |
58 | fz_write_int32_le(ctx, zip->output, sum); /* crc-32 */ |
59 | fz_write_int32_le(ctx, zip->output, (int)buf->len); /* csize */ |
60 | fz_write_int32_le(ctx, zip->output, (int)buf->len); /* usize */ |
61 | fz_write_int16_le(ctx, zip->output, (int)strlen(name)); /* file name length */ |
62 | fz_write_int16_le(ctx, zip->output, 0); /* extra field length */ |
63 | fz_write_data(ctx, zip->output, name, strlen(name)); |
64 | fz_write_data(ctx, zip->output, buf->data, buf->len); |
65 | |
66 | ++zip->count; |
67 | } |
68 | |
69 | void |
70 | fz_close_zip_writer(fz_context *ctx, fz_zip_writer *zip) |
71 | { |
72 | int64_t offset = fz_tell_output(ctx, zip->output); |
73 | |
74 | fz_write_data(ctx, zip->output, zip->central->data, zip->central->len); |
75 | |
76 | fz_write_int32_le(ctx, zip->output, ZIP_END_OF_CENTRAL_DIRECTORY_SIG); |
77 | fz_write_int16_le(ctx, zip->output, 0); /* number of this disk */ |
78 | fz_write_int16_le(ctx, zip->output, 0); /* number of disk where central directory starts */ |
79 | fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in this disk */ |
80 | fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in total */ |
81 | fz_write_int32_le(ctx, zip->output, (int)zip->central->len); /* size of the central directory */ |
82 | fz_write_int32_le(ctx, zip->output, (int)offset); /* offset of the central directory */ |
83 | fz_write_int16_le(ctx, zip->output, 5); /* zip file comment length */ |
84 | |
85 | fz_write_data(ctx, zip->output, "MuPDF" , 5); |
86 | |
87 | fz_close_output(ctx, zip->output); |
88 | |
89 | zip->closed = 1; |
90 | } |
91 | |
92 | void |
93 | fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip) |
94 | { |
95 | if (!zip) |
96 | return; |
97 | if (!zip->closed) |
98 | fz_warn(ctx, "dropping unclosed zip writer" ); |
99 | fz_drop_output(ctx, zip->output); |
100 | fz_drop_buffer(ctx, zip->central); |
101 | fz_free(ctx, zip); |
102 | } |
103 | |
104 | fz_zip_writer * |
105 | fz_new_zip_writer(fz_context *ctx, const char *filename) |
106 | { |
107 | fz_zip_writer *zip = fz_malloc_struct(ctx, fz_zip_writer); |
108 | fz_try(ctx) |
109 | { |
110 | zip->output = fz_new_output_with_path(ctx, filename, 0); |
111 | zip->central = fz_new_buffer(ctx, 0); |
112 | } |
113 | fz_catch(ctx) |
114 | { |
115 | fz_drop_output(ctx, zip->output); |
116 | fz_drop_buffer(ctx, zip->central); |
117 | fz_free(ctx, zip); |
118 | fz_rethrow(ctx); |
119 | } |
120 | return zip; |
121 | } |
122 | |