1 /*
2 * IO layer : zlib streambuf
3 *
4 * Authors:
5 * Johan Ceuppens <jceuppen at easynet dot be>
6 *
7 * Copyright (C) 2004 Johan Ceuppens
8 *
9 * Released under GNU LGPL, read the file 'COPYING.LIB' for more information
10 */
12 #include <cstring>
13 #include <string>
14 #include <string.h>
15 #include <vector>
16 #include "streams-zlib.h"
18 namespace Inkscape {
20 /**
21 * ZlibBuffer
22 */
24 ZlibBuffer::ZlibBuffer(URIHandle& urih)
25 : _urihandle(&urih), _putsize(BUFSIZE_STREAM), _getsize(BUFSIZE_STREAM)
26 {
27 init_inflation();
28 }
30 int ZlibBuffer::allocate_buffers()
31 {
32 if (!eback()) {
33 char *buf = new char[_getsize + _putsize];
34 setg(buf, buf , buf);
35 buf += _getsize;
36 setp(buf, buf + _putsize);
37 return 1;
38 }
39 return 0;
40 }
42 int ZlibBuffer::reallocate_buffers(int new_getsize, int new_putsize)
43 {
44 char *new_buffer = new char[new_getsize + new_putsize];
46 std::memcpy(new_buffer, eback(), _getsize);
47 std::memcpy(new_buffer, eback() + _getsize, _putsize);
49 setg(new_buffer, new_buffer + (gptr() - eback()),
50 new_buffer + new_getsize);
51 new_buffer += new_getsize;
52 setp(new_buffer, new_buffer + new_putsize);
54 _getsize = new_getsize;
55 _putsize = new_putsize;
57 return 1;
58 }
60 int ZlibBuffer::underflow()
61 {
62 if (eback() == 0 && allocate_buffers() == 0)
63 return EOF;
65 if (consume_and_inflate() == EOF)
66 return EOF;
68 return *(unsigned char *)gptr();
69 }
71 int ZlibBuffer::overflow(int c)
72 {
73 if (c == EOF)
74 return flush_output();
76 if (pbase() == 0 && allocate_buffers() == 0)
77 return EOF;
79 if (pptr() >= epptr() &&
80 flush_output() == EOF)
81 return EOF;
83 putchar(c);
85 if (pptr() >= epptr() &&
86 flush_output() == EOF)
87 return EOF;
89 return c;
90 }
92 int ZlibBuffer::consume(guint8 *buf, int nbytes)
93 {
94 return do_consume(buf, nbytes);
95 }
97 int ZlibBuffer::do_consume(guint8 *buf, int nbytes)
98 {
99 nbytes = _urihandle->read(buf, nbytes);
101 if (nbytes == EOF)
102 return EOF;
103 else if (nbytes == 0)
104 return EOF;
106 return nbytes;
107 }
109 int ZlibBuffer::do_consume_and_inflate(int nbytes)
110 {
111 std::vector<guint8> buf(nbytes);
113 int ret=consume(&buf[0], nbytes);
115 if ( ret != EOF ) {
116 ret = 1;
117 GByteArray *gba = inflate(&buf[0], nbytes);
118 copy_to_get(gba->data, gba->len);
119 g_byte_array_free(gba, TRUE);
120 }
122 return ret;
123 }
125 int ZlibBuffer::consume_and_inflate()
126 {
127 return do_consume_and_inflate(BUFSIZE_STREAM);
128 }
130 int ZlibBuffer::flush_output()
131 {
132 if (pptr() <= pbase())
133 return 0;
134 int len = pptr() - pbase();
135 int nbytes = _urihandle->write(pbase(), len);
136 setp(pbase(), pbase() + BUFSIZE_STREAM);
137 if (len == nbytes)
138 return 0;
139 else
140 return EOF;
141 }
143 void ZlibBuffer::init_inflation() throw(ZlibBufferException)
144 {
145 memset(&_zs, 0, sizeof(z_stream));
147 _zs.zalloc = Z_NULL;
148 _zs.zfree = Z_NULL;
149 _zs.opaque = Z_NULL;
151 if(inflateInit2(&_zs, -15) != Z_OK) {
152 throw ZlibBufferException();
153 }
155 }
157 void ZlibBuffer::reset_inflation() throw(ZlibBufferException)
158 {
159 if (inflateReset(&_zs) != Z_OK)
160 throw ZlibBufferException();
161 }
163 GByteArray *ZlibBuffer::inflate(guint8 *in_buffer, int nbytes)
164 {
165 return do_inflate(in_buffer, nbytes);
166 }
168 GByteArray *ZlibBuffer::do_inflate(guint8 *data, int nbytes)
169 {
170 GByteArray *gba = g_byte_array_new();
171 guint8 out_buffer[BUFSIZE_STREAM];
173 _zs.avail_in = 0;
174 guint32 crc = crc32(0, Z_NULL, 0);
176 if (!_zs.avail_in) {
177 _zs.avail_in = nbytes;
178 _zs.next_in = (Bytef *)data;
179 crc = crc32(crc, (Bytef *)data, _zs.avail_in);
180 }
181 do {
182 _zs.next_out = out_buffer;
183 _zs.avail_out = BUFSIZE_STREAM;
185 int ret = ::inflate(&_zs, Z_NO_FLUSH);
186 if (BUFSIZE_STREAM != _zs.avail_out) {
187 unsigned int tmp_len = BUFSIZE_STREAM - _zs.avail_out;
188 g_byte_array_append(gba, out_buffer, tmp_len);
189 }
191 if (ret == Z_STREAM_END) {
192 break;
193 }
194 if (ret != Z_OK) {
195 std::fprintf(stderr, "decompression error %d\n", ret);
196 break;
197 }
198 } while (_zs.avail_in);
200 return gba;
201 }
203 int ZlibBuffer::copy_to_get(guint8 *data, int nbytes)
204 {
205 return do_copy_to_get(data, nbytes);
206 }
208 int ZlibBuffer::do_copy_to_get(guint8 *data, int nbytes)
209 {
210 if (nbytes + gptr() - eback() > _getsize)
211 reallocate_buffers(nbytes + gptr() - eback() + BUFSIZE_STREAM,
212 _putsize);
214 std::memcpy(gptr(), data, nbytes);
215 setg(eback(), gptr(), gptr() + nbytes);
216 return 1;
217 }
219 } // namespace Inkscape
221 /*
222 Local Variables:
223 mode:c++
224 c-file-style:"stroustrup"
225 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
226 indent-tabs-mode:nil
227 fill-column:99
228 End:
229 */
230 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :