1
2
3
4
5
6 using System;
7 using System.IO;
8
9 namespace System.IO.Compression
10 {
11 public const int minimumBZip2CompressionLevel = 1;
12 public const int optimalBZip2CompressionLevel = 9;
13 public const int defaultBZip2CompressionLevel = optimalBZip2CompressionLevel;
14
15 public const int defaultBZip2WorkFactor = 0;
16 public const int maximumBZip2WorkFactor = 250;
17 public const int BZ_OK = 0;
18 public const int BZ_SEQUENCE_ERROR = -1;
19 public const int BZ_STREAM_END = 4;
20 public const int BZ_UNEXPECTED_EOF = -7;
21 public const int BZ_RUN = 0;
22 public const int BZ_FINISH = 2;
23
24 public nothrow string ExpandBZip2Error(const string& message, int errorCode)
25 {
26 string expandedMessage = message;
27 expandedMessage.Append(" error ").Append(RtRetvalStrBZip2(errorCode)).Append(" code ").Append(ToString(errorCode));
28 return expandedMessage;
29 }
30
31 public class BZip2Exception : Exception
32 {
33 public BZip2Exception(const string& message_, int errorCode_) : base(ExpandBZip2Error(message_, errorCode_)), errorCode(errorCode_)
34 {
35 }
36 public inline nothrow int ErrorCode() const
37 {
38 return errorCode;
39 }
40 private int errorCode;
41 }
42
43 public class BZip2Stream : ByteStream
44 {
45 public BZip2Stream(const SharedPtr<ByteStream>& underlyingStream_, int compressionLevel_) : this(underlyingStream_, compressionLevel_, defaultBZip2WorkFactor)
46 {
47 }
48 public BZip2Stream(const SharedPtr<ByteStream>& underlyingStream_, int compressionLevel_, int compressionWorkFactor_) :
49 this(underlyingStream_, compressionLevel_, compressionWorkFactor_, 16384)
50 {
51 }
52 public BZip2Stream(const SharedPtr<ByteStream>& underlyingStream_, int compressionLevel_, int compressionWorkFactor_, long bufferSize_) :
53 underlyingStream(underlyingStream_), mode(CompressionMode.compress), bufferSize(bufferSize_), inAvail(0u), endOfInput(false), endOfStream(false),
54 in(bufferSize), outHave(0u), outAvail(0u), outPos(0), out(bufferSize), handle(null)
55 {
56 int ret = RtInitBZip2(mode, compressionLevel_, compressionWorkFactor_, &handle);
57 if (ret < 0)
58 {
59 throw BZip2Exception("Could not create BZip2Stream", ret);
60 }
61 }
62 public BZip2Stream(const SharedPtr<ByteStream>& underlyingStream_, CompressionMode mode_) : this(underlyingStream_, mode_, 16384)
63 {
64 }
65 public BZip2Stream(const SharedPtr<ByteStream>& underlyingStream_, CompressionMode mode_, long bufferSize_) :
66 underlyingStream(underlyingStream_), mode(mode_), bufferSize(bufferSize_), inAvail(0u), endOfInput(false), endOfStream(false), in(bufferSize),
67 outHave(0u), outAvail(0u), outPos(0), out(bufferSize), handle(null)
68 {
69 int ret = RtInitBZip2(mode, defaultBZip2CompressionLevel, defaultBZip2WorkFactor, &handle);
70 if (ret < 0)
71 {
72 throw BZip2Exception("Could not create BZip2Stream", ret);
73 }
74 }
75 public inline nothrow CompressionMode Mode() const
76 {
77 return mode;
78 }
79 public ~BZip2Stream()
80 {
81 if (handle != null)
82 {
83 try
84 {
85 if (mode == CompressionMode.compress)
86 {
87 Finish();
88 }
89 }
90 catch (const Exception& ex)
91 {
92
93 }
94 RtDoneBZip2(mode, handle);
95 }
96 }
97 public override int ReadByte()
98 {
99 byte x = 0u;
100 long bytesRead = this->Read(&x, 1);
101 if (bytesRead == 0)
102 {
103 return -1;
104 }
105 return x;
106 }
107 public override long Read(byte* buf, long count)
108 {
109 if (mode != CompressionMode.decompress)
110 {
111 throw BZip2Exception("Cannot read from BZip2Stream in CompressionMode.compress", BZ_SEQUENCE_ERROR);
112 }
113 long bytesRead = 0;
114 do
115 {
116 if (inAvail == 0u && !endOfInput)
117 {
118 inAvail = cast<uint>(underlyingStream->Read(cast<byte*>(in.Mem()), bufferSize));
119 if (inAvail == 0u)
120 {
121 endOfInput = true;
122 }
123 RtSetInputBZip2(in.Mem(), inAvail, handle);
124 }
125 do
126 {
127 if (outHave == 0u && !endOfStream)
128 {
129 int ret = RtDecompressBZip2(out.Mem(), cast<uint>(bufferSize), &outHave, &outAvail, &inAvail, handle);
130 if (ret < 0)
131 {
132 throw BZip2Exception("BZip2Stream could not decompress", ret);
133 }
134 if (ret == BZ_STREAM_END)
135 {
136 endOfStream = true;
137 }
138 outPos = 0;
139 }
140 while (count > 0 && outHave > 0u)
141 {
142 *buf++ = out[outPos++];
143 --count;
144 --outHave;
145 ++bytesRead;
146 }
147 }
148 while (count > 0 && outAvail == 0u);
149 }
150 while (count > 0 && !endOfStream && !endOfInput);
151 if (endOfInput && !endOfStream)
152 {
153 throw BZip2Exception("BZip2Stream unexpected end of input", BZ_UNEXPECTED_EOF);
154 }
155 return bytesRead;
156 }
157 public override void Write(byte x)
158 {
159 this->Write(&x, 1);
160 }
161 public override void Write(byte* buf, long count)
162 {
163 if (mode != CompressionMode.compress)
164 {
165 throw BZip2Exception("Cannot write to BZip2Stream in CompressionMode.decompress", BZ_SEQUENCE_ERROR);
166 }
167 while (count > 0)
168 {
169 byte* inP = cast<byte*>(in.Mem());
170 inAvail = 0u;
171 while (count > 0 && inAvail < cast<uint>(bufferSize))
172 {
173 *inP++ = *buf++;
174 --count;
175 ++inAvail;
176 }
177 RtSetInputBZip2(in.Mem(), inAvail, handle);
178 do
179 {
180 uint have = 0u;
181 int ret = RtCompressBZip2(out.Mem(), cast<uint>(bufferSize), &have, &outAvail, handle, BZ_RUN);
182 if (ret < 0)
183 {
184 throw BZip2Exception("BZip2Stream could not compress", ret);
185 }
186 underlyingStream->Write(cast<byte*>(out.Mem()), cast<long>(have));
187 }
188 while (outAvail == 0);
189 }
190 }
191 private void Finish()
192 {
193 int ret = BZ_OK;
194 do
195 {
196 uint have = 0u;
197 ret = RtCompressBZip2(out.Mem(), cast<uint>(bufferSize), &have, &outAvail, handle, BZ_FINISH);
198 if (ret < 0)
199 {
200 throw BZip2Exception("BZip2Stream could not compress", ret);
201 }
202 underlyingStream->Write(cast<byte*>(out.Mem()), cast<long>(have));
203 }
204 while (ret != BZ_STREAM_END);
205 }
206 private SharedPtr<ByteStream> underlyingStream;
207 private CompressionMode mode;
208 private long bufferSize;
209 private uint inAvail;
210 private bool endOfInput;
211 private bool endOfStream;
212 private IOBuffer in;
213 private uint outHave;
214 private uint outAvail;
215 private long outPos;
216 private IOBuffer out;
217 private void* handle;
218 }
219 }