1use bit_field::BitField as _;
2use bitflags::bitflags;
3use ironrdp_core::{
4 cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult,
5 ReadCursor, WriteCursor,
6};
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9
10use crate::codecs::rfx::Block;
11
12const CONTEXT_ID: u8 = 0;
13const TILE_SIZE: u16 = 0x0040;
14const COLOR_CONVERSION_ICT: u16 = 1;
15const CLW_XFORM_DWT_53_A: u16 = 1;
16const SCALAR_QUANTIZATION: u16 = 1;
17const LRF: bool = true;
18const CBT_REGION: u16 = 0xcac1;
19const NUMBER_OF_TILESETS: u16 = 1;
20const CBT_TILESET: u16 = 0xcac2;
21const IDX: u16 = 0;
22const IS_LAST_TILESET_FLAG: bool = true;
23const RECTANGLE_SIZE: usize = 8;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct ContextPdu {
30 pub flags: OperatingMode,
31 pub entropy_algorithm: EntropyAlgorithm,
32}
33
34impl ContextPdu {
35 const NAME: &'static str = "RfxContext";
36
37 const FIXED_PART_SIZE: usize = 1 + 2 + 2 ;
38}
39
40impl Encode for ContextPdu {
41 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
42 ensure_fixed_part_size!(in: dst);
43
44 dst.write_u8(CONTEXT_ID);
45 dst.write_u16(TILE_SIZE);
46
47 let mut properties: u16 = 0;
48 properties.set_bits(0..3, self.flags.bits());
49 properties.set_bits(3..5, COLOR_CONVERSION_ICT);
50 properties.set_bits(5..9, CLW_XFORM_DWT_53_A);
51 properties.set_bits(9..13, self.entropy_algorithm.to_u16().unwrap());
52 properties.set_bits(13..15, SCALAR_QUANTIZATION);
53 properties.set_bit(15, false); dst.write_u16(properties);
55
56 Ok(())
57 }
58
59 fn name(&self) -> &'static str {
60 Self::NAME
61 }
62
63 fn size(&self) -> usize {
64 Self::FIXED_PART_SIZE
65 }
66}
67
68impl<'de> Decode<'de> for ContextPdu {
69 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
70 ensure_fixed_part_size!(in: src);
71
72 let id = src.read_u8();
73 if id != CONTEXT_ID {
74 return Err(invalid_field_err!("ctxId", "Invalid context ID"));
75 }
76
77 let tile_size = src.read_u16();
78 if tile_size != TILE_SIZE {
79 return Err(invalid_field_err!("tileSize", "Invalid tile size"));
80 }
81
82 let properties = src.read_u16();
83 let flags = OperatingMode::from_bits_truncate(properties.get_bits(0..3));
84 let color_conversion_transform = properties.get_bits(3..5);
85 if color_conversion_transform != COLOR_CONVERSION_ICT {
86 return Err(invalid_field_err!("cct", "Invalid color conversion transform"));
87 }
88
89 let dwt = properties.get_bits(5..9);
90 if dwt != CLW_XFORM_DWT_53_A {
91 return Err(invalid_field_err!("dwt", "Invalid DWT"));
92 }
93
94 let entropy_algorithm_bits = properties.get_bits(9..13);
95 let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits)
96 .ok_or_else(|| invalid_field_err!("entropy_algorithm", "Invalid entropy algorithm"))?;
97
98 let quantization_type = properties.get_bits(13..15);
99 if quantization_type != SCALAR_QUANTIZATION {
100 return Err(invalid_field_err!("qt", "Invalid quantization type"));
101 }
102
103 let _reserved = properties.get_bit(15);
104
105 Ok(Self {
106 flags,
107 entropy_algorithm,
108 })
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct FrameBeginPdu {
117 pub index: u32,
118 pub number_of_regions: i16,
119}
120
121impl FrameBeginPdu {
122 const NAME: &'static str = "RfxFrameBegin";
123
124 const FIXED_PART_SIZE: usize = 4 + 2 ;
125}
126
127impl Encode for FrameBeginPdu {
128 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
129 ensure_fixed_part_size!(in: dst);
130
131 dst.write_u32(self.index);
132 dst.write_i16(self.number_of_regions);
133
134 Ok(())
135 }
136
137 fn name(&self) -> &'static str {
138 Self::NAME
139 }
140
141 fn size(&self) -> usize {
142 Self::FIXED_PART_SIZE
143 }
144}
145
146impl<'de> Decode<'de> for FrameBeginPdu {
147 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
148 ensure_fixed_part_size!(in: src);
149
150 let index = src.read_u32();
151 let number_of_regions = src.read_i16();
152
153 Ok(Self {
154 index,
155 number_of_regions,
156 })
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
164pub struct FrameEndPdu;
165
166impl FrameEndPdu {
167 const NAME: &'static str = "RfxFrameEnd";
168
169 const FIXED_PART_SIZE: usize = 0;
170}
171
172impl Encode for FrameEndPdu {
173 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
174 ensure_fixed_part_size!(in: dst);
175
176 Ok(())
177 }
178
179 fn name(&self) -> &'static str {
180 Self::NAME
181 }
182
183 fn size(&self) -> usize {
184 Self::FIXED_PART_SIZE
185 }
186}
187
188impl<'de> Decode<'de> for FrameEndPdu {
189 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
190 ensure_fixed_part_size!(in: src);
191
192 Ok(Self)
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct RegionPdu {
201 pub rectangles: Vec<RfxRectangle>,
202}
203
204impl RegionPdu {
205 const NAME: &'static str = "RfxRegion";
206
207 const FIXED_PART_SIZE: usize = 1 + 2 + 2 + 2 ;
208}
209
210impl Encode for RegionPdu {
211 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
212 ensure_fixed_part_size!(in: dst);
213
214 let mut region_flags = 0;
215 region_flags.set_bit(0, LRF);
216 dst.write_u8(region_flags);
217
218 dst.write_u16(cast_length!("numRectangles", self.rectangles.len())?);
219 for rectangle in self.rectangles.iter() {
220 rectangle.encode(dst)?;
221 }
222
223 dst.write_u16(CBT_REGION);
224 dst.write_u16(NUMBER_OF_TILESETS);
225
226 Ok(())
227 }
228
229 fn name(&self) -> &'static str {
230 Self::NAME
231 }
232
233 fn size(&self) -> usize {
234 Self::FIXED_PART_SIZE + self.rectangles.len() * RECTANGLE_SIZE
235 }
236}
237
238impl<'de> Decode<'de> for RegionPdu {
239 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
240 ensure_fixed_part_size!(in: src);
241
242 let region_flags = src.read_u8();
243 let lrf = region_flags.get_bit(0);
244 if lrf != LRF {
245 return Err(invalid_field_err!("lrf", "Invalid lrf"));
246 }
247
248 let number_of_rectangles = usize::from(src.read_u16());
249
250 ensure_size!(in: src, size: number_of_rectangles * RECTANGLE_SIZE);
251
252 let rectangles = (0..number_of_rectangles)
253 .map(|_| RfxRectangle::decode(src))
254 .collect::<Result<Vec<_>, _>>()?;
255
256 ensure_size!(in: src, size: 4);
257
258 let region_type = src.read_u16();
259 if region_type != CBT_REGION {
260 return Err(invalid_field_err!("regionType", "Invalid region type"));
261 }
262
263 let number_of_tilesets = src.read_u16();
264 if number_of_tilesets != NUMBER_OF_TILESETS {
265 return Err(invalid_field_err!("numTilesets", "Invalid number of tilesets"));
266 }
267
268 Ok(Self { rectangles })
269 }
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct TileSetPdu<'a> {
277 pub entropy_algorithm: EntropyAlgorithm,
278 pub quants: Vec<Quant>,
279 pub tiles: Vec<Tile<'a>>,
280}
281
282impl TileSetPdu<'_> {
283 const NAME: &'static str = "RfxTileSet";
284
285 const FIXED_PART_SIZE: usize = 2 + 2 + 2 + 1 + 1 + 2 + 4 ;
286}
287
288impl Encode for TileSetPdu<'_> {
289 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
290 ensure_fixed_part_size!(in: dst);
291
292 dst.write_u16(CBT_TILESET);
293 dst.write_u16(IDX);
294
295 let mut properties: u16 = 0;
296 properties.set_bit(0, IS_LAST_TILESET_FLAG);
297 properties.set_bits(1..4, OperatingMode::empty().bits()); properties.set_bits(4..6, COLOR_CONVERSION_ICT);
299 properties.set_bits(6..10, CLW_XFORM_DWT_53_A);
300 properties.set_bits(10..14, self.entropy_algorithm.to_u16().unwrap());
301 properties.set_bits(14..16, SCALAR_QUANTIZATION);
302 dst.write_u16(properties);
303
304 dst.write_u8(cast_length!("numQuant", self.quants.len())?);
305 dst.write_u8(TILE_SIZE as u8);
306 dst.write_u16(cast_length!("numTiles", self.tiles.len())?);
307
308 let tiles_data_size = self.tiles.iter().map(|t| Block::Tile(t.clone()).size()).sum::<usize>();
309 dst.write_u32(cast_length!("tilesDataSize", tiles_data_size)?);
310
311 for quant in &self.quants {
312 quant.encode(dst)?;
313 }
314
315 for tile in &self.tiles {
316 Block::Tile(tile.clone()).encode(dst)?;
317 }
318
319 Ok(())
320 }
321
322 fn name(&self) -> &'static str {
323 Self::NAME
324 }
325
326 fn size(&self) -> usize {
327 Self::FIXED_PART_SIZE
328 + self.quants.iter().map(Encode::size).sum::<usize>()
329 + self.tiles.iter().map(|t| Block::Tile(t.clone()).size()).sum::<usize>()
330 }
331}
332
333impl<'de> Decode<'de> for TileSetPdu<'de> {
334 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
335 ensure_fixed_part_size!(in: src);
336
337 let subtype = src.read_u16();
338 if subtype != CBT_TILESET {
339 return Err(invalid_field_err!("subtype", "Invalid message type"));
340 }
341
342 let id_of_context = src.read_u16();
343 if id_of_context != IDX {
344 return Err(invalid_field_err!("id_of_context", "Invalid RFX context"));
345 }
346
347 let properties = src.read_u16();
348 let is_last = properties.get_bit(0);
349 if is_last != IS_LAST_TILESET_FLAG {
350 return Err(invalid_field_err!("last", "Invalid last flag"));
351 }
352
353 let color_conversion_transform = properties.get_bits(4..6);
359 if color_conversion_transform != COLOR_CONVERSION_ICT {
360 return Err(invalid_field_err!("cct", "Invalid color conversion"));
361 }
362
363 let dwt = properties.get_bits(6..10);
364 if dwt != CLW_XFORM_DWT_53_A {
365 return Err(invalid_field_err!("xft", "Invalid DWT"));
366 }
367
368 let entropy_algorithm_bits = properties.get_bits(10..14);
369 let entropy_algorithm = EntropyAlgorithm::from_u16(entropy_algorithm_bits)
370 .ok_or_else(|| invalid_field_err!("entropy", "Invalid entropy algorithm"))?;
371
372 let quantization_type = properties.get_bits(14..16);
373 if quantization_type != SCALAR_QUANTIZATION {
374 return Err(invalid_field_err!("scalar", "Invalid quantization type"));
375 }
376
377 let number_of_quants = usize::from(src.read_u8());
378
379 let tile_size = u16::from(src.read_u8());
380 if tile_size != TILE_SIZE {
381 return Err(invalid_field_err!("tile_size", "Invalid tile size"));
382 }
383
384 let number_of_tiles = src.read_u16();
385 let _tiles_data_size = src.read_u32() as usize;
386
387 let quants = (0..number_of_quants)
388 .map(|_| Quant::decode(src))
389 .collect::<Result<Vec<_>, _>>()?;
390
391 let tiles = (0..number_of_tiles)
392 .map(|_| Block::decode(src))
393 .collect::<Result<Vec<_>, _>>()?;
394
395 let tiles = tiles
396 .into_iter()
397 .map(|b| match b {
398 Block::Tile(tile) => Ok(tile),
399 _ => Err(invalid_field_err!("tile", "Invalid block type, expected Tile")),
400 })
401 .collect::<Result<Vec<_>, _>>()?;
402
403 Ok(Self {
404 entropy_algorithm,
405 quants,
406 tiles,
407 })
408 }
409}
410#[derive(Debug, Clone, PartialEq, Eq)]
414pub struct RfxRectangle {
415 pub x: u16,
416 pub y: u16,
417 pub width: u16,
418 pub height: u16,
419}
420
421impl RfxRectangle {
422 const NAME: &'static str = "RfxRectangle";
423
424 const FIXED_PART_SIZE: usize = 4 * 2 ;
425}
426
427impl Encode for RfxRectangle {
428 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
429 ensure_fixed_part_size!(in: dst);
430
431 dst.write_u16(self.x);
432 dst.write_u16(self.y);
433 dst.write_u16(self.width);
434 dst.write_u16(self.height);
435
436 Ok(())
437 }
438
439 fn name(&self) -> &'static str {
440 Self::NAME
441 }
442
443 fn size(&self) -> usize {
444 Self::FIXED_PART_SIZE
445 }
446}
447
448impl<'de> Decode<'de> for RfxRectangle {
449 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
450 ensure_fixed_part_size!(in: src);
451
452 let x = src.read_u16();
453 let y = src.read_u16();
454 let width = src.read_u16();
455 let height = src.read_u16();
456
457 Ok(Self { x, y, width, height })
458 }
459}
460
461#[derive(Debug, Clone, PartialEq, Eq)]
465pub struct Quant {
466 pub ll3: u8,
467 pub lh3: u8,
468 pub hl3: u8,
469 pub hh3: u8,
470 pub lh2: u8,
471 pub hl2: u8,
472 pub hh2: u8,
473 pub lh1: u8,
474 pub hl1: u8,
475 pub hh1: u8,
476}
477
478impl Default for Quant {
485 fn default() -> Self {
486 Self {
487 ll3: 6,
488 lh3: 6,
489 hl3: 6,
490 hh3: 6,
491 lh2: 7,
492 hl2: 7,
493 hh2: 8,
494 lh1: 8,
495 hl1: 8,
496 hh1: 9,
497 }
498 }
499}
500
501impl Quant {
502 const NAME: &'static str = "RfxFrameEnd";
503
504 const FIXED_PART_SIZE: usize = 5 ;
505}
506
507impl Encode for Quant {
508 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
509 ensure_fixed_part_size!(in: dst);
510
511 let mut level3 = 0;
512 level3.set_bits(0..4, u16::from(self.ll3));
513 level3.set_bits(4..8, u16::from(self.lh3));
514 level3.set_bits(8..12, u16::from(self.hl3));
515 level3.set_bits(12..16, u16::from(self.hh3));
516
517 let mut level2_with_lh1 = 0;
518 level2_with_lh1.set_bits(0..4, u16::from(self.lh2));
519 level2_with_lh1.set_bits(4..8, u16::from(self.hl2));
520 level2_with_lh1.set_bits(8..12, u16::from(self.hh2));
521 level2_with_lh1.set_bits(12..16, u16::from(self.lh1));
522
523 let mut level1 = 0;
524 level1.set_bits(0..4, self.hl1);
525 level1.set_bits(4..8, self.hh1);
526
527 dst.write_u16(level3);
528 dst.write_u16(level2_with_lh1);
529 dst.write_u8(level1);
530
531 Ok(())
532 }
533
534 fn name(&self) -> &'static str {
535 Self::NAME
536 }
537
538 fn size(&self) -> usize {
539 Self::FIXED_PART_SIZE
540 }
541}
542
543impl<'de> Decode<'de> for Quant {
544 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
545 #![allow(clippy::similar_names)] ensure_fixed_part_size!(in: src);
547
548 let level3 = src.read_u16();
549 let ll3 = level3.get_bits(0..4) as u8;
550 let lh3 = level3.get_bits(4..8) as u8;
551 let hl3 = level3.get_bits(8..12) as u8;
552 let hh3 = level3.get_bits(12..16) as u8;
553
554 let level2_with_lh1 = src.read_u16();
555 let lh2 = level2_with_lh1.get_bits(0..4) as u8;
556 let hl2 = level2_with_lh1.get_bits(4..8) as u8;
557 let hh2 = level2_with_lh1.get_bits(8..12) as u8;
558 let lh1 = level2_with_lh1.get_bits(12..16) as u8;
559
560 let level1 = src.read_u8();
561 let hl1 = level1.get_bits(0..4);
562 let hh1 = level1.get_bits(4..8);
563
564 Ok(Self {
565 ll3,
566 lh3,
567 hl3,
568 hh3,
569 lh2,
570 hl2,
571 hh2,
572 lh1,
573 hl1,
574 hh1,
575 })
576 }
577}
578#[derive(Debug, Clone, PartialEq, Eq)]
582pub struct Tile<'a> {
583 pub y_quant_index: u8,
584 pub cb_quant_index: u8,
585 pub cr_quant_index: u8,
586
587 pub x: u16,
588 pub y: u16,
589
590 pub y_data: &'a [u8],
591 pub cb_data: &'a [u8],
592 pub cr_data: &'a [u8],
593}
594
595impl Tile<'_> {
596 const NAME: &'static str = "RfxTile";
597
598 const FIXED_PART_SIZE: usize = 1 + 1 + 1 + 2 + 2 + 2 + 2 + 2 ;
599}
600
601impl Encode for Tile<'_> {
602 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
603 ensure_size!(in: dst, size: self.size());
604
605 dst.write_u8(self.y_quant_index);
606 dst.write_u8(self.cb_quant_index);
607 dst.write_u8(self.cr_quant_index);
608
609 dst.write_u16(self.x);
610 dst.write_u16(self.y);
611
612 dst.write_u16(cast_length!("YLen", self.y_data.len())?);
613 dst.write_u16(cast_length!("CbLen", self.cb_data.len())?);
614 dst.write_u16(cast_length!("CrLen", self.cr_data.len())?);
615
616 dst.write_slice(self.y_data);
617 dst.write_slice(self.cb_data);
618 dst.write_slice(self.cr_data);
619
620 Ok(())
621 }
622
623 fn name(&self) -> &'static str {
624 Self::NAME
625 }
626
627 fn size(&self) -> usize {
628 Self::FIXED_PART_SIZE + self.y_data.len() + self.cb_data.len() + self.cr_data.len()
629 }
630}
631
632impl<'de> Decode<'de> for Tile<'de> {
633 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
634 #![allow(clippy::similar_names)] ensure_fixed_part_size!(in: src);
636
637 let y_quant_index = src.read_u8();
638 let cb_quant_index = src.read_u8();
639 let cr_quant_index = src.read_u8();
640
641 let x = src.read_u16();
642 let y = src.read_u16();
643
644 let y_component_length = usize::from(src.read_u16());
645 let cb_component_length = usize::from(src.read_u16());
646 let cr_component_length = usize::from(src.read_u16());
647
648 ensure_size!(in: src, size: y_component_length + cb_component_length + cr_component_length);
649
650 let y_data = src.read_slice(y_component_length);
651 let cb_data = src.read_slice(cb_component_length);
652 let cr_data = src.read_slice(cr_component_length);
653
654 Ok(Self {
655 y_quant_index,
656 cb_quant_index,
657 cr_quant_index,
658
659 x,
660 y,
661
662 y_data,
663 cb_data,
664 cr_data,
665 })
666 }
667}
668
669#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
670#[repr(u16)]
671pub enum EntropyAlgorithm {
672 Rlgr1 = 0x01,
673 Rlgr3 = 0x04,
674}
675
676bitflags! {
677 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
678 pub struct OperatingMode: u16 {
679 const IMAGE_MODE = 0x02; }
681}