|
|
1.1 root 1: /*
2: Hatari
3:
4: Zipped disc support, uses zlib
5: */
6:
7: #include <stdio.h>
8: #include <stdlib.h>
9: #include <string.h>
10: #include <unistd.h>
11: #include <dirent.h>
12:
13: #include "zlib.h"
14: #include "main.h"
15: #include "msa.h"
16: #include "floppy.h"
17: #include "file.h"
18: #include "errlog.h"
19: #include "unzip.h"
20: #include "zip.h"
21: #include "memAlloc.h"
22:
23: #define SAVE_TO_GZIP_IMAGES
24: /* #define SAVE_TO_ZIP_IMAGES */
25:
26: #define ZIP_PATH_MAX 256
27:
28: #define ZIP_FILE_ST 1
29: #define ZIP_FILE_MSA 2
30:
31:
32: int Zip_FileNameHasSlash(char *fn)
33: {
34: int i=0;
35: while( fn[i] != '\0' )
36: {
37: if( fn[i] == '\\' || fn[i] == '/') return( i );
38: i++;
39: }
40: return( -1 );
41: }
42:
43: /*-----------------------------------------------------------------------*/
44: /*
45: Returns a list of files from a zip file. returns NULL on failure,
46: returns a pointer to an array of strings if successful. Sets nfiles
47: to the number of files.
48: */
49: zip_dir *ZIP_GetFiles(char *pszFileName)
50: {
51: int nfiles;
52: int i;
53: unz_global_info gi;
54: int err;
55: unzFile uf;
56: char **filelist;
57: unz_file_info file_info;
58: char filename_inzip[ZIP_PATH_MAX];
59: zip_dir *zd;
60:
61: uf = unzOpen(pszFileName);
62: if (uf==NULL)
63: {
64: printf("Cannot open %s\n", pszFileName);
65: return(0);
66: }
67:
68: err = unzGetGlobalInfo (uf,&gi);
69: if (err!=UNZ_OK){
70: printf("error %d with zipfile in unzGetGlobalInfo \n",err);
71: return(NULL);
72: }
73:
74: /* allocate a file list */
75: filelist = (char **)Memory_Alloc(gi.number_entry*sizeof(char *));
76: nfiles = gi.number_entry; /* set the number of files */
77:
78: for(i=0;i<gi.number_entry;i++)
79: {
80: err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip, ZIP_PATH_MAX,NULL,0,NULL,0);
81: if (err!=UNZ_OK)
82: {
83: Memory_Free(filelist);
84: return(NULL);
85: }
86: filelist[i] = (char *)Memory_Alloc(strlen(filename_inzip) + 1);
87: strcpy(filelist[i], filename_inzip);
88: if ((i+1)<gi.number_entry)
89: {
90: err = unzGoToNextFile(uf);
91: if (err!=UNZ_OK)
92: {
93: ErrLog_File("ERROR ZIP_GetFiles with zipfile\n");
94: /* deallocate memory */
95: for(;i>0;i--)Memory_Free(filelist[i]);
96: Memory_Free(filelist);
97: return(NULL);
98: }
99: }
100: }
101:
102: zd = (zip_dir *)Memory_Alloc(sizeof(zip_dir));
103: zd->names = filelist;
104: zd->nfiles = nfiles;
105: return( zd );
106: }
107:
108: /*-----------------------------------------------------------------------*/
109: /*
110: Returns a list of files from the directory (dir) in a zip file list (zip)
111: sets entries to the number of entries and returns a dirent structure, or
112: NULL on failure. NOTE: only f_name is set in the dirent structures.
113: */
114: struct dirent **ZIP_GetFilesDir(zip_dir *zip, char *dir, int *entries)
115: {
116: int i,j;
117: zip_dir *files;
118: char *temp;
119: BOOL flag;
120: int slash;
121: struct dirent **fentries;
122:
123: files = (zip_dir *)Memory_Alloc(sizeof(zip_dir));
124: files->names = (char **)Memory_Alloc(zip->nfiles * sizeof(char *));
125:
126: /* add ".." directory */
127: files->nfiles = 1;
128: temp = (char *)Memory_Alloc(4);
129: temp[0] = temp[1] = '.';
130: temp[2] = '/'; temp[3] = '\0';
131: files->names[0] = temp;
132:
133: for(i=0;i<zip->nfiles;i++)
134: {
135: if(strlen(zip->names[i]) > strlen(dir))
136: {
137: if(strncasecmp(zip->names[i], dir, strlen(dir)) == 0)
138: {
139: temp = zip->names[i];
140: temp = (char *)(temp + strlen(dir));
141: if( temp[0] != '\0')
142: {
143: if( (slash=Zip_FileNameHasSlash(temp)) > 0)
144: {
145: /* file is in a subdirectory, add this subdirectory if it doesn't exist in the list */
146: flag = FALSE;
147: for(j = files->nfiles-1;j>0;j--)
148: if(strncasecmp(temp, files->names[j], slash+1) == 0)
149: flag=TRUE;
150: if( flag == FALSE )
151: {
152: files->names[files->nfiles] = (char *)Memory_Alloc(slash+1);
153: strncpy(files->names[files->nfiles], temp, slash+1);
154: ((char *)files->names[files->nfiles])[slash+1] = '\0';
155: files->nfiles++;
156: }
157: }
158: else
159: {
160: /* add a filename */
161: files->names[files->nfiles] = (char *)Memory_Alloc(strlen(temp)+1);
162: strncpy(files->names[files->nfiles], temp, strlen(temp));
163: ((char *)files->names[files->nfiles])[strlen(temp)] = '\0';
164: files->nfiles++;
165: }
166: }
167: }
168: }
169: }
170:
171: /* copy to a dirent structure */
172: *entries = files->nfiles;
173: fentries = (struct dirent **)Memory_Alloc(sizeof(struct dirent *)*files->nfiles);
174: for(i=0; i<files->nfiles; i++)
175: {
176: fentries[i] = (struct dirent *)Memory_Alloc(sizeof(struct dirent));
177: strcpy(fentries[i]->d_name, files->names[i]);
178: Memory_Free(files->names[i]);
179: }
180: Memory_Free(files);
181: return(fentries);
182: }
183:
184: /*-----------------------------------------------------------------------*/
185: /*
186: Check an image file in the archive, return the uncompressed length
187: */
188: long ZIP_CheckImageFile(unzFile uf, char *filename, int *ST_or_MSA)
189: {
190: unz_file_info file_info;
191:
192: if (unzLocateFile(uf,filename, 0)!=UNZ_OK)
193: {
194: fprintf(stderr, "Error: File \"%s\"not found in the archive!", filename);
195: return(-1);
196: }
197:
198: if( unzGetCurrentFileInfo(uf,&file_info,filename, ZIP_PATH_MAX,NULL,0,NULL,0) != UNZ_OK)
199: {
200: fprintf(stderr, "Error with zipfile in unzGetCurrentFileInfo \n");
201: return(-1);
202: }
203:
204: /* check for a .msa or .st extention */
205: if(File_FileNameIsMSA(filename))
206: {
207: *ST_or_MSA = ZIP_FILE_MSA;
208: return( file_info.uncompressed_size );
209: }
210:
211: if(File_FileNameIsST(filename))
212: {
213: *ST_or_MSA = ZIP_FILE_ST;
214: return( file_info.uncompressed_size );
215: }
216:
217: fprintf(stderr, "Not an .ST or .MSA file.\n");
218: return(0);
219: }
220:
221: /*-----------------------------------------------------------------------*/
222: /*
223: Return the first .zip or .msa file in a zip, or NULL on failure
224: */
225: char *ZIP_FirstFile(char *filename)
226: {
227: zip_dir *files;
228: int i;
229: char *name;
230:
231: if((files = ZIP_GetFiles(filename)) == NULL) return(NULL);
232: name = Memory_Alloc(ZIP_PATH_MAX);
233:
234: name[0] = '\0';
235: for(i=files->nfiles-1;i>=0;i--)
236: if(File_FileNameIsMSA(files->names[i]) ||
237: File_FileNameIsST(files->names[i]))
238: strncpy(name, files->names[i], ZIP_PATH_MAX);
239:
240: /* free the files */
241: for(i=0;i<files->nfiles;i++)
242: Memory_Free(files->names[i]);
243: Memory_Free(files);
244:
245: if(name[0] == '\0')
246: return(NULL);
247: return(name);
248: }
249:
250:
251: /*-----------------------------------------------------------------------*/
252: /*
253: Extract a file (filename) from a ZIP-file (uf), the number of
254: bytes to uncompress is size. Returns a pointer to a buffer containing
255: the uncompressed data, or NULL.
256: */
257: char *ZIP_ExtractFile(unzFile uf, char *filename, uLong size)
258: {
259: int err = UNZ_OK;
260: char filename_inzip[ZIP_PATH_MAX];
261: FILE *fout=NULL;
262: void* buf;
263: uInt size_buf;
264:
265: unz_file_info file_info;
266: uLong ratio=0;
267:
268:
269: if (unzLocateFile(uf,filename, 0)!=UNZ_OK)
270: {
271: fprintf(stderr, "ERROR ZIP_ExtractFile could not find file in archive\n");
272: ErrLog_File("ERROR ZIP_ExtractFile could not find file in archive\n");
273: return NULL;
274: }
275:
276: err = unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
277:
278: if (err!=UNZ_OK)
279: {
280: fprintf(stderr, "ERROR ZIP_ExtractFile could not find file in archive\n");
281: ErrLog_File("ERROR ZIP_ExtractFile could not get file info\n");
282: return NULL;
283: }
284:
285: size_buf = size;
286: buf = Memory_Alloc(size_buf);
287:
288: err = unzOpenCurrentFile(uf);
289: if (err!=UNZ_OK)
290: {
291: fprintf(stderr, "ERROR ZIP_ExtractFile could not find file in archive\n");
292: ErrLog_File("ERROR ZIP_ExtractFile could not open file\n");
293: return(NULL);
294: }
295:
296: do
297: {
298: err = unzReadCurrentFile(uf,buf,size_buf);
299: if (err<0)
300: {
301: fprintf(stderr, "ERROR ZIP_ExtractFile could not find file in archive\n");
302: ErrLog_File("ERROR ZIP_ExtractFile could not read file\n");
303: return(NULL);
304: }
305: } while (err>0);
306:
307: return buf;
308: }
309:
310: /*-----------------------------------------------------------------------*/
311: /*
312: Load .ZIP file into memory, return number of bytes loaded
313:
314: */
315: int ZIP_ReadDisc(char *pszFileName, char *pszZipPath, unsigned char *pBuffer)
316: {
317: uLong ImageSize=0;
318: char *temp;
319: unzFile uf=NULL;
320: char *buf;
321: int ST_or_MSA;
322: BOOL pathAllocated=FALSE;
323:
324: uf = unzOpen(pszFileName);
325: if (uf==NULL)
326: {
327: printf("Cannot open %s\n", pszFileName);
328: return(0);
329: }
330:
331: if (pszZipPath == NULL || pszZipPath[0] == 0)
332: {
333: if((pszZipPath = ZIP_FirstFile(pszFileName)) == NULL)
334: {
335: printf("Cannot open %s\n", pszFileName);
336: return(0);
337: }
338: pathAllocated=TRUE;
339: }
340:
341: if((ImageSize = ZIP_CheckImageFile(uf, pszZipPath, &ST_or_MSA)) <= 0)
342: {
343: return(0);
344: }
345:
346: if(ImageSize > DRIVE_BUFFER_BYTES)
347: {
348: ErrLog_File("ERROR ZIP_ReadDisc uncompressed .msa or .st file is larger than buffer\n");
349: return(0);
350: }
351:
352: /* extract to buf */
353: buf=ZIP_ExtractFile(uf, pszZipPath, ImageSize);
354: unzCloseCurrentFile(uf);
355: if(buf == NULL)
356: {
357: return(0); /* failed extraction, return error */
358: }
359:
360: if(ST_or_MSA == ZIP_FILE_ST)
361: {
362: /* copy the ST image */
363: memcpy(pBuffer, buf, (size_t)ImageSize);
364: } else {
365: /* uncompress the MSA file */
366: ImageSize = MSA_UnCompress(buf, pBuffer);
367: }
368:
369: /* Free the buffer */
370: Memory_Free(buf);
371: if(pathAllocated == TRUE)
372: Memory_Free(pszZipPath);
373:
374: return(ImageSize);
375: }
376:
377:
378: /*-----------------------------------------------------------------------*/
379: /*
380: Save .ZIP file from memory buffer. Returns TRUE is all OK
381:
382: Not yet implemented.
383: */
384: BOOL ZIP_WriteDisc(char *pszFileName,unsigned char *pBuffer,int ImageSize)
385: {
386: return(FALSE);
387: }
388:
389: /*-----------------------------------------------------------------------*/
390: /*
391: Load .GZ file into memory, return number of bytes loaded
392:
393: */
394: int GZIP_ReadDisc(char *pszFileName,unsigned char *pBuffer)
395: {
396: /* allocate buffer to store uncompressed bytes */
397: long ImageSize=0;
398: char *buf;
399: gzFile in;
400: int err=0;
401:
402: if((in = gzopen(pszFileName, "rb")) == NULL)
403: {
404: fprintf(stderr, "Error: could not open %s\n", pszFileName);
405: return(0);
406: }
407:
408: buf = (char *)Memory_Alloc(DRIVE_BUFFER_BYTES);
409: do {
410: ImageSize += err;
411: err = gzread(in, (char *)(buf + ImageSize), 256);
412: } while(err > 0 && ImageSize < DRIVE_BUFFER_BYTES);
413:
414: if(err < 0 || ImageSize >= DRIVE_BUFFER_BYTES)
415: {
416: fprintf(stderr, "Error: could not decompress %s\n", pszFileName);
417: return(0);
418: }
419:
420: gzclose(in);
421:
422: /* is it a gzipped .ST or .MSA file? */
423: if(File_FileNameIsSTGZ(pszFileName))
424: {
425: /* copy the ST image */
426: memcpy(pBuffer, buf, (size_t)ImageSize);
427: } else {
428: /* uncompress the MSA file */
429: ImageSize = MSA_UnCompress(buf, pBuffer);
430: }
431:
432: Memory_Free(buf);
433: return(ImageSize);
434: }
435:
436: /*-----------------------------------------------------------------------*/
437: /*
438: Save .GZ file from memory buffer. Returns TRUE is all OK
439:
440: Not yet implemented.
441: */
442: BOOL GZIP_WriteDisc(char *pszFileName,unsigned char *pBuffer,int ImageSize)
443: {
444: #ifdef SAVE_TO_GZIP_IMAGES
445: gzFile out;
446: int size;
447:
448: /* is it a gzipped .ST or .MSA file? */
449: if(File_FileNameIsSTGZ(pszFileName))
450: {
451: if((out = gzopen(pszFileName, "wb6 ")) == NULL)
452: {
453: fprintf(stderr, "Could not write to %s\n", pszFileName);
454: return(FALSE);
455: }
456:
457: if(gzwrite(out, pBuffer, ImageSize) != ImageSize)
458: {
459: fprintf(stderr, "Could not write to %s\n", pszFileName);
460: return(FALSE);
461: }
462: fprintf(stderr,"wrote %s\n", pszFileName);
463: gzclose(out);
464: } else {
465: }
466:
467: return(TRUE);
468:
469: #else
470: return(FALSE);
471: #endif
472: }
473:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.