2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
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
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.
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.
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
26 #include "ArchSpecific.h"
27 #include "ScopedPtr.h"
28 #include <ec/cpp/ECTag.h> // Needed for CECTag
31 * RLE encoder implementation. This is RLE implementation for very specific
32 * purpose: encode DIFFERENCE between subsequent states of status bar.
34 * This difference is calculated by xor-ing with previous data
36 * We can't use implementation with "control char" since this encoder
37 * will process binary data - not ascii (or unicode) strings
39 void RLE_Data::setup(int len
, bool use_diff
, uint8
* content
)
42 m_use_diff
= use_diff
;
45 m_buff
= new uint8
[m_len
];
47 memcpy(m_buff
, content
, m_len
);
49 memset(m_buff
, 0, m_len
);
57 RLE_Data
&RLE_Data::operator=(const RLE_Data
&obj
)
63 setup(obj
.m_len
, obj
.m_use_diff
, obj
.m_buff
);
73 void RLE_Data::ResetEncoder()
80 bool RLE_Data::Realloc(int size
)
82 if ( size
== m_len
) {
91 uint8
*buff
= new uint8
[size
];
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
);
98 memcpy(buff
, m_buff
, size
);
107 const uint8
*RLE_Data::Decode(const uint8
*buff
, int len
)
109 uint8
* decBuf
= m_len
? new uint8
[m_len
] : 0;
111 // If data exceeds the buffer, switch to counting only.
112 // Then resize and make a second pass.
113 for (bool overrun
= true; overrun
;) {
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
);
126 // This is a single byte.
135 overrun
= j
> m_len
; // overrun, make a second pass
136 Realloc(j
); // size has changed, adjust
139 decBuf
= new uint8
[m_len
];
144 // Recreate data from diff
147 for (int k
= 0; k
< m_len
; k
++) {
148 m_buff
[k
] ^= decBuf
[k
];
151 memcpy(m_buff
, decBuf
, m_len
);
157 const uint8
* RLE_Data::Encode(const uint8
*data
, int inlen
, int &outlen
, bool &changed
)
159 changed
= Realloc(inlen
); // adjust size if necessary
166 // calculate difference from prev
169 for (int i
= 0; i
< m_len
; i
++) {
170 m_buff
[i
] ^= data
[i
];
176 memcpy(m_buff
, data
, m_len
);
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];
186 while ( i
!= m_len
) {
187 uint8 curr_val
= m_buff
[i
];
189 while ( (i
!= m_len
) && (curr_val
== m_buff
[i
]) && ((i
- seq_start
) < 0xff)) {
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
;
198 // single value - put it as is
199 enc_buff
[j
++] = curr_val
;
206 // If using differential encoder, remember current data for
209 memcpy(m_buff
, data
, m_len
);
215 const uint8
* RLE_Data::Encode(const ArrayOfUInts16
&data
, int &outlen
, bool &changed
)
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();
222 return Encode(0, 0, outlen
, changed
);
224 CScopedArray
<uint8
> buf(size
);
225 uint8
* bufPtr
= buf
.get();
227 for (int i
= 0; i
< size
; i
++) {
229 bufPtr
[i
] = (ui
> 0xff) ? 0xff : (uint8
) ui
;
231 return Encode(bufPtr
, size
, outlen
, changed
);
234 const uint8
* RLE_Data::Encode(const ArrayOfUInts64
&data
, int &outlen
, bool &changed
)
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();
243 return Encode(0, 0, outlen
, changed
);
245 CScopedArray
<uint8
> buf(size
* 8);
246 uint8
* bufPtr
= buf
.get();
247 for (int i
= 0; i
< size
; i
++) {
249 for (int j
= 0; j
< 8; j
++) {
250 bufPtr
[i
+ j
* size
] = u
& 0xff;
254 return Encode(bufPtr
, size
* 8, outlen
, changed
);
257 void RLE_Data::Decode(const uint8
*data
, int len
, ArrayOfUInts64
&outdata
)
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
++) {
265 for (int j
= 8; j
--;) {
267 u
|= decoded
[i
+ j
* size
];
273 void PartFileEncoderData::DecodeParts(const CECTag
* tag
, ArrayOfUInts16
&outdata
)
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
++) {
283 void PartFileEncoderData::DecodeGaps(const CECTag
* tag
, ArrayOfUInts64
&outdata
)
285 m_gap_status
.Decode((uint8
*)tag
->GetTagData(), tag
->GetTagDataLen(), outdata
);
288 void PartFileEncoderData::DecodeReqs(const CECTag
* tag
, ArrayOfUInts64
&outdata
)
290 m_req_status
.Decode((uint8
*)tag
->GetTagData(), tag
->GetTagDataLen(), outdata
);
294 // File_checked_for_headers