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
16struct fz_zip_writer_s
17{
18 fz_output *output;
19 fz_buffer *central;
20 int count;
21 int closed;
22};
23
24void
25fz_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
69void
70fz_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
92void
93fz_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
104fz_zip_writer *
105fz_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