1 /**
2 * Lzma Compressor
3 * 
4 * Copyright:
5 * (C) 2001 Peter J Jones
6 *     2001-2007 Jack Lloyd
7 *     2012 Vojtech Kral
8 * (C) 2014-2015 Etienne Cimon
9 *
10 * License:
11 * Botan is released under the Simplified BSD License (see LICENSE.md)
12 */
13 module botan.compression.lzma;
14 
15 import botan.constants;
16 static if (BOTAN_HAS_LZMA):
17 
18 import botan.filters.filter;
19 
20 import botan.utils.exceptn;
21 import std.exception;
22 import botan.compression.lzma_hd;
23 import botan.compression.compress;
24 import botan.algo_base.transform;
25 import botan.utils.types;
26 import core.exception;
27 
28 /**
29 * LZMA Compression
30 */
31 class LZMACompression : StreamCompression, Transformation
32 {
33 public:
34     /**
35       * @param level how much effort to use on compressing (0 to 9);
36       *        higher levels are slower but tend to give better
37       *        compression
38       */
39     this(size_t level = 6) {
40         m_level = level;
41     }
42     
43     override string name() const { return "LZMACompression"; }
44     
45 protected:
46     override CompressionStream makeStream() const
47     {
48         return new LZMACompressionStream(m_level);
49     }
50 
51 
52     const size_t m_level;
53     // interface fall-through
54     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
55     override string provider() const { return "core"; }
56     override size_t updateGranularity() const { return 1; }
57     override size_t minimumFinalSize() const { return 0; }    
58     override size_t defaultNonceLength() const { return 0; }    
59     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
60     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
61     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
62     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
63     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
64     override void clear() { return super.clear(); }
65 }
66 
67 /**
68 * LZMA Deccompression
69 */
70 class LZMADecompression : StreamDecompression, Transformation
71 {
72 public:
73     override string name() const { return "LZMADecompression"; }
74 protected:
75     override CompressionStream makeStream() const
76     {
77         return new LZMADecompressionStream;
78     }
79 
80     // interface fall-through
81     override void flush(ref SecureVector!ubyte buf, size_t offset) { super.flush(buf, offset); }
82     override string provider() const { return "core"; }
83     override size_t updateGranularity() const { return 1; }
84     override size_t minimumFinalSize() const { return 0; }    
85     override size_t defaultNonceLength() const { return 0; }    
86     override bool validNonceLength(size_t nonce_len) const { return nonce_len == 0; }
87     override SecureVector!ubyte startRaw(const(ubyte)* data, size_t data_len) { return super.startRaw(data, data_len); }
88     override void update(ref SecureVector!ubyte buf, size_t offset) { super.update(buf, offset); }
89     override void finish(ref SecureVector!ubyte buf, size_t offset) { super.finish(buf, offset); }
90     override size_t outputLength(size_t input_length) const { return super.outputLength(input_length); }
91     override void clear() { return super.clear(); }
92 }
93 
94 class LZMAStream : ZlibStyleStream!(lzma_stream, ubyte), CompressionStream
95 {
96 public:
97     this()
98     {
99         auto a = new .lzma_allocator;
100         a.opaque = cast(void*)alloc();
101         a.alloc = &CompressionAllocInfo.malloc!size_t;
102         a.free = &CompressionAllocInfo.free;
103         streamp().allocator = a;
104     }
105     
106     ~this()
107     {
108         .lzma_end(streamp());
109         delete streamp().allocator;
110     }
111     
112     override bool run(uint flags)
113     {
114         lzma_ret rc = .lzma_code(streamp(), cast(lzma_action)(flags));
115         
116         if (rc == LZMA_MEM_ERROR)
117             throw new InvalidMemoryOperationError();
118         else if (rc != LZMA_OK && rc != LZMA_STREAM_END)
119             throw new Exception("Lzma error");
120         
121         return (rc == LZMA_STREAM_END);
122     }
123     
124     override uint runFlag() const { return LZMA_RUN; }
125     override uint flushFlag() const { return LZMA_FULL_FLUSH; }
126     override uint finishFlag() const { return LZMA_FINISH; }
127 
128 	override void nextIn(ubyte* b, size_t len) { super.nextIn(b, len); }    
129 	override void nextOut(ubyte* b, size_t len) { super.nextOut(b, len); }    
130 	override size_t availIn() const { return super.availIn(); }    
131 	override size_t availOut() const { return super.availOut; }
132 }
133 
134 class LZMACompressionStream : LZMAStream
135 {
136 public:
137     this(size_t level)
138     {
139         lzma_ret rc = .lzma_easy_encoder(streamp(), cast(uint) level, LZMA_CHECK_CRC64);
140         
141         if (rc == LZMA_MEM_ERROR)
142             throw new InvalidMemoryOperationError();
143         else if (rc != LZMA_OK)
144             throw new Exception("lzma compress initialization failed: " ~ rc.to!string);
145     }
146 }
147 
148 class LZMADecompressionStream : LZMAStream
149 {
150 public:
151     this()
152     {
153         lzma_ret rc = .lzma_stream_decoder(streamp(), ulong.max,
154             LZMA_TELL_UNSUPPORTED_CHECK);
155         
156         if (rc == LZMA_MEM_ERROR)
157             throw new InvalidMemoryOperationError();
158         else if (rc != LZMA_OK)
159             throw new Exception("Bad setting in lzma_stream_decoder");
160     }
161 }