1 /* Copyright 2015 the unarr project authors (see AUTHORS file).
2    License: LGPLv3 */
3 
4 #ifndef zip_zip_h
5 #define zip_zip_h
6 
7 #include "../common/unarr-imp.h"
8 
9 #ifdef HAVE_ZLIB
10 #include <zlib.h>
11 #endif
12 #include "inflate.h"
13 #ifdef HAVE_BZIP2
14 #include <bzlib.h>
15 #endif
16 #ifdef HAVE_LIBLZMA
17 #include <lzma.h>
18 #else
19 #include "../lzmasdk/LzmaDec.h"
20 #endif
21 #include "../lzmasdk/Ppmd8.h"
22 
23 typedef struct ar_archive_zip_s ar_archive_zip;
24 
25 /***** parse-zip *****/
26 
27 enum zip_signatures {
28     SIG_LOCAL_FILE_HEADER = 0x04034B50,
29     SIG_CENTRAL_DIRECTORY = 0x02014B50,
30     SIG_END_OF_CENTRAL_DIRECTORY_64 = 0x06064B50,
31     SIG_END_OF_CENTRAL_DIRECTORY_64_LOCATOR = 0x07064B50,
32     SIG_END_OF_CENTRAL_DIRECTORY = 0x06054B50,
33 };
34 
35 enum compression_method {
36     METHOD_STORE = 0, METHOD_DEFLATE = 8,
37     METHOD_DEFLATE64 = 9, METHOD_BZIP2 = 12, METHOD_LZMA = 14,
38     METHOD_XZ = 95, METHOD_PPMD = 98,
39 };
40 
41 #define ZIP_LOCAL_ENTRY_FIXED_SIZE 30
42 #define ZIP_DIR_ENTRY_FIXED_SIZE 46
43 #define ZIP_END_OF_CENTRAL_DIR_SIZE 22
44 
45 struct zip_entry {
46     uint32_t signature;
47     uint16_t version;
48     uint16_t min_version;
49     uint16_t flags;
50     uint16_t method;
51     uint32_t dosdate;
52     uint32_t crc;
53     uint64_t datasize;
54     uint64_t uncompressed;
55     uint16_t namelen;
56     uint16_t extralen;
57     uint16_t commentlen;
58     uint32_t disk;
59     uint16_t attr_internal;
60     uint32_t attr_external;
61     off64_t header_offset;
62 };
63 
64 struct zip_eocd64 {
65     uint32_t signature;
66     uint16_t version;
67     uint16_t min_version;
68     uint32_t diskno;
69     uint32_t diskno_dir;
70     uint64_t numentries_disk;
71     uint64_t numentries;
72     uint64_t dir_size;
73     off64_t dir_offset;
74     uint16_t commentlen;
75 };
76 
77 struct ar_archive_zip_entry {
78     off64_t offset;
79     uint16_t method;
80     uint16_t flags;
81     uint32_t crc;
82     char *name;
83     uint32_t dosdate;
84 };
85 
86 bool zip_seek_to_compressed_data(ar_archive_zip *zip);
87 bool zip_parse_local_file_entry(ar_archive_zip *zip, struct zip_entry *entry);
88 off64_t zip_find_next_local_file_entry(ar_stream *stream, off64_t offset);
89 bool zip_parse_directory_entry(ar_archive_zip *zip, struct zip_entry *entry);
90 off64_t zip_find_end_of_last_directory_entry(ar_stream *stream, struct zip_eocd64 *eocd);
91 bool zip_parse_end_of_central_directory(ar_stream *stream, struct zip_eocd64 *eocd);
92 off64_t zip_find_end_of_central_directory(ar_stream *stream);
93 const char *zip_get_name(ar_archive *ar);
94 
95 /***** uncompress-zip *****/
96 
97 struct ar_archive_zip_uncomp;
98 
99 typedef uint32_t (* zip_uncomp_uncompress_data_fn)(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk);
100 typedef void (* zip_uncomp_clear_state_fn)(struct ar_archive_zip_uncomp *uncomp);
101 
102 struct InputBuffer {
103     uint8_t data[4096];
104     uint16_t offset;
105     uint16_t bytes_left;
106     bool at_eof;
107 };
108 
109 struct ByteReader {
110     IByteIn super;
111     struct InputBuffer *input;
112     ar_archive_zip *zip;
113 };
114 
115 struct ar_archive_zip_uncomp {
116     bool initialized;
117     zip_uncomp_uncompress_data_fn uncompress_data;
118     zip_uncomp_clear_state_fn clear_state;
119     union {
120 #ifdef HAVE_ZLIB
121         z_stream zstream;
122 #endif
123         inflate_state *inflate;
124 #ifdef HAVE_BZIP2
125         bz_stream bstream;
126 #endif
127 #ifdef HAVE_LIBLZMA
128         lzma_stream lzmastream;
129 #else
130         struct {
131             CLzmaDec dec;
132             ELzmaFinishMode finish;
133             ISzAlloc alloc;
134         } lzma;
135 #endif //HAVE_LIBLZMA
136         struct {
137             CPpmd8 ctx;
138             struct ByteReader bytein;
139             ISzAlloc alloc;
140         } ppmd8;
141     } state;
142     struct InputBuffer input;
143 };
144 
145 bool zip_uncompress_part(ar_archive_zip *zip, void *buffer, size_t buffer_size);
146 void zip_clear_uncompress(struct ar_archive_zip_uncomp *uncomp);
147 
148 /***** zip *****/
149 
150 struct ar_archive_zip_dir {
151     /* off64_t offset; // use ar_archive::entry_offset_first */
152     off64_t end_offset;
153 };
154 
155 struct ar_archive_zip_progress {
156     size_t data_left;
157     size_t bytes_done;
158     uint32_t crc;
159 };
160 
161 struct ar_archive_zip_s {
162     ar_archive super;
163     struct ar_archive_zip_dir dir;
164     struct ar_archive_zip_entry entry;
165     struct ar_archive_zip_uncomp uncomp;
166     struct ar_archive_zip_progress progress;
167     bool deflatedonly;
168     off64_t comment_offset;
169     uint16_t comment_size;
170 };
171 
172 #endif
173