centralDir.cpp

Engine/source/core/util/zip/centralDir.cpp

More...

Namespaces:

namespace

Namespace for the zip code.

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