Torque3D Documentation / _generateds / zipSubStream.cpp

zipSubStream.cpp

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

More...

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 "zlib.h"
 25#include "core/util/zip/zipSubStream.h"
 26
 27
 28const U32 ZipSubRStream::csm_streamCaps      = U32(Stream::StreamRead) | U32(Stream::StreamPosition);
 29const U32 ZipSubRStream::csm_inputBufferSize = 4096;
 30
 31const U32 ZipSubWStream::csm_streamCaps      = U32(Stream::StreamWrite);
 32const U32 ZipSubWStream::csm_bufferSize      = (2048 * 1024);
 33
 34//--------------------------------------------------------------------------
 35//--------------------------------------
 36//
 37ZipSubRStream::ZipSubRStream()
 38 : m_pStream(NULL),
 39   m_uncompressedSize(0),
 40   m_currentPosition(0),
 41   m_EOS(false),
 42   m_pZipStream(NULL),
 43   m_pInputBuffer(NULL),
 44   m_originalSlavePosition(0),
 45   m_lastBytesRead(0)
 46{
 47   //
 48}
 49
 50//--------------------------------------
 51ZipSubRStream::~ZipSubRStream()
 52{
 53   detachStream();
 54}
 55
 56//--------------------------------------
 57bool ZipSubRStream::attachStream(Stream* io_pSlaveStream)
 58{
 59   AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
 60   AssertFatal(m_pStream == NULL,       "Already attached!");
 61
 62   m_pStream          = io_pSlaveStream;
 63   m_originalSlavePosition = io_pSlaveStream->getPosition();
 64   m_uncompressedSize = 0;
 65   m_currentPosition  = 0;
 66   m_EOS = false;
 67
 68   // Initialize zipStream state...
 69   m_pZipStream   = new z_stream_s;
 70   m_pInputBuffer = new U8[csm_inputBufferSize];
 71
 72   m_pZipStream->zalloc = Z_NULL;
 73   m_pZipStream->zfree  = Z_NULL;
 74   m_pZipStream->opaque = Z_NULL;
 75
 76   U32 buffSize = fillBuffer(csm_inputBufferSize);
 77
 78   m_pZipStream->next_in  = m_pInputBuffer;
 79   m_pZipStream->avail_in = buffSize;
 80   m_pZipStream->total_in = 0;
 81   inflateInit2(m_pZipStream, -MAX_WBITS);
 82
 83   setStatus(Ok);
 84   return true;
 85}
 86
 87//--------------------------------------
 88void ZipSubRStream::detachStream()
 89{
 90   if (m_pZipStream != NULL)
 91   {
 92      // close out zip stream...
 93      inflateEnd(m_pZipStream);
 94
 95      delete [] m_pInputBuffer;
 96      m_pInputBuffer = NULL;
 97      delete m_pZipStream;
 98      m_pZipStream = NULL;
 99   }
100
101   m_pStream          = NULL;
102   m_originalSlavePosition = 0;
103   m_uncompressedSize = 0;
104   m_currentPosition  = 0;
105   m_EOS              = false;
106   setStatus(Closed);
107}
108
109//--------------------------------------
110Stream* ZipSubRStream::getStream()
111{
112   return m_pStream;
113}
114
115//--------------------------------------
116void ZipSubRStream::setUncompressedSize(const U32 in_uncSize)
117{
118   AssertFatal(m_pStream != NULL, "error, no stream to set unc size for");
119
120   m_uncompressedSize = in_uncSize;
121}
122
123//--------------------------------------
124bool ZipSubRStream::_read(const U32 in_numBytes, void *out_pBuffer)
125{
126   m_lastBytesRead = 0;
127   if (in_numBytes == 0)
128      return true;
129
130   AssertFatal(out_pBuffer != NULL, "NULL output buffer");
131   if (getStatus() == Closed) {
132      AssertFatal(false, "Attempted read from closed stream");
133      return false;
134   }
135
136
137   if (Ok != getStatus())
138      return false;
139
140   if (m_EOS)
141   {
142      setStatus(EOS);
143      return true;
144   };
145
146   // Ok, we need to call inflate() until the output buffer is full.
147   //  first, set up the output portion of the z_stream
148   //
149   m_pZipStream->next_out  = (Bytef*)out_pBuffer;
150   m_pZipStream->avail_out = in_numBytes;
151   m_pZipStream->total_out = 0;
152
153   while (m_pZipStream->avail_out != 0)
154   {
155      S32 retVal = Z_OK;
156
157      if(m_pZipStream->avail_in == 0)
158      {
159         // check if there is more output pending
160         inflate(m_pZipStream, Z_SYNC_FLUSH);
161
162         if(m_pZipStream->total_out != in_numBytes)
163         {
164            // Need to provide more input bytes for the stream to read...
165            U32 buffSize = fillBuffer(csm_inputBufferSize);
166            //AssertFatal(buffSize != 0, "Must find a more graceful way to handle this");
167
168            m_pZipStream->next_in  = m_pInputBuffer;
169            m_pZipStream->avail_in = buffSize;
170            m_pZipStream->total_in = 0;
171         }
172      }
173
174      // need to get more?
175      if(m_pZipStream->total_out != in_numBytes)
176         retVal = inflate(m_pZipStream, Z_SYNC_FLUSH);
177
178      AssertFatal(retVal != Z_BUF_ERROR, "Should never run into a buffer error");
179      AssertFatal(retVal == Z_OK || retVal == Z_STREAM_END, "error in the stream");
180
181      m_lastBytesRead = m_pZipStream->total_out;
182
183      if (retVal == Z_STREAM_END)
184      {
185         if (m_pZipStream->avail_out != 0)
186            m_EOS = true;
187
188         setStatus(EOS);
189         m_currentPosition += m_pZipStream->total_out;
190         return true;
191      }
192   }
193   AssertFatal(m_pZipStream->total_out == in_numBytes,
194               "Error, didn't finish the decompression!");
195
196   // If we're here, everything went peachy...
197   setStatus(Ok);
198   m_currentPosition += m_pZipStream->total_out;
199
200   return true;
201}
202
203//--------------------------------------
204bool ZipSubRStream::hasCapability(const Capability in_cap) const
205{
206   return (csm_streamCaps & U32(in_cap)) != 0;
207}
208
209//--------------------------------------
210U32 ZipSubRStream::getPosition() const
211{
212   AssertFatal(m_pStream != NULL, "Error, not attached");
213
214   return m_currentPosition;
215}
216
217//--------------------------------------
218bool ZipSubRStream::setPosition(const U32 in_newPosition)
219{
220   AssertFatal(m_pStream != NULL, "Error, not attached");
221
222   if (in_newPosition == 0)
223   {
224      Stream* pStream = getStream();
225      U32 resetPosition = m_originalSlavePosition;
226      U32 uncompressedSize = m_uncompressedSize;
227      detachStream();
228      pStream->setPosition(resetPosition);
229      attachStream(pStream);
230      setUncompressedSize(uncompressedSize);
231      return true;
232   }
233   else
234   {
235      if (in_newPosition > m_uncompressedSize)
236         return false;
237
238      U32 newPosition = in_newPosition;
239      if (newPosition < m_currentPosition)
240      {
241         Stream* pStream = getStream();
242         U32 resetPosition = m_originalSlavePosition;
243         U32 uncompressedSize = m_uncompressedSize;
244         detachStream();
245         pStream->setPosition(resetPosition);
246         attachStream(pStream);
247         setUncompressedSize(uncompressedSize);
248      }
249      else
250      {
251         newPosition -= m_currentPosition;
252      }
253
254      bool bRet = true;
255      char *buffer = new char[2048];
256      while (newPosition >= 2048)
257      {
258         newPosition -= 2048;
259         if (!_read(2048,buffer))
260         {
261            bRet = false;
262            break;
263         }
264      };
265      if (bRet && newPosition > 0)
266      {
267         if (!_read(newPosition,buffer))
268         {
269            bRet = false;
270         };
271      };
272
273      delete [] buffer;
274
275      return bRet;
276
277   }
278}
279
280//--------------------------------------
281U32 ZipSubRStream::getStreamSize()
282{
283   AssertFatal(m_pStream != NULL, "No stream to size()");
284   AssertFatal(m_uncompressedSize != 0, "No data?  Properties probably not set...");
285
286   return m_uncompressedSize;
287}
288
289//--------------------------------------
290U32 ZipSubRStream::fillBuffer(const U32 in_attemptSize)
291{
292   AssertFatal(m_pStream != NULL, "No stream to fill from?");
293   AssertFatal(m_pStream->getStatus() != Stream::Closed,
294               "Fill from a closed stream?");
295
296   U32 streamSize = m_pStream->getStreamSize();
297   U32 currPos    = m_pStream->getPosition();
298
299   U32 actualReadSize;
300   if (in_attemptSize + currPos > streamSize) {
301      actualReadSize = streamSize - currPos;
302   } else {
303      actualReadSize = in_attemptSize;
304   }
305
306   if (m_pStream->read(actualReadSize, m_pInputBuffer) == true) {
307      return actualReadSize;
308   } else {
309      AssertWarn(false, "Read failed while trying to fill buffer");
310      return 0;
311   }
312}
313
314
315//--------------------------------------------------------------------------
316ZipSubWStream::ZipSubWStream()
317 : m_pStream(NULL),
318   m_pZipStream(NULL),
319   m_currPosition(0),
320   m_pOutputBuffer(NULL),
321   m_pInputBuffer(NULL),
322   m_lastBytesRead(0),
323   m_lastBytesWritten(0)
324{
325   //
326}
327
328//--------------------------------------
329ZipSubWStream::~ZipSubWStream()
330{
331   detachStream();
332}
333
334//--------------------------------------
335bool ZipSubWStream::attachStream(Stream* io_pSlaveStream)
336{
337   AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
338   AssertFatal(m_pStream == NULL,       "Already attached!");
339
340   m_pStream      = io_pSlaveStream;
341   m_currPosition = 0;
342
343   m_pOutputBuffer = new U8[csm_bufferSize];
344   m_pInputBuffer  = new U8[csm_bufferSize];
345
346   // Initialize zipStream state...
347   m_pZipStream = new z_stream_s;
348
349   m_pZipStream->zalloc = Z_NULL;
350   m_pZipStream->zfree  = Z_NULL;
351   m_pZipStream->opaque = Z_NULL;
352
353   m_pZipStream->next_in   = m_pInputBuffer;
354   m_pZipStream->avail_in  = csm_bufferSize;
355   m_pZipStream->total_in  = 0;
356   m_pZipStream->next_out  = m_pOutputBuffer;
357   m_pZipStream->avail_out = csm_bufferSize;
358   m_pZipStream->total_out = 0;
359
360   deflateInit2(m_pZipStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
361
362   setStatus(Ok);
363   return true;
364}
365
366//--------------------------------------
367void ZipSubWStream::detachStream()
368{
369   // Must finish...
370   if (m_pZipStream != NULL)
371   {
372      m_pZipStream->avail_in = 0;
373      deflate(m_pZipStream, Z_FINISH);
374
375      // write the remainder
376      m_pStream->write(csm_bufferSize - m_pZipStream->avail_out, m_pOutputBuffer);
377
378      // close out zip stream...
379      deflateEnd(m_pZipStream);
380
381      delete m_pZipStream;
382      m_pZipStream = NULL;
383
384      delete [] m_pInputBuffer;
385      delete [] m_pOutputBuffer;
386      m_pInputBuffer  = NULL;
387      m_pOutputBuffer = NULL;
388   }
389
390   m_pStream      = NULL;
391   m_currPosition = 0;
392   setStatus(Closed);
393}
394
395//--------------------------------------
396Stream* ZipSubWStream::getStream()
397{
398   return m_pStream;
399}
400
401//--------------------------------------
402bool ZipSubWStream::_read(const U32, void*)
403{
404   AssertFatal(false, "Cannot read from a ZipSubWStream");
405
406   setStatus(IllegalCall);
407   return false;
408}
409
410//--------------------------------------
411bool ZipSubWStream::_write(const U32 numBytes, const void *pBuffer)
412{
413   m_lastBytesWritten = 0;
414   if (numBytes == 0)
415      return true;
416
417   AssertFatal(pBuffer != NULL, "NULL input buffer");
418   if (getStatus() == Closed)
419   {
420      AssertFatal(false, "Attempted write to a closed stream");
421      return false;
422   }
423
424   m_pZipStream->next_in = (U8*)pBuffer;
425   m_pZipStream->avail_in = numBytes;
426
427   // write as many bufferSize chunks as possible
428   while(m_pZipStream->avail_in != 0)
429   {
430      if(m_pZipStream->avail_out == 0)
431      {
432         if(!m_pStream->write(csm_bufferSize, m_pOutputBuffer))
433            return(false);
434
435         m_pZipStream->next_out = m_pOutputBuffer;
436         m_pZipStream->avail_out = csm_bufferSize;
437      }
438
439      S32 retVal = deflate(m_pZipStream, Z_NO_FLUSH);
440      AssertFatal(retVal !=  Z_BUF_ERROR, "ZipSubWStream::_write: invalid buffer");
441   }
442
443   setStatus(Ok);
444   m_currPosition += m_pZipStream->total_out;
445
446   m_lastBytesWritten = m_pZipStream->total_out;
447
448   return true;
449}
450
451//--------------------------------------
452bool ZipSubWStream::hasCapability(const Capability in_cap) const
453{
454   return (csm_streamCaps & U32(in_cap)) != 0;
455}
456
457//--------------------------------------
458U32 ZipSubWStream::getPosition() const
459{
460   AssertFatal(m_pStream != NULL, "Error, not attached");
461
462   return m_currPosition;
463}
464
465//--------------------------------------
466bool ZipSubWStream::setPosition(const U32 /*in_newPosition*/)
467{
468   AssertFatal(m_pStream != NULL, "Error, not attached");
469   AssertFatal(false, "Not implemented!");
470
471   // Erk.  How do we do this.
472   return false;
473}
474
475U32 ZipSubWStream::getStreamSize()
476{
477   AssertFatal(false, "Undecided how to implement this!");
478   return 0;
479}
480
481