a9f41bb906eb36384646c81626dd38d85053b8c0
[mupen64plus-pandora.git] / source / mupen64launcher / src / czip.cpp
1 /**
2  *  @section LICENSE
3  *
4  *  PickleLauncher
5  *  Copyright (C) 2010-2011 Scott Smith
6  *
7  *  This program is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  *  @section LOCATION
21  */
22
23  /*
24    czip.cpp is based on miniunz.c
25
26    miniunz.c
27    Version 1.1, February 14h, 2010
28    sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
29
30          Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
31
32          Modifications of Unzip for Zip64
33          Copyright (C) 2007-2008 Even Rouault
34
35          Modifications for Zip64 support on both zip and unzip
36          Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
37 */
38
39 #include "czip.h"
40
41 CZip::CZip() : CBase(),
42     UnzipFiles          ()
43 {
44 }
45
46 CZip::~CZip()
47 {
48 }
49
50 void CZip::ListFiles( const string& zipfile, vector<string>& list )
51 {
52     uint32_t i;
53     int32_t err;
54     unzFile uf=NULL;
55     unz_global_info64 gi;
56
57     // Open the zip file
58     uf = unzOpen64( zipfile.c_str() );
59
60     if (uf != NULL)
61     {
62         // Get file info for the zip file
63         err = unzGetGlobalInfo64( uf,&gi );
64         if (err != UNZ_OK)
65         {
66             Log( "error %d with zipfile in unzGetGlobalInfo\n",err);
67             return;
68         }
69     }
70     else
71     {
72         Log( "error with zipfile %s in unzOpen64\n", zipfile.c_str() );
73         return;
74     }
75     Log( "Reading zip file %s\n", zipfile.c_str() );
76
77     // Spit out some information about the files in the zip for debug
78     Log( "  Length  Method     Size Ratio   Date    Time   CRC-32     Name\n" );
79     Log( "  ------  ------     ---- -----   ----    ----   ------     ----\n" );
80     for (i=0; i<gi.number_entry; i++)
81     {
82         char filename_inzip[256];
83         unz_file_info64 file_info;
84         uLong ratio=0;
85         const char *string_method = NULL;
86         char charCrypt=' ';
87         err = unzGetCurrentFileInfo64( uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0 );
88         if (err != UNZ_OK)
89         {
90             Log( "error %d with zipfile in unzGetCurrentFileInfo\n",err);
91             break;
92         }
93         if (file_info.uncompressed_size > 0)
94             ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size);
95
96         /* display a '*' if the file is crypted */
97         if ((file_info.flag & 1) != 0)
98             charCrypt='*';
99
100         if (file_info.compression_method == 0)
101             string_method="Stored";
102         else
103         if (file_info.compression_method == Z_DEFLATED)
104         {
105             uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
106             if (iLevel==0)
107               string_method="Defl:N";
108             else if (iLevel==1)
109               string_method="Defl:X";
110             else if ((iLevel==2) || (iLevel==3))
111               string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
112         }
113         else
114         if (file_info.compression_method == Z_BZIP2ED)
115         {
116               string_method="BZip2 ";
117         }
118         else
119             string_method="Unkn. ";
120
121         Display64BitsSize( file_info.uncompressed_size,7 );
122         Log( "  %6s%c",string_method,charCrypt);
123         Display64BitsSize( file_info.compressed_size,7 );
124         Log( " %3lu%%  %2.2lu-%2.2lu-%2.2lu  %2.2lu:%2.2lu  %8.8lx   %s\n",
125                 ratio,
126                 (uLong)file_info.tmu_date.tm_mon + 1,
127                 (uLong)file_info.tmu_date.tm_mday,
128                 (uLong)file_info.tmu_date.tm_year % 100,
129                 (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
130                 (uLong)file_info.crc,filename_inzip);
131         if ((i+1) < gi.number_entry)
132         {
133             err = unzGoToNextFile( uf );
134             if (err != UNZ_OK)
135             {
136                 Log( "error %d with zipfile in unzGoToNextFile\n",err);
137                 break;
138             }
139         }
140
141         // Save the names of the files in the zip
142         list.push_back( filename_inzip );
143     }
144
145     // Close the zip file
146     unzClose( uf );
147 }
148
149 void CZip::ExtractFile( const string& zipfile, const string& location, const string& filename )
150 {
151     uint32_t i;
152     int32_t err;
153     unzFile uf = NULL;
154     unz_global_info64 gi;
155
156     // Open the zip file
157     uf = unzOpen64( zipfile.c_str() );
158
159     if (uf != NULL)
160     {
161         // Get file info for the zip file
162         err = unzGetGlobalInfo64( uf,&gi );
163         if (err != UNZ_OK)
164         {
165             Log( "error %d with zipfile in unzGetGlobalInfo\n",err);
166             return;
167         }
168     }
169     else
170     {
171         Log( "error with zipfile %s in unzOpen64\n", zipfile.c_str() );
172         return;
173     }
174
175     for (i=0; i<gi.number_entry; i++)
176     {
177         char filename_inzip[256];
178         unz_file_info64 file_info;
179
180         err = unzGetCurrentFileInfo64( uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0 );
181         if (err != UNZ_OK)
182         {
183             Log( "error %d with zipfile in unzGetCurrentFileInfo\n",err);
184             break;
185         }
186
187         if (filename.compare(filename_inzip) == 0)
188         {
189             Extract( uf, location );
190             break;
191         }
192
193         if ((i+1) < gi.number_entry)
194         {
195             err = unzGoToNextFile( uf );
196             if (err != UNZ_OK)
197             {
198                 Log( "error %d with zipfile in unzGoToNextFile\n",err);
199                 break;
200             }
201         }
202     }
203
204     // Close the zip file
205     unzClose( uf );
206 }
207
208 void CZip::ExtractFiles( const string& zipfile, const string& location )
209 {
210     uint16_t i;
211     int32_t err;
212     unzFile uf=NULL;
213     unz_global_info64 gi;
214
215     uf = unzOpen64( zipfile.c_str() );
216
217     if (uf != NULL)
218     {
219         err = unzGetGlobalInfo64( uf, &gi );
220         if (err != UNZ_OK)
221         {
222             Log( "error %d with zipfile in unzGetGlobalInfo \n", err );
223             return;
224         }
225     }
226     else
227     {
228         Log( "error with zipfile in unzOpen64 \n" );
229         return;
230     }
231
232     for (i=0;i<gi.number_entry;i++)
233     {
234         if (Extract( uf, location ) != UNZ_OK)
235         {
236             break;
237         }
238
239         if ((uint16_t)(i+1) < gi.number_entry)
240         {
241             // Go the next file
242             err = unzGoToNextFile( uf );
243             if (err != UNZ_OK)
244             {
245                 Log( "error %d with zipfile in unzGoToNextFile\n", err );
246                 break;
247             }
248         }
249     }
250
251     // Close the zip file
252     unzClose( uf );
253 }
254
255 #define WRITEBUFFERSIZE (8192)
256 int32_t CZip::Extract( unzFile uf, const string& location )
257 {
258     string write_filename;
259     void*   buf;
260     char    filename_inzip[256];
261     int32_t err=UNZ_OK;
262     FILE*   fout=NULL;
263     unz_file_info64 file_info;
264
265     err = unzGetCurrentFileInfo64( uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0 );
266     if (err != UNZ_OK)
267     {
268         Log( "error %d with zipfile in unzGetCurrentFileInfo\n", err );
269         return err;
270     }
271
272     buf = (void*)malloc(WRITEBUFFERSIZE);
273     if (buf == NULL)
274     {
275         Log( "Error allocating memory\n" );
276         free(buf);
277         return UNZ_INTERNALERROR;
278     }
279
280     err = unzOpenCurrentFile( uf );
281     if (err != UNZ_OK)
282     {
283         Log( "error %d with zipfile in unzOpenCurrentFile\n", err );
284         free(buf);
285         return err;
286     }
287
288     write_filename = location + '/' + string(filename_inzip);
289
290     fout = fopen64( write_filename.c_str(), "wb" );
291
292     if (fout != NULL)
293     {
294         Log( " extracting: %s\n", write_filename.c_str() );
295
296         do {
297             err = unzReadCurrentFile( uf, buf, WRITEBUFFERSIZE );
298             if (err < 0)
299             {
300                 Log( "error %d with zipfile in unzReadCurrentFile\n",err);
301                 break;
302             }
303             if (err > 0)
304             {
305                 if (fwrite( buf, err, 1, fout ) != 1)
306                 {
307                     Log( "error in writing extracted file\n" );
308                     err = UNZ_ERRNO;
309                     break;
310                 }
311             }
312         }
313         while (err > 0);
314
315         if (fout)
316         {
317             fclose( fout );
318         }
319     }
320
321     if (err==UNZ_OK)
322     {
323         err = unzCloseCurrentFile( uf );
324         if (err != UNZ_OK)
325         {
326             Log( "error %d with zipfile in unzCloseCurrentFile\n",err);
327         }
328
329         AddUnzipFile( write_filename );
330     }
331     else
332     {
333         unzCloseCurrentFile( uf ); /* don't lose the error */
334     }
335
336     free(buf);
337     return err;
338 }
339
340 void CZip::Display64BitsSize(ZPOS64_T n, int size_char)
341 {
342   /* to avoid compatibility problem , we do here the conversion */
343   char number[21];
344   int offset=19;
345   int pos_string = 19;
346   number[20]=0;
347   for (;;) {
348       number[offset]=(char)((n%10)+'0');
349       if (number[offset] != '0')
350           pos_string=offset;
351       n/=10;
352       if (offset==0)
353           break;
354       offset--;
355   }
356   {
357       int size_display_string = 19-pos_string;
358       while (size_char > size_display_string)
359       {
360           size_char--;
361           Log( " " );
362       }
363   }
364
365   Log( "%s",&number[pos_string]);
366 }
367
368 void CZip::AddUnzipFile( const string& filename )
369 {
370     uint16_t i;
371
372     for (i=0; i<UnzipFiles.size(); i++)
373     {
374         if (UnzipFiles.at(i) == filename)
375             return;
376     }
377     UnzipFiles.push_back( filename );
378 }
379
380 void CZip::DelUnzipFiles( void )
381 {
382     uint16_t i;
383
384     for (i=0; i<UnzipFiles.size(); i++)
385     {
386 #if defined(DEBUG)
387         Log( "Removing file %s\n", UnzipFiles.at(i).c_str() );
388 #endif
389         remove( UnzipFiles.at(i).c_str() );
390     }
391     UnzipFiles.clear();
392 }
393
394 int8_t CZip::SaveUnzipList( const string& location )
395 {
396     uint8_t i;
397     ofstream   fout;
398
399     fout.open(location.c_str(), ios_base::trunc);
400
401     if (!fout)
402     {
403         Log( "Failed to open ziplist at %s\n", location.c_str() );
404         return 1;
405     }
406
407     // Write out the profile
408     if (fout.is_open())
409     {
410         for (i=0; i<UnzipFiles.size(); i++)
411         {
412             if (UnzipFiles.at(i).length()>0)
413             {
414 #if defined(DEBUG)
415                 Log( "Saving file %s to ziplist\n", UnzipFiles.at(i).c_str());
416 #endif
417                 fout << UnzipFiles.at(i) << endl;
418             }
419         }
420     }
421
422     return 0;
423 }
424
425 int8_t CZip::LoadUnzipList( const string& location )
426 {
427     string          line;
428     ifstream        fin;
429
430     fin.open(location.c_str(), ios_base::in);
431
432     if (!fin)
433     {
434         Log( "Failed to open unziplist at %s\n", location.c_str() );
435         return 0;   // Dont stop the app if it cant be opened, default values will be used and then save to file.
436     }
437
438     UnzipFiles.clear();
439
440     // Read in the profile
441     if (fin.is_open())
442     {
443         while (!fin.eof())
444         {
445             getline(fin,line);
446
447             if (line.length() > 0)
448             {
449                 UnzipFiles.push_back(line);
450             }
451         }
452     }
453
454     return 0;
455 }
456