1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 //
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
23 //
24 
25 #include "RLE.h"
26 #include "ArchSpecific.h"
27 #include "ScopedPtr.h"
28 #include <ec/cpp/ECTag.h>		// Needed for CECTag
29 
30 /*
31  * RLE encoder implementation. This is RLE implementation for very specific
32  * purpose: encode DIFFERENCE between subsequent states of status bar.
33  *
34  * This difference is calculated by xor-ing with previous data
35  *
36  * We can't use implementation with "control char" since this encoder
37  * will process binary data - not ascii (or unicode) strings
38  */
setup(int len,bool use_diff,uint8 * content)39 void RLE_Data::setup(int len, bool use_diff, uint8 * content)
40 {
41 	m_len = len;
42 	m_use_diff = use_diff;
43 
44 	if (m_len) {
45 		m_buff = new uint8[m_len];
46 		if (content) {
47 			memcpy(m_buff, content, m_len);
48 		} else {
49 			memset(m_buff, 0, m_len);
50 		}
51 		//
52 	} else {
53 		m_buff = 0;
54 	}
55 }
56 
operator =(const RLE_Data & obj)57 RLE_Data &RLE_Data::operator=(const RLE_Data &obj)
58 {
59 	if (this == &obj)
60 		return *this;
61 
62 	delete [] m_buff;
63 	setup(obj.m_len, obj.m_use_diff, obj.m_buff);
64 
65 	return *this;
66 }
67 
~RLE_Data()68 RLE_Data::~RLE_Data()
69 {
70 	delete [] m_buff;
71 }
72 
ResetEncoder()73 void RLE_Data::ResetEncoder()
74 {
75 	delete m_buff;
76 	m_len = 0;
77 	m_buff = 0;
78 }
79 
Realloc(int size)80 bool RLE_Data::Realloc(int size)
81 {
82 	if ( size == m_len ) {
83 		return false;
84 	}
85 	if (size == 0) {
86 		delete [] m_buff;
87 		m_buff = 0;
88 		m_len = 0;
89 		return true;
90 	}
91 	uint8 *buff = new uint8[size];
92 	if (m_len == 0) {
93 		memset(buff, 0, size);
94 	} else if ( size > m_len ) {
95 		memset(buff + m_len, 0, size - m_len);
96 		memcpy(buff, m_buff, m_len);
97 	} else {
98 		memcpy(buff, m_buff, size);
99 	}
100 	delete [] m_buff;
101 	m_buff = buff;
102 
103 	m_len = size;
104 	return true;
105 }
106 
Decode(const uint8 * buff,int len)107 const uint8 *RLE_Data::Decode(const uint8 *buff, int len)
108 {
109 	uint8 * decBuf = m_len ? new uint8[m_len] : 0;
110 
111 	// If data exceeds the buffer, switch to counting only.
112 	// Then resize and make a second pass.
113 	for (bool overrun = true; overrun;) {
114 		overrun = false;
115 		int j = 0;
116 		for (int i = 0; i < len;) {
117 			if (i < len - 2 && buff[i+1] == buff[i]) {
118 				// This is a sequence.
119 				uint8 seqLen = buff[i + 2];
120 				if (j + seqLen <= m_len) {
121 					memset(decBuf + j, buff[i], seqLen);
122 				}
123 				j += seqLen;
124 				i += 3;
125 			} else {
126 				// This is a single byte.
127 				if (j < m_len) {
128 					decBuf[j] = buff[i];
129 				}
130 				j++;
131 				i++;
132 			}
133 		}
134 		if (j != m_len) {
135 			overrun = j > m_len;	// overrun, make a second pass
136 			Realloc(j);				// size has changed, adjust
137 			if (overrun) {
138 				delete[] decBuf;
139 				decBuf = new uint8[m_len];
140 			}
141 		}
142 	}
143 	//
144 	// Recreate data from diff
145 	//
146 	if ( m_use_diff ) {
147 		for (int k = 0; k < m_len; k++) {
148 			m_buff[k] ^= decBuf[k];
149 		}
150 	} else {
151 		memcpy(m_buff, decBuf, m_len);
152 	}
153 	delete[] decBuf;
154 	return m_buff;
155 }
156 
Encode(const uint8 * data,int inlen,int & outlen,bool & changed)157 const uint8 * RLE_Data::Encode(const uint8 *data, int inlen, int &outlen, bool &changed)
158 {
159 	changed = Realloc(inlen);		// adjust size if necessary
160 
161 	if (m_len == 0) {
162 		outlen = 0;
163 		return NULL;
164 	}
165 	//
166 	// calculate difference from prev
167 	//
168 	if ( m_use_diff ) {
169 		for (int i = 0; i < m_len; i++) {
170 			m_buff[i] ^= data[i];
171 			if (m_buff[i]) {
172 				changed = true;
173 			}
174 		}
175 	} else {
176 		memcpy(m_buff, data, m_len);
177 		changed = true;
178 	}
179 
180 	//
181 	// now RLE
182 	//
183 	// In worst case 2-byte sequence is encoded as 3. So, data can grow by 50%.
184 	uint8 * enc_buff = new uint8[m_len * 3/2 + 1];
185 	int i = 0, j = 0;
186 	while ( i != m_len ) {
187 		uint8 curr_val = m_buff[i];
188 		int seq_start = i;
189 		while ( (i != m_len) && (curr_val == m_buff[i]) && ((i - seq_start) < 0xff)) {
190 			i++;
191 		}
192 		if (i - seq_start > 1) {
193 			// if there's 2 or more equal vals - put it twice in stream
194 			enc_buff[j++] = curr_val;
195 			enc_buff[j++] = curr_val;
196 			enc_buff[j++] = i - seq_start;
197 		} else {
198 			// single value - put it as is
199 			enc_buff[j++] = curr_val;
200 		}
201 	}
202 
203 	outlen = j;
204 
205 	//
206 	// If using differential encoder, remember current data for
207 	// later use
208 	if ( m_use_diff ) {
209 		memcpy(m_buff, data, m_len);
210 	}
211 
212 	return enc_buff;
213 }
214 
Encode(const ArrayOfUInts16 & data,int & outlen,bool & changed)215 const uint8 * RLE_Data::Encode(const ArrayOfUInts16 &data, int &outlen, bool &changed)
216 {
217 	// To encode, first copy the UInts16 to a uint8 array
218 	// and limit them to 0xff.
219 	// The encoded size is the size of data.
220 	int size = (int) data.size();
221 	if (size == 0) {
222 		return Encode(0, 0, outlen, changed);
223 	}
224 	CScopedArray<uint8> buf(size);
225 	uint8 * bufPtr = buf.get();
226 
227 	for (int i = 0; i < size; i++) {
228 		uint16 ui = data[i];
229 		bufPtr[i] = (ui > 0xff) ? 0xff : (uint8) ui;
230 	}
231 	return Encode(bufPtr, size, outlen, changed);
232 }
233 
Encode(const ArrayOfUInts64 & data,int & outlen,bool & changed)234 const uint8 * RLE_Data::Encode(const ArrayOfUInts64 &data, int &outlen, bool &changed)
235 {
236 	// uint64 is copied to a uint8 buffer
237 	// first all low bytes, then all second low bytes and so on
238 	// so inital RLE will benefit from high bytes being equal (zero)
239 	// 0x000003045A6A7A8A, 0x000003045B6B7B8B
240 	// 8A8B7A7B6A6B5A5B0404030300000000
241 	int size = (int) data.size();
242 	if (size == 0) {
243 		return Encode(0, 0, outlen, changed);
244 	}
245 	CScopedArray<uint8> buf(size * 8);
246 	uint8 * bufPtr = buf.get();
247 	for (int i = 0; i < size; i++) {
248 		uint64 u = data[i];
249 		for (int j = 0; j < 8; j++) {
250 			bufPtr[i + j * size] = u & 0xff;
251 			u >>= 8;
252 		}
253 	}
254 	return Encode(bufPtr, size * 8, outlen, changed);
255 }
256 
Decode(const uint8 * data,int len,ArrayOfUInts64 & outdata)257 void RLE_Data::Decode(const uint8 *data, int len, ArrayOfUInts64 &outdata)
258 {
259 	const uint8 * decoded = Decode(data, len);
260 	wxASSERT(m_len % 8 == 0);
261 	int size = m_len / 8;
262 	outdata.resize(size);
263 	for (int i = 0; i < size; i++) {
264 		uint64 u = 0;
265 		for (int j = 8; j--;) {
266 			u <<= 8;
267 			u |= decoded[i + j * size];
268 		}
269 		outdata[i] = u;
270 	}
271 }
272 
DecodeParts(const CECTag * tag,ArrayOfUInts16 & outdata)273 void PartFileEncoderData::DecodeParts(const CECTag * tag, ArrayOfUInts16 &outdata)
274 {
275 	const uint8 * buf = m_part_status.Decode((uint8 *)tag->GetTagData(), tag->GetTagDataLen());
276 	int size = m_part_status.Size();
277 	outdata.resize(size);
278 	for (int i = 0; i < size; i++) {
279 		outdata[i] = buf[i];
280 	}
281 }
282 
DecodeGaps(const CECTag * tag,ArrayOfUInts64 & outdata)283 void PartFileEncoderData::DecodeGaps(const CECTag * tag, ArrayOfUInts64 &outdata)
284 {
285 	m_gap_status.Decode((uint8 *)tag->GetTagData(), tag->GetTagDataLen(), outdata);
286 }
287 
DecodeReqs(const CECTag * tag,ArrayOfUInts64 & outdata)288 void PartFileEncoderData::DecodeReqs(const CECTag * tag, ArrayOfUInts64 &outdata)
289 {
290 	m_req_status.Decode((uint8 *)tag->GetTagData(), tag->GetTagDataLen(), outdata);
291 }
292 
293 
294 // File_checked_for_headers
295