ironrdp_cliprdr/pdu/format_data/
mod.rs

1mod file_list;
2mod metafile;
3mod palette;
4
5pub use self::file_list::*;
6pub use self::metafile::*;
7pub use self::palette::*;
8
9#[rustfmt::skip]
10use std::borrow::Cow;
11
12use ironrdp_core::{
13    cast_int, ensure_fixed_part_size, ensure_size, Decode, DecodeResult, Encode, EncodeResult, IntoOwned, ReadCursor,
14    WriteCursor,
15};
16use ironrdp_pdu::impl_pdu_borrowing;
17use ironrdp_pdu::utils::{read_string_from_cursor, to_utf16_bytes, CharacterSet};
18
19use super::ClipboardFormatId;
20use crate::pdu::{ClipboardPduFlags, PartialHeader};
21
22/// Represents `CLIPRDR_FORMAT_DATA_RESPONSE`
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct FormatDataResponse<'a> {
25    is_error: bool,
26    data: Cow<'a, [u8]>,
27}
28
29impl_pdu_borrowing!(FormatDataResponse<'_>, OwnedFormatDataResponse);
30
31impl IntoOwned for FormatDataResponse<'_> {
32    type Owned = OwnedFormatDataResponse;
33
34    fn into_owned(self) -> Self::Owned {
35        OwnedFormatDataResponse {
36            is_error: self.is_error,
37            data: Cow::Owned(self.data.into_owned()),
38        }
39    }
40}
41
42impl<'a> FormatDataResponse<'a> {
43    const NAME: &'static str = "CLIPRDR_FORMAT_DATA_RESPONSE";
44
45    /// Creates new format data response from raw data.
46    pub fn new_data(data: impl Into<Cow<'a, [u8]>>) -> Self {
47        Self {
48            is_error: false,
49            data: data.into(),
50        }
51    }
52
53    /// Creates new error format data response.
54    pub fn new_error() -> Self {
55        Self {
56            is_error: true,
57            data: Cow::Borrowed(&[]),
58        }
59    }
60
61    pub fn data(&self) -> &[u8] {
62        &self.data
63    }
64
65    pub fn is_error(&self) -> bool {
66        self.is_error
67    }
68
69    /// Creates new format data response from clipboard palette. Please note that this method
70    /// allocates memory for the data automatically. If you want to avoid this, you can use
71    /// `new_data` method and encode [`ClipboardPalette`] prior to the call.
72    pub fn new_palette(palette: &ClipboardPalette) -> EncodeResult<Self> {
73        let mut data = vec![0u8; palette.size()];
74
75        let mut cursor = WriteCursor::new(&mut data);
76        palette.encode(&mut cursor)?;
77
78        Ok(Self {
79            is_error: false,
80            data: data.into(),
81        })
82    }
83
84    /// Creates new format data response from packed metafile. Please note that this method
85    /// allocates memory for the data automatically. If you want to avoid this, you can use
86    /// `new_data` method and encode [`PackedMetafile`] prior to the call.
87    pub fn new_metafile(metafile: &PackedMetafile<'_>) -> EncodeResult<Self> {
88        let mut data = vec![0u8; metafile.size()];
89
90        let mut cursor = WriteCursor::new(&mut data);
91        metafile.encode(&mut cursor)?;
92
93        Ok(Self {
94            is_error: false,
95            data: data.into(),
96        })
97    }
98
99    /// Creates new format data response from packed file list. Please note that this method
100    /// allocates memory for the data automatically. If you want to avoid this, you can use
101    /// `new_data` method and encode [`PackedFileList`] prior to the call.
102    pub fn new_file_list(list: &PackedFileList) -> EncodeResult<Self> {
103        let mut data = vec![0u8; list.size()];
104
105        let mut cursor = WriteCursor::new(&mut data);
106        list.encode(&mut cursor)?;
107
108        Ok(Self {
109            is_error: false,
110            data: data.into(),
111        })
112    }
113
114    /// Creates new format data response from string.
115    pub fn new_unicode_string(value: &str) -> Self {
116        let mut encoded = to_utf16_bytes(value);
117        encoded.push(b'\0');
118        encoded.push(b'\0');
119
120        Self {
121            is_error: false,
122            data: encoded.into(),
123        }
124    }
125
126    /// Creates new format data response from string.
127    pub fn new_string(value: &str) -> Self {
128        let mut encoded = value.as_bytes().to_vec();
129        encoded.push(b'\0');
130
131        Self {
132            is_error: false,
133            data: encoded.into(),
134        }
135    }
136
137    /// Reads inner data as [`ClipboardPalette`]
138    pub fn to_palette(&self) -> DecodeResult<ClipboardPalette> {
139        let mut cursor = ReadCursor::new(&self.data);
140        ClipboardPalette::decode(&mut cursor)
141    }
142
143    /// Reads inner data as [`PackedMetafile`]
144    pub fn to_metafile(&self) -> DecodeResult<PackedMetafile<'_>> {
145        let mut cursor = ReadCursor::new(&self.data);
146        PackedMetafile::decode(&mut cursor)
147    }
148
149    /// Reads inner data as [`PackedFileList`]
150    pub fn to_file_list(&self) -> DecodeResult<PackedFileList> {
151        let mut cursor = ReadCursor::new(&self.data);
152        PackedFileList::decode(&mut cursor)
153    }
154
155    /// Reads inner data as string
156    pub fn to_string(&self) -> DecodeResult<String> {
157        let mut cursor = ReadCursor::new(&self.data);
158        read_string_from_cursor(&mut cursor, CharacterSet::Ansi, true)
159    }
160
161    /// Reads inner data as unicode string
162    pub fn to_unicode_string(&self) -> DecodeResult<String> {
163        let mut cursor = ReadCursor::new(&self.data);
164        read_string_from_cursor(&mut cursor, CharacterSet::Unicode, true)
165    }
166
167    pub fn into_data(self) -> Cow<'a, [u8]> {
168        self.data
169    }
170}
171
172impl Encode for FormatDataResponse<'_> {
173    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
174        let flags = if self.is_error {
175            ClipboardPduFlags::RESPONSE_FAIL
176        } else {
177            ClipboardPduFlags::RESPONSE_OK
178        };
179
180        let header = PartialHeader::new_with_flags(cast_int!("dataLen", self.data.len())?, flags);
181        header.encode(dst)?;
182
183        ensure_size!(in: dst, size: self.data.len());
184        dst.write_slice(&self.data);
185
186        Ok(())
187    }
188
189    fn name(&self) -> &'static str {
190        Self::NAME
191    }
192
193    fn size(&self) -> usize {
194        PartialHeader::SIZE + self.data.len()
195    }
196}
197
198impl<'de> Decode<'de> for FormatDataResponse<'de> {
199    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
200        let header = PartialHeader::decode(src)?;
201
202        let is_error = header.message_flags.contains(ClipboardPduFlags::RESPONSE_FAIL);
203
204        ensure_size!(in: src, size: header.data_length());
205        let data = src.read_slice(header.data_length());
206
207        Ok(Self {
208            is_error,
209            data: Cow::Borrowed(data),
210        })
211    }
212}
213
214/// Represents `CLIPRDR_FORMAT_DATA_REQUEST`
215#[derive(Debug, Clone, PartialEq, Eq)]
216pub struct FormatDataRequest {
217    pub format: ClipboardFormatId,
218}
219
220impl FormatDataRequest {
221    const NAME: &'static str = "CLIPRDR_FORMAT_DATA_REQUEST";
222    const FIXED_PART_SIZE: usize = 4 /* format */;
223}
224
225impl Encode for FormatDataRequest {
226    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
227        let header = PartialHeader::new(cast_int!("dataLen", Self::FIXED_PART_SIZE)?);
228        header.encode(dst)?;
229
230        ensure_fixed_part_size!(in: dst);
231        dst.write_u32(self.format.value());
232
233        Ok(())
234    }
235
236    fn name(&self) -> &'static str {
237        Self::NAME
238    }
239
240    fn size(&self) -> usize {
241        PartialHeader::SIZE + Self::FIXED_PART_SIZE
242    }
243}
244
245impl<'de> Decode<'de> for FormatDataRequest {
246    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
247        let _header = PartialHeader::decode(src)?;
248
249        ensure_fixed_part_size!(in: src);
250        let format = ClipboardFormatId::new(src.read_u32());
251
252        Ok(Self { format })
253    }
254}