xref: /aosp_15_r20/external/libwebsockets/lib/roles/http/server/fops-zip.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Original code used in this source file:
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * https://github.com/PerBothner/DomTerm.git @912add15f3d0aec
7*1c60b9acSAndroid Build Coastguard Worker  *
8*1c60b9acSAndroid Build Coastguard Worker  * ./lws-term/io.c
9*1c60b9acSAndroid Build Coastguard Worker  * ./lws-term/junzip.c
10*1c60b9acSAndroid Build Coastguard Worker  *
11*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2017  Per Bothner <[email protected]>
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * MIT License
14*1c60b9acSAndroid Build Coastguard Worker  *
15*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
16*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to deal
17*1c60b9acSAndroid Build Coastguard Worker  * in the Software without restriction, including without limitation the rights
18*1c60b9acSAndroid Build Coastguard Worker  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19*1c60b9acSAndroid Build Coastguard Worker  * ( copies of the Software, and to permit persons to whom the Software is
20*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
21*1c60b9acSAndroid Build Coastguard Worker  *
22*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
23*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
24*1c60b9acSAndroid Build Coastguard Worker  *
25*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30*1c60b9acSAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31*1c60b9acSAndroid Build Coastguard Worker  * SOFTWARE.
32*1c60b9acSAndroid Build Coastguard Worker  *
33*1c60b9acSAndroid Build Coastguard Worker  * Somewhat rewritten by AG
34*1c60b9acSAndroid Build Coastguard Worker  */
35*1c60b9acSAndroid Build Coastguard Worker 
36*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
37*1c60b9acSAndroid Build Coastguard Worker 
38*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_MINIZ)
39*1c60b9acSAndroid Build Coastguard Worker #include <miniz.h>
40*1c60b9acSAndroid Build Coastguard Worker #else
41*1c60b9acSAndroid Build Coastguard Worker #include <zlib.h>
42*1c60b9acSAndroid Build Coastguard Worker #endif
43*1c60b9acSAndroid Build Coastguard Worker 
44*1c60b9acSAndroid Build Coastguard Worker /*
45*1c60b9acSAndroid Build Coastguard Worker  * This code works with zip format containers which may have files compressed
46*1c60b9acSAndroid Build Coastguard Worker  * with gzip deflate (type 8) or store uncompressed (type 0).
47*1c60b9acSAndroid Build Coastguard Worker  *
48*1c60b9acSAndroid Build Coastguard Worker  * Linux zip produces such zipfiles by default, eg
49*1c60b9acSAndroid Build Coastguard Worker  *
50*1c60b9acSAndroid Build Coastguard Worker  *  $ zip ../myzip.zip file1 file2 file3
51*1c60b9acSAndroid Build Coastguard Worker  */
52*1c60b9acSAndroid Build Coastguard Worker 
53*1c60b9acSAndroid Build Coastguard Worker #define ZIP_COMPRESSION_METHOD_STORE 0
54*1c60b9acSAndroid Build Coastguard Worker #define ZIP_COMPRESSION_METHOD_DEFLATE 8
55*1c60b9acSAndroid Build Coastguard Worker 
56*1c60b9acSAndroid Build Coastguard Worker typedef struct {
57*1c60b9acSAndroid Build Coastguard Worker 	lws_filepos_t		filename_start;
58*1c60b9acSAndroid Build Coastguard Worker 	uint32_t		crc32;
59*1c60b9acSAndroid Build Coastguard Worker 	uint32_t		comp_size;
60*1c60b9acSAndroid Build Coastguard Worker 	uint32_t		uncomp_size;
61*1c60b9acSAndroid Build Coastguard Worker 	uint32_t		offset;
62*1c60b9acSAndroid Build Coastguard Worker 	uint32_t		mod_time;
63*1c60b9acSAndroid Build Coastguard Worker 	uint16_t		filename_len;
64*1c60b9acSAndroid Build Coastguard Worker 	uint16_t		extra;
65*1c60b9acSAndroid Build Coastguard Worker 	uint16_t		method;
66*1c60b9acSAndroid Build Coastguard Worker 	uint16_t		file_com_len;
67*1c60b9acSAndroid Build Coastguard Worker } lws_fops_zip_hdr_t;
68*1c60b9acSAndroid Build Coastguard Worker 
69*1c60b9acSAndroid Build Coastguard Worker typedef struct {
70*1c60b9acSAndroid Build Coastguard Worker 	struct lws_fop_fd	fop_fd; /* MUST BE FIRST logical fop_fd into
71*1c60b9acSAndroid Build Coastguard Worker 	 	 	 	 	 * file inside zip: fops_zip fops */
72*1c60b9acSAndroid Build Coastguard Worker 	lws_fop_fd_t		zip_fop_fd; /* logical fop fd on to zip file
73*1c60b9acSAndroid Build Coastguard Worker 	 	 	 	 	     * itself: using platform fops */
74*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_hdr_t	hdr;
75*1c60b9acSAndroid Build Coastguard Worker 	z_stream		inflate;
76*1c60b9acSAndroid Build Coastguard Worker 	lws_filepos_t		content_start;
77*1c60b9acSAndroid Build Coastguard Worker 	lws_filepos_t		exp_uncomp_pos;
78*1c60b9acSAndroid Build Coastguard Worker 	union {
79*1c60b9acSAndroid Build Coastguard Worker 		uint8_t		trailer8[8];
80*1c60b9acSAndroid Build Coastguard Worker 		uint32_t	trailer32[2];
81*1c60b9acSAndroid Build Coastguard Worker 	} u;
82*1c60b9acSAndroid Build Coastguard Worker 	uint8_t			rbuf[128]; /* decompression chunk size */
83*1c60b9acSAndroid Build Coastguard Worker 	int			entry_count;
84*1c60b9acSAndroid Build Coastguard Worker 
85*1c60b9acSAndroid Build Coastguard Worker 	unsigned int		decompress:1; /* 0 = direct from file */
86*1c60b9acSAndroid Build Coastguard Worker 	unsigned int		add_gzip_container:1;
87*1c60b9acSAndroid Build Coastguard Worker } *lws_fops_zip_t;
88*1c60b9acSAndroid Build Coastguard Worker 
89*1c60b9acSAndroid Build Coastguard Worker struct lws_plat_file_ops fops_zip;
90*1c60b9acSAndroid Build Coastguard Worker #define fop_fd_to_priv(FD) ((lws_fops_zip_t)(FD))
91*1c60b9acSAndroid Build Coastguard Worker 
92*1c60b9acSAndroid Build Coastguard Worker static const uint8_t hd[] = { 31, 139, 8, 0, 0, 0, 0, 0, 0, 3 };
93*1c60b9acSAndroid Build Coastguard Worker 
94*1c60b9acSAndroid Build Coastguard Worker enum {
95*1c60b9acSAndroid Build Coastguard Worker 	ZC_SIGNATURE				= 0,
96*1c60b9acSAndroid Build Coastguard Worker 	ZC_VERSION_MADE_BY 			= 4,
97*1c60b9acSAndroid Build Coastguard Worker 	ZC_VERSION_NEEDED_TO_EXTRACT 		= 6,
98*1c60b9acSAndroid Build Coastguard Worker 	ZC_GENERAL_PURPOSE_BIT_FLAG 		= 8,
99*1c60b9acSAndroid Build Coastguard Worker 	ZC_COMPRESSION_METHOD 			= 10,
100*1c60b9acSAndroid Build Coastguard Worker 	ZC_LAST_MOD_FILE_TIME 			= 12,
101*1c60b9acSAndroid Build Coastguard Worker 	ZC_LAST_MOD_FILE_DATE 			= 14,
102*1c60b9acSAndroid Build Coastguard Worker 	ZC_CRC32 				= 16,
103*1c60b9acSAndroid Build Coastguard Worker 	ZC_COMPRESSED_SIZE 			= 20,
104*1c60b9acSAndroid Build Coastguard Worker 	ZC_UNCOMPRESSED_SIZE 			= 24,
105*1c60b9acSAndroid Build Coastguard Worker 	ZC_FILE_NAME_LENGTH 			= 28,
106*1c60b9acSAndroid Build Coastguard Worker 	ZC_EXTRA_FIELD_LENGTH 			= 30,
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker 	ZC_FILE_COMMENT_LENGTH 			= 32,
109*1c60b9acSAndroid Build Coastguard Worker 	ZC_DISK_NUMBER_START 			= 34,
110*1c60b9acSAndroid Build Coastguard Worker 	ZC_INTERNAL_FILE_ATTRIBUTES 		= 36,
111*1c60b9acSAndroid Build Coastguard Worker 	ZC_EXTERNAL_FILE_ATTRIBUTES 		= 38,
112*1c60b9acSAndroid Build Coastguard Worker 	ZC_REL_OFFSET_LOCAL_HEADER 		= 42,
113*1c60b9acSAndroid Build Coastguard Worker 	ZC_DIRECTORY_LENGTH 			= 46,
114*1c60b9acSAndroid Build Coastguard Worker 
115*1c60b9acSAndroid Build Coastguard Worker 	ZE_SIGNATURE_OFFSET 			= 0,
116*1c60b9acSAndroid Build Coastguard Worker 	ZE_DESK_NUMBER 				= 4,
117*1c60b9acSAndroid Build Coastguard Worker 	ZE_CENTRAL_DIRECTORY_DISK_NUMBER 	= 6,
118*1c60b9acSAndroid Build Coastguard Worker 	ZE_NUM_ENTRIES_THIS_DISK 		= 8,
119*1c60b9acSAndroid Build Coastguard Worker 	ZE_NUM_ENTRIES 				= 10,
120*1c60b9acSAndroid Build Coastguard Worker 	ZE_CENTRAL_DIRECTORY_SIZE 		= 12,
121*1c60b9acSAndroid Build Coastguard Worker 	ZE_CENTRAL_DIR_OFFSET 			= 16,
122*1c60b9acSAndroid Build Coastguard Worker 	ZE_ZIP_COMMENT_LENGTH 			= 20,
123*1c60b9acSAndroid Build Coastguard Worker 	ZE_DIRECTORY_LENGTH 			= 22,
124*1c60b9acSAndroid Build Coastguard Worker 
125*1c60b9acSAndroid Build Coastguard Worker 	ZL_REL_OFFSET_CONTENT			= 28,
126*1c60b9acSAndroid Build Coastguard Worker 	ZL_HEADER_LENGTH			= 30,
127*1c60b9acSAndroid Build Coastguard Worker 
128*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_SEEK_END_RECORD		= 1,
129*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_READ_END_RECORD,
130*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_END_RECORD_MAGIC,
131*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_END_RECORD_SANITY,
132*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_CENTRAL_SEEK,
133*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_CENTRAL_READ,
134*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_CENTRAL_SANITY,
135*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_NAME_TOO_LONG,
136*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_NAME_SEEK,
137*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_NAME_READ,
138*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_CONTENT_SANITY,
139*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_CONTENT_SEEK,
140*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_SCAN_SEEK,
141*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_NOT_FOUND,
142*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_ZLIB_INIT,
143*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_READ_CONTENT,
144*1c60b9acSAndroid Build Coastguard Worker 	LWS_FZ_ERR_SEEK_COMPRESSED,
145*1c60b9acSAndroid Build Coastguard Worker };
146*1c60b9acSAndroid Build Coastguard Worker 
147*1c60b9acSAndroid Build Coastguard Worker #define eff_size(_priv) (_priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE ? \
148*1c60b9acSAndroid Build Coastguard Worker 				  _priv->hdr.uncomp_size : _priv->hdr.comp_size)
149*1c60b9acSAndroid Build Coastguard Worker 
150*1c60b9acSAndroid Build Coastguard Worker static uint16_t
get_u16(void * p)151*1c60b9acSAndroid Build Coastguard Worker get_u16(void *p)
152*1c60b9acSAndroid Build Coastguard Worker {
153*1c60b9acSAndroid Build Coastguard Worker 	const uint8_t *c = (const uint8_t *)p;
154*1c60b9acSAndroid Build Coastguard Worker 
155*1c60b9acSAndroid Build Coastguard Worker 	return (uint16_t)((c[0] | (c[1] << 8)));
156*1c60b9acSAndroid Build Coastguard Worker }
157*1c60b9acSAndroid Build Coastguard Worker 
158*1c60b9acSAndroid Build Coastguard Worker static uint32_t
get_u32(void * p)159*1c60b9acSAndroid Build Coastguard Worker get_u32(void *p)
160*1c60b9acSAndroid Build Coastguard Worker {
161*1c60b9acSAndroid Build Coastguard Worker 	const uint8_t *c = (const uint8_t *)p;
162*1c60b9acSAndroid Build Coastguard Worker 
163*1c60b9acSAndroid Build Coastguard Worker 	return (uint32_t)((c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)));
164*1c60b9acSAndroid Build Coastguard Worker }
165*1c60b9acSAndroid Build Coastguard Worker 
166*1c60b9acSAndroid Build Coastguard Worker int
lws_fops_zip_scan(lws_fops_zip_t priv,const char * name,int len)167*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
168*1c60b9acSAndroid Build Coastguard Worker {
169*1c60b9acSAndroid Build Coastguard Worker 	lws_filepos_t amount;
170*1c60b9acSAndroid Build Coastguard Worker 	uint8_t buf[96];
171*1c60b9acSAndroid Build Coastguard Worker 	int i;
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker 	if (lws_vfs_file_seek_end(priv->zip_fop_fd, -ZE_DIRECTORY_LENGTH) < 0)
174*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_SEEK_END_RECORD;
175*1c60b9acSAndroid Build Coastguard Worker 
176*1c60b9acSAndroid Build Coastguard Worker 	if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
177*1c60b9acSAndroid Build Coastguard Worker 			      ZE_DIRECTORY_LENGTH))
178*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_READ_END_RECORD;
179*1c60b9acSAndroid Build Coastguard Worker 
180*1c60b9acSAndroid Build Coastguard Worker 	if (amount != ZE_DIRECTORY_LENGTH)
181*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_READ_END_RECORD;
182*1c60b9acSAndroid Build Coastguard Worker 
183*1c60b9acSAndroid Build Coastguard Worker 	/*
184*1c60b9acSAndroid Build Coastguard Worker 	 * We require the zip to have the last record right at the end
185*1c60b9acSAndroid Build Coastguard Worker 	 * Linux zip always does this if no zip comment.
186*1c60b9acSAndroid Build Coastguard Worker 	 */
187*1c60b9acSAndroid Build Coastguard Worker 	if (buf[0] != 'P' || buf[1] != 'K' || buf[2] != 5 || buf[3] != 6)
188*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_END_RECORD_MAGIC;
189*1c60b9acSAndroid Build Coastguard Worker 
190*1c60b9acSAndroid Build Coastguard Worker 	i = get_u16(buf + ZE_NUM_ENTRIES);
191*1c60b9acSAndroid Build Coastguard Worker 
192*1c60b9acSAndroid Build Coastguard Worker 	if (get_u16(buf + ZE_DESK_NUMBER) ||
193*1c60b9acSAndroid Build Coastguard Worker 	    get_u16(buf + ZE_CENTRAL_DIRECTORY_DISK_NUMBER) ||
194*1c60b9acSAndroid Build Coastguard Worker 	    i != get_u16(buf + ZE_NUM_ENTRIES_THIS_DISK))
195*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_END_RECORD_SANITY;
196*1c60b9acSAndroid Build Coastguard Worker 
197*1c60b9acSAndroid Build Coastguard Worker 	/* end record is OK... look for our file in the central dir */
198*1c60b9acSAndroid Build Coastguard Worker 
199*1c60b9acSAndroid Build Coastguard Worker 	if (lws_vfs_file_seek_set(priv->zip_fop_fd,
200*1c60b9acSAndroid Build Coastguard Worker 				  get_u32(buf + ZE_CENTRAL_DIR_OFFSET)) < 0)
201*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_CENTRAL_SEEK;
202*1c60b9acSAndroid Build Coastguard Worker 
203*1c60b9acSAndroid Build Coastguard Worker 	while (i--) {
204*1c60b9acSAndroid Build Coastguard Worker 		priv->content_start = lws_vfs_tell(priv->zip_fop_fd);
205*1c60b9acSAndroid Build Coastguard Worker 
206*1c60b9acSAndroid Build Coastguard Worker 		if (lws_vfs_file_read(priv->zip_fop_fd, &amount, buf,
207*1c60b9acSAndroid Build Coastguard Worker 				      ZC_DIRECTORY_LENGTH))
208*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_CENTRAL_READ;
209*1c60b9acSAndroid Build Coastguard Worker 
210*1c60b9acSAndroid Build Coastguard Worker 		if (amount != ZC_DIRECTORY_LENGTH)
211*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_CENTRAL_READ;
212*1c60b9acSAndroid Build Coastguard Worker 
213*1c60b9acSAndroid Build Coastguard Worker 		if (get_u32(buf + ZC_SIGNATURE) != 0x02014B50)
214*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_CENTRAL_SANITY;
215*1c60b9acSAndroid Build Coastguard Worker 
216*1c60b9acSAndroid Build Coastguard Worker                lwsl_debug("cstart 0x%lx\n", (unsigned long)priv->content_start);
217*1c60b9acSAndroid Build Coastguard Worker 
218*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.filename_len = get_u16(buf + ZC_FILE_NAME_LENGTH);
219*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.extra = get_u16(buf + ZC_EXTRA_FIELD_LENGTH);
220*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.filename_start = lws_vfs_tell(priv->zip_fop_fd);
221*1c60b9acSAndroid Build Coastguard Worker 
222*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.method = get_u16(buf + ZC_COMPRESSION_METHOD);
223*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.crc32 = get_u32(buf + ZC_CRC32);
224*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.comp_size = get_u32(buf + ZC_COMPRESSED_SIZE);
225*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.uncomp_size = get_u32(buf + ZC_UNCOMPRESSED_SIZE);
226*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.offset = get_u32(buf + ZC_REL_OFFSET_LOCAL_HEADER);
227*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.mod_time = get_u32(buf + ZC_LAST_MOD_FILE_TIME);
228*1c60b9acSAndroid Build Coastguard Worker 		priv->hdr.file_com_len = get_u16(buf + ZC_FILE_COMMENT_LENGTH);
229*1c60b9acSAndroid Build Coastguard Worker 
230*1c60b9acSAndroid Build Coastguard Worker 		if (priv->hdr.filename_len != len)
231*1c60b9acSAndroid Build Coastguard Worker 			goto next;
232*1c60b9acSAndroid Build Coastguard Worker 
233*1c60b9acSAndroid Build Coastguard Worker 		if (len >= (int)sizeof(buf) - 1)
234*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_TOO_LONG;
235*1c60b9acSAndroid Build Coastguard Worker 
236*1c60b9acSAndroid Build Coastguard Worker 		if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
237*1c60b9acSAndroid Build Coastguard Worker 							&amount, buf, (unsigned int)len))
238*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_READ;
239*1c60b9acSAndroid Build Coastguard Worker 		if ((int)amount != len)
240*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_READ;
241*1c60b9acSAndroid Build Coastguard Worker 
242*1c60b9acSAndroid Build Coastguard Worker 		buf[len] = '\0';
243*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("check %s vs %s\n", buf, name);
244*1c60b9acSAndroid Build Coastguard Worker 
245*1c60b9acSAndroid Build Coastguard Worker 		if (strcmp((const char *)buf, name))
246*1c60b9acSAndroid Build Coastguard Worker 			goto next;
247*1c60b9acSAndroid Build Coastguard Worker 
248*1c60b9acSAndroid Build Coastguard Worker 		/* we found a match */
249*1c60b9acSAndroid Build Coastguard Worker 		if (lws_vfs_file_seek_set(priv->zip_fop_fd, priv->hdr.offset) < 0)
250*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_SEEK;
251*1c60b9acSAndroid Build Coastguard Worker 		if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
252*1c60b9acSAndroid Build Coastguard Worker 							&amount, buf,
253*1c60b9acSAndroid Build Coastguard Worker 							ZL_HEADER_LENGTH))
254*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_READ;
255*1c60b9acSAndroid Build Coastguard Worker 		if (amount != ZL_HEADER_LENGTH)
256*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_NAME_READ;
257*1c60b9acSAndroid Build Coastguard Worker 
258*1c60b9acSAndroid Build Coastguard Worker 		priv->content_start = priv->hdr.offset +
259*1c60b9acSAndroid Build Coastguard Worker 				      ZL_HEADER_LENGTH +
260*1c60b9acSAndroid Build Coastguard Worker 				      priv->hdr.filename_len +
261*1c60b9acSAndroid Build Coastguard Worker 				      get_u16(buf + ZL_REL_OFFSET_CONTENT);
262*1c60b9acSAndroid Build Coastguard Worker 
263*1c60b9acSAndroid Build Coastguard Worker 		lwsl_debug("content supposed to start at 0x%lx\n",
264*1c60b9acSAndroid Build Coastguard Worker                           (unsigned long)priv->content_start);
265*1c60b9acSAndroid Build Coastguard Worker 
266*1c60b9acSAndroid Build Coastguard Worker 		if (priv->content_start > priv->zip_fop_fd->len)
267*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_CONTENT_SANITY;
268*1c60b9acSAndroid Build Coastguard Worker 
269*1c60b9acSAndroid Build Coastguard Worker 		if (lws_vfs_file_seek_set(priv->zip_fop_fd,
270*1c60b9acSAndroid Build Coastguard Worker 					  (lws_fileofs_t)priv->content_start) < 0)
271*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_CONTENT_SEEK;
272*1c60b9acSAndroid Build Coastguard Worker 
273*1c60b9acSAndroid Build Coastguard Worker 		/* we are aligned at the start of the content */
274*1c60b9acSAndroid Build Coastguard Worker 
275*1c60b9acSAndroid Build Coastguard Worker 		priv->exp_uncomp_pos = 0;
276*1c60b9acSAndroid Build Coastguard Worker 
277*1c60b9acSAndroid Build Coastguard Worker 		return 0;
278*1c60b9acSAndroid Build Coastguard Worker 
279*1c60b9acSAndroid Build Coastguard Worker next:
280*1c60b9acSAndroid Build Coastguard Worker 		if (i && lws_vfs_file_seek_set(priv->zip_fop_fd,
281*1c60b9acSAndroid Build Coastguard Worker 					       (lws_fileofs_t)priv->content_start +
282*1c60b9acSAndroid Build Coastguard Worker 					       (ZC_DIRECTORY_LENGTH +
283*1c60b9acSAndroid Build Coastguard Worker 					       priv->hdr.filename_len +
284*1c60b9acSAndroid Build Coastguard Worker 					       priv->hdr.extra +
285*1c60b9acSAndroid Build Coastguard Worker 					       priv->hdr.file_com_len)) < 0)
286*1c60b9acSAndroid Build Coastguard Worker 			return LWS_FZ_ERR_SCAN_SEEK;
287*1c60b9acSAndroid Build Coastguard Worker 	}
288*1c60b9acSAndroid Build Coastguard Worker 
289*1c60b9acSAndroid Build Coastguard Worker 	return LWS_FZ_ERR_NOT_FOUND;
290*1c60b9acSAndroid Build Coastguard Worker }
291*1c60b9acSAndroid Build Coastguard Worker 
292*1c60b9acSAndroid Build Coastguard Worker static int
lws_fops_zip_reset_inflate(lws_fops_zip_t priv)293*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_reset_inflate(lws_fops_zip_t priv)
294*1c60b9acSAndroid Build Coastguard Worker {
295*1c60b9acSAndroid Build Coastguard Worker 	if (priv->decompress)
296*1c60b9acSAndroid Build Coastguard Worker 		inflateEnd(&priv->inflate);
297*1c60b9acSAndroid Build Coastguard Worker 
298*1c60b9acSAndroid Build Coastguard Worker 	priv->inflate.zalloc = Z_NULL;
299*1c60b9acSAndroid Build Coastguard Worker 	priv->inflate.zfree = Z_NULL;
300*1c60b9acSAndroid Build Coastguard Worker 	priv->inflate.opaque = Z_NULL;
301*1c60b9acSAndroid Build Coastguard Worker 	priv->inflate.avail_in = 0;
302*1c60b9acSAndroid Build Coastguard Worker 	priv->inflate.next_in = Z_NULL;
303*1c60b9acSAndroid Build Coastguard Worker 
304*1c60b9acSAndroid Build Coastguard Worker 	if (inflateInit2(&priv->inflate, -MAX_WBITS) != Z_OK) {
305*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("inflate init failed\n");
306*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_ZLIB_INIT;
307*1c60b9acSAndroid Build Coastguard Worker 	}
308*1c60b9acSAndroid Build Coastguard Worker 
309*1c60b9acSAndroid Build Coastguard Worker 	if (lws_vfs_file_seek_set(priv->zip_fop_fd, (lws_fileofs_t)priv->content_start) < 0)
310*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_CONTENT_SEEK;
311*1c60b9acSAndroid Build Coastguard Worker 
312*1c60b9acSAndroid Build Coastguard Worker 	priv->exp_uncomp_pos = 0;
313*1c60b9acSAndroid Build Coastguard Worker 
314*1c60b9acSAndroid Build Coastguard Worker 	return 0;
315*1c60b9acSAndroid Build Coastguard Worker }
316*1c60b9acSAndroid Build Coastguard Worker 
317*1c60b9acSAndroid Build Coastguard Worker static lws_fop_fd_t
lws_fops_zip_open(const struct lws_plat_file_ops * fops,const char * vfs_path,const char * vpath,lws_fop_flags_t * flags)318*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
319*1c60b9acSAndroid Build Coastguard Worker 		  const char *vpath, lws_fop_flags_t *flags)
320*1c60b9acSAndroid Build Coastguard Worker {
321*1c60b9acSAndroid Build Coastguard Worker 	lws_fop_flags_t local_flags = 0;
322*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_t priv;
323*1c60b9acSAndroid Build Coastguard Worker 	char rp[192];
324*1c60b9acSAndroid Build Coastguard Worker 	int m;
325*1c60b9acSAndroid Build Coastguard Worker 
326*1c60b9acSAndroid Build Coastguard Worker 	/*
327*1c60b9acSAndroid Build Coastguard Worker 	 * vpath points at the / after the fops signature in vfs_path, eg
328*1c60b9acSAndroid Build Coastguard Worker 	 * with a vfs_path "/var/www/docs/manual.zip/index.html", vpath
329*1c60b9acSAndroid Build Coastguard Worker 	 * will come pointing at "/index.html"
330*1c60b9acSAndroid Build Coastguard Worker 	 */
331*1c60b9acSAndroid Build Coastguard Worker 
332*1c60b9acSAndroid Build Coastguard Worker 	priv = lws_zalloc(sizeof(*priv), "fops_zip priv");
333*1c60b9acSAndroid Build Coastguard Worker 	if (!priv)
334*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
335*1c60b9acSAndroid Build Coastguard Worker 
336*1c60b9acSAndroid Build Coastguard Worker 	priv->fop_fd.fops = &fops_zip;
337*1c60b9acSAndroid Build Coastguard Worker 
338*1c60b9acSAndroid Build Coastguard Worker 	m = sizeof(rp) - 1;
339*1c60b9acSAndroid Build Coastguard Worker 	if ((vpath - vfs_path - 1) < m)
340*1c60b9acSAndroid Build Coastguard Worker 		m = lws_ptr_diff(vpath, vfs_path) - 1;
341*1c60b9acSAndroid Build Coastguard Worker 	lws_strncpy(rp, vfs_path, (unsigned int)m + 1);
342*1c60b9acSAndroid Build Coastguard Worker 
343*1c60b9acSAndroid Build Coastguard Worker 	/* open the zip file itself using the incoming fops, not fops_zip */
344*1c60b9acSAndroid Build Coastguard Worker 
345*1c60b9acSAndroid Build Coastguard Worker 	priv->zip_fop_fd = fops->LWS_FOP_OPEN(fops, rp, NULL, &local_flags);
346*1c60b9acSAndroid Build Coastguard Worker 	if (!priv->zip_fop_fd) {
347*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: unable to open zip %s\n", __func__, rp);
348*1c60b9acSAndroid Build Coastguard Worker 		goto bail1;
349*1c60b9acSAndroid Build Coastguard Worker 	}
350*1c60b9acSAndroid Build Coastguard Worker 
351*1c60b9acSAndroid Build Coastguard Worker 	if (*vpath == '/')
352*1c60b9acSAndroid Build Coastguard Worker 		vpath++;
353*1c60b9acSAndroid Build Coastguard Worker 
354*1c60b9acSAndroid Build Coastguard Worker 	m = lws_fops_zip_scan(priv, vpath, (int)strlen(vpath));
355*1c60b9acSAndroid Build Coastguard Worker 	if (m) {
356*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("unable to find record matching '%s' %d\n", vpath, m);
357*1c60b9acSAndroid Build Coastguard Worker 		goto bail2;
358*1c60b9acSAndroid Build Coastguard Worker 	}
359*1c60b9acSAndroid Build Coastguard Worker 
360*1c60b9acSAndroid Build Coastguard Worker 	/* the directory metadata tells us modification time, so pass it on */
361*1c60b9acSAndroid Build Coastguard Worker 	priv->fop_fd.mod_time = priv->hdr.mod_time;
362*1c60b9acSAndroid Build Coastguard Worker 	*flags |= LWS_FOP_FLAG_MOD_TIME_VALID | LWS_FOP_FLAG_VIRTUAL;
363*1c60b9acSAndroid Build Coastguard Worker 	priv->fop_fd.flags = *flags;
364*1c60b9acSAndroid Build Coastguard Worker 
365*1c60b9acSAndroid Build Coastguard Worker 	/* The zip fop_fd is left pointing at the start of the content.
366*1c60b9acSAndroid Build Coastguard Worker 	 *
367*1c60b9acSAndroid Build Coastguard Worker 	 * 1) Content could be uncompressed (STORE), and we can always serve
368*1c60b9acSAndroid Build Coastguard Worker 	 *    that directly
369*1c60b9acSAndroid Build Coastguard Worker 	 *
370*1c60b9acSAndroid Build Coastguard Worker 	 * 2) Content could be compressed (GZIP), and the client can handle
371*1c60b9acSAndroid Build Coastguard Worker 	 *    receiving GZIP... we can wrap it in a GZIP header and trailer
372*1c60b9acSAndroid Build Coastguard Worker 	 *    and serve the content part directly.  The flag indicating we
373*1c60b9acSAndroid Build Coastguard Worker 	 *    are providing GZIP directly is set so lws will send the right
374*1c60b9acSAndroid Build Coastguard Worker 	 *    headers.
375*1c60b9acSAndroid Build Coastguard Worker 	 *
376*1c60b9acSAndroid Build Coastguard Worker 	 * 3) Content could be compressed (GZIP) but the client can't handle
377*1c60b9acSAndroid Build Coastguard Worker 	 *    receiving GZIP... we can decompress it and serve as it is
378*1c60b9acSAndroid Build Coastguard Worker 	 *    inflated piecemeal.
379*1c60b9acSAndroid Build Coastguard Worker 	 *
380*1c60b9acSAndroid Build Coastguard Worker 	 * 4) Content may be compressed some unknown way... fail
381*1c60b9acSAndroid Build Coastguard Worker 	 *
382*1c60b9acSAndroid Build Coastguard Worker 	 */
383*1c60b9acSAndroid Build Coastguard Worker 	if (priv->hdr.method == ZIP_COMPRESSION_METHOD_STORE) {
384*1c60b9acSAndroid Build Coastguard Worker 		/*
385*1c60b9acSAndroid Build Coastguard Worker 		 * it is stored uncompressed, leave it indicated as
386*1c60b9acSAndroid Build Coastguard Worker 		 * uncompressed, and just serve it from inside the
387*1c60b9acSAndroid Build Coastguard Worker 		 * zip with no gzip container;
388*1c60b9acSAndroid Build Coastguard Worker 		 */
389*1c60b9acSAndroid Build Coastguard Worker 
390*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("direct zip serving (stored)\n");
391*1c60b9acSAndroid Build Coastguard Worker 
392*1c60b9acSAndroid Build Coastguard Worker 		priv->fop_fd.len = priv->hdr.uncomp_size;
393*1c60b9acSAndroid Build Coastguard Worker 
394*1c60b9acSAndroid Build Coastguard Worker 		return &priv->fop_fd;
395*1c60b9acSAndroid Build Coastguard Worker 	}
396*1c60b9acSAndroid Build Coastguard Worker 
397*1c60b9acSAndroid Build Coastguard Worker 	if ((*flags & LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP) &&
398*1c60b9acSAndroid Build Coastguard Worker 	    priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
399*1c60b9acSAndroid Build Coastguard Worker 
400*1c60b9acSAndroid Build Coastguard Worker 		/*
401*1c60b9acSAndroid Build Coastguard Worker 		 * We can serve the gzipped file contents directly as gzip
402*1c60b9acSAndroid Build Coastguard Worker 		 * from inside the zip container; client says it is OK.
403*1c60b9acSAndroid Build Coastguard Worker 		 *
404*1c60b9acSAndroid Build Coastguard Worker 		 * To convert to standalone gzip, we have to add a 10-byte
405*1c60b9acSAndroid Build Coastguard Worker 		 * constant header and a variable 8-byte trailer around the
406*1c60b9acSAndroid Build Coastguard Worker 		 * content.
407*1c60b9acSAndroid Build Coastguard Worker 		 *
408*1c60b9acSAndroid Build Coastguard Worker 		 * The 8-byte trailer is prepared now and held in the priv.
409*1c60b9acSAndroid Build Coastguard Worker 		 */
410*1c60b9acSAndroid Build Coastguard Worker 
411*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("direct zip serving (gzipped)\n");
412*1c60b9acSAndroid Build Coastguard Worker 
413*1c60b9acSAndroid Build Coastguard Worker 		priv->fop_fd.len = sizeof(hd) + priv->hdr.comp_size +
414*1c60b9acSAndroid Build Coastguard Worker 				   sizeof(priv->u);
415*1c60b9acSAndroid Build Coastguard Worker 
416*1c60b9acSAndroid Build Coastguard Worker 		if (lws_is_be()) {
417*1c60b9acSAndroid Build Coastguard Worker 			uint8_t *p = priv->u.trailer8;
418*1c60b9acSAndroid Build Coastguard Worker 
419*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)priv->hdr.crc32;
420*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)(priv->hdr.crc32 >> 8);
421*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)(priv->hdr.crc32 >> 16);
422*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)(priv->hdr.crc32 >> 24);
423*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)priv->hdr.uncomp_size;
424*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)(priv->hdr.uncomp_size >> 8);
425*1c60b9acSAndroid Build Coastguard Worker 			*p++ = (uint8_t)(priv->hdr.uncomp_size >> 16);
426*1c60b9acSAndroid Build Coastguard Worker 			*p   = (uint8_t)(priv->hdr.uncomp_size >> 24);
427*1c60b9acSAndroid Build Coastguard Worker 		} else {
428*1c60b9acSAndroid Build Coastguard Worker 			priv->u.trailer32[0] = priv->hdr.crc32;
429*1c60b9acSAndroid Build Coastguard Worker 			priv->u.trailer32[1] = priv->hdr.uncomp_size;
430*1c60b9acSAndroid Build Coastguard Worker 		}
431*1c60b9acSAndroid Build Coastguard Worker 
432*1c60b9acSAndroid Build Coastguard Worker 		*flags |= LWS_FOP_FLAG_COMPR_IS_GZIP;
433*1c60b9acSAndroid Build Coastguard Worker 		priv->fop_fd.flags = *flags;
434*1c60b9acSAndroid Build Coastguard Worker 		priv->add_gzip_container = 1;
435*1c60b9acSAndroid Build Coastguard Worker 
436*1c60b9acSAndroid Build Coastguard Worker 		return &priv->fop_fd;
437*1c60b9acSAndroid Build Coastguard Worker 	}
438*1c60b9acSAndroid Build Coastguard Worker 
439*1c60b9acSAndroid Build Coastguard Worker 	if (priv->hdr.method == ZIP_COMPRESSION_METHOD_DEFLATE) {
440*1c60b9acSAndroid Build Coastguard Worker 
441*1c60b9acSAndroid Build Coastguard Worker 		/* we must decompress it to serve it */
442*1c60b9acSAndroid Build Coastguard Worker 
443*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("decompressed zip serving\n");
444*1c60b9acSAndroid Build Coastguard Worker 
445*1c60b9acSAndroid Build Coastguard Worker 		priv->fop_fd.len = priv->hdr.uncomp_size;
446*1c60b9acSAndroid Build Coastguard Worker 
447*1c60b9acSAndroid Build Coastguard Worker 		if (lws_fops_zip_reset_inflate(priv)) {
448*1c60b9acSAndroid Build Coastguard Worker 			lwsl_err("inflate init failed\n");
449*1c60b9acSAndroid Build Coastguard Worker 			goto bail2;
450*1c60b9acSAndroid Build Coastguard Worker 		}
451*1c60b9acSAndroid Build Coastguard Worker 
452*1c60b9acSAndroid Build Coastguard Worker 		priv->decompress = 1;
453*1c60b9acSAndroid Build Coastguard Worker 
454*1c60b9acSAndroid Build Coastguard Worker 		return &priv->fop_fd;
455*1c60b9acSAndroid Build Coastguard Worker 	}
456*1c60b9acSAndroid Build Coastguard Worker 
457*1c60b9acSAndroid Build Coastguard Worker 	/* we can't handle it ... */
458*1c60b9acSAndroid Build Coastguard Worker 
459*1c60b9acSAndroid Build Coastguard Worker 	lwsl_err("zipped file %s compressed in unknown way (%d)\n", vfs_path,
460*1c60b9acSAndroid Build Coastguard Worker 		 priv->hdr.method);
461*1c60b9acSAndroid Build Coastguard Worker 
462*1c60b9acSAndroid Build Coastguard Worker bail2:
463*1c60b9acSAndroid Build Coastguard Worker 	lws_vfs_file_close(&priv->zip_fop_fd);
464*1c60b9acSAndroid Build Coastguard Worker bail1:
465*1c60b9acSAndroid Build Coastguard Worker 	free(priv);
466*1c60b9acSAndroid Build Coastguard Worker 
467*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
468*1c60b9acSAndroid Build Coastguard Worker }
469*1c60b9acSAndroid Build Coastguard Worker 
470*1c60b9acSAndroid Build Coastguard Worker /* ie, we are closing the fop_fd for the file inside the gzip */
471*1c60b9acSAndroid Build Coastguard Worker 
472*1c60b9acSAndroid Build Coastguard Worker static int
lws_fops_zip_close(lws_fop_fd_t * fd)473*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_close(lws_fop_fd_t *fd)
474*1c60b9acSAndroid Build Coastguard Worker {
475*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_t priv = fop_fd_to_priv(*fd);
476*1c60b9acSAndroid Build Coastguard Worker 
477*1c60b9acSAndroid Build Coastguard Worker 	if (priv->decompress)
478*1c60b9acSAndroid Build Coastguard Worker 		inflateEnd(&priv->inflate);
479*1c60b9acSAndroid Build Coastguard Worker 
480*1c60b9acSAndroid Build Coastguard Worker 	lws_vfs_file_close(&priv->zip_fop_fd); /* close the gzip fop_fd */
481*1c60b9acSAndroid Build Coastguard Worker 
482*1c60b9acSAndroid Build Coastguard Worker 	free(priv);
483*1c60b9acSAndroid Build Coastguard Worker 	*fd = NULL;
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 	return 0;
486*1c60b9acSAndroid Build Coastguard Worker }
487*1c60b9acSAndroid Build Coastguard Worker 
488*1c60b9acSAndroid Build Coastguard Worker static lws_fileofs_t
lws_fops_zip_seek_cur(lws_fop_fd_t fd,lws_fileofs_t offset_from_cur_pos)489*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_seek_cur(lws_fop_fd_t fd, lws_fileofs_t offset_from_cur_pos)
490*1c60b9acSAndroid Build Coastguard Worker {
491*1c60b9acSAndroid Build Coastguard Worker 	fd->pos = (lws_filepos_t)((lws_fileofs_t)fd->pos + offset_from_cur_pos);
492*1c60b9acSAndroid Build Coastguard Worker 
493*1c60b9acSAndroid Build Coastguard Worker 	return (lws_fileofs_t)fd->pos;
494*1c60b9acSAndroid Build Coastguard Worker }
495*1c60b9acSAndroid Build Coastguard Worker 
496*1c60b9acSAndroid Build Coastguard Worker static int
lws_fops_zip_read(lws_fop_fd_t fd,lws_filepos_t * amount,uint8_t * buf,lws_filepos_t len)497*1c60b9acSAndroid Build Coastguard Worker lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,
498*1c60b9acSAndroid Build Coastguard Worker 		  lws_filepos_t len)
499*1c60b9acSAndroid Build Coastguard Worker {
500*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_t priv = fop_fd_to_priv(fd);
501*1c60b9acSAndroid Build Coastguard Worker 	lws_filepos_t ramount, rlen, cur = lws_vfs_tell(fd);
502*1c60b9acSAndroid Build Coastguard Worker 	int ret;
503*1c60b9acSAndroid Build Coastguard Worker 
504*1c60b9acSAndroid Build Coastguard Worker 	if (priv->decompress) {
505*1c60b9acSAndroid Build Coastguard Worker 
506*1c60b9acSAndroid Build Coastguard Worker 		if (priv->exp_uncomp_pos != fd->pos) {
507*1c60b9acSAndroid Build Coastguard Worker 			/*
508*1c60b9acSAndroid Build Coastguard Worker 			 *  there has been a seek in the uncompressed fop_fd
509*1c60b9acSAndroid Build Coastguard Worker 			 * we have to restart the decompression and loop eating
510*1c60b9acSAndroid Build Coastguard Worker 			 * the decompressed data up to the seek point
511*1c60b9acSAndroid Build Coastguard Worker 			 */
512*1c60b9acSAndroid Build Coastguard Worker 			lwsl_info("seek in decompressed\n");
513*1c60b9acSAndroid Build Coastguard Worker 
514*1c60b9acSAndroid Build Coastguard Worker 			lws_fops_zip_reset_inflate(priv);
515*1c60b9acSAndroid Build Coastguard Worker 
516*1c60b9acSAndroid Build Coastguard Worker 			while (priv->exp_uncomp_pos != fd->pos) {
517*1c60b9acSAndroid Build Coastguard Worker 				rlen = len;
518*1c60b9acSAndroid Build Coastguard Worker 				if (rlen > fd->pos - priv->exp_uncomp_pos)
519*1c60b9acSAndroid Build Coastguard Worker 					rlen = fd->pos - priv->exp_uncomp_pos;
520*1c60b9acSAndroid Build Coastguard Worker 				if (lws_fops_zip_read(fd, amount, buf, rlen))
521*1c60b9acSAndroid Build Coastguard Worker 					return LWS_FZ_ERR_SEEK_COMPRESSED;
522*1c60b9acSAndroid Build Coastguard Worker 			}
523*1c60b9acSAndroid Build Coastguard Worker 			*amount = 0;
524*1c60b9acSAndroid Build Coastguard Worker 		}
525*1c60b9acSAndroid Build Coastguard Worker 
526*1c60b9acSAndroid Build Coastguard Worker 		priv->inflate.avail_out = (unsigned int)len;
527*1c60b9acSAndroid Build Coastguard Worker 		priv->inflate.next_out = buf;
528*1c60b9acSAndroid Build Coastguard Worker 
529*1c60b9acSAndroid Build Coastguard Worker spin:
530*1c60b9acSAndroid Build Coastguard Worker 		if (!priv->inflate.avail_in) {
531*1c60b9acSAndroid Build Coastguard Worker 			rlen = sizeof(priv->rbuf);
532*1c60b9acSAndroid Build Coastguard Worker 			if (rlen > eff_size(priv) - (cur - priv->content_start))
533*1c60b9acSAndroid Build Coastguard Worker 				rlen = eff_size(priv) - (cur - priv->content_start);
534*1c60b9acSAndroid Build Coastguard Worker 
535*1c60b9acSAndroid Build Coastguard Worker 			if (priv->zip_fop_fd->fops->LWS_FOP_READ(
536*1c60b9acSAndroid Build Coastguard Worker 					priv->zip_fop_fd, &ramount, priv->rbuf,
537*1c60b9acSAndroid Build Coastguard Worker 					rlen))
538*1c60b9acSAndroid Build Coastguard Worker 				return LWS_FZ_ERR_READ_CONTENT;
539*1c60b9acSAndroid Build Coastguard Worker 
540*1c60b9acSAndroid Build Coastguard Worker 			cur += ramount;
541*1c60b9acSAndroid Build Coastguard Worker 
542*1c60b9acSAndroid Build Coastguard Worker 			priv->inflate.avail_in = (unsigned int)ramount;
543*1c60b9acSAndroid Build Coastguard Worker 			priv->inflate.next_in = priv->rbuf;
544*1c60b9acSAndroid Build Coastguard Worker 		}
545*1c60b9acSAndroid Build Coastguard Worker 
546*1c60b9acSAndroid Build Coastguard Worker 		ret = inflate(&priv->inflate, Z_NO_FLUSH);
547*1c60b9acSAndroid Build Coastguard Worker 		if (ret == Z_STREAM_ERROR)
548*1c60b9acSAndroid Build Coastguard Worker 			return ret;
549*1c60b9acSAndroid Build Coastguard Worker 
550*1c60b9acSAndroid Build Coastguard Worker 		switch (ret) {
551*1c60b9acSAndroid Build Coastguard Worker 		case Z_NEED_DICT:
552*1c60b9acSAndroid Build Coastguard Worker 			ret = Z_DATA_ERROR;
553*1c60b9acSAndroid Build Coastguard Worker 			/* fallthru */
554*1c60b9acSAndroid Build Coastguard Worker 		case Z_DATA_ERROR:
555*1c60b9acSAndroid Build Coastguard Worker 		case Z_MEM_ERROR:
556*1c60b9acSAndroid Build Coastguard Worker 
557*1c60b9acSAndroid Build Coastguard Worker 			return ret;
558*1c60b9acSAndroid Build Coastguard Worker 		}
559*1c60b9acSAndroid Build Coastguard Worker 
560*1c60b9acSAndroid Build Coastguard Worker 		if (!priv->inflate.avail_in && priv->inflate.avail_out &&
561*1c60b9acSAndroid Build Coastguard Worker 		     cur != priv->content_start + priv->hdr.comp_size)
562*1c60b9acSAndroid Build Coastguard Worker 			goto spin;
563*1c60b9acSAndroid Build Coastguard Worker 
564*1c60b9acSAndroid Build Coastguard Worker 		*amount = len - priv->inflate.avail_out;
565*1c60b9acSAndroid Build Coastguard Worker 
566*1c60b9acSAndroid Build Coastguard Worker 		priv->exp_uncomp_pos += *amount;
567*1c60b9acSAndroid Build Coastguard Worker 		fd->pos += *amount;
568*1c60b9acSAndroid Build Coastguard Worker 
569*1c60b9acSAndroid Build Coastguard Worker 		return 0;
570*1c60b9acSAndroid Build Coastguard Worker 	}
571*1c60b9acSAndroid Build Coastguard Worker 
572*1c60b9acSAndroid Build Coastguard Worker 	if (priv->add_gzip_container) {
573*1c60b9acSAndroid Build Coastguard Worker 
574*1c60b9acSAndroid Build Coastguard Worker 		lwsl_info("%s: gzip + container\n", __func__);
575*1c60b9acSAndroid Build Coastguard Worker 		*amount = 0;
576*1c60b9acSAndroid Build Coastguard Worker 
577*1c60b9acSAndroid Build Coastguard Worker 		/* place the canned header at the start */
578*1c60b9acSAndroid Build Coastguard Worker 
579*1c60b9acSAndroid Build Coastguard Worker 		if (len && fd->pos < sizeof(hd)) {
580*1c60b9acSAndroid Build Coastguard Worker 			rlen = sizeof(hd) - fd->pos;
581*1c60b9acSAndroid Build Coastguard Worker 			if (rlen > len)
582*1c60b9acSAndroid Build Coastguard Worker 				rlen = len;
583*1c60b9acSAndroid Build Coastguard Worker 			/* provide stuff from canned header */
584*1c60b9acSAndroid Build Coastguard Worker 			memcpy(buf, hd + fd->pos, (size_t)rlen);
585*1c60b9acSAndroid Build Coastguard Worker 			fd->pos += rlen;
586*1c60b9acSAndroid Build Coastguard Worker 			buf += rlen;
587*1c60b9acSAndroid Build Coastguard Worker 			len -= rlen;
588*1c60b9acSAndroid Build Coastguard Worker 			*amount += rlen;
589*1c60b9acSAndroid Build Coastguard Worker 		}
590*1c60b9acSAndroid Build Coastguard Worker 
591*1c60b9acSAndroid Build Coastguard Worker 		/* serve gzipped data direct from zipfile */
592*1c60b9acSAndroid Build Coastguard Worker 
593*1c60b9acSAndroid Build Coastguard Worker 		if (len && fd->pos >= sizeof(hd) &&
594*1c60b9acSAndroid Build Coastguard Worker 		    fd->pos < priv->hdr.comp_size + sizeof(hd)) {
595*1c60b9acSAndroid Build Coastguard Worker 
596*1c60b9acSAndroid Build Coastguard Worker 			rlen = priv->hdr.comp_size - (priv->zip_fop_fd->pos -
597*1c60b9acSAndroid Build Coastguard Worker 						      priv->content_start);
598*1c60b9acSAndroid Build Coastguard Worker 			if (rlen > len)
599*1c60b9acSAndroid Build Coastguard Worker 				rlen = len;
600*1c60b9acSAndroid Build Coastguard Worker 
601*1c60b9acSAndroid Build Coastguard Worker 			if (rlen &&
602*1c60b9acSAndroid Build Coastguard Worker 			    priv->zip_fop_fd->pos < (priv->hdr.comp_size +
603*1c60b9acSAndroid Build Coastguard Worker 					    	     priv->content_start)) {
604*1c60b9acSAndroid Build Coastguard Worker 				if (lws_vfs_file_read(priv->zip_fop_fd,
605*1c60b9acSAndroid Build Coastguard Worker 						      &ramount, buf, rlen))
606*1c60b9acSAndroid Build Coastguard Worker 					return LWS_FZ_ERR_READ_CONTENT;
607*1c60b9acSAndroid Build Coastguard Worker 				*amount += ramount;
608*1c60b9acSAndroid Build Coastguard Worker 				fd->pos += ramount; // virtual pos
609*1c60b9acSAndroid Build Coastguard Worker 				buf += ramount;
610*1c60b9acSAndroid Build Coastguard Worker 				len -= ramount;
611*1c60b9acSAndroid Build Coastguard Worker 			}
612*1c60b9acSAndroid Build Coastguard Worker 		}
613*1c60b9acSAndroid Build Coastguard Worker 
614*1c60b9acSAndroid Build Coastguard Worker 		/* place the prepared trailer at the end */
615*1c60b9acSAndroid Build Coastguard Worker 
616*1c60b9acSAndroid Build Coastguard Worker 		if (len && fd->pos >= priv->hdr.comp_size + sizeof(hd) &&
617*1c60b9acSAndroid Build Coastguard Worker 		    fd->pos < priv->hdr.comp_size + sizeof(hd) +
618*1c60b9acSAndroid Build Coastguard Worker 		    	      sizeof(priv->u)) {
619*1c60b9acSAndroid Build Coastguard Worker 			cur = fd->pos - priv->hdr.comp_size - sizeof(hd);
620*1c60b9acSAndroid Build Coastguard Worker 			rlen = sizeof(priv->u) - cur;
621*1c60b9acSAndroid Build Coastguard Worker 			if (rlen > len)
622*1c60b9acSAndroid Build Coastguard Worker 				rlen = len;
623*1c60b9acSAndroid Build Coastguard Worker 
624*1c60b9acSAndroid Build Coastguard Worker 			memcpy(buf, priv->u.trailer8 + cur, (size_t)rlen);
625*1c60b9acSAndroid Build Coastguard Worker 
626*1c60b9acSAndroid Build Coastguard Worker 			*amount += rlen;
627*1c60b9acSAndroid Build Coastguard Worker 			fd->pos += rlen;
628*1c60b9acSAndroid Build Coastguard Worker 		}
629*1c60b9acSAndroid Build Coastguard Worker 
630*1c60b9acSAndroid Build Coastguard Worker 		return 0;
631*1c60b9acSAndroid Build Coastguard Worker 	}
632*1c60b9acSAndroid Build Coastguard Worker 
633*1c60b9acSAndroid Build Coastguard Worker 	lwsl_info("%s: store\n", __func__);
634*1c60b9acSAndroid Build Coastguard Worker 
635*1c60b9acSAndroid Build Coastguard Worker 	if (len > eff_size(priv) - cur)
636*1c60b9acSAndroid Build Coastguard Worker 		len = eff_size(priv) - cur;
637*1c60b9acSAndroid Build Coastguard Worker 
638*1c60b9acSAndroid Build Coastguard Worker 	if (priv->zip_fop_fd->fops->LWS_FOP_READ(priv->zip_fop_fd,
639*1c60b9acSAndroid Build Coastguard Worker 						 amount, buf, len))
640*1c60b9acSAndroid Build Coastguard Worker 		return LWS_FZ_ERR_READ_CONTENT;
641*1c60b9acSAndroid Build Coastguard Worker 
642*1c60b9acSAndroid Build Coastguard Worker 	fd->pos += *amount;
643*1c60b9acSAndroid Build Coastguard Worker 
644*1c60b9acSAndroid Build Coastguard Worker 	return 0;
645*1c60b9acSAndroid Build Coastguard Worker }
646*1c60b9acSAndroid Build Coastguard Worker 
647*1c60b9acSAndroid Build Coastguard Worker struct lws_plat_file_ops fops_zip = {
648*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_open,
649*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_close,
650*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_seek_cur,
651*1c60b9acSAndroid Build Coastguard Worker 	lws_fops_zip_read,
652*1c60b9acSAndroid Build Coastguard Worker 	NULL,
653*1c60b9acSAndroid Build Coastguard Worker 	{ { ".zip/", 5 }, { ".jar/", 5 }, { ".war/", 5 } },
654*1c60b9acSAndroid Build Coastguard Worker 	NULL,
655*1c60b9acSAndroid Build Coastguard Worker };
656