blob: ba5cb7c85eda928dc78825ae04357945c6fb3b3c [file] [log] [blame]
Reid Spencer460eb632004-10-04 10:49:41 +00001//===- lib/Support/Compressor.cpp -------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Reid Spencer and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the llvm::Compressor class, an abstraction for memory
11// block compression.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Config/config.h"
16#include "llvm/Support/Compressor.h"
17#include "llvm/ADT/StringExtras.h"
18#include <cassert>
19#include <string>
20
21#ifdef HAVE_BZIP2
Reid Spencerebf2bda2004-11-19 15:56:28 +000022#ifdef HAVE_BZLIB_H
Reid Spencer460eb632004-10-04 10:49:41 +000023#include <bzlib.h>
Reid Spencerebf2bda2004-11-19 15:56:28 +000024#define BZIP2_GOOD
25#endif
26#endif
Reid Spencer460eb632004-10-04 10:49:41 +000027
28#ifdef HAVE_ZLIB
Reid Spencerebf2bda2004-11-19 15:56:28 +000029#ifdef HAVE_ZLIB_H
Reid Spencer460eb632004-10-04 10:49:41 +000030#include <zlib.h>
Reid Spencerebf2bda2004-11-19 15:56:28 +000031#define ZLIB_GOOD
32#endif
Reid Spencer460eb632004-10-04 10:49:41 +000033#endif
34
Reid Spencer460eb632004-10-04 10:49:41 +000035namespace {
36
37inline int getdata(char*& buffer, unsigned& size,
Reid Spencer469c34b2004-10-04 17:29:25 +000038 llvm::Compressor::OutputDataCallback* cb, void* context) {
Reid Spencer460eb632004-10-04 10:49:41 +000039 buffer = 0;
40 size = 0;
Reid Spencer469c34b2004-10-04 17:29:25 +000041 int result = (*cb)(buffer, size, context);
Reid Spencer460eb632004-10-04 10:49:41 +000042 assert(buffer != 0 && "Invalid result from Compressor callback");
43 assert(size != 0 && "Invalid result from Compressor callback");
44 return result;
45}
46
47//===----------------------------------------------------------------------===//
Reid Spencer047c0092004-10-04 17:45:44 +000048//=== NULLCOMP - a compression like set of routines that just copies data
49//=== without doing any compression. This is provided so that if the
50//=== configured environment doesn't have a compression library the
51//=== program can still work, albeit using more data/memory.
Reid Spencer460eb632004-10-04 10:49:41 +000052//===----------------------------------------------------------------------===//
53
Reid Spencer047c0092004-10-04 17:45:44 +000054struct NULLCOMP_stream {
Reid Spencer460eb632004-10-04 10:49:41 +000055 // User provided fields
56 char* next_in;
57 unsigned avail_in;
58 char* next_out;
59 unsigned avail_out;
60
61 // Information fields
62 uint64_t output_count; // Total count of output bytes
Reid Spencer460eb632004-10-04 10:49:41 +000063};
64
Reid Spencer047c0092004-10-04 17:45:44 +000065void NULLCOMP_init(NULLCOMP_stream* s) {
Reid Spencer460eb632004-10-04 10:49:41 +000066 s->output_count = 0;
Reid Spencer460eb632004-10-04 10:49:41 +000067}
68
Reid Spencer047c0092004-10-04 17:45:44 +000069bool NULLCOMP_compress(NULLCOMP_stream* s) {
70 assert(s && "Invalid NULLCOMP_stream");
Reid Spencer460eb632004-10-04 10:49:41 +000071 assert(s->next_in != 0);
72 assert(s->next_out != 0);
73 assert(s->avail_in >= 1);
74 assert(s->avail_out >= 1);
75
Reid Spencer460eb632004-10-04 10:49:41 +000076 if (s->avail_out >= s->avail_in) {
77 ::memcpy(s->next_out, s->next_in, s->avail_in);
78 s->output_count += s->avail_in;
79 s->avail_out -= s->avail_in;
80 s->next_in += s->avail_in;
81 s->avail_in = 0;
82 return true;
83 } else {
84 ::memcpy(s->next_out, s->next_in, s->avail_out);
85 s->output_count += s->avail_out;
86 s->avail_in -= s->avail_out;
87 s->next_in += s->avail_out;
88 s->avail_out = 0;
89 return false;
90 }
91}
92
Reid Spencer047c0092004-10-04 17:45:44 +000093bool NULLCOMP_decompress(NULLCOMP_stream* s) {
94 assert(s && "Invalid NULLCOMP_stream");
Reid Spencer460eb632004-10-04 10:49:41 +000095 assert(s->next_in != 0);
96 assert(s->next_out != 0);
97 assert(s->avail_in >= 1);
98 assert(s->avail_out >= 1);
99
Reid Spencer460eb632004-10-04 10:49:41 +0000100 if (s->avail_out >= s->avail_in) {
101 ::memcpy(s->next_out, s->next_in, s->avail_in);
102 s->output_count += s->avail_in;
103 s->avail_out -= s->avail_in;
104 s->next_in += s->avail_in;
105 s->avail_in = 0;
106 return true;
107 } else {
108 ::memcpy(s->next_out, s->next_in, s->avail_out);
109 s->output_count += s->avail_out;
110 s->avail_in -= s->avail_out;
111 s->next_in += s->avail_out;
112 s->avail_out = 0;
113 return false;
114 }
115}
116
Reid Spencer047c0092004-10-04 17:45:44 +0000117void NULLCOMP_end(NULLCOMP_stream* strm) {
Reid Spencer460eb632004-10-04 10:49:41 +0000118}
119
Reid Spencere3c6ad72004-11-14 22:04:46 +0000120/// This structure is only used when a bytecode file is compressed.
121/// As bytecode is being decompressed, the memory buffer might need
122/// to be reallocated. The buffer allocation is handled in a callback
123/// and this structure is needed to retain information across calls
124/// to the callback.
125/// @brief An internal buffer object used for handling decompression
126struct BufferContext {
127 char* buff;
128 unsigned size;
129 BufferContext(unsigned compressedSize ) {
130 // Null to indicate malloc of a new block
131 buff = 0;
132
133 // Compute the initial length of the uncompression buffer. Note that this
134 // is twice the length of the compressed buffer and will be doubled again
135 // in the callback for an initial allocation of 4x compressedSize. This
136 // calculation is based on the typical compression ratio of bzip2 on LLVM
137 // bytecode files which typically ranges in the 50%-75% range. Since we
138 // tyipcally get at least 50%, doubling is insufficient. By using a 4x
139 // multiplier on the first allocation, we minimize the impact of having to
140 // copy the buffer on reallocation.
141 size = compressedSize*2;
142 }
143
144 /// This function handles allocation of the buffer used for decompression of
145 /// compressed bytecode files. It is called by Compressor::decompress which is
146 /// called by BytecodeReader::ParseBytecode.
147 static unsigned callback(char*&buff, unsigned& sz, void* ctxt){
148 // Case the context variable to our BufferContext
149 BufferContext* bc = reinterpret_cast<BufferContext*>(ctxt);
150
151 // Compute the new, doubled, size of the block
152 unsigned new_size = bc->size * 2;
153
154 // Extend or allocate the block (realloc(0,n) == malloc(n))
155 char* new_buff = (char*) ::realloc(bc->buff, new_size);
156
157 // Figure out what to return to the Compressor. If this is the first call,
158 // then bc->buff will be null. In this case we want to return the entire
159 // buffer because there was no previous allocation. Otherwise, when the
160 // buffer is reallocated, we save the new base pointer in the BufferContext.buff
161 // field but return the address of only the extension, mid-way through the
162 // buffer (since its size was doubled). Furthermore, the sz result must be
163 // 1/2 the total size of the buffer.
164 if (bc->buff == 0 ) {
165 buff = bc->buff = new_buff;
166 sz = new_size;
167 } else {
168 bc->buff = new_buff;
169 buff = new_buff + bc->size;
170 sz = bc->size;
171 }
172
173 // Retain the size of the allocated block
174 bc->size = new_size;
175
176 // Make sure we fail (return 1) if we didn't get any memory.
177 return (bc->buff == 0 ? 1 : 0);
178 }
179};
180
181// This structure retains the context when compressing the bytecode file. The
182// WriteCompressedData function below uses it to keep track of the previously
183// filled chunk of memory (which it writes) and how many bytes have been
184// written.
185struct WriterContext {
186 // Initialize the context
187 WriterContext(std::ostream*OS, unsigned CS)
188 : chunk(0), sz(0), written(0), compSize(CS), Out(OS) {}
189
190 // Make sure we clean up memory
191 ~WriterContext() {
192 if (chunk)
193 delete [] chunk;
194 }
195
196 // Write the chunk
197 void write(unsigned size = 0) {
198 unsigned write_size = (size == 0 ? sz : size);
199 Out->write(chunk,write_size);
200 written += write_size;
201 delete [] chunk;
202 chunk = 0;
203 sz = 0;
204 }
205
206 // This function is a callback used by the Compressor::compress function to
207 // allocate memory for the compression buffer. This function fulfills that
208 // responsibility but also writes the previous (now filled) buffer out to the
209 // stream.
210 static unsigned callback(char*& buffer, unsigned& size, void* context) {
211 // Cast the context to the structure it must point to.
212 WriterContext* ctxt =
213 reinterpret_cast<WriterContext*>(context);
214
215 // If there's a previously allocated chunk, it must now be filled with
216 // compressed data, so we write it out and deallocate it.
217 if (ctxt->chunk != 0 && ctxt->sz > 0 ) {
218 ctxt->write();
219 }
220
221 // Compute the size of the next chunk to allocate. We attempt to allocate
222 // enough memory to handle the compression in a single memory allocation. In
223 // general, the worst we do on compression of bytecode is about 50% so we
224 // conservatively estimate compSize / 2 as the size needed for the
225 // compression buffer. compSize is the size of the compressed data, provided
226 // by WriteBytecodeToFile.
227 size = ctxt->sz = ctxt->compSize / 2;
228
229 // Allocate the chunks
230 buffer = ctxt->chunk = new char [size];
231
232 // We must return 1 if the allocation failed so that the Compressor knows
233 // not to use the buffer pointer.
234 return (ctxt->chunk == 0 ? 1 : 0);
235 }
236
237 char* chunk; // pointer to the chunk of memory filled by compression
238 unsigned sz; // size of chunk
239 unsigned written; // aggregate total of bytes written in all chunks
240 unsigned compSize; // size of the uncompressed buffer
241 std::ostream* Out; // The stream we write the data to.
242};
243
Reid Spencer460eb632004-10-04 10:49:41 +0000244}
245
246namespace llvm {
247
248// Compress in one of three ways
Reid Spencere3c6ad72004-11-14 22:04:46 +0000249uint64_t Compressor::compress(const char* in, unsigned size,
250 OutputDataCallback* cb, Algorithm hint, void* context ) {
Reid Spencer460eb632004-10-04 10:49:41 +0000251 assert(in && "Can't compress null buffer");
252 assert(size && "Can't compress empty buffer");
253 assert(cb && "Can't compress without a callback function");
254
255 uint64_t result = 0;
256
257 switch (hint) {
258 case COMP_TYPE_BZIP2: {
Reid Spencerebf2bda2004-11-19 15:56:28 +0000259#if defined(BZIP2_GOOD)
Reid Spencer460eb632004-10-04 10:49:41 +0000260 // Set up the bz_stream
261 bz_stream bzdata;
262 bzdata.bzalloc = 0;
263 bzdata.bzfree = 0;
264 bzdata.opaque = 0;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000265 bzdata.next_in = (char*)in;
Reid Spencer460eb632004-10-04 10:49:41 +0000266 bzdata.avail_in = size;
267 bzdata.next_out = 0;
268 bzdata.avail_out = 0;
Reid Spencer580a1162004-11-09 17:58:09 +0000269 switch ( BZ2_bzCompressInit(&bzdata, 5, 0, 100) ) {
Reid Spencer460eb632004-10-04 10:49:41 +0000270 case BZ_CONFIG_ERROR: throw std::string("bzip2 library mis-compiled");
271 case BZ_PARAM_ERROR: throw std::string("Compressor internal error");
272 case BZ_MEM_ERROR: throw std::string("Out of memory");
273 case BZ_OK:
274 default:
275 break;
276 }
277
278 // Get a block of memory
Reid Spencer469c34b2004-10-04 17:29:25 +0000279 if (0 != getdata(bzdata.next_out, bzdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000280 BZ2_bzCompressEnd(&bzdata);
281 throw std::string("Can't allocate output buffer");
282 }
283
284 // Put compression code in first byte
285 (*bzdata.next_out++) = COMP_TYPE_BZIP2;
286 bzdata.avail_out--;
287
288 // Compress it
289 int bzerr = BZ_FINISH_OK;
290 while (BZ_FINISH_OK == (bzerr = BZ2_bzCompress(&bzdata, BZ_FINISH))) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000291 if (0 != getdata(bzdata.next_out, bzdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000292 BZ2_bzCompressEnd(&bzdata);
293 throw std::string("Can't allocate output buffer");
294 }
295 }
296 switch (bzerr) {
297 case BZ_SEQUENCE_ERROR:
298 case BZ_PARAM_ERROR: throw std::string("Param/Sequence error");
299 case BZ_FINISH_OK:
300 case BZ_STREAM_END: break;
301 default: throw std::string("Oops: ") + utostr(unsigned(bzerr));
302 }
303
304 // Finish
305 result = (static_cast<uint64_t>(bzdata.total_out_hi32) << 32) |
306 bzdata.total_out_lo32 + 1;
307
308 BZ2_bzCompressEnd(&bzdata);
309 break;
310#else
311 // FALL THROUGH
312#endif
313 }
314
315 case COMP_TYPE_ZLIB: {
Reid Spencerebf2bda2004-11-19 15:56:28 +0000316#if defined(ZLIB_GOOD)
Reid Spencer460eb632004-10-04 10:49:41 +0000317 z_stream zdata;
318 zdata.zalloc = Z_NULL;
319 zdata.zfree = Z_NULL;
320 zdata.opaque = Z_NULL;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000321 zdata.next_in = (Bytef*)in;
Reid Spencer460eb632004-10-04 10:49:41 +0000322 zdata.avail_in = size;
Reid Spencer580a1162004-11-09 17:58:09 +0000323 if (Z_OK != deflateInit(&zdata,6))
Reid Spencer460eb632004-10-04 10:49:41 +0000324 throw std::string(zdata.msg ? zdata.msg : "zlib error");
325
Reid Spencer469c34b2004-10-04 17:29:25 +0000326 if (0 != getdata((char*&)(zdata.next_out), zdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000327 deflateEnd(&zdata);
328 throw std::string("Can't allocate output buffer");
329 }
330
331 (*zdata.next_out++) = COMP_TYPE_ZLIB;
332 zdata.avail_out--;
333
334 int flush = 0;
335 while ( Z_OK == deflate(&zdata,0) && zdata.avail_out == 0) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000336 if (0 != getdata((char*&)zdata.next_out, zdata.avail_out, cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000337 deflateEnd(&zdata);
338 throw std::string("Can't allocate output buffer");
339 }
340 }
341
342 while ( Z_STREAM_END != deflate(&zdata, Z_FINISH)) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000343 if (0 != getdata((char*&)zdata.next_out, zdata.avail_out, cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000344 deflateEnd(&zdata);
345 throw std::string("Can't allocate output buffer");
346 }
347 }
348
349 result = static_cast<uint64_t>(zdata.total_out) + 1;
350 deflateEnd(&zdata);
351 break;
352
353#else
354 // FALL THROUGH
355#endif
356 }
357
358 case COMP_TYPE_SIMPLE: {
Reid Spencer047c0092004-10-04 17:45:44 +0000359 NULLCOMP_stream sdata;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000360 sdata.next_in = (char*)in;
Reid Spencer460eb632004-10-04 10:49:41 +0000361 sdata.avail_in = size;
Reid Spencer047c0092004-10-04 17:45:44 +0000362 NULLCOMP_init(&sdata);
Reid Spencer460eb632004-10-04 10:49:41 +0000363
Reid Spencer469c34b2004-10-04 17:29:25 +0000364 if (0 != getdata(sdata.next_out, sdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000365 throw std::string("Can't allocate output buffer");
366 }
367
368 *(sdata.next_out++) = COMP_TYPE_SIMPLE;
369 sdata.avail_out--;
370
Reid Spencer047c0092004-10-04 17:45:44 +0000371 while (!NULLCOMP_compress(&sdata)) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000372 if (0 != getdata(sdata.next_out, sdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000373 throw std::string("Can't allocate output buffer");
374 }
375 }
376
377 result = sdata.output_count + 1;
Reid Spencer047c0092004-10-04 17:45:44 +0000378 NULLCOMP_end(&sdata);
Reid Spencer460eb632004-10-04 10:49:41 +0000379 break;
380 }
381 default:
382 throw std::string("Invalid compression type hint");
383 }
384 return result;
385}
386
Reid Spencere3c6ad72004-11-14 22:04:46 +0000387uint64_t
388Compressor::compressToNewBuffer(const char* in, unsigned size, char*&out,
389 Algorithm hint) {
390 BufferContext bc(size);
391 unsigned result = compress(in,size,BufferContext::callback,hint,(void*)&bc);
392 out = bc.buff;
393 return result;
394}
395
396uint64_t
397Compressor::compressToStream(const char*in, unsigned size, std::ostream& out,
398 Algorithm hint) {
399 // Set up the context and writer
400 WriterContext ctxt(&out,size / 2);
401
402 // Compress everything after the magic number (which we'll alter)
403 uint64_t zipSize = Compressor::compress(in,size,
404 WriterContext::callback, hint, (void*)&ctxt);
405
406 if (ctxt.chunk) {
407 ctxt.write(zipSize - ctxt.written);
408 }
409 return zipSize;
410}
411
Reid Spencer460eb632004-10-04 10:49:41 +0000412// Decompress in one of three ways
Reid Spencere3c6ad72004-11-14 22:04:46 +0000413uint64_t Compressor::decompress(const char *in, unsigned size,
Reid Spencer469c34b2004-10-04 17:29:25 +0000414 OutputDataCallback* cb, void* context) {
Reid Spencer460eb632004-10-04 10:49:41 +0000415 assert(in && "Can't decompress null buffer");
416 assert(size > 1 && "Can't decompress empty buffer");
417 assert(cb && "Can't decompress without a callback function");
418
419 uint64_t result = 0;
420
421 switch (*in++) {
422 case COMP_TYPE_BZIP2: {
Reid Spencerebf2bda2004-11-19 15:56:28 +0000423#if !defined(BZIP2_GOOD)
Reid Spencer460eb632004-10-04 10:49:41 +0000424 throw std::string("Can't decompress BZIP2 data");
425#else
426 // Set up the bz_stream
427 bz_stream bzdata;
428 bzdata.bzalloc = 0;
429 bzdata.bzfree = 0;
430 bzdata.opaque = 0;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000431 bzdata.next_in = (char*)in;
Reid Spencer460eb632004-10-04 10:49:41 +0000432 bzdata.avail_in = size - 1;
433 bzdata.next_out = 0;
434 bzdata.avail_out = 0;
435 switch ( BZ2_bzDecompressInit(&bzdata, 0, 0) ) {
436 case BZ_CONFIG_ERROR: throw std::string("bzip2 library mis-compiled");
437 case BZ_PARAM_ERROR: throw std::string("Compressor internal error");
438 case BZ_MEM_ERROR: throw std::string("Out of memory");
439 case BZ_OK:
440 default:
441 break;
442 }
443
444 // Get a block of memory
Reid Spencer469c34b2004-10-04 17:29:25 +0000445 if (0 != getdata(bzdata.next_out, bzdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000446 BZ2_bzDecompressEnd(&bzdata);
447 throw std::string("Can't allocate output buffer");
448 }
449
450 // Decompress it
451 int bzerr = BZ_OK;
452 while (BZ_OK == (bzerr = BZ2_bzDecompress(&bzdata))) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000453 if (0 != getdata(bzdata.next_out, bzdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000454 BZ2_bzDecompressEnd(&bzdata);
455 throw std::string("Can't allocate output buffer");
456 }
457 }
458
459 switch (bzerr) {
460 case BZ_PARAM_ERROR: throw std::string("Compressor internal error");
461 case BZ_MEM_ERROR: throw std::string("Out of memory");
462 case BZ_DATA_ERROR: throw std::string("Data integrity error");
463 case BZ_DATA_ERROR_MAGIC:throw std::string("Data is not BZIP2");
464 default: throw("Ooops");
465 case BZ_STREAM_END:
466 break;
467 }
468
469 // Finish
470 result = (static_cast<uint64_t>(bzdata.total_out_hi32) << 32) |
471 bzdata.total_out_lo32;
472 BZ2_bzDecompressEnd(&bzdata);
473 break;
Reid Spencer460eb632004-10-04 10:49:41 +0000474#endif
Chris Lattnerebe989c2004-10-04 16:33:25 +0000475 }
Reid Spencer460eb632004-10-04 10:49:41 +0000476
477 case COMP_TYPE_ZLIB: {
Reid Spencerebf2bda2004-11-19 15:56:28 +0000478#if !defined(ZLIB_GOOD)
Reid Spencer460eb632004-10-04 10:49:41 +0000479 throw std::string("Can't decompress ZLIB data");
480#else
481 z_stream zdata;
482 zdata.zalloc = Z_NULL;
483 zdata.zfree = Z_NULL;
484 zdata.opaque = Z_NULL;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000485 zdata.next_in = (Bytef*)(in);
Reid Spencer460eb632004-10-04 10:49:41 +0000486 zdata.avail_in = size - 1;
487 if ( Z_OK != inflateInit(&zdata))
488 throw std::string(zdata.msg ? zdata.msg : "zlib error");
489
Reid Spencer469c34b2004-10-04 17:29:25 +0000490 if (0 != getdata((char*&)zdata.next_out, zdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000491 inflateEnd(&zdata);
492 throw std::string("Can't allocate output buffer");
493 }
494
495 int zerr = Z_OK;
496 while (Z_OK == (zerr = inflate(&zdata,0))) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000497 if (0 != getdata((char*&)zdata.next_out, zdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000498 inflateEnd(&zdata);
499 throw std::string("Can't allocate output buffer");
500 }
501 }
502
503 if (zerr != Z_STREAM_END)
504 throw std::string(zdata.msg?zdata.msg:"zlib error");
505
506 result = static_cast<uint64_t>(zdata.total_out);
507 inflateEnd(&zdata);
508 break;
509#endif
510 }
511
512 case COMP_TYPE_SIMPLE: {
Reid Spencer047c0092004-10-04 17:45:44 +0000513 NULLCOMP_stream sdata;
Reid Spencere3c6ad72004-11-14 22:04:46 +0000514 sdata.next_in = (char*)in;
Reid Spencer460eb632004-10-04 10:49:41 +0000515 sdata.avail_in = size - 1;
Reid Spencer047c0092004-10-04 17:45:44 +0000516 NULLCOMP_init(&sdata);
Reid Spencer460eb632004-10-04 10:49:41 +0000517
Reid Spencer469c34b2004-10-04 17:29:25 +0000518 if (0 != getdata(sdata.next_out, sdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000519 throw std::string("Can't allocate output buffer");
520 }
521
Reid Spencer047c0092004-10-04 17:45:44 +0000522 while (!NULLCOMP_decompress(&sdata)) {
Reid Spencer469c34b2004-10-04 17:29:25 +0000523 if (0 != getdata(sdata.next_out, sdata.avail_out,cb,context)) {
Reid Spencer460eb632004-10-04 10:49:41 +0000524 throw std::string("Can't allocate output buffer");
525 }
526 }
527
528 result = sdata.output_count;
Reid Spencer047c0092004-10-04 17:45:44 +0000529 NULLCOMP_end(&sdata);
Reid Spencer460eb632004-10-04 10:49:41 +0000530 break;
531 }
532
533 default:
534 throw std::string("Unknown type of compressed data");
535 }
536
537 return result;
538}
539
Reid Spencere3c6ad72004-11-14 22:04:46 +0000540uint64_t
541Compressor::decompressToNewBuffer(const char* in, unsigned size, char*&out) {
542 BufferContext bc(size);
543 unsigned result = decompress(in,size,BufferContext::callback,(void*)&bc);
544 out = bc.buff;
545 return result;
546}
547
548uint64_t
549Compressor::decompressToStream(const char*in, unsigned size, std::ostream& out){
550 // Set up the context and writer
551 WriterContext ctxt(&out,size / 2);
552
553 // Compress everything after the magic number (which we'll alter)
554 uint64_t zipSize = Compressor::decompress(in,size,
555 WriterContext::callback, (void*)&ctxt);
556
557 if (ctxt.chunk) {
558 ctxt.write(zipSize - ctxt.written);
559 }
560 return zipSize;
561}
562
Reid Spencer460eb632004-10-04 10:49:41 +0000563}
564
565// vim: sw=2 ai