blob: 4053bd1918ae2447d42b1da5491aefaea492c37a [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* 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
Pierre Ossman6f318e42015-11-11 13:11:09 +010019#include <assert.h>
20
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <rdr/ZlibInStream.h>
22#include <rdr/Exception.h>
23#include <zlib.h>
24
25using namespace rdr;
26
27enum { DEFAULT_BUF_SIZE = 16384 };
28
29ZlibInStream::ZlibInStream(int bufSize_)
30 : underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0),
Pierre Ossman6f318e42015-11-11 13:11:09 +010031 zs(NULL), bytesIn(0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000032{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000033 ptr = end = start = new U8[bufSize];
Pierre Ossman6f318e42015-11-11 13:11:09 +010034 init();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000035}
36
37ZlibInStream::~ZlibInStream()
38{
Pierre Ossman6f318e42015-11-11 13:11:09 +010039 deinit();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000040 delete [] start;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000041}
42
43void ZlibInStream::setUnderlying(InStream* is, int bytesIn_)
44{
45 underlying = is;
46 bytesIn = bytesIn_;
47 ptr = end = start;
48}
49
50int ZlibInStream::pos()
51{
52 return offset + ptr - start;
53}
54
Pierre Ossman6f318e42015-11-11 13:11:09 +010055void ZlibInStream::removeUnderlying()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000056{
57 ptr = end = start;
58 if (!underlying) return;
59
60 while (bytesIn > 0) {
61 decompress(true);
62 end = start; // throw away any data
63 }
64 underlying = 0;
65}
66
Pierre Ossman6f318e42015-11-11 13:11:09 +010067void ZlibInStream::reset()
68{
69 deinit();
70 init();
71}
72
73void ZlibInStream::init()
74{
75 assert(zs == NULL);
76
77 zs = new z_stream;
78 zs->zalloc = Z_NULL;
79 zs->zfree = Z_NULL;
80 zs->opaque = Z_NULL;
81 zs->next_in = Z_NULL;
82 zs->avail_in = 0;
83 if (inflateInit(zs) != Z_OK) {
84 delete zs;
85 zs = NULL;
86 throw Exception("ZlibInStream: inflateInit failed");
87 }
88}
89
90void ZlibInStream::deinit()
91{
92 assert(zs != NULL);
93 removeUnderlying();
94 inflateEnd(zs);
95 delete zs;
96 zs = NULL;
97}
98
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000099int ZlibInStream::overrun(int itemSize, int nItems, bool wait)
100{
101 if (itemSize > bufSize)
102 throw Exception("ZlibInStream overrun: max itemSize exceeded");
103 if (!underlying)
104 throw Exception("ZlibInStream overrun: no underlying stream");
105
106 if (end - ptr != 0)
107 memmove(start, ptr, end - ptr);
108
109 offset += ptr - start;
110 end -= ptr - start;
111 ptr = start;
112
113 while (end - ptr < itemSize) {
114 if (!decompress(wait))
115 return 0;
116 }
117
118 if (itemSize * nItems > end - ptr)
119 nItems = (end - ptr) / itemSize;
120
121 return nItems;
122}
123
124// decompress() calls the decompressor once. Note that this won't necessarily
125// generate any output data - it may just consume some input data. Returns
126// false if wait is false and we would block on the underlying stream.
127
128bool ZlibInStream::decompress(bool wait)
129{
130 zs->next_out = (U8*)end;
131 zs->avail_out = start + bufSize - end;
132
133 int n = underlying->check(1, 1, wait);
134 if (n == 0) return false;
135 zs->next_in = (U8*)underlying->getptr();
136 zs->avail_in = underlying->getend() - underlying->getptr();
137 if ((int)zs->avail_in > bytesIn)
138 zs->avail_in = bytesIn;
139
140 int rc = inflate(zs, Z_SYNC_FLUSH);
141 if (rc != Z_OK) {
142 throw Exception("ZlibInStream: inflate failed");
143 }
144
145 bytesIn -= zs->next_in - underlying->getptr();
146 end = zs->next_out;
147 underlying->setptr(zs->next_in);
148 return true;
149}