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 { 47 stricmp(const std::string& str) : str_(str) 48 {} 49 50 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 */ 70 bool ZipFile::IsZipFile(const std::string& /*FileName*/) 71 { 72 return true; 73 } 74 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 */ 96 bool ZipFile::IsValidZipFileVersionNumber(const std::string& /*FileName*/) 97 { 98 return true; 99 } 100 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 */ 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 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 */ 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 */ 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 */ 181 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 */ 213 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 */ 229 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