|
|
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.