centralDir.cpp
Engine/source/core/util/zip/centralDir.cpp
Namespaces:
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "core/stream/stream.h" 25#include "core/strings/stringFunctions.h" 26 27#include "core/util/zip/centralDir.h" 28#include "core/util/zip/compressor.h" 29 30#include "core/util/safeDelete.h" 31 32namespace Zip 33{ 34 35//----------------------------------------------------------------------------- 36// CentralDir Class 37//----------------------------------------------------------------------------- 38 39CentralDir::CentralDir() 40{ 41 mHeaderSig = mCentralDirSignature; 42 43 mDiskNumStart = 0; 44 45 mInternalFileAttr = 0; 46 mExternalFileAttr = 0; 47 48 mLocalHeadOffset = 0; 49 50 mVersionMadeBy = 0; 51 52 mFileComment = NULL; 53 54 mInternalFlags = 0; 55} 56 57CentralDir::CentralDir(FileHeader &fh) : FileHeader(fh) 58{ 59 mHeaderSig = mCentralDirSignature; 60 61 mDiskNumStart = 0; 62 63 mInternalFileAttr = 0; 64 mExternalFileAttr = 0; 65 66 mLocalHeadOffset = 0; 67 68 mVersionMadeBy = 0; 69 70 mFileComment = NULL; 71} 72 73CentralDir::~CentralDir() 74{ 75 SAFE_DELETE_ARRAY(mFileComment); 76} 77 78//----------------------------------------------------------------------------- 79 80bool CentralDir::read(Stream *stream) 81{ 82 stream->read(&mHeaderSig); 83 if(mHeaderSig != mCentralDirSignature) 84 return false; 85 86 stream->read(&mVersionMadeBy); 87 stream->read(&mExtractVer); 88 stream->read(&mFlags); 89 stream->read(&mCompressMethod); 90 stream->read(&mModTime); 91 stream->read(&mModDate); 92 stream->read(&mCRC32); 93 stream->read(&mCompressedSize); 94 stream->read(&mUncompressedSize); 95 96 U16 fnLen, efLen, fcLen; 97 stream->read(&fnLen); 98 stream->read(&efLen); 99 stream->read(&fcLen); 100 101 stream->read(&mDiskNumStart); 102 103 stream->read(&mInternalFileAttr); 104 stream->read(&mExternalFileAttr); 105 106 stream->read(&mLocalHeadOffset); 107 108 char *fn = new char[fnLen + 1]; 109 stream->read(fnLen, fn); 110 fn[fnLen] = 0; 111 mFilename = String(fn); 112 SAFE_DELETE_ARRAY(fn); 113 114 115 // [tom, 10/28/2006] We currently only need the extra fields when we want to 116 // open the file, so we won't bother reading them here. This avoids keeping 117 // them in memory twice. 118 119 //readExtraFields(stream, efLen); 120 stream->setPosition(stream->getPosition() + efLen); 121 122 fn = new char[fcLen + 1]; 123 stream->read(fcLen, fn); 124 fn[fcLen] = 0; 125 126 SAFE_DELETE_ARRAY(mFileComment); 127 mFileComment = fn; 128 129 // Sanity checks to make life easier elsewhere 130 if(mCompressMethod != Stored && mUncompressedSize == 0 && mCompressedSize == 0) 131 mCompressMethod = Stored; 132 133 return true; 134} 135 136bool CentralDir::write(Stream *stream) 137{ 138 mHeaderSig = mCentralDirSignature; 139 stream->write(mHeaderSig); 140 141 stream->write(mVersionMadeBy); 142 stream->write(mExtractVer); 143 stream->write(mFlags); 144 stream->write(mCompressMethod); 145 stream->write(mModTime); 146 stream->write(mModDate); 147 stream->write(mCRC32); 148 stream->write(mCompressedSize); 149 stream->write(mUncompressedSize); 150 151 U16 fnLen = mFilename.length(), 152 efLen = 0, 153 fcLen = mFileComment ? (U16)dStrlen(mFileComment) : 0; 154 stream->write(fnLen); 155 stream->write(efLen); 156 stream->write(fcLen); 157 158 stream->write(mDiskNumStart); 159 160 stream->write(mInternalFileAttr); 161 stream->write(mExternalFileAttr); 162 163 stream->write(mLocalHeadOffset); 164 165 if(fnLen) 166 stream->write(fnLen, mFilename); 167 168 // FIXME [tom, 10/29/2006] Write extra fields here 169 170 if(fcLen) 171 stream->write(fcLen, mFileComment); 172 173 return true; 174} 175 176//----------------------------------------------------------------------------- 177 178void CentralDir::setFileComment(const char *comment) 179{ 180 SAFE_DELETE_ARRAY(mFileComment); 181 dsize_t commentLen = dStrlen(comment) + 1; 182 mFileComment = new char [commentLen]; 183 dStrcpy(mFileComment, comment, commentLen); 184} 185 186//----------------------------------------------------------------------------- 187// EndOfCentralDir Class 188//----------------------------------------------------------------------------- 189 190EndOfCentralDir::EndOfCentralDir() 191{ 192 mHeaderSig = mEOCDSignature; 193 194 mDiskNum = 0; 195 mStartCDDiskNum = 0; 196 mNumEntriesInThisCD = 0; 197 mTotalEntriesInCD = 0; 198 mCDSize = 0; 199 mCDOffset = 0; 200 mCommentSize = 0; 201 mZipComment = NULL; 202} 203 204EndOfCentralDir::~EndOfCentralDir() 205{ 206 SAFE_DELETE_ARRAY(mZipComment); 207} 208 209//----------------------------------------------------------------------------- 210 211bool EndOfCentralDir::read(Stream *stream) 212{ 213 stream->read(&mHeaderSig); 214 if(mHeaderSig != mEOCDSignature) 215 return false; 216 217 stream->read(&mDiskNum); 218 stream->read(&mStartCDDiskNum); 219 stream->read(&mNumEntriesInThisCD); 220 stream->read(&mTotalEntriesInCD); 221 stream->read(&mCDSize); 222 stream->read(&mCDOffset); 223 224 stream->read(&mCommentSize); 225 226 char *comment = new char[mCommentSize + 1]; 227 stream->read(mCommentSize, comment); 228 comment[mCommentSize] = 0; 229 230 SAFE_DELETE_ARRAY(mZipComment); 231 mZipComment = comment; 232 233 return true; 234} 235 236bool EndOfCentralDir::write(Stream *stream) 237{ 238 stream->write(mHeaderSig); 239 240 stream->write(mDiskNum); 241 stream->write(mStartCDDiskNum); 242 stream->write(mNumEntriesInThisCD); 243 stream->write(mTotalEntriesInCD); 244 stream->write(mCDSize); 245 stream->write(mCDOffset); 246 247 stream->write(mCommentSize); 248 if(mZipComment && mCommentSize) 249 stream->write(mCommentSize, mZipComment); 250 251 return true; 252} 253 254//----------------------------------------------------------------------------- 255 256// [tom, 10/19/2006] I know, i know ... this'll get rewritten. 257// [tom, 1/23/2007] Maybe. 258 259bool EndOfCentralDir::findInStream(Stream *stream) 260{ 261 U32 initialPos = stream->getPosition(); 262 U32 size = stream->getStreamSize(); 263 U32 pos; 264 if(size == 0) 265 return false; 266 267 if(! stream->setPosition(size - mRecordSize)) 268 goto hell; 269 270 U32 sig; 271 stream->read(&sig); 272 273 if(sig == mEOCDSignature) 274 { 275 stream->setPosition(size - mRecordSize); 276 return true; 277 } 278 279 // OK, so we couldn't find the EOCD where we expected it. The zip file 280 // either has comments or isn't a zip file. We need to search the last 281 // 64Kb of the file for the EOCD. 282 283 pos = size > mEOCDSearchSize ? size - mEOCDSearchSize : 0; 284 if(! stream->setPosition(pos)) 285 goto hell; 286 287 while(pos < (size - 4)) 288 { 289 stream->read(&sig); 290 291 if(sig == mEOCDSignature) 292 { 293 stream->setPosition(pos); 294 return true; 295 } 296 297 pos++; 298 if(! stream->setPosition(pos)) 299 goto hell; 300 } 301 302hell: 303 stream->setPosition(initialPos); 304 return false; 305} 306 307//----------------------------------------------------------------------------- 308 309void EndOfCentralDir::setZipComment(U16 commentSize, const char *zipComment) 310{ 311 SAFE_DELETE_ARRAY(mZipComment); 312 mZipComment = new char [commentSize]; 313 dMemcpy((void *)mZipComment, zipComment, commentSize); 314 mCommentSize = commentSize; 315} 316 317void EndOfCentralDir::setZipComment(const char *zipComment) 318{ 319 setZipComment(dStrlen(zipComment), zipComment); 320} 321 322} // end namespace Zip 323