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