You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ZlibOutStream.cxx 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #include <rdr/ZlibOutStream.h>
  19. #include <rdr/Exception.h>
  20. #include <os/print.h>
  21. #include <zlib.h>
  22. using namespace rdr;
  23. enum { DEFAULT_BUF_SIZE = 16384 };
  24. ZlibOutStream::ZlibOutStream(OutStream* os, int bufSize_, int compressLevel)
  25. : underlying(os), compressionLevel(compressLevel), newLevel(compressLevel),
  26. bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0)
  27. {
  28. zs = new z_stream;
  29. zs->zalloc = Z_NULL;
  30. zs->zfree = Z_NULL;
  31. zs->opaque = Z_NULL;
  32. if (deflateInit(zs, compressLevel) != Z_OK) {
  33. delete zs;
  34. throw Exception("ZlibOutStream: deflateInit failed");
  35. }
  36. ptr = start = new U8[bufSize];
  37. end = start + bufSize;
  38. }
  39. ZlibOutStream::~ZlibOutStream()
  40. {
  41. try {
  42. flush();
  43. } catch (Exception&) {
  44. }
  45. delete [] start;
  46. deflateEnd(zs);
  47. delete zs;
  48. }
  49. void ZlibOutStream::setUnderlying(OutStream* os)
  50. {
  51. underlying = os;
  52. }
  53. void ZlibOutStream::setCompressionLevel(int level)
  54. {
  55. if (level < -1 || level > 9)
  56. level = -1; // Z_DEFAULT_COMPRESSION
  57. newLevel = level;
  58. }
  59. int ZlibOutStream::length()
  60. {
  61. return offset + ptr - start;
  62. }
  63. void ZlibOutStream::flush()
  64. {
  65. zs->next_in = start;
  66. zs->avail_in = ptr - start;
  67. // fprintf(stderr,"zos flush: avail_in %d\n",zs->avail_in);
  68. while (zs->avail_in != 0) {
  69. do {
  70. underlying->check(1);
  71. zs->next_out = underlying->getptr();
  72. zs->avail_out = underlying->getend() - underlying->getptr();
  73. // fprintf(stderr,"zos flush: calling deflate, avail_in %d, avail_out %d\n",
  74. // zs->avail_in,zs->avail_out);
  75. checkCompressionLevel();
  76. int rc = deflate(zs, Z_SYNC_FLUSH);
  77. if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed");
  78. // fprintf(stderr,"zos flush: after deflate: %d bytes\n",
  79. // zs->next_out-underlying->getptr());
  80. underlying->setptr(zs->next_out);
  81. } while (zs->avail_out == 0);
  82. }
  83. offset += ptr - start;
  84. ptr = start;
  85. }
  86. int ZlibOutStream::overrun(int itemSize, int nItems)
  87. {
  88. // fprintf(stderr,"ZlibOutStream overrun\n");
  89. if (itemSize > bufSize)
  90. throw Exception("ZlibOutStream overrun: max itemSize exceeded");
  91. while (end - ptr < itemSize) {
  92. zs->next_in = start;
  93. zs->avail_in = ptr - start;
  94. do {
  95. underlying->check(1);
  96. zs->next_out = underlying->getptr();
  97. zs->avail_out = underlying->getend() - underlying->getptr();
  98. // fprintf(stderr,"zos overrun: calling deflate, avail_in %d, avail_out %d\n",
  99. // zs->avail_in,zs->avail_out);
  100. checkCompressionLevel();
  101. int rc = deflate(zs, 0);
  102. if (rc != Z_OK) throw Exception("ZlibOutStream: deflate failed");
  103. // fprintf(stderr,"zos overrun: after deflate: %d bytes\n",
  104. // zs->next_out-underlying->getptr());
  105. underlying->setptr(zs->next_out);
  106. } while (zs->avail_out == 0);
  107. // output buffer not full
  108. if (zs->avail_in == 0) {
  109. offset += ptr - start;
  110. ptr = start;
  111. } else {
  112. // but didn't consume all the data? try shifting what's left to the
  113. // start of the buffer.
  114. fprintf(stderr,"z out buf not full, but in data not consumed\n");
  115. memmove(start, zs->next_in, ptr - zs->next_in);
  116. offset += zs->next_in - start;
  117. ptr -= zs->next_in - start;
  118. }
  119. }
  120. if (itemSize * nItems > end - ptr)
  121. nItems = (end - ptr) / itemSize;
  122. return nItems;
  123. }
  124. void ZlibOutStream::checkCompressionLevel()
  125. {
  126. if (newLevel != compressionLevel) {
  127. if (deflateParams (zs, newLevel, Z_DEFAULT_STRATEGY) != Z_OK) {
  128. throw Exception("ZlibOutStream: deflateParams failed");
  129. }
  130. compressionLevel = newLevel;
  131. }
  132. }