zipSubStream.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "zlib.h"
  23. #include "io/zip/zipSubStream.h"
  24. const U32 ZipSubRStream::csm_streamCaps = U32(Stream::StreamRead) | U32(Stream::StreamPosition);
  25. const U32 ZipSubRStream::csm_inputBufferSize = 4096;
  26. const U32 ZipSubWStream::csm_streamCaps = U32(Stream::StreamWrite);
  27. const U32 ZipSubWStream::csm_bufferSize = (2048 * 1024);
  28. //--------------------------------------------------------------------------
  29. //--------------------------------------
  30. //
  31. ZipSubRStream::ZipSubRStream()
  32. : m_pStream(NULL),
  33. m_uncompressedSize(0),
  34. m_currentPosition(0),
  35. m_EOS(false),
  36. m_pZipStream(NULL),
  37. m_originalSlavePosition(0)
  38. {
  39. //
  40. }
  41. //--------------------------------------
  42. ZipSubRStream::~ZipSubRStream()
  43. {
  44. detachStream();
  45. }
  46. //--------------------------------------
  47. bool ZipSubRStream::attachStream(Stream* io_pSlaveStream)
  48. {
  49. AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
  50. AssertFatal(m_pStream == NULL, "Already attached!");
  51. m_pStream = io_pSlaveStream;
  52. m_originalSlavePosition = io_pSlaveStream->getPosition();
  53. m_uncompressedSize = 0;
  54. m_currentPosition = 0;
  55. m_EOS = false;
  56. // Initialize zipStream state...
  57. m_pZipStream = new z_stream_s;
  58. m_pInputBuffer = new U8[csm_inputBufferSize];
  59. m_pZipStream->zalloc = Z_NULL;
  60. m_pZipStream->zfree = Z_NULL;
  61. m_pZipStream->opaque = Z_NULL;
  62. U32 buffSize = fillBuffer(csm_inputBufferSize);
  63. m_pZipStream->next_in = m_pInputBuffer;
  64. m_pZipStream->avail_in = buffSize;
  65. m_pZipStream->total_in = 0;
  66. inflateInit2(m_pZipStream, -MAX_WBITS);
  67. setStatus(Ok);
  68. return true;
  69. }
  70. //--------------------------------------
  71. void ZipSubRStream::detachStream()
  72. {
  73. if (m_pZipStream != NULL)
  74. {
  75. // close out zip stream...
  76. inflateEnd(m_pZipStream);
  77. delete [] m_pInputBuffer;
  78. m_pInputBuffer = NULL;
  79. delete m_pZipStream;
  80. m_pZipStream = NULL;
  81. }
  82. m_pStream = NULL;
  83. m_originalSlavePosition = 0;
  84. m_uncompressedSize = 0;
  85. m_currentPosition = 0;
  86. m_EOS = false;
  87. setStatus(Closed);
  88. }
  89. //--------------------------------------
  90. Stream* ZipSubRStream::getStream()
  91. {
  92. return m_pStream;
  93. }
  94. //--------------------------------------
  95. void ZipSubRStream::setUncompressedSize(const U32 in_uncSize)
  96. {
  97. AssertFatal(m_pStream != NULL, "error, no stream to set unc size for");
  98. m_uncompressedSize = in_uncSize;
  99. }
  100. //--------------------------------------
  101. bool ZipSubRStream::_read(const U32 in_numBytes, void *out_pBuffer)
  102. {
  103. if (in_numBytes == 0)
  104. return true;
  105. AssertFatal(out_pBuffer != NULL, "NULL output buffer");
  106. if (getStatus() == Closed) {
  107. AssertFatal(false, "Attempted read from closed stream");
  108. return false;
  109. }
  110. if (Ok != getStatus())
  111. return false;
  112. if (m_EOS)
  113. {
  114. setStatus(EOS);
  115. return true;
  116. };
  117. // Ok, we need to call inflate() until the output buffer is full.
  118. // first, set up the output portion of the z_stream
  119. //
  120. m_pZipStream->next_out = (Bytef*)out_pBuffer;
  121. m_pZipStream->avail_out = in_numBytes;
  122. m_pZipStream->total_out = 0;
  123. while (m_pZipStream->avail_out != 0)
  124. {
  125. S32 retVal = Z_OK;
  126. if(m_pZipStream->avail_in == 0)
  127. {
  128. // check if there is more output pending
  129. inflate(m_pZipStream, Z_SYNC_FLUSH);
  130. if(m_pZipStream->total_out != in_numBytes)
  131. {
  132. // Need to provide more input bytes for the stream to read...
  133. U32 buffSize = fillBuffer(csm_inputBufferSize);
  134. //AssertFatal(buffSize != 0, "Must find a more graceful way to handle this");
  135. m_pZipStream->next_in = m_pInputBuffer;
  136. m_pZipStream->avail_in = buffSize;
  137. m_pZipStream->total_in = 0;
  138. }
  139. }
  140. // need to get more?
  141. if(m_pZipStream->total_out != in_numBytes)
  142. retVal = inflate(m_pZipStream, Z_SYNC_FLUSH);
  143. AssertFatal(retVal != Z_BUF_ERROR, "Should never run into a buffer error");
  144. AssertFatal(retVal == Z_OK || retVal == Z_STREAM_END, "error in the stream");
  145. if (retVal == Z_STREAM_END)
  146. {
  147. if (m_pZipStream->avail_out != 0)
  148. m_EOS = true;
  149. setStatus(Ok);
  150. m_currentPosition += m_pZipStream->total_out;
  151. return true;
  152. }
  153. }
  154. AssertFatal(m_pZipStream->total_out == in_numBytes,
  155. "Error, didn't finish the decompression!");
  156. // If we're here, everything went peachy...
  157. setStatus(Ok);
  158. m_currentPosition += m_pZipStream->total_out;
  159. return true;
  160. }
  161. //--------------------------------------
  162. bool ZipSubRStream::hasCapability(const Capability in_cap) const
  163. {
  164. return (csm_streamCaps & U32(in_cap)) != 0;
  165. }
  166. //--------------------------------------
  167. U32 ZipSubRStream::getPosition() const
  168. {
  169. AssertFatal(m_pStream != NULL, "Error, not attached");
  170. return m_currentPosition;
  171. }
  172. //--------------------------------------
  173. bool ZipSubRStream::setPosition(const U32 in_newPosition)
  174. {
  175. AssertFatal(m_pStream != NULL, "Error, not attached");
  176. if (in_newPosition == 0)
  177. {
  178. Stream* pStream = getStream();
  179. U32 resetPosition = m_originalSlavePosition;
  180. U32 uncompressedSize = m_uncompressedSize;
  181. detachStream();
  182. pStream->setPosition(resetPosition);
  183. attachStream(pStream);
  184. setUncompressedSize(uncompressedSize);
  185. return true;
  186. }
  187. else
  188. {
  189. if (in_newPosition > m_uncompressedSize)
  190. return false;
  191. U32 newPosition = in_newPosition;
  192. if (newPosition < m_currentPosition)
  193. {
  194. Stream* pStream = getStream();
  195. U32 resetPosition = m_originalSlavePosition;
  196. U32 uncompressedSize = m_uncompressedSize;
  197. detachStream();
  198. pStream->setPosition(resetPosition);
  199. attachStream(pStream);
  200. setUncompressedSize(uncompressedSize);
  201. }
  202. else
  203. {
  204. newPosition -= m_currentPosition;
  205. }
  206. bool bRet = true;
  207. char *buffer = new char[2048];
  208. while (newPosition >= 2048)
  209. {
  210. newPosition -= 2048;
  211. if (!_read(2048,buffer))
  212. {
  213. bRet = false;
  214. break;
  215. }
  216. };
  217. if (bRet && newPosition > 0)
  218. {
  219. if (!_read(newPosition,buffer))
  220. {
  221. bRet = false;
  222. };
  223. };
  224. delete [] buffer;
  225. return bRet;
  226. }
  227. }
  228. //--------------------------------------
  229. U32 ZipSubRStream::getStreamSize()
  230. {
  231. AssertFatal(m_pStream != NULL, "No stream to size()");
  232. // Commented out the assert below as files with no contents are possible in a Zip
  233. //AssertFatal(m_uncompressedSize != 0, "No data? Properties probably not set...");
  234. return m_uncompressedSize;
  235. }
  236. //--------------------------------------
  237. U32 ZipSubRStream::fillBuffer(const U32 in_attemptSize)
  238. {
  239. AssertFatal(m_pStream != NULL, "No stream to fill from?");
  240. AssertFatal(m_pStream->getStatus() != Stream::Closed,
  241. "Fill from a closed stream?");
  242. U32 streamSize = m_pStream->getStreamSize();
  243. U32 currPos = m_pStream->getPosition();
  244. U32 actualReadSize;
  245. if (in_attemptSize + currPos > streamSize) {
  246. actualReadSize = streamSize - currPos;
  247. } else {
  248. actualReadSize = in_attemptSize;
  249. }
  250. if (m_pStream->read(actualReadSize, m_pInputBuffer) == true) {
  251. return actualReadSize;
  252. } else {
  253. AssertWarn(false, "Read failed while trying to fill buffer");
  254. return 0;
  255. }
  256. }
  257. //--------------------------------------------------------------------------
  258. ZipSubWStream::ZipSubWStream()
  259. : m_pStream(NULL),
  260. m_currPosition(0),
  261. m_pZipStream(NULL)
  262. {
  263. //
  264. }
  265. //--------------------------------------
  266. ZipSubWStream::~ZipSubWStream()
  267. {
  268. detachStream();
  269. }
  270. //--------------------------------------
  271. bool ZipSubWStream::attachStream(Stream* io_pSlaveStream)
  272. {
  273. AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
  274. AssertFatal(m_pStream == NULL, "Already attached!");
  275. m_pStream = io_pSlaveStream;
  276. m_currPosition = 0;
  277. m_pOutputBuffer = new U8[csm_bufferSize];
  278. m_pInputBuffer = new U8[csm_bufferSize];
  279. // Initialize zipStream state...
  280. m_pZipStream = new z_stream_s;
  281. m_pZipStream->zalloc = Z_NULL;
  282. m_pZipStream->zfree = Z_NULL;
  283. m_pZipStream->opaque = Z_NULL;
  284. m_pZipStream->next_in = m_pInputBuffer;
  285. m_pZipStream->avail_in = csm_bufferSize;
  286. m_pZipStream->total_in = 0;
  287. m_pZipStream->next_out = m_pOutputBuffer;
  288. m_pZipStream->avail_out = csm_bufferSize;
  289. m_pZipStream->total_out = 0;
  290. deflateInit2(m_pZipStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
  291. setStatus(Ok);
  292. return true;
  293. }
  294. //--------------------------------------
  295. void ZipSubWStream::detachStream()
  296. {
  297. // Must finish...
  298. if (m_pZipStream != NULL)
  299. {
  300. m_pZipStream->avail_in = 0;
  301. deflate(m_pZipStream, Z_FINISH);
  302. // write the remainder
  303. m_pStream->write(csm_bufferSize - m_pZipStream->avail_out, m_pOutputBuffer);
  304. // close out zip stream...
  305. deflateEnd(m_pZipStream);
  306. delete m_pZipStream;
  307. m_pZipStream = NULL;
  308. delete [] m_pInputBuffer;
  309. delete [] m_pOutputBuffer;
  310. m_pInputBuffer = NULL;
  311. m_pOutputBuffer = NULL;
  312. }
  313. m_pStream = NULL;
  314. m_currPosition = 0;
  315. setStatus(Closed);
  316. }
  317. //--------------------------------------
  318. Stream* ZipSubWStream::getStream()
  319. {
  320. return m_pStream;
  321. }
  322. //--------------------------------------
  323. bool ZipSubWStream::_read(const U32, void*)
  324. {
  325. AssertFatal(false, "Cannot read from a ZipSubWStream");
  326. setStatus(IllegalCall);
  327. return false;
  328. }
  329. //--------------------------------------
  330. bool ZipSubWStream::_write(const U32 numBytes, const void *pBuffer)
  331. {
  332. if (numBytes == 0)
  333. return true;
  334. AssertFatal(pBuffer != NULL, "NULL input buffer");
  335. if (getStatus() == Closed)
  336. {
  337. AssertFatal(false, "Attempted write to a closed stream");
  338. return false;
  339. }
  340. m_pZipStream->next_in = (U8*)pBuffer;
  341. m_pZipStream->avail_in = numBytes;
  342. // write as many bufferSize chunks as possible
  343. while(m_pZipStream->avail_in != 0)
  344. {
  345. if(m_pZipStream->avail_out == 0)
  346. {
  347. if(!m_pStream->write(csm_bufferSize, m_pOutputBuffer))
  348. return(false);
  349. m_pZipStream->next_out = m_pOutputBuffer;
  350. m_pZipStream->avail_out = csm_bufferSize;
  351. }
  352. S32 retVal;
  353. retVal = deflate(m_pZipStream, Z_NO_FLUSH);
  354. AssertFatal(retVal != Z_BUF_ERROR, "ZipSubWStream::_write: invalid buffer");
  355. }
  356. setStatus(Ok);
  357. m_currPosition += m_pZipStream->total_out;
  358. return true;
  359. }
  360. //--------------------------------------
  361. bool ZipSubWStream::hasCapability(const Capability in_cap) const
  362. {
  363. return (csm_streamCaps & U32(in_cap)) != 0;
  364. }
  365. //--------------------------------------
  366. U32 ZipSubWStream::getPosition() const
  367. {
  368. AssertFatal(m_pStream != NULL, "Error, not attached");
  369. return m_currPosition;
  370. }
  371. //--------------------------------------
  372. bool ZipSubWStream::setPosition(const U32 /*in_newPosition*/)
  373. {
  374. AssertFatal(m_pStream != NULL, "Error, not attached");
  375. AssertFatal(false, "Not implemented!");
  376. // Erk. How do we do this.
  377. return false;
  378. }
  379. U32 ZipSubWStream::getStreamSize()
  380. {
  381. AssertFatal(false, "Undecided how to implement this!");
  382. return 0;
  383. }