rdp/codec/
rle.rs

1use model::error::{RdpResult, Error, RdpError, RdpErrorKind};
2use std::io::{Cursor, Read};
3use byteorder::{ReadBytesExt, LittleEndian};
4
5/// All this uncompress code
6/// Are directly inspired from the source code
7/// of rdesktop and diretly port to rust
8/// Need a little bit of refactoring for rust
9
10fn process_plane(input: &mut dyn Read, width: u32, height: u32, output: &mut [u8]) -> RdpResult<()> {
11    let mut indexw;
12	let mut indexh= 0;
13	let mut code ;
14	let mut collen;
15	let mut replen;
16	let mut color:i8;
17	let mut x;
18	let mut revcode;
19
20    let mut this_line: u32;
21    let mut last_line: u32 = 0;
22
23	while indexh < height {
24		let mut out = (width * height * 4) - ((indexh + 1) * width * 4);
25		color = 0;
26		this_line = out;
27		indexw = 0;
28		if last_line == 0 {
29			while indexw < width {
30				code = input.read_u8()?;
31				replen = code & 0xf;
32				collen = (code >> 4) & 0xf;
33				revcode = (replen << 4) | collen;
34				if (revcode <= 47) && (revcode >= 16) {
35					replen = revcode;
36					collen = 0;
37				}
38				while collen > 0 {
39					color = input.read_u8()? as i8;
40					output[out as usize] = color as u8;
41					out += 4;
42					indexw += 1;
43					collen -= 1;
44				}
45				while replen > 0 {
46					output[out as usize] = color as u8;
47					out += 4;
48					indexw += 1;
49					replen -= 1;
50				}
51			}
52		}
53		else
54		{
55			while indexw < width {
56				code = input.read_u8()?;
57				replen = code & 0xf;
58				collen = (code >> 4) & 0xf;
59				revcode = (replen << 4) | collen;
60				if (revcode <= 47) && (revcode >= 16) {
61					replen = revcode;
62					collen = 0;
63				}
64				while collen > 0 {
65					x = input.read_u8()?;
66					if x & 1 != 0{
67						x = x >> 1;
68						x = x + 1;
69						color = -(x as i32) as i8;
70					}
71					else
72					{
73						x = x >> 1;
74						color = x as i8;
75					}
76					x = (output[(last_line + (indexw * 4)) as usize] as i32 + color as i32) as u8;
77					output[out as usize] = x;
78					out += 4;
79					indexw += 1;
80					collen -= 1;
81				}
82				while replen > 0 {
83					x = (output[(last_line + (indexw * 4)) as usize] as i32 + color as i32) as u8;
84					output[out as usize] = x;
85					out += 4;
86					indexw += 1;
87					replen -= 1;
88				}
89			}
90		}
91		indexh += 1;
92		last_line = this_line;
93	}
94    Ok(())
95}
96
97/// Run length encoding decoding function for 32 bpp
98pub fn rle_32_decompress(input: &[u8], width: u32, height: u32, output: &mut [u8]) -> RdpResult<()> {
99    let mut input_cursor = Cursor::new(input);
100
101	if input_cursor.read_u8()? != 0x10 {
102		return Err(Error::RdpError(RdpError::new(RdpErrorKind::UnexpectedType, "Bad header")))
103	}
104
105	process_plane(&mut input_cursor, width, height, &mut output[3..])?;
106	process_plane(&mut input_cursor, width, height, &mut output[2..])?;
107	process_plane(&mut input_cursor, width, height, &mut output[1..])?;
108	process_plane(&mut input_cursor, width, height, &mut output[0..])?;
109
110	Ok(())
111}
112
113macro_rules! repeat {
114    ($expr:expr, $count:expr, $x:expr, $width:expr) => {
115    	while (($count & !0x7) != 0) && ($x + 8) < $width {
116    		$expr; $count -= 1; $x += 1;
117    		$expr; $count -= 1; $x += 1;
118    		$expr; $count -= 1; $x += 1;
119    		$expr; $count -= 1; $x += 1;
120    		$expr; $count -= 1; $x += 1;
121    		$expr; $count -= 1; $x += 1;
122    		$expr; $count -= 1; $x += 1;
123    		$expr; $count -= 1; $x += 1;
124		}
125		while $count > 0 && $x < $width {
126			$expr;
127			$count -= 1;
128			$x += 1;
129		}
130    };
131}
132
133pub fn rle_16_decompress(input: &[u8], width: usize, mut height: usize, output: &mut [u16]) -> RdpResult<()> {
134	let mut input_cursor = Cursor::new(input);
135
136	let mut code: u8;
137	let mut opcode: u8;
138	let mut lastopcode: u8 = 0xFF;
139	let mut count: u16;
140	let mut offset: u16;
141	let mut isfillormix;
142	let mut insertmix = false;
143	let mut x: usize = width;
144	let mut prevline : Option<usize> = None;
145	let mut line : Option<usize> = None;
146	let mut colour1= 0;
147	let mut colour2 = 0;
148	let mut mix = 0xffff;
149	let mut mask:u8 = 0;
150	let mut fom_mask : u8;
151	let mut mixmask:u8;
152	let mut bicolour = false;
153
154	while (input_cursor.position() as usize) < input.len() {
155		fom_mask = 0;
156		code = input_cursor.read_u8()?;
157		opcode = code >> 4;
158
159		match opcode {
160			0xC | 0xD | 0xE => {
161				opcode -= 6;
162				count = (code & 0xf) as u16;
163				offset = 16;
164			}
165			0xF => {
166				opcode = code & 0xf;
167				if opcode < 9 {
168					count = input_cursor.read_u16::<LittleEndian>()?
169				} else if opcode < 0xb {
170					count = 8
171				} else {
172					count = 1
173				}
174				offset = 0;
175			}
176			_ => {
177				opcode >>= 1;
178				count = (code & 0x1f) as u16;
179				offset = 32;
180			}
181		}
182
183		if offset != 0 {
184			isfillormix = (opcode == 2) || (opcode == 7);
185			if count == 0 {
186				if isfillormix {
187					count = input_cursor.read_u8()? as u16 + 1;
188				} else {
189					count = input_cursor.read_u8()? as u16 + offset;
190				}
191			} else if isfillormix {
192				count <<= 3;
193			}
194		}
195
196		match opcode {
197			0 => {
198				if lastopcode == opcode && !(x == width && prevline == None) {
199					insertmix = true;
200				}
201			},
202			8 => {
203				colour1 = input_cursor.read_u16::<LittleEndian>()?;
204				colour2 = input_cursor.read_u16::<LittleEndian>()?;
205			},
206			3 => {
207				colour2 = input_cursor.read_u16::<LittleEndian>()?;
208			},
209			6 | 7 => {
210				mix = input_cursor.read_u16::<LittleEndian>()?;
211				opcode -= 5;
212			}
213			9 => {
214				mask = 0x03;
215				opcode = 0x02;
216				fom_mask = 3;
217			},
218			0xa => {
219				mask = 0x05;
220				opcode = 0x02;
221				fom_mask = 5;
222			}
223			_ => ()
224		}
225		lastopcode = opcode;
226		mixmask = 0;
227
228		while count > 0 {
229			if x >= width {
230				if height <= 0 {
231					return Err(Error::RdpError(RdpError::new(RdpErrorKind::InvalidData, "error during decompress")))
232				}
233				x = 0;
234				height -= 1;
235				prevline = line;
236				line = Some(height * width);
237			}
238
239			match opcode {
240				0 => {
241					if insertmix {
242						if let Some(e) = prevline {
243							output[line.unwrap() + x] = output[e + x] ^ mix;
244						}
245						else {
246							output[line.unwrap() + x] = mix;
247						}
248						insertmix = false;
249						count -= 1;
250						x += 1;
251					}
252
253					if let Some(e) = prevline {
254						repeat!(output[line.unwrap() + x] = output[e + x], count, x, width);
255					}
256					else {
257						repeat!(output[line.unwrap() + x] = 0, count, x, width);
258					}
259				},
260				1 => {
261					if let Some(e) = prevline {
262						repeat!(output[line.unwrap() + x] = output[e + x] ^ mix, count, x, width);
263					}
264					else {
265						repeat!(output[line.unwrap() + x] = mix, count, x, width);
266					}
267				},
268				2 => {
269					if let Some(e) = prevline {
270						repeat!({
271							mixmask <<= 1;
272							if mixmask == 0 {
273								mask = if fom_mask != 0 { fom_mask } else { input_cursor.read_u8()? };
274								mixmask = 1;
275							}
276							if (mask & mixmask) != 0 {
277								output[line.unwrap() + x] = output[e + x] ^ mix;
278							}
279							else {
280								output[line.unwrap() + x] = output[e + x];
281							}
282						}, count, x, width);
283					}
284					else {
285						repeat!({
286							mixmask <<= 1;
287							if mixmask == 0 {
288								mask = if fom_mask != 0 { fom_mask } else { input_cursor.read_u8()? };
289								mixmask = 1;
290							}
291							if (mask & mixmask) != 0 {
292								output[line.unwrap() + x] = mix;
293							}
294							else {
295								output[line.unwrap() + x] = 0;
296							}
297						}, count, x, width);
298					}
299				},
300				3 => {
301					repeat!(output[line.unwrap() + x] = colour2, count, x, width);
302				},
303				4 => {
304					repeat!(output[line.unwrap() + x] = input_cursor.read_u16::<LittleEndian>()?, count, x, width);
305				},
306				8 => {
307					repeat!({
308						if bicolour {
309							output[line.unwrap() + x] = colour2;
310							bicolour = false;
311						} else {
312							output[line.unwrap() + x] = colour1;
313							bicolour = true;
314							count += 1;
315						};
316					}, count, x, width);
317				},
318				0xd => {
319					repeat!(output[line.unwrap() + x] = 0xffff, count, x, width);
320				},
321				0xe => {
322					repeat!(output[line.unwrap() + x] = 0, count, x, width);
323				}
324				_ => panic!("opcode")
325			}
326		}
327	}
328
329	Ok(())
330}
331
332
333pub fn rgb565torgb32(input: &[u16], width: usize, height: usize) -> Vec<u8> {
334	let mut result_32_bpp = vec![0 as u8; width as usize * height as usize * 4];
335	for i in 0..height {
336		for j in 0..width {
337			let index = (i * width + j) as usize;
338			let v = input[index];
339			result_32_bpp[index * 4 + 3] = 0xff;
340			result_32_bpp[index * 4 + 2] = (((((v >> 11) & 0x1f) * 527) + 23) >> 6) as u8;
341			result_32_bpp[index * 4 + 1] = (((((v >> 5) & 0x3f) * 259) + 33) >> 6) as u8;
342			result_32_bpp[index * 4] = ((((v & 0x1f) * 527) + 23) >> 6) as u8;
343		}
344	}
345	result_32_bpp
346}