2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 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 bool RLE_Data::Realloc(int size
)
75 if ( size
== m_len
) {
84 uint8
*buff
= new uint8
[size
];
86 memset(buff
, 0, size
);
87 } else if ( size
> m_len
) {
88 memset(buff
+ m_len
, 0, size
- m_len
);
89 memcpy(buff
, m_buff
, m_len
);
91 memcpy(buff
, m_buff
, size
);
100 const uint8
*RLE_Data::Decode(const uint8
*buff
, int len
)
102 uint8
* decBuf
= m_len
? new uint8
[m_len
] : 0;
104 // If data exceeds the buffer, switch to counting only.
105 // Then resize and make a second pass.
106 for (bool overrun
= true; overrun
;) {
109 for (int i
= 0; i
< len
;) {
110 if (i
< len
- 2 && buff
[i
+1] == buff
[i
]) {
111 // This is a sequence.
112 uint8 seqLen
= buff
[i
+ 2];
113 if (j
+ seqLen
<= m_len
) {
114 memset(decBuf
+ j
, buff
[i
], seqLen
);
119 // This is a single byte.
128 overrun
= j
> m_len
; // overrun, make a second pass
129 Realloc(j
); // size has changed, adjust
132 decBuf
= new uint8
[m_len
];
137 // Recreate data from diff
140 for (int k
= 0; k
< m_len
; k
++) {
141 m_buff
[k
] ^= decBuf
[k
];
144 memcpy(m_buff
, decBuf
, m_len
);
150 const uint8
* RLE_Data::Encode(const uint8
*data
, int inlen
, int &outlen
, bool &changed
)
152 changed
= Realloc(inlen
); // adjust size if necessary
159 // calculate difference from prev
162 for (int i
= 0; i
< m_len
; i
++) {
163 m_buff
[i
] ^= data
[i
];
169 memcpy(m_buff
, data
, m_len
);
176 // In worst case 2-byte sequence is encoded as 3. So, data can grow by 50%.
177 uint8
* enc_buff
= new uint8
[m_len
* 3/2 + 1];
179 while ( i
!= m_len
) {
180 uint8 curr_val
= m_buff
[i
];
182 while ( (i
!= m_len
) && (curr_val
== m_buff
[i
]) && ((i
- seq_start
) < 0xff)) {
185 if (i
- seq_start
> 1) {
186 // if there's 2 or more equal vals - put it twice in stream
187 enc_buff
[j
++] = curr_val
;
188 enc_buff
[j
++] = curr_val
;
189 enc_buff
[j
++] = i
- seq_start
;
191 // single value - put it as is
192 enc_buff
[j
++] = curr_val
;
199 // If using differential encoder, remember current data for
202 memcpy(m_buff
, data
, m_len
);
208 const uint8
* RLE_Data::Encode(const ArrayOfUInts16
&data
, int &outlen
, bool &changed
)
210 // To encode, first copy the UInts16 to a uint8 array
211 // and limit them to 0xff.
212 // The encoded size is the size of data.
213 int size
= (int) data
.size();
215 return Encode(0, 0, outlen
, changed
);
217 CScopedPtr
<uint8
> buf(new uint8
[size
]);
218 uint8
* bufPtr
= buf
.get();
220 for (int i
= 0; i
< size
; i
++) {
222 bufPtr
[i
] = (ui
> 0xff) ? 0xff : (uint8
) ui
;
224 return Encode(bufPtr
, size
, outlen
, changed
);
227 const uint8
* RLE_Data::Encode(const ArrayOfUInts64
&data
, int &outlen
, bool &changed
)
229 // uint64 is copied to a uint8 buffer
230 // first all low bytes, then all second low bytes and so on
231 // so inital RLE will benefit from high bytes being equal (zero)
232 // 0x000003045A6A7A8A, 0x000003045B6B7B8B
233 // 8A8B7A7B6A6B5A5B0404030300000000
234 int size
= (int) data
.size();
236 return Encode(0, 0, outlen
, changed
);
238 CScopedPtr
<uint8
> buf(new uint8
[size
* 8]);
239 uint8
* bufPtr
= buf
.get();
240 for (int i
= 0; i
< size
; i
++) {
242 for (int j
= 0; j
< 8; j
++) {
243 bufPtr
[i
+ j
* size
] = u
& 0xff;
247 return Encode(bufPtr
, size
* 8, outlen
, changed
);
250 void RLE_Data::Decode(const uint8
*data
, int len
, ArrayOfUInts64
&outdata
)
252 const uint8
* decoded
= Decode(data
, len
);
253 wxASSERT(m_len
% 8 == 0);
254 int size
= m_len
/ 8;
255 outdata
.resize(size
);
256 for (int i
= 0; i
< size
; i
++) {
258 for (int j
= 8; j
--;) {
260 u
|= decoded
[i
+ j
* size
];
266 void PartFileEncoderData::DecodeGaps(const CECTag
* tag
, ArrayOfUInts64
&outdata
)
268 m_gap_status
.Decode((uint8
*)tag
->GetTagData(), tag
->GetTagDataLen(), outdata
);
272 // File_checked_for_headers