blob: 6f3a7d02fb7b33181004bc0ce82fef0cc01b55bb [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
19#include <rdr/ZlibInStream.h>
20#include <rdr/Exception.h>
21#include <zlib.h>
22
23using namespace rdr;
24
25enum { DEFAULT_BUF_SIZE = 16384 };
26
27ZlibInStream::ZlibInStream(int bufSize_)
28 : underlying(0), bufSize(bufSize_ ? bufSize_ : DEFAULT_BUF_SIZE), offset(0),
29 bytesIn(0)
30{
31 zs = new z_stream;
32 zs->zalloc = Z_NULL;
33 zs->zfree = Z_NULL;
34 zs->opaque = Z_NULL;
35 zs->next_in = Z_NULL;
36 zs->avail_in = 0;
37 if (inflateInit(zs) != Z_OK) {
38 delete zs;
39 throw Exception("ZlibInStream: inflateInit failed");
40 }
41 ptr = end = start = new U8[bufSize];
42}
43
44ZlibInStream::~ZlibInStream()
45{
46 delete [] start;
47 inflateEnd(zs);
48 delete zs;
49}
50
51void ZlibInStream::setUnderlying(InStream* is, int bytesIn_)
52{
53 underlying = is;
54 bytesIn = bytesIn_;
55 ptr = end = start;
56}
57
58int ZlibInStream::pos()
59{
60 return offset + ptr - start;
61}
62
63void ZlibInStream::reset()
64{
65 ptr = end = start;
66 if (!underlying) return;
67
68 while (bytesIn > 0) {
69 decompress(true);
70 end = start; // throw away any data
71 }
72 underlying = 0;
73}
74
75int ZlibInStream::overrun(int itemSize, int nItems, bool wait)
76{
77 if (itemSize > bufSize)
78 throw Exception("ZlibInStream overrun: max itemSize exceeded");
79 if (!underlying)
80 throw Exception("ZlibInStream overrun: no underlying stream");
81
82 if (end - ptr != 0)
83 memmove(start, ptr, end - ptr);
84
85 offset += ptr - start;
86 end -= ptr - start;
87 ptr = start;
88
89 while (end - ptr < itemSize) {
90 if (!decompress(wait))
91 return 0;
92 }
93
94 if (itemSize * nItems > end - ptr)
95 nItems = (end - ptr) / itemSize;
96
97 return nItems;
98}
99
100// decompress() calls the decompressor once. Note that this won't necessarily
101// generate any output data - it may just consume some input data. Returns
102// false if wait is false and we would block on the underlying stream.
103
104bool ZlibInStream::decompress(bool wait)
105{
106 zs->next_out = (U8*)end;
107 zs->avail_out = start + bufSize - end;
108
109 int n = underlying->check(1, 1, wait);
110 if (n == 0) return false;
111 zs->next_in = (U8*)underlying->getptr();
112 zs->avail_in = underlying->getend() - underlying->getptr();
113 if ((int)zs->avail_in > bytesIn)
114 zs->avail_in = bytesIn;
115
116 int rc = inflate(zs, Z_SYNC_FLUSH);
117 if (rc != Z_OK) {
118 throw Exception("ZlibInStream: inflate failed");
119 }
120
121 bytesIn -= zs->next_in - underlying->getptr();
122 end = zs->next_out;
123 underlying->setptr(zs->next_in);
124 return true;
125}