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