1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22 #include "../my_config.h"
23 
24 #include "wrapperlib.hpp"
25 #include "erreurs.hpp"
26 
27 #define CHECK_Z if(z_ptr == nullptr) throw SRC_BUG
28 #define CHECK_BZ if(bz_ptr == nullptr) throw SRC_BUG
29 #define CHECK_LZMA if(lzma_ptr == nullptr) throw SRC_BUG;
30 
31 using namespace std;
32 
33 namespace libdar
34 {
35 
36 #if LIBZ_AVAILABLE
37     static S_I zlib2wrap_code(S_I code);
38     static S_I wrap2zlib_code(S_I code);
39 #endif
40 #if LIBBZ2_AVAILABLE
41     static S_I bzlib2wrap_code(S_I code);
42     static S_I wrap2bzlib_code(S_I code);
43 #endif
44 #if LIBLZMA_AVAILABLE
45     static S_I lzma2wrap_code(S_I code);
46     static lzma_action wrap2lzma_code(S_I code);
47 #endif
48 
wrapperlib(wrapperlib_mode mode)49     wrapperlib::wrapperlib(wrapperlib_mode mode)
50     {
51         switch(mode)
52         {
53         case zlib_mode:
54 #if LIBZ_AVAILABLE
55 	    meta_new(z_ptr, 1);
56             if(z_ptr == nullptr)
57                 throw Ememory("wrapperlib::wrapperlib");
58 #if LIBBZ2_AVAILABLE
59             bz_ptr = nullptr;
60 #endif
61 #if LIBLZMA_AVAILABLE
62 	    lzma_ptr = nullptr;
63 #endif
64             z_ptr->zalloc = nullptr;
65             z_ptr->zfree = nullptr;
66             z_ptr->opaque = nullptr;
67             x_compressInit = & wrapperlib::z_compressInit;
68             x_decompressInit = & wrapperlib::z_decompressInit;
69             x_compressEnd = & wrapperlib::z_compressEnd;
70             x_decompressEnd = & wrapperlib::z_decompressEnd;
71             x_compress = & wrapperlib::z_compress;
72             x_decompress = & wrapperlib::z_decompress;
73             x_set_next_in = & wrapperlib::z_set_next_in;
74             x_set_avail_in = & wrapperlib::z_set_avail_in;
75             x_get_avail_in = & wrapperlib::z_get_avail_in;
76             x_get_total_in = & wrapperlib::z_get_total_in;
77             x_set_next_out = & wrapperlib::z_set_next_out;
78             x_get_next_out = & wrapperlib::z_get_next_out;
79             x_set_avail_out = & wrapperlib::z_set_avail_out;
80             x_get_avail_out = & wrapperlib::z_get_avail_out;
81             x_get_total_out = & wrapperlib::z_get_total_out;
82             break;
83 #else
84 	    throw Ecompilation("zlib compression support");
85 #endif
86         case bzlib_mode:
87 #if LIBBZ2_AVAILABLE
88 	    meta_new(bz_ptr, 1);
89             if(bz_ptr == nullptr)
90                 throw Ememory("wrapperlib::wrapperlib");
91 #if LIBZ_AVAILABLE
92             z_ptr = nullptr;
93 #endif
94 #if LIBLZMA_AVAILABLE
95 	    lzma_ptr = nullptr;
96 #endif
97             bz_ptr->bzalloc = nullptr;
98             bz_ptr->bzfree = nullptr;
99             bz_ptr->opaque = nullptr;
100             x_compressInit = & wrapperlib::bz_compressInit;
101             x_decompressInit = & wrapperlib::bz_decompressInit;
102             x_compressEnd = & wrapperlib::bz_compressEnd;
103             x_decompressEnd = & wrapperlib::bz_decompressEnd;
104             x_compress = & wrapperlib::bz_compress;
105             x_decompress = & wrapperlib::bz_decompress;
106             x_set_next_in = & wrapperlib::bz_set_next_in;
107             x_set_avail_in = & wrapperlib::bz_set_avail_in;
108             x_get_avail_in = & wrapperlib::bz_get_avail_in;
109             x_get_total_in = & wrapperlib::bz_get_total_in;
110             x_set_next_out = & wrapperlib::bz_set_next_out;
111             x_get_next_out = & wrapperlib::bz_get_next_out;
112             x_set_avail_out = & wrapperlib::bz_set_avail_out;
113             x_get_avail_out = & wrapperlib::bz_get_avail_out;
114             x_get_total_out = & wrapperlib::bz_get_total_out;
115             break;
116 #else
117 	    throw Ecompilation("libbz2 compression support");
118 #endif
119 	case xz_mode:
120 #if LIBZ_AVAILABLE
121             z_ptr = nullptr;
122 #endif
123 #if LIBBZ2_AVAILABLE
124             bz_ptr = nullptr;
125 #endif
126 #if LIBLZMA_AVAILABLE
127 	    meta_new(lzma_ptr, 1);
128 	    if(lzma_ptr == nullptr)
129 		throw Ememory("wrapperlib::wrapperlib");
130 	    *lzma_ptr = LZMA_STREAM_INIT;
131             x_compressInit = & wrapperlib::lzma_compressInit;
132             x_decompressInit = & wrapperlib::lzma_decompressInit;
133             x_compressEnd = & wrapperlib::lzma_end;
134             x_decompressEnd = & wrapperlib::lzma_end;
135             x_compress = & wrapperlib::lzma_encode;
136             x_decompress = & wrapperlib::lzma_encode;
137             x_set_next_in = & wrapperlib::lzma_set_next_in;
138             x_set_avail_in = & wrapperlib::lzma_set_avail_in;
139             x_get_avail_in = & wrapperlib::lzma_get_avail_in;
140             x_get_total_in = & wrapperlib::lzma_get_total_in;
141             x_set_next_out = & wrapperlib::lzma_set_next_out;
142             x_get_next_out = & wrapperlib::lzma_get_next_out;
143             x_set_avail_out = & wrapperlib::lzma_set_avail_out;
144             x_get_avail_out = & wrapperlib::lzma_get_avail_out;
145             x_get_total_out = & wrapperlib::lzma_get_total_out;
146 #endif
147 	    break;
148         default:
149             throw SRC_BUG;
150         }
151         level = -1;
152     }
153 
wrapperlib(const wrapperlib & ref)154     wrapperlib::wrapperlib(const wrapperlib & ref)
155     {
156         throw Efeature(gettext("Cannot copy a wrapperlib object (NOT IMPLEMENTED)"));
157     }
158 
operator =(const wrapperlib & ref)159     const wrapperlib & wrapperlib::operator = (const wrapperlib & ref)
160     {
161         throw Efeature(gettext("Cannot copy a wrapperlib object (NOT IMPLEMENTED)"));
162     }
163 
~wrapperlib()164     wrapperlib::~wrapperlib()
165     {
166 #if LIBZ_AVAILABLE
167         if(z_ptr != nullptr)
168 	    meta_delete(z_ptr);
169 #endif
170 #if LIBBZ2_AVAILABLE
171         if(bz_ptr != nullptr)
172 	    meta_delete(bz_ptr);
173 #endif
174 #if LIBLZMA_AVAILABLE
175 	if(lzma_ptr != nullptr)
176 	{
177 	    ::lzma_end(lzma_ptr);
178 	    meta_delete(lzma_ptr);
179 	}
180 #endif
181     }
182 
183 ////////////// Zlib routines /////////////
184 
185 #if LIBZ_AVAILABLE
z_compressInit(U_I compression_level)186     S_I wrapperlib::z_compressInit(U_I compression_level)
187     {
188         CHECK_Z;
189         return zlib2wrap_code(deflateInit(z_ptr, compression_level));
190     }
191 
z_decompressInit()192     S_I wrapperlib::z_decompressInit()
193     {
194         CHECK_Z;
195         return zlib2wrap_code(inflateInit(z_ptr));
196     }
197 
z_compressEnd()198     S_I wrapperlib::z_compressEnd()
199     {
200         CHECK_Z;
201         return zlib2wrap_code(deflateEnd(z_ptr));
202     }
203 
z_decompressEnd()204     S_I wrapperlib::z_decompressEnd()
205     {
206         CHECK_Z;
207         return zlib2wrap_code(inflateEnd(z_ptr));
208     }
209 
z_compress(S_I flag)210     S_I wrapperlib::z_compress(S_I flag)
211     {
212         CHECK_Z;
213         return zlib2wrap_code(deflate(z_ptr, wrap2zlib_code(flag)));
214     }
215 
z_decompress(S_I flag)216     S_I wrapperlib::z_decompress(S_I flag)
217     {
218         CHECK_Z;
219         return zlib2wrap_code(inflate(z_ptr, wrap2zlib_code(flag)));
220     }
221 
z_set_next_in(const char * x)222     void wrapperlib::z_set_next_in(const char *x)
223     {
224         CHECK_Z;
225         z_ptr->next_in = (Bytef *)x;
226     }
227 
z_set_avail_in(U_I x)228     void wrapperlib::z_set_avail_in(U_I x)
229     {
230         CHECK_Z;
231         z_ptr->avail_in = x;
232     }
233 
z_get_avail_in() const234     U_I wrapperlib::z_get_avail_in() const
235     {
236         CHECK_Z;
237         return z_ptr->avail_in;
238     }
239 
z_get_total_in() const240     U_64 wrapperlib::z_get_total_in() const
241     {
242         CHECK_Z;
243         return z_ptr->total_in;
244     }
245 
z_set_next_out(char * x)246     void wrapperlib::z_set_next_out(char *x)
247     {
248         CHECK_Z;
249         z_ptr->next_out = (Bytef *)x;
250     }
251 
z_get_next_out() const252     char *wrapperlib::z_get_next_out() const
253     {
254         CHECK_Z;
255         return (char *)z_ptr->next_out;
256     }
257 
z_set_avail_out(U_I x)258     void wrapperlib::z_set_avail_out(U_I x)
259     {
260         CHECK_Z;
261         z_ptr->avail_out = x;
262     }
263 
z_get_avail_out() const264     U_I wrapperlib::z_get_avail_out() const
265     {
266         CHECK_Z;
267         return z_ptr->avail_out;
268     }
269 
z_get_total_out() const270     U_64 wrapperlib::z_get_total_out() const
271     {
272         CHECK_Z;
273         return z_ptr->total_out;
274     }
275 #endif
276 
277 ////////////// BZlib routines /////////////
278 
279 #if LIBBZ2_AVAILABLE
bz_set_next_in(const char * x)280     void wrapperlib::bz_set_next_in(const char *x)
281     {
282         CHECK_BZ;
283         bz_ptr->next_in = (char*)x;	// It must be a bug in bz that the input is not a const char*
284     }
285 
bz_set_avail_in(U_I x)286     void wrapperlib::bz_set_avail_in(U_I x)
287     {
288         CHECK_BZ;
289         bz_ptr->avail_in = x;
290     }
291 
bz_get_avail_in() const292     U_I wrapperlib::bz_get_avail_in() const
293     {
294         CHECK_BZ;
295         return bz_ptr->avail_in;
296     }
297 
bz_get_total_in() const298     U_64 wrapperlib::bz_get_total_in() const
299     {
300         CHECK_BZ;
301         return ((U_64)(bz_ptr->total_in_hi32) << 32) | ((U_64)(bz_ptr->total_in_lo32));
302     }
303 
bz_set_next_out(char * x)304     void wrapperlib::bz_set_next_out(char *x)
305     {
306         CHECK_BZ;
307         bz_ptr->next_out = x;
308     }
309 
bz_get_next_out() const310     char *wrapperlib::bz_get_next_out() const
311     {
312         CHECK_BZ;
313         return bz_ptr->next_out;
314     }
315 
bz_set_avail_out(U_I x)316     void wrapperlib::bz_set_avail_out(U_I x)
317     {
318         CHECK_BZ;
319         bz_ptr->avail_out = x;
320     }
321 
bz_get_avail_out() const322     U_I wrapperlib::bz_get_avail_out() const
323     {
324         CHECK_BZ;
325         return bz_ptr->avail_out;
326     }
327 
bz_get_total_out() const328     U_64 wrapperlib::bz_get_total_out() const
329     {
330         CHECK_BZ;
331         return ((U_64)(bz_ptr->total_out_hi32) << 32) | ((U_64)(bz_ptr->total_out_lo32));
332     }
333 
334 
bz_compressInit(U_I compression_level)335     S_I wrapperlib::bz_compressInit(U_I compression_level)
336     {
337         CHECK_BZ;
338         return bzlib2wrap_code(BZ2_bzCompressInit(bz_ptr, compression_level, 0, 30));
339     }
340 
bz_decompressInit()341     S_I wrapperlib::bz_decompressInit()
342     {
343         CHECK_BZ;
344         return bzlib2wrap_code(BZ2_bzDecompressInit(bz_ptr, 0,0));
345     }
346 
bz_compressEnd()347     S_I wrapperlib::bz_compressEnd()
348     {
349         CHECK_BZ;
350         return bzlib2wrap_code(BZ2_bzCompressEnd(bz_ptr));
351     }
352 
bz_decompressEnd()353     S_I wrapperlib::bz_decompressEnd()
354     {
355         CHECK_BZ;
356         return bzlib2wrap_code(BZ2_bzDecompressEnd(bz_ptr));
357     }
358 
bz_compress(S_I flag)359     S_I wrapperlib::bz_compress(S_I flag)
360     {
361         S_I ret;
362         CHECK_BZ;
363         ret = BZ2_bzCompress(bz_ptr, wrap2bzlib_code(flag));
364         if(ret == BZ_SEQUENCE_ERROR)
365             ret = BZ_STREAM_END;
366         return bzlib2wrap_code(ret);
367     }
368 
bz_decompress(S_I flag)369     S_I wrapperlib::bz_decompress(S_I flag)
370     {
371             // flag is not used here.
372         S_I ret;
373         CHECK_BZ;
374         ret = BZ2_bzDecompress(bz_ptr);
375         if(ret == BZ_SEQUENCE_ERROR)
376             ret = BZ_STREAM_END;
377         return bzlib2wrap_code(ret);
378     }
379 #endif
380 
381 ////////////// LZMA routines /////////////
382 
383 #if LIBLZMA_AVAILABLE
lzma_compressInit(U_I compression_level)384     S_I wrapperlib::lzma_compressInit(U_I compression_level)
385     {
386         CHECK_LZMA;
387         return lzma2wrap_code(lzma_easy_encoder(lzma_ptr,
388 						compression_level,
389 						LZMA_CHECK_CRC32));
390 	    // CR32 is large enough, even no LZMA_CHECK_NONE would
391 	    // be possible as compressed data is protected by libdar
392 	    // CRC which width is proportionnal to the size of the
393 	    // compressed file.
394     }
395 
lzma_decompressInit()396     S_I wrapperlib::lzma_decompressInit()
397     {
398         CHECK_LZMA;
399         return lzma2wrap_code(lzma_auto_decoder(lzma_ptr,
400 						UINT64_MAX,
401 						0));
402     }
403 
lzma_end()404     S_I wrapperlib::lzma_end()
405     {
406         CHECK_LZMA;
407         return WR_OK; // nothing done
408     }
409 
lzma_encode(S_I flag)410     S_I wrapperlib::lzma_encode(S_I flag)
411     {
412         CHECK_LZMA;
413         return lzma2wrap_code(lzma_code(lzma_ptr, wrap2lzma_code(flag)));
414     }
415 
lzma_set_next_in(const char * x)416     void wrapperlib::lzma_set_next_in(const char *x)
417     {
418         CHECK_LZMA;
419         lzma_ptr->next_in = (Bytef *)x;
420     }
421 
lzma_set_avail_in(U_I x)422     void wrapperlib::lzma_set_avail_in(U_I x)
423     {
424         CHECK_LZMA;
425         lzma_ptr->avail_in = x;
426     }
427 
lzma_get_avail_in() const428     U_I wrapperlib::lzma_get_avail_in() const
429     {
430         CHECK_LZMA;
431         return lzma_ptr->avail_in;
432     }
433 
lzma_get_total_in() const434     U_64 wrapperlib::lzma_get_total_in() const
435     {
436         CHECK_LZMA;
437         return lzma_ptr->total_in;
438     }
439 
lzma_set_next_out(char * x)440     void wrapperlib::lzma_set_next_out(char *x)
441     {
442         CHECK_LZMA;
443         lzma_ptr->next_out = (Bytef *)x;
444     }
445 
lzma_get_next_out() const446     char *wrapperlib::lzma_get_next_out() const
447     {
448         CHECK_LZMA;
449         return (char *)lzma_ptr->next_out;
450     }
451 
lzma_set_avail_out(U_I x)452     void wrapperlib::lzma_set_avail_out(U_I x)
453     {
454         CHECK_LZMA;
455         lzma_ptr->avail_out = x;
456     }
457 
lzma_get_avail_out() const458     U_I wrapperlib::lzma_get_avail_out() const
459     {
460         CHECK_LZMA;
461         return lzma_ptr->avail_out;
462     }
463 
lzma_get_total_out() const464     U_64 wrapperlib::lzma_get_total_out() const
465     {
466         CHECK_LZMA;
467         return lzma_ptr->total_out;
468     }
469 #endif
470 
compressReset()471     S_I wrapperlib::compressReset()
472     {
473         S_I ret;
474 
475         if(level < 0)
476             throw Erange("wrapperlib::compressReset", gettext("compressReset called but compressInit never called before"));
477         ret = compressEnd();
478         if(ret == WR_OK)
479             return compressInit(level);
480         else
481             return ret;
482     }
483 
decompressReset()484     S_I wrapperlib::decompressReset()
485     {
486         S_I ret = decompressEnd();
487 
488         if(ret == WR_OK)
489             return decompressInit();
490         else
491             return ret;
492     }
493 
494 #if LIBZ_AVAILABLE
zlib2wrap_code(S_I code)495     static S_I zlib2wrap_code(S_I code)
496     {
497         switch(code)
498         {
499         case Z_OK:
500             return WR_OK;
501         case Z_MEM_ERROR:
502             return WR_MEM_ERROR;
503         case Z_VERSION_ERROR:
504             return WR_VERSION_ERROR;
505         case Z_STREAM_END:
506             return WR_STREAM_END;
507         case Z_DATA_ERROR:
508             return WR_DATA_ERROR;
509         case Z_BUF_ERROR:
510             return WR_BUF_ERROR;
511         case Z_STREAM_ERROR:
512             return WR_STREAM_ERROR;
513         case Z_NEED_DICT:
514 	    return WR_DATA_ERROR;
515 		// we do not use explicit dictionnary for compression,
516 		// this is zlib assumes it requires a dictionnary, this is
517 		// to be considered a data error.
518         default:
519             throw SRC_BUG; // unexpected error code
520         }
521     }
522 
wrap2zlib_code(S_I code)523     static S_I wrap2zlib_code(S_I code)
524     {
525         switch(code)
526         {
527         case WR_NO_FLUSH:
528             return Z_NO_FLUSH;
529         case WR_FINISH:
530             return Z_FINISH;
531         default:
532             throw SRC_BUG;
533         }
534     }
535 
536 
537 #endif
538 
539 #if LIBBZ2_AVAILABLE
bzlib2wrap_code(S_I code)540     static S_I bzlib2wrap_code(S_I code)
541     {
542         switch(code)
543         {
544         case BZ_OK:
545         case BZ_RUN_OK:
546         case BZ_FLUSH_OK:
547         case BZ_FINISH_OK:
548             return WR_OK;
549         case BZ_PARAM_ERROR:
550             return WR_STREAM_ERROR;
551         case BZ_CONFIG_ERROR:
552             return WR_VERSION_ERROR;
553         case BZ_MEM_ERROR:
554             return WR_MEM_ERROR;
555         case BZ_DATA_ERROR:
556         case BZ_DATA_ERROR_MAGIC:
557             return WR_DATA_ERROR;
558         case BZ_STREAM_END:
559             return WR_STREAM_END;
560         case BZ_SEQUENCE_ERROR:
561         default:
562             throw SRC_BUG;
563         }
564     }
565 
wrap2bzlib_code(S_I code)566     static S_I wrap2bzlib_code(S_I code)
567     {
568         switch(code)
569         {
570         case WR_NO_FLUSH:
571             return BZ_RUN;
572         case WR_FINISH:
573             return BZ_FINISH;
574         default:
575             throw SRC_BUG;
576         }
577     }
578 #endif
579 
580 #if LIBLZMA_AVAILABLE
lzma2wrap_code(S_I code)581     static S_I lzma2wrap_code(S_I code)
582     {
583         switch(code)
584         {
585         case LZMA_OK:
586             return WR_OK;
587         case LZMA_MEM_ERROR:
588             return WR_MEM_ERROR;
589         case LZMA_OPTIONS_ERROR:
590 	case LZMA_FORMAT_ERROR: // no memory usage limit used from libdar, only file format error can generate this code
591             return WR_VERSION_ERROR;
592         case LZMA_STREAM_END:
593             return WR_STREAM_END;
594         case LZMA_DATA_ERROR:
595             return WR_DATA_ERROR;
596         case LZMA_BUF_ERROR:
597             return WR_BUF_ERROR;
598 	case LZMA_NO_CHECK:
599 	case LZMA_UNSUPPORTED_CHECK:
600             return WR_STREAM_ERROR;
601 	case LZMA_PROG_ERROR:
602 	    throw SRC_BUG; // error in libdar calling liblzma
603 	case LZMA_GET_CHECK:
604 	    throw SRC_BUG;
605 		// can be retured by lzma_code "only if the decoder was initialized with the LZMA_TELL_ANY_CHECK flag"
606 		// flag we do not use from libdar
607         default:
608             throw SRC_BUG; // unexpected error code
609         }
610     }
611 
wrap2lzma_code(S_I code)612     static lzma_action wrap2lzma_code(S_I code)
613     {
614         switch(code)
615         {
616         case WR_NO_FLUSH:
617             return LZMA_RUN;
618         case WR_FINISH:
619             return LZMA_FINISH;
620         default:
621             throw SRC_BUG;
622         }
623     }
624 
625 #endif
626 
627 } // end of namespace
628