1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_shell.hxx"
26 #include "zipexcptn.hxx"
27 #include "internal/zipfile.hxx"
28 #include "internal/global.hxx"
29 
30 #include <malloc.h>
31 #include <algorithm>
32 #include <functional>
33 
34 #include <string.h>
35 
36 #ifdef OS2
37 #include <alloca.h>
38 #define _alloca alloca
39 #define ERROR_NOT_ENOUGH_MEMORY 8
40 #endif
41 
42 namespace internal
43 {
44     /* for case in-sensitive string comparison */
45     struct stricmp : public std::unary_function<std::string, bool>
46     {
stricmpinternal::stricmp47         stricmp(const std::string& str) : str_(str)
48         {}
49 
operator ()internal::stricmp50         bool operator() (const std::string& other)
51         { return (0 == _stricmp(str_.c_str(), other.c_str())); }
52 
53         std::string str_;
54     };
55 } // namespace internal
56 
57 /** Checks whether a file is a zip file or not
58 
59 	@precond	The given parameter must be a string with length > 0
60 			The file must exist
61 			The file must be readable for the current user
62 
63 	@returns	true if the file is a zip file
64 			false if the file is not a zip file
65 
66 	@throws	ParameterException if the given file name is empty
67 			IOException if the specified file doesn't exist
68 			AccessViolationException if read access to the file is denied
69 */
IsZipFile(const std::string &)70 bool ZipFile::IsZipFile(const std::string& /*FileName*/)
71 {
72 	return true;
73 }
74 
IsZipFile(void *)75 bool ZipFile::IsZipFile(void* /*stream*/)
76 {
77 	return true;
78 }
79 
80 
81 /** Returns wheter the version of the specified zip file may be uncompressed with the
82 	      currently used zlib version or not
83 
84 	@precond	The given parameter must be a string with length > 0
85 			The file must exist
86 			The file must be readable for the current user
87 			The file must be a valid zip file
88 
89 	@returns	true if the file may be uncompressed with the currently used zlib
90 			false if the file may not be uncompressed with the currently used zlib
91 
92 	@throws	ParameterException if the given file name is empty
93 			IOException if the specified file doesn't exist or is no zip file
94 			AccessViolationException if read access to the file is denied
95 */
IsValidZipFileVersionNumber(const std::string &)96 bool ZipFile::IsValidZipFileVersionNumber(const std::string& /*FileName*/)
97 {
98 	return true;
99 }
100 
IsValidZipFileVersionNumber(void *)101 bool ZipFile::IsValidZipFileVersionNumber(void* /* stream*/)
102 {
103 	return true;
104 }
105 
106 
107 /** Constructs a zip file from a zip file
108 
109 	@precond	The given parameter must be a string with length > 0
110 			The file must exist
111 			The file must be readable for the current user
112 
113 	@throws	ParameterException if the given file name is empty
114 			IOException if the specified file doesn't exist or is no valid zip file
115 			AccessViolationException if read access to the file is denied
116 			WrongZipVersionException if the zip file cannot be uncompressed
117 			with the used zlib version
118 */
ZipFile(const std::string & FileName)119 ZipFile::ZipFile(const std::string& FileName)
120 {
121 	m_uzFile = unzOpen(FileName.c_str());
122 
123 	if (0 == m_uzFile)
124 		throw IOException(-1);
125 }
126 
ZipFile(void * stream,zlib_filefunc_def * fa)127 ZipFile::ZipFile(void* stream, zlib_filefunc_def* fa)
128 {
129 	fa->opaque = stream;
130 	m_uzFile = unzOpen2((const char *)NULL, fa);
131 
132 	if (0 == m_uzFile)
133 		throw IOException(-1);
134 }
135 
136 
137 /** Destroys a zip file
138 */
~ZipFile()139 ZipFile::~ZipFile()
140 {
141 	unzClose(m_uzFile);
142 }
143 
144 /** Provides an interface to read the uncompressed data of a content of the zip file
145 
146 	@precond	The specified content must exist in this file
147 			ppstm must not be NULL
148 */
GetUncompressedContent(const std::string & ContentName,ZipContentBuffer_t & ContentBuffer)149 void ZipFile::GetUncompressedContent(
150 	const std::string& ContentName, /*inout*/ ZipContentBuffer_t& ContentBuffer)
151 {
152 	int rc = unzLocateFile(m_uzFile, ContentName.c_str(), 0);
153 
154 	if (UNZ_END_OF_LIST_OF_FILE == rc)
155 		throw ZipContentMissException(rc);
156 
157 	unz_file_info finfo;
158 	unzGetCurrentFileInfo(m_uzFile, &finfo, 0, 0, 0, 0, 0, 0);
159 
160 	ContentBuffer.resize(finfo.uncompressed_size);
161 
162 	rc = unzOpenCurrentFile(m_uzFile);
163 
164 	if (UNZ_OK != rc)
165 		throw ZipException(rc);
166 
167 	rc = unzReadCurrentFile(m_uzFile, &ContentBuffer[0], finfo.uncompressed_size);
168 
169 	if (rc < 0)
170 		throw ZipException(rc);
171 
172 	rc = unzCloseCurrentFile(m_uzFile);
173 
174 	if (rc < 0)
175 		throw ZipException(rc);
176 }
177 
178 /** Returns a list with the content names contained within this file
179 
180 */
GetDirectory() const181 ZipFile::DirectoryPtr_t ZipFile::GetDirectory() const
182 {
183 	DirectoryPtr_t dir(new Directory_t());
184 
185 	long lmax = GetFileLongestFileNameLength() + 1;
186 	char* szFileName = reinterpret_cast<char*>(_alloca(lmax));
187 
188 	if (!szFileName)
189 		throw ZipException(ERROR_NOT_ENOUGH_MEMORY);
190 
191 	int rc = unzGoToFirstFile(m_uzFile);
192 
193 	while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
194 	{
195 		unz_file_info finfo;
196 		unzGetCurrentFileInfo(
197 			m_uzFile, &finfo, szFileName, lmax, 0, 0, 0, 0);
198 
199 		dir->push_back(szFileName);
200 
201 		rc = unzGoToNextFile(m_uzFile);
202 	}
203 
204 	if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
205 		throw ZipException(rc);
206 
207 	return dir;
208 }
209 
210 /** Convinience query function may even realized with
211 	iterating over a ZipFileDirectory returned by
212 	GetDirectory */
HasContent(const std::string & ContentName) const213 bool ZipFile::HasContent(const std::string& ContentName) const
214 {
215     //#i34314# we need to compare package content names
216     //case in-sensitive as it is not defined that such
217     //names must be handled case sensitive
218 	DirectoryPtr_t dir = GetDirectory();
219 	Directory_t::iterator iter =
220         std::find_if(dir->begin(), dir->end(), internal::stricmp(ContentName));
221 
222 	return (iter != dir->end());
223 }
224 
225 
226 /** Returns the length of the longest file name
227 		in the current zip file
228 */
GetFileLongestFileNameLength() const229 long ZipFile::GetFileLongestFileNameLength() const
230 {
231 	long lmax = 0;
232 	unz_file_info finfo;
233 
234 	int rc = unzGoToFirstFile(m_uzFile);
235 
236 	while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
237 	{
238 		unzGetCurrentFileInfo(m_uzFile,	&finfo, 0, 0, 0, 0, 0, 0);
239 		lmax = std::max<long>(lmax, finfo.size_filename);
240 		rc = unzGoToNextFile(m_uzFile);
241 	}
242 
243 	if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
244 		throw ZipException(rc);
245 
246 	return lmax;
247 }
248 
249