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
46 {
47 typedef std::string argument_type;
48 typedef bool result_type;
stricmpinternal::stricmp49 stricmp(const std::string& str) : str_(str)
50 {}
51
operator ()internal::stricmp52 bool operator() (const std::string& other)
53 { return (0 == _stricmp(str_.c_str(), other.c_str())); }
54
55 std::string str_;
56 };
57 } // namespace internal
58
59 /** Checks whether a file is a zip file or not
60
61 @precond The given parameter must be a string with length > 0
62 The file must exist
63 The file must be readable for the current user
64
65 @returns true if the file is a zip file
66 false if the file is not a zip file
67
68 @throws ParameterException if the given file name is empty
69 IOException if the specified file doesn't exist
70 AccessViolationException if read access to the file is denied
71 */
IsZipFile(const std::string &)72 bool ZipFile::IsZipFile(const std::string& /*FileName*/)
73 {
74 return true;
75 }
76
IsZipFile(void *)77 bool ZipFile::IsZipFile(void* /*stream*/)
78 {
79 return true;
80 }
81
82
83 /** Returns wheter the version of the specified zip file may be uncompressed with the
84 currently used zlib version or not
85
86 @precond The given parameter must be a string with length > 0
87 The file must exist
88 The file must be readable for the current user
89 The file must be a valid zip file
90
91 @returns true if the file may be uncompressed with the currently used zlib
92 false if the file may not be uncompressed with the currently used zlib
93
94 @throws ParameterException if the given file name is empty
95 IOException if the specified file doesn't exist or is no zip file
96 AccessViolationException if read access to the file is denied
97 */
IsValidZipFileVersionNumber(const std::string &)98 bool ZipFile::IsValidZipFileVersionNumber(const std::string& /*FileName*/)
99 {
100 return true;
101 }
102
IsValidZipFileVersionNumber(void *)103 bool ZipFile::IsValidZipFileVersionNumber(void* /* stream*/)
104 {
105 return true;
106 }
107
108
109 /** Constructs a zip file from a zip file
110
111 @precond The given parameter must be a string with length > 0
112 The file must exist
113 The file must be readable for the current user
114
115 @throws ParameterException if the given file name is empty
116 IOException if the specified file doesn't exist or is no valid zip file
117 AccessViolationException if read access to the file is denied
118 WrongZipVersionException if the zip file cannot be uncompressed
119 with the used zlib version
120 */
ZipFile(const std::string & FileName)121 ZipFile::ZipFile(const std::string& FileName)
122 {
123 m_uzFile = unzOpen(FileName.c_str());
124
125 if (0 == m_uzFile)
126 throw IOException(-1);
127 }
128
ZipFile(void * stream,zlib_filefunc_def * fa)129 ZipFile::ZipFile(void* stream, zlib_filefunc_def* fa)
130 {
131 fa->opaque = stream;
132 m_uzFile = unzOpen2((const char *)NULL, fa);
133
134 if (0 == m_uzFile)
135 throw IOException(-1);
136 }
137
138
139 /** Destroys a zip file
140 */
~ZipFile()141 ZipFile::~ZipFile()
142 {
143 unzClose(m_uzFile);
144 }
145
146 /** Provides an interface to read the uncompressed data of a content of the zip file
147
148 @precond The specified content must exist in this file
149 ppstm must not be NULL
150 */
GetUncompressedContent(const std::string & ContentName,ZipContentBuffer_t & ContentBuffer)151 void ZipFile::GetUncompressedContent(
152 const std::string& ContentName, /*inout*/ ZipContentBuffer_t& ContentBuffer)
153 {
154 int rc = unzLocateFile(m_uzFile, ContentName.c_str(), 0);
155
156 if (UNZ_END_OF_LIST_OF_FILE == rc)
157 throw ZipContentMissException(rc);
158
159 unz_file_info finfo;
160 unzGetCurrentFileInfo(m_uzFile, &finfo, 0, 0, 0, 0, 0, 0);
161
162 ContentBuffer.resize(finfo.uncompressed_size);
163
164 rc = unzOpenCurrentFile(m_uzFile);
165
166 if (UNZ_OK != rc)
167 throw ZipException(rc);
168
169 rc = unzReadCurrentFile(m_uzFile, &ContentBuffer[0], finfo.uncompressed_size);
170
171 if (rc < 0)
172 throw ZipException(rc);
173
174 rc = unzCloseCurrentFile(m_uzFile);
175
176 if (rc < 0)
177 throw ZipException(rc);
178 }
179
180 /** Returns a list with the content names contained within this file
181
182 */
GetDirectory() const183 ZipFile::DirectoryPtr_t ZipFile::GetDirectory() const
184 {
185 DirectoryPtr_t dir(new Directory_t());
186
187 long lmax = GetFileLongestFileNameLength() + 1;
188 char* szFileName = reinterpret_cast<char*>(_alloca(lmax));
189
190 if (!szFileName)
191 throw ZipException(ERROR_NOT_ENOUGH_MEMORY);
192
193 int rc = unzGoToFirstFile(m_uzFile);
194
195 while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
196 {
197 unz_file_info finfo;
198 unzGetCurrentFileInfo(
199 m_uzFile, &finfo, szFileName, lmax, 0, 0, 0, 0);
200
201 dir->push_back(szFileName);
202
203 rc = unzGoToNextFile(m_uzFile);
204 }
205
206 if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
207 throw ZipException(rc);
208
209 return dir;
210 }
211
212 /** Convenience query function may even realized with
213 iterating over a ZipFileDirectory returned by
214 GetDirectory */
HasContent(const std::string & ContentName) const215 bool ZipFile::HasContent(const std::string& ContentName) const
216 {
217 //#i34314# we need to compare package content names
218 //case in-sensitive as it is not defined that such
219 //names must be handled case sensitive
220 DirectoryPtr_t dir = GetDirectory();
221 Directory_t::iterator iter =
222 std::find_if(dir->begin(), dir->end(), internal::stricmp(ContentName));
223
224 return (iter != dir->end());
225 }
226
227
228 /** Returns the length of the longest file name
229 in the current zip file
230 */
GetFileLongestFileNameLength() const231 long ZipFile::GetFileLongestFileNameLength() const
232 {
233 long lmax = 0;
234 unz_file_info finfo;
235
236 int rc = unzGoToFirstFile(m_uzFile);
237
238 while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
239 {
240 unzGetCurrentFileInfo(m_uzFile, &finfo, 0, 0, 0, 0, 0, 0);
241 lmax = std::max<long>(lmax, finfo.size_filename);
242 rc = unzGoToNextFile(m_uzFile);
243 }
244
245 if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
246 throw ZipException(rc);
247
248 return lmax;
249 }
250