initial upstream import
[drnoksnes] / loadzip.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41  
42 #include "port.h"
43
44 #ifdef UNZIP_SUPPORT
45 /**********************************************************************************************/
46 /* Loadzip.CPP                                                                                */
47 /* This file contains a function for loading a SNES ROM image from a zip file                 */
48 /**********************************************************************************************/
49
50 #include <string.h>
51 #include <ctype.h>
52
53 #ifndef NO_INLINE_SET_GET
54 #define NO_INLINE_SET_GET
55 #endif
56
57 #include "snes9x.h"
58 #include "memmap.h"
59
60 #include "unzip.h"
61 //#include <assert.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64
65 bool8 LoadZip(const char* zipname,
66               int32 *TotalFileSize,
67               int32 *headers)
68 {
69     *TotalFileSize = 0;
70     *headers = 0;
71     
72     unzFile file = unzOpen(zipname);
73     if(file == NULL)
74         return (FALSE);
75
76     // find largest file in zip file (under MAX_ROM_SIZE)
77     // or a file with extension .1
78     char filename[132];
79     int filesize = 0;
80     int port = unzGoToFirstFile(file);
81     unz_file_info info;
82     while(port == UNZ_OK)
83     {
84         char name[132];
85         unzGetCurrentFileInfo(file, &info, name,128, NULL,0, NULL,0);
86
87 #if 0
88         int calc_size = info.uncompressed_size / 0x2000;
89         calc_size *= 0x2000;
90         if(!(info.uncompressed_size - calc_size == 512 || info.uncompressed_size == calc_size))
91         {
92             port = unzGoToNextFile(file);
93             continue;
94         }
95 #endif
96
97         if(info.uncompressed_size > (CMemory::MAX_ROM_SIZE + 512))
98         {
99             port = unzGoToNextFile(file);
100             continue;
101         }
102         
103         if ((int) info.uncompressed_size > filesize)
104         {
105             strcpy(filename,name);
106             filesize = info.uncompressed_size;
107         }
108         int len = strlen(name);
109         if(name[len-2] == '.' && name[len-1] == '1')
110         {
111             strcpy(filename,name);
112             filesize = info.uncompressed_size;
113             break;
114         }
115         port = unzGoToNextFile(file);
116     }
117     if( !(port == UNZ_END_OF_LIST_OF_FILE || port == UNZ_OK) || filesize == 0)
118     {
119         unzClose(file);
120         return (FALSE);
121     }
122
123     // Find extension
124     char tmp[2];
125     tmp[0] = tmp[1] = 0;
126     char *ext = strrchr(filename,'.');
127     if(ext) ext++;
128     else ext = tmp;
129     
130     uint8 *ptr = Memory.ROM;
131     bool8 more = FALSE;
132
133     unzLocateFile(file,filename,1);
134     unzGetCurrentFileInfo(file, &info, filename,128, NULL,0, NULL,0);
135     
136     if( unzOpenCurrentFile(file) != UNZ_OK )
137     {
138         unzClose(file);
139         return (FALSE);
140     }
141
142     do
143     {
144 //      assert(info.uncompressed_size <= CMemory::MAX_ROM_SIZE + 512);
145         int FileSize = info.uncompressed_size;
146         
147         int calc_size = FileSize / 0x2000;
148         calc_size *= 0x2000;
149         
150         int l = unzReadCurrentFile(file,ptr,FileSize);
151         if(unzCloseCurrentFile(file) == UNZ_CRCERROR)
152         {
153                 unzClose(file);
154             return (FALSE);
155         }
156         
157         if(l <= 0 || l != FileSize)
158         {
159             unzClose(file);
160             switch(l)
161             {
162                 case UNZ_ERRNO:
163                     break;
164                 case UNZ_EOF:
165                     break;
166                 case UNZ_PARAMERROR:
167                     break;
168                 case UNZ_BADZIPFILE:
169                     break;
170                 case UNZ_INTERNALERROR:
171                     break;
172                 case UNZ_CRCERROR:
173                     break;
174             }
175             return (FALSE);
176         }
177
178         if ((FileSize - calc_size == 512 && !Settings.ForceNoHeader) ||
179             Settings.ForceHeader)
180         {
181             memmove (ptr, ptr + 512, calc_size);
182             (*headers)++;
183             FileSize -= 512;
184         }
185         ptr += FileSize;
186         (*TotalFileSize) += FileSize;
187
188         int len;
189         if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 0x200 &&
190             (isdigit (ext [0]) && ext [1] == 0 && ext [0] < '9'))
191         {
192             more = TRUE;
193             ext [0]++;
194         }
195         else if (ptr - Memory.ROM < CMemory::MAX_ROM_SIZE + 0x200 &&
196                  (((len = strlen (filename)) == 7 || len == 8) &&
197                   strncasecmp (filename, "sf", 2) == 0 &&
198                   isdigit (filename [2]) && isdigit (filename [3]) && isdigit (filename [4]) &&
199                   isdigit (filename [5]) && isalpha (filename [len - 1])))
200         {
201             more = TRUE;
202             filename [len - 1]++;
203         }
204         else
205             more = FALSE;
206         
207         if(more)
208         {
209             if( unzLocateFile(file,filename,1) != UNZ_OK ||
210                 unzGetCurrentFileInfo(file, &info, filename,128, NULL,0, NULL,0) != UNZ_OK ||
211                 unzOpenCurrentFile(file) != UNZ_OK)
212                 break;
213         }
214         
215     } while(more);
216     
217     unzClose(file);
218     return (TRUE);
219 }
220 #endif