ironrdp_cliprdr/pdu/format_data/
metafile.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::borrow::Cow;

use bitflags::bitflags;
use ironrdp_core::{
    ensure_fixed_part_size, ensure_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
};

bitflags! {
    /// Represents `mappingMode` fields of `CLIPRDR_MFPICT` structure.
    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct PackedMetafileMappingMode: u32 {
        /// Each logical unit is mapped to one device pixel. Positive x is to the right; positive
        /// y is down.
        const TEXT = 0x0000_0001;
        /// Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive
        /// y is up.
        const LO_METRIC = 0x0000_0002;
        /// Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive
        /// y is up.
        const HI_METRIC = 0x0000_0003;
        /// Each logical unit is mapped to 0.01 inch. Positive x is to the right; positive y is up.
        const LO_ENGLISH = 0x0000_0004;
        /// Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is up.
        const HI_ENGLISH = 0x0000_0005;
        /// Each logical unit is mapped to 1/20 of a printer's point (1/1440 of an inch), also
        /// called a twip. Positive x is to the right; positive y is up.
        const TWIPS = 0x0000_0006;
        /// Logical units are mapped to arbitrary units with equally scaled axes; one unit along
        /// the x-axis is equal to one unit along the y-axis.
        const ISOTROPIC = 0x0000_0007;
        /// Logical units are mapped to arbitrary units with arbitrarily scaled axes.
        const ANISOTROPIC = 0x0000_0008;
    }
}

/// Represents `CLIPRDR_MFPICT`
///
/// NOTE: `Decode` implementation will read all remaining data in cursor as metafile contents.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PackedMetafile<'a> {
    pub mapping_mode: PackedMetafileMappingMode,
    pub x_ext: u32,
    pub y_ext: u32,
    /// The variable sized contents of the metafile as specified in [MS-WMF] section 2
    data: Cow<'a, [u8]>,
}

impl PackedMetafile<'_> {
    const NAME: &'static str = "CLIPRDR_MFPICT";
    const FIXED_PART_SIZE: usize = 4 /* mode */ + 4 /* xExt */ + 4 /* yExt */;

    pub fn new(
        mapping_mode: PackedMetafileMappingMode,
        x_ext: u32,
        y_ext: u32,
        data: impl Into<Cow<'static, [u8]>>,
    ) -> Self {
        Self {
            mapping_mode,
            x_ext,
            y_ext,
            data: data.into(),
        }
    }

    pub fn data(&self) -> &[u8] {
        &self.data
    }
}

impl Encode for PackedMetafile<'_> {
    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
        ensure_size!(in: dst, size: self.size());

        dst.write_u32(self.mapping_mode.bits());
        dst.write_u32(self.x_ext);
        dst.write_u32(self.y_ext);
        dst.write_slice(&self.data);

        Ok(())
    }

    fn name(&self) -> &'static str {
        Self::NAME
    }

    fn size(&self) -> usize {
        Self::FIXED_PART_SIZE + self.data.len()
    }
}

impl<'de> Decode<'de> for PackedMetafile<'de> {
    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
        ensure_fixed_part_size!(in: src);

        let mapping_mode = PackedMetafileMappingMode::from_bits_truncate(src.read_u32());
        let x_ext = src.read_u32();
        let y_ext = src.read_u32();

        let data_len = src.len();

        let data = src.read_slice(data_len);

        Ok(Self {
            mapping_mode,
            x_ext,
            y_ext,
            data: Cow::Borrowed(data),
        })
    }
}