1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU Library General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 
24 # include <limits.h>
25 
26 #include "utils.h"
27 #include "unzip.h"
28 
29 #define CASESENSITIVITY (0)
30 #define WRITEBUFFERSIZE (8192)
31 #define MAXFILENAME (256)
32 
33 static char possible_filename_in_zip[PATH_MAX];
34 
35 /*!
36  * find_possible_filename_in_zip : Look whether the given archive contains a rom
37  * @param zipfilename Name of the archive file in zip format in which to search for a rom
38  * @return NULL in case of error or no rom found else a pointer to a statically allocated
39  * storage containing the filename found inside
40  */
41 char *
find_possible_filename_in_zip(char * zipfilename)42 find_possible_filename_in_zip (char *zipfilename)
43 {
44   uLong i;
45   unz_global_info gi;
46   unzFile uf;
47   int err;
48 
49 #if !defined(FINAL_RELEASE)
50   fprintf (stderr,
51 	   "entering function to find a possible rom name in the archive %s\n",
52 	   zipfilename);
53 #endif
54 
55   if (zipfilename == NULL)
56     return NULL;
57 
58   uf = unzOpen (zipfilename);
59 
60   if (uf == NULL)
61     {
62       strcat (zipfilename, ".zip");
63       uf = unzOpen (zipfilename);
64     }
65 
66   if (uf == NULL)
67     return NULL;
68 
69 #if !defined(FINAL_RELEASE)
70   fprintf (stderr, "Opened the archive");
71 #endif
72 
73   err = unzGetGlobalInfo (uf, &gi);
74   if (err != UNZ_OK)
75     {
76       return NULL;
77     }
78 
79   for (i = 0; i < gi.number_entry; i++)
80     {
81       char filename_inzip[256];
82       unz_file_info file_info;
83 
84 #if !defined(FINAL_RELEASE)
85       fprintf (stderr, "Testing entry #%ld\n", i);
86 #endif
87 
88       err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip,
89 				   sizeof (filename_inzip), NULL, 0, NULL, 0);
90 
91       if (err != UNZ_OK)
92 	{
93 	  return NULL;
94 	}
95 
96 #if !defined(FINAL_RELEASE)
97       fprintf (stderr, "Filename for this entry is %s\n", filename_inzip);
98 #endif
99 
100       if (strcasestr (filename_inzip, ".PCE"))
101 	{
102 	  strncpy (possible_filename_in_zip, filename_inzip, PATH_MAX);
103 	  return possible_filename_in_zip;
104 	}
105 
106       if ((i + 1) < gi.number_entry)
107 	{
108 	  err = unzGoToNextFile (uf);
109 	  if (err != UNZ_OK)
110 	    {
111 	      return NULL;
112 	    }
113 	}
114     }
115 
116   return NULL;
117 }
118 
119 /*!
120  * do_extract_currentfile_in_memory : Extract the current pointed file in the zip archive into a buffer
121  * @param uf the archive file handle
122  * @param unzipped_size a pointer to the size of the unzipped data, it is filled by this function for caller
123  * @return uncompressed data as pointer, to be freed by caller or NULL in case of problem
124  */
125 static char *
do_extract_currentfile_in_memory(unzFile uf,size_t * unzipped_size)126 do_extract_currentfile_in_memory (unzFile uf, size_t * unzipped_size)
127 {
128   char filename_inzip[256];
129   char *filename_withoutpath;
130   char *p;
131   int err = UNZ_OK;
132   FILE *fout = NULL;
133   void *buf;
134   uInt size_buf;
135   unz_file_info file_info;
136   char *return_value = NULL;
137 
138   err = unzGetCurrentFileInfo (uf, &file_info, filename_inzip,
139 			       sizeof (filename_inzip), NULL, 0, NULL, 0);
140 
141   if (err != UNZ_OK)
142     {
143       Log ("error %d with zipfile in unzGetCurrentFileInfo\n", err);
144       return NULL;
145     }
146 
147   size_buf = WRITEBUFFERSIZE;
148   buf = (void *) malloc (size_buf);
149   if (buf == NULL)
150     {
151       Log ("Error allocating memory\n");
152       return UNZ_INTERNALERROR;
153     }
154 
155   p = filename_withoutpath = filename_inzip;
156   while ((*p) != '\0')
157     {
158       if (((*p) == '/') || ((*p) == '\\'))
159 	filename_withoutpath = p + 1;
160       p++;
161     }
162 
163   if ((*filename_withoutpath) != '\0')
164     {
165       const char *write_filename;
166       int skip = 0;
167 
168       write_filename = filename_withoutpath;
169 
170       err = unzOpenCurrentFile (uf);
171       if (err != UNZ_OK)
172 	{
173 	  Log ("error %d with zipfile in unzOpenCurrentFile\n", err);
174 	  return NULL;
175 	}
176 
177       *unzipped_size = 0;
178 
179       do
180 	{
181 	  err = unzReadCurrentFile (uf, buf, size_buf);
182 	  if (err < 0)
183 	    {
184 	      Log ("error %d with zipfile in unzReadCurrentFile\n", err);
185 	      break;
186 	    }
187 	  if (err > 0)
188 	    {
189 	      *unzipped_size += err;
190 	      return_value = realloc (return_value, *unzipped_size);
191 	      if (return_value == NULL)
192 		{
193 		  err = UNZ_ERRNO;
194 		  break;
195 		}
196 	      memcpy (return_value + *unzipped_size - err, buf, err);
197 	    }
198 	}
199       while (err > 0);
200 
201       if (err != UNZ_OK)
202 	{
203 	  Log ("Error %s with zipfile in uncompressing\n", strerror (errno));
204 	}
205 
206       err = unzCloseCurrentFile (uf);
207       if (err != UNZ_OK)
208 	{
209 	  Log ("error %d with zipfile in unzCloseCurrentFile\n", err);
210 	}
211     }
212 
213   free (buf);
214   return return_value;
215 }
216 
217 /*!
218  * do_extract_onefile_in_memory : Extract an archived file into a buffer
219  * @param uf Handle to the archive in ip format in which to read data
220  * @param filename Name of the file archived in the zip file the data of which we want
221  * @param unzipped_size Pointer to the size of the extracted data
222  * @return NULL in case of problem or a pointer to the archived file content. It is allocated
223  */
224 static char *
do_extract_onefile_in_memory(unzFile uf,const char * filename,size_t * unzipped_size)225 do_extract_onefile_in_memory (unzFile uf, const char *filename,
226 			      size_t * unzipped_size)
227 {
228   if (unzLocateFile (uf, filename, CASESENSITIVITY) != UNZ_OK)
229     {
230       Log ("file %s not found in the zipfile\n", filename);
231       return NULL;
232     }
233 
234   return do_extract_currentfile_in_memory (uf, unzipped_size);
235 }
236 
237 /*!
238  * extract_file_in_memory : Extract an archived file into a buffer
239  * @param zipfilename Name of the archive in zip format in which to read data
240  * @param archivedfile Name of the file archived in the zip file the data of which we want
241  * @param unzipped_size Pointer to the size of the extracted data
242  * @return NULL in case of problem or a pointer to the archived file content. It is allocated
243  * dynamically and needs to be explicitely freed
244  */
245 extern char *
extract_file_in_memory(char * zipfilename,char * archivedfile,size_t * unzipped_size)246 extract_file_in_memory (char *zipfilename, char *archivedfile,
247 			size_t * unzipped_size)
248 {
249   unzFile uf;
250   int err;
251   char *return_value;
252 
253   if (zipfilename == NULL)
254     return NULL;
255 
256   uf = unzOpen (zipfilename);
257 
258   if (uf == NULL)
259     {
260       strcat (zipfilename, ".zip");
261       uf = unzOpen (zipfilename);
262     }
263 
264   if (uf == NULL)
265     return NULL;
266 
267   return_value =
268     do_extract_onefile_in_memory (uf, archivedfile, unzipped_size);
269 
270   unzCloseCurrentFile (uf);
271 
272   return return_value;
273 }
274