Annotation of hatari/src/zip.c, revision 1.1.1.4

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: 
1.1.1.4 ! root        7:   Zipped disk support, uses zlib
1.1       root        8: */
1.1.1.4 ! root        9: char ZIP_rcsid[] = "Hatari $Id: zip.c,v 1.13 2005/09/26 15:20:14 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.4 ! root      288: static long ZIP_CheckImageFile(unzFile uf, char *filename, int *pDiskType)
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.4 ! root      307:       *pDiskType = 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.4 ! root      313:       *pDiskType = 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:     {
1.1.1.4 ! root      319:       *pDiskType = ZIP_FILE_DIM;
1.1.1.2   root      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.4 ! root      371: static void *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.4 ! root      427: Uint8 *ZIP_ReadDisk(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;
1.1.1.4 ! root      432:   int nDiskType = -1;
1.1       root      433:   BOOL pathAllocated=FALSE;
1.1.1.4 ! root      434:   Uint8 *pDiskBuffer = NULL;
1.1.1.2   root      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.4 ! root      456:   if((ImageSize = ZIP_CheckImageFile(uf, pszZipPath, &nDiskType)) <= 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.4 ! root      471:   if (nDiskType == ZIP_FILE_ST)
1.1.1.2   root      472:     {
                    473:       /* ST image => return buffer directly */
1.1.1.4 ! root      474:       pDiskBuffer = buf;
1.1.1.2   root      475:     }
1.1.1.4 ! root      476:   else if (nDiskType == ZIP_FILE_MSA)
1.1       root      477:     {
                    478:       /* uncompress the MSA file */
1.1.1.4 ! root      479:       pDiskBuffer = MSA_UnCompress(buf, &ImageSize);
1.1       root      480:     }
1.1.1.4 ! root      481:   else if (nDiskType == ZIP_FILE_DIM)
1.1.1.2   root      482:     {
                    483:       /* Skip DIM header */
                    484:       ImageSize -= 32;
1.1.1.4 ! root      485:       pDiskBuffer = malloc(ImageSize);
        !           486:       if (pDiskBuffer)
        !           487:         memcpy(pDiskBuffer, buf+32, ImageSize);
1.1.1.2   root      488:       else
1.1.1.4 ! root      489:         perror("ZIP_ReadDisk");
1.1.1.2   root      490:     }
                    491: 
                    492:   /* Free the buffers */
1.1.1.4 ! root      493:   if (pDiskBuffer != 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.4 ! root      498:   if (pDiskBuffer != NULL)
1.1.1.2   root      499:     *pImageSize = ImageSize;
                    500: 
1.1.1.4 ! root      501:   return pDiskBuffer;
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: */
1.1.1.4 ! root      511: BOOL ZIP_WriteDisk(char *pszFileName,unsigned char *pBuffer,int ImageSize)
1.1       root      512: {
                    513:   return(FALSE);
                    514: }
                    515: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.