xref: /trunk/main/shell/source/all/zipfile/zipfile.cxx (revision e32ec1a966a7222d04c4ed2904dd376185cdeba0)
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