Fixed sdps crash for some size flash.bin
[mfgtools.git] / libuuu / zip.cpp
blobc3121eedbd8570fd580bf2c5f6ee500235aca8aa
1 /*
2 * Copyright 2018 NXP.
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.
31 #include <string.h>
32 #include <iostream>
33 #include <fstream>
34 #include "buffer.h"
35 #include "libcomm.h"
36 #include "libuuu.h"
37 #include "liberror.h"
38 #include "zip.h"
40 #define CHUNK 0x10000
42 int Zip::BuildDirInfo()
44 shared_ptr<FileBuffer> zipfile = get_file_buffer(m_filename);
45 if (zipfile == nullptr)
47 return -1;
50 size_t i;
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)
61 {//zip64
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");
71 return -1;
73 break;
76 if (zipfile->size() - j > 0x10000)
78 set_last_err_string("Can't find EOCD, not a zip file");
79 return -1;
83 break;
86 if (zipfile->size() - i > 0x10000)
88 set_last_err_string("Can't find EOCD, not a zip file");
89 return -1;
93 if (peocd == 0)
95 set_last_err_string("Can't find EOCD, not a zip file");
96 return -1;
99 i = peocd64? peocd64->offset:peocd->offset_of_central_dir;
100 size_t total = i;
101 total += peocd64 ? peocd64->size: peocd->size_of_central_dir;
103 while (i < total)
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");
109 return -1;
111 Zip_file_Info info;
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)
120 size_t e;
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);
125 if (ext->tag == 0x1)
127 size_t cur64 = 0;
128 if (info.m_filesize == 0xFFFFFFFF)
130 info.m_filesize = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64));
131 cur64 += 8;
134 if (cur64 > ext->size)
136 set_last_err_string("error pass zip64");
137 return -1;
140 if (info.m_compressedsize == 0xFFFFFFFF)
142 info.m_compressedsize = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64));
143 cur64 += 8;
146 if (cur64 > ext->size)
148 set_last_err_string("error pass zip64");
149 return -1;
152 if (info.m_offset == 0xFFFFFFFF)
154 info.m_offset = *((uint64_t*)(((uint8_t*)ext) + sizeof(Zip_ext) + cur64));
155 cur64 += 8;
158 if (cur64 > ext->size)
160 set_last_err_string("error pass zip64");
161 return -1;
164 break;
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;
173 return 0;
176 bool Zip::check_file_exist(string filename)
178 if (m_filemap.find(filename) == m_filemap.end())
180 string err;
181 err += "Can't find file ";
182 err += filename;
183 set_last_err_string(err);
184 return false;
187 return true;
190 int Zip::get_file_buff(string filename, shared_ptr<FileBuffer> p)
192 if (m_filemap.find(filename) == m_filemap.end())
194 string err;
195 err += "Can't find file ";
196 err += filename;
197 set_last_err_string(err);
198 return -1;
201 uuu_notify ut;
202 ut.type = uuu_notify::NOTIFY_DECOMPRESS_START;
203 ut.str = (char*)filename.c_str();
204 call_notify(ut);
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();
231 uuu_notify ut;
232 ut.type = uuu_notify::NOTIFY_DECOMPRESS_SIZE;
233 ut.total = m_filesize;
234 call_notify(ut);
235 size_t lastpos = 0;
237 shared_ptr<FileBuffer> zipfile = get_file_buffer(pZip->get_filename());
238 if (zipfile == nullptr)
239 return -1;
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");
245 return -1;
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();
255 return 0;
258 if (file_desc->compress_method != 8)
260 set_last_err_string("Unsupported compress method");
261 return -1;
264 int ret;
265 size_t pos = 0;
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;
277 do {
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 */
286 switch (ret) {
287 case Z_NEED_DICT:
288 ret = Z_DATA_ERROR; /* and fall through */
289 FALLTHROUGH
290 // FALLTHROUGH
291 case Z_DATA_ERROR:
292 FALLTHROUGH
293 // FALLTHROUGH
294 case Z_MEM_ERROR:
295 (void)inflateEnd(&m_strm);
296 return -1;
298 size_t have = each_out_size - m_strm.avail_out;
300 p->m_available_size = pos;
301 p->m_request_cv.notify_all();
303 pos += have;
305 if (pos - lastpos > 100 * 1024 * 1024)
307 uuu_notify ut;
308 ut.type = uuu_notify::NOTIFY_DECOMPRESS_POS;
309 ut.index = pos;
310 call_notify(ut);
311 lastpos = 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");
322 return -1;
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;
331 call_notify(ut);
333 return 0;