1 /*
2  * This file is part of NumptyPhysics
3  * Copyright (C) 2008 Tim Edmonds
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 3 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  */
16 
17 #include "ZipFile.h"
18 #include <string>
19 #include <cstring>
20 #include <cstdio>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include <zlib.h>
26 
27 //zip file structs and uncompress_int below lifted from navit project (GPL).
28 struct zip_lfh {
29 	int ziplocsig;
30 	short zipver;
31 	short zipgenfld;
32 	short zipmthd;
33 	short ziptime;
34 	short zipdate;
35 	int zipcrc;
36 	unsigned int zipsize;
37 	unsigned int zipuncmp;
38 	unsigned short zipfnln;
39 	unsigned short zipxtraln;
40 	char zipname[0];
41 } __attribute__ ((packed));
42 
43 struct zip_cd {
44 	int zipcensig;
45 	char zipcver;
46 	char zipcos;
47 	char zipcvxt;
48 	char zipcexos;
49 	short zipcflg;
50 	short zipcmthd;
51 	short ziptim;
52 	short zipdat;
53 	int zipccrc;
54 	unsigned int zipcsiz;
55 	unsigned int zipcunc;
56 	unsigned short zipcfnl;
57 	unsigned short zipcxtl;
58 	unsigned short zipccml;
59 	unsigned short zipdsk;
60 	unsigned short zipint;
61 	unsigned int zipext;
62 	unsigned int zipofst;
63 	char zipcfn[0];
64 } __attribute__ ((packed));
65 
66 struct zip_eoc {
67 	int zipesig;
68 	unsigned short zipedsk;
69 	unsigned short zipecen;
70 	unsigned short zipenum;
71 	unsigned short zipecenn;
72 	unsigned int zipecsz;
73 	unsigned int zipeofst;
74 	short zipecoml;
75 	char zipecom[0];
76 } __attribute__ ((packed));
77 
uncompress_int(unsigned char * dest,int * destLen,const unsigned char * source,int sourceLen)78 int uncompress_int(unsigned char *dest, int *destLen,
79 		   const unsigned char *source, int sourceLen)
80 {
81   z_stream stream;
82   int err;
83 
84   stream.next_in = (Bytef*)source;
85   stream.avail_in = (uInt)sourceLen;
86   stream.next_out = dest;
87   stream.avail_out = (uInt)*destLen;
88 
89   stream.zalloc = (alloc_func)0;
90   stream.zfree = (free_func)0;
91 
92   err = inflateInit2(&stream, -MAX_WBITS);
93   if (err != Z_OK) return err;
94 
95   err = inflate(&stream, Z_FINISH);
96   if (err != Z_STREAM_END) {
97     inflateEnd(&stream);
98     if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
99       return Z_DATA_ERROR;
100     return err;
101     }
102   *destLen = stream.total_out;
103 
104   err = inflateEnd(&stream);
105   return err;
106 }
107 
108 
109 
ZipFile(const std::string & fn)110 ZipFile::ZipFile(const std::string& fn)
111 {
112   m_temp = NULL;
113   m_fd=open(fn.c_str(), O_RDONLY);
114   struct stat stat;
115   fstat(m_fd, &stat);
116   m_dataLen = stat.st_size;
117   // TODO - win32
118   m_data = (unsigned char*)mmap(NULL,m_dataLen,PROT_READ,MAP_PRIVATE, m_fd, 0);
119   if ( !m_data ) throw "mmap failed";
120   if ( *(int*)&m_data[0] != 0x04034b50 ) throw "bad zip magic";
121   m_eoc = (zip_eoc*)&m_data[m_dataLen-sizeof(zip_eoc)];
122   m_firstcd = (zip_cd*)&m_data[m_eoc->zipeofst];
123   if ( m_eoc && m_firstcd ) {
124     m_entries = m_eoc->zipenum;
125   } else {
126     m_entries = 0;
127   }
128 }
129 
130 
~ZipFile()131 ZipFile::~ZipFile()
132 {
133   delete[] m_temp;
134   if ( m_data ) munmap( m_data, m_dataLen );
135   if ( m_fd ) close( m_fd );
136 }
137 
138 
entryName(int n)139 std::string ZipFile::entryName( int n )
140 {
141   if ( n < 0 || n >= m_entries ) return std::string();
142   zip_cd* cd = m_firstcd;
143   for ( int count=0; cd < (zip_cd*)m_eoc && count < n; count++ ) {
144     cd = (zip_cd*)(((char*)cd) + sizeof(zip_cd) + cd->zipcfnl + cd->zipcxtl + cd->zipccml);
145   }
146   zip_lfh* lfh = (zip_lfh*)&m_data[cd->zipofst];
147 
148   if ( lfh ) {
149     return std::string(lfh->zipname,lfh->zipfnln);
150   }
151   return std::string();
152 }
153 
extract(int n,int * l)154 unsigned char* ZipFile::extract( int n, int *l )
155 {
156   if ( n < 0 || n >= m_entries ) return NULL;
157   zip_cd* cd = m_firstcd;
158   for ( int count=0; cd < (zip_cd*)m_eoc && count < n; count++ ) {
159     cd = (zip_cd*)(((char*)cd) + sizeof(zip_cd) + cd->zipcfnl + cd->zipcxtl + cd->zipccml);
160   }
161   zip_lfh* lfh = (zip_lfh*)&m_data[cd->zipofst];
162 
163   if ( lfh ) {
164     *l = lfh->zipuncmp;
165     unsigned char* zdat = (unsigned char*)lfh + sizeof(*lfh) + lfh->zipfnln + lfh->zipxtraln;
166     switch (lfh->zipmthd) {
167     case 0:
168       return zdat;
169     case 8:
170       delete[] m_temp;
171       m_temp = new unsigned char[*l];
172       if ( uncompress_int(m_temp, l, zdat, lfh->zipsize) == Z_OK) {
173 	return m_temp;
174       }
175     }
176   }
177   return NULL;
178 }
179 
180 
181 
182 
183