4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
42 int Zip::BuildDirInfo()
44 shared_ptr
<FileBuffer
> zipfile
= get_file_buffer(m_filename
);
45 if (zipfile
== nullptr)
51 Zip_eocd
*peocd
= nullptr;
52 Zip64_eocd_locator
*peocd64_loc
= nullptr;
53 Zip64_eocd
*peocd64
= nullptr;
55 for (i
= zipfile
->size() - sizeof(Zip_eocd
); i
> 0; i
--)
57 peocd
= (Zip_eocd
*)(zipfile
->data() + i
);
58 if (peocd
->sign
== EOCD_SIGNATURE
)
60 if (peocd
->offset_of_central_dir
== 0xFFFFFFFF)
62 for (size_t j
= i
- sizeof(Zip64_eocd_locator
); j
> 0; j
--)
64 peocd64_loc
= (Zip64_eocd_locator
*)(zipfile
->data() + j
);
65 if (peocd64_loc
->sign
== EOCD64_LOCATOR_SIGNATURE
)
67 peocd64
= (Zip64_eocd
*)(zipfile
->data() + peocd64_loc
->offset_of_eocd
);
68 if (peocd64
->sign
!= EOCD64_SIGNATURE
)
70 set_last_err_string("Can't find EOCD64_SIGNATURE, not a zip64 file");
76 if (zipfile
->size() - j
> 0x10000)
78 set_last_err_string("Can't find EOCD, not a zip file");
86 if (zipfile
->size() - i
> 0x10000)
88 set_last_err_string("Can't find EOCD, not a zip file");
95 set_last_err_string("Can't find EOCD, not a zip file");
99 i
= peocd64
? peocd64
->offset
:peocd
->offset_of_central_dir
;
101 total
+= peocd64
? peocd64
->size
: peocd
->size_of_central_dir
;
105 Zip_central_dir
*pdir
= (Zip_central_dir
*)(zipfile
->data() + i
);
106 if (pdir
->sign
!= DIR_SIGNATURE
)
108 set_last_err_string("DIR signature mismatched");
112 info
.m_filename
.append((char*)pdir
->filename
, pdir
->file_name_length
);
113 info
.m_offset
= pdir
->offset
;
114 info
.m_filesize
= pdir
->uncompressed_size
;
115 info
.m_timestamp
= (pdir
->last_modify_date
<< 16) + pdir
->last_modify_time
;
116 info
.m_compressedsize
= pdir
->compressed_size
;
118 if (pdir
->extrafield_length
)
121 for (e
= 0; e
< pdir
->extrafield_length
; /*dummy*/)
123 Zip_ext
*ext
= (Zip_ext
*)(zipfile
->data() + e
+ i
+ sizeof(Zip_central_dir
) + pdir
->file_name_length
);
128 if (info
.m_filesize
== 0xFFFFFFFF)
130 info
.m_filesize
= *((uint64_t*)(((uint8_t*)ext
) + sizeof(Zip_ext
) + cur64
));
134 if (cur64
> ext
->size
)
136 set_last_err_string("error pass zip64");
140 if (info
.m_compressedsize
== 0xFFFFFFFF)
142 info
.m_compressedsize
= *((uint64_t*)(((uint8_t*)ext
) + sizeof(Zip_ext
) + cur64
));
146 if (cur64
> ext
->size
)
148 set_last_err_string("error pass zip64");
152 if (info
.m_offset
== 0xFFFFFFFF)
154 info
.m_offset
= *((uint64_t*)(((uint8_t*)ext
) + sizeof(Zip_ext
) + cur64
));
158 if (cur64
> ext
->size
)
160 set_last_err_string("error pass zip64");
166 e
+= ext
->size
+ sizeof(Zip_ext
);
169 i
+= sizeof(Zip_central_dir
) + pdir
->extrafield_length
+ pdir
->file_name_length
+ pdir
->file_comment_length
;
170 m_filemap
[info
.m_filename
] = info
;
176 bool Zip::check_file_exist(string filename
)
178 if (m_filemap
.find(filename
) == m_filemap
.end())
181 err
+= "Can't find file ";
183 set_last_err_string(err
);
190 int Zip::get_file_buff(string filename
, shared_ptr
<FileBuffer
> p
)
192 if (m_filemap
.find(filename
) == m_filemap
.end())
195 err
+= "Can't find file ";
197 set_last_err_string(err
);
202 ut
.type
= uuu_notify::NOTIFY_DECOMPRESS_START
;
203 ut
.str
= (char*)filename
.c_str();
206 return m_filemap
[filename
].decompress(this, p
);
209 int Zip::Open(string filename
)
211 m_filename
= filename
;
212 return BuildDirInfo();
215 Zip_file_Info::Zip_file_Info()
220 Zip_file_Info::~Zip_file_Info()
222 memset(&m_strm
, 0, sizeof(m_strm
));
225 int Zip_file_Info::decompress(Zip
*pZip
, shared_ptr
<FileBuffer
>p
)
227 p
->resize(m_filesize
);
228 atomic_fetch_or(&p
->m_dataflags
, FILEBUFFER_FLAG_KNOWN_SIZE
);
229 p
->m_request_cv
.notify_all();
232 ut
.type
= uuu_notify::NOTIFY_DECOMPRESS_SIZE
;
233 ut
.total
= m_filesize
;
237 shared_ptr
<FileBuffer
> zipfile
= get_file_buffer(pZip
->get_filename());
238 if (zipfile
== nullptr)
241 Zip_file_desc
*file_desc
=(Zip_file_desc
*)(zipfile
->data() + m_offset
);
242 if (file_desc
->sign
!= FILE_SIGNATURE
)
244 set_last_err_string("file signature miss matched");
248 size_t off
= sizeof(Zip_file_desc
) + file_desc
->file_name_length
+ file_desc
->extrafield_length
;
250 if (file_desc
->compress_method
== 0)
252 p
->ref_other_buffer(zipfile
, m_offset
+ off
, m_filesize
);
253 atomic_fetch_or(&p
->m_dataflags
, FILEBUFFER_FLAG_LOADED
);
254 p
->m_request_cv
.notify_all();
258 if (file_desc
->compress_method
!= 8)
260 set_last_err_string("Unsupported compress method");
267 memset(&m_strm
, 0, sizeof(m_strm
));
268 inflateInit2(&m_strm
, -MAX_WBITS
);
270 /* decompress until deflate stream ends or end of file */
271 m_strm
.avail_in
= m_compressedsize
;
272 m_strm
.next_in
= zipfile
->data() + m_offset
+ off
;
273 m_strm
.total_in
= m_compressedsize
;
275 /* run inflate() on input until output buffer not full */
276 size_t each_out_size
= CHUNK
;
279 if (p
->size() - pos
< each_out_size
)
280 each_out_size
= p
->size() - pos
;
282 m_strm
.avail_out
= each_out_size
;
283 m_strm
.next_out
= p
->data() + pos
;
284 ret
= inflate(&m_strm
, Z_NO_FLUSH
);
285 //assert(ret != Z_STREAM_ERROR); /* state not clobbered */
288 ret
= Z_DATA_ERROR
; /* and fall through */
295 (void)inflateEnd(&m_strm
);
298 size_t have
= each_out_size
- m_strm
.avail_out
;
300 p
->m_available_size
= pos
;
301 p
->m_request_cv
.notify_all();
305 if (pos
- lastpos
> 100 * 1024 * 1024)
308 ut
.type
= uuu_notify::NOTIFY_DECOMPRESS_POS
;
314 } while (ret
!= Z_STREAM_END
);
316 /* clean up and return */
317 (void)inflateEnd(&m_strm
);
319 if (ret
!= Z_STREAM_END
)
321 set_last_err_string("decompress error");
325 p
->m_available_size
= m_filesize
;
326 atomic_fetch_or(&p
->m_dataflags
, FILEBUFFER_FLAG_LOADED
);
327 p
->m_request_cv
.notify_all();
329 ut
.type
= uuu_notify::NOTIFY_DECOMPRESS_POS
;
330 ut
.index
= m_filesize
;