xim_parser/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(any(test, feature = "std"))]
6extern crate std;
7
8use alloc::vec::Vec;
9
10pub mod attrs;
11mod parser;
12
13pub use parser::*;
14
15pub fn write_extend_vec(f: impl XimWrite, out: &mut Vec<u8>) {
16    let from = out.len();
17    out.extend(core::iter::repeat(0).take(f.size()));
18    f.write(&mut Writer::new(&mut out[from..]));
19}
20
21pub fn write_to_vec(f: impl XimWrite) -> Vec<u8> {
22    let mut out: Vec<u8> = core::iter::repeat(0).take(f.size()).collect();
23    f.write(&mut Writer::new(&mut out));
24    out
25}
26
27#[cfg(test)]
28mod tests {
29    use crate::{parser::*, write_to_vec};
30    use alloc::vec;
31    use alloc::vec::Vec;
32    use pretty_assertions::assert_eq;
33
34    #[cfg(target_endian = "little")]
35    #[test]
36    fn read_connect_req() {
37        let req: Request = read(b"\x01\x00\x00\x00\x6c\x00\x00\x00\x00\x00\x00\x00").unwrap();
38
39        assert_eq!(
40            req,
41            Request::Connect {
42                endian: Endian::Native,
43                client_auth_protocol_names: vec![],
44                client_minor_protocol_version: 0,
45                client_major_protocol_version: 0,
46            }
47        );
48    }
49
50    #[test]
51    fn read_open() {
52        let req = read::<Request>(&[
53            30, 0, 2, 0, 5, 101, 110, 95, 85, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54        ])
55        .unwrap();
56        assert_eq!(
57            req,
58            Request::Open {
59                locale: "en_US".into(),
60            }
61        );
62    }
63
64    #[test]
65    fn read_query() {
66        let req = read::<Request>(&[
67            40, 0, 5, 0, 0, 0, 13, 0, 12, 88, 73, 77, 95, 69, 88, 84, 95, 77, 79, 86, 69, 0, 0, 0,
68        ])
69        .unwrap();
70        assert_eq!(
71            req,
72            Request::QueryExtension {
73                input_method_id: 0,
74                extensions: vec!["XIM_EXT_MOVE".into(),],
75            }
76        );
77    }
78
79    #[test]
80    fn read_input_styles() {
81        let styles: InputStyleList = read(&[1, 0, 0, 0, 4, 1, 0, 0]).unwrap();
82
83        assert_eq!(
84            styles,
85            InputStyleList {
86                styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA]
87            }
88        );
89    }
90
91    #[test]
92    fn commit() {
93        let req = Request::Commit {
94            input_method_id: 1,
95            input_context_id: 1,
96            data: CommitData::Chars {
97                commited: xim_ctext::utf8_to_compound_text("맘"),
98                syncronous: false,
99            },
100        };
101
102        write_to_vec(req);
103    }
104
105    #[test]
106    fn set_event_mask() {
107        let req = Request::SetEventMask {
108            input_method_id: 2,
109            input_context_id: 1,
110            forward_event_mask: 3,
111            synchronous_event_mask: 4294967292,
112        };
113        let out = write_to_vec(&req);
114        assert_eq!(
115            out,
116            [37, 0, 3, 0, 2, 0, 1, 0, 3, 0, 0, 0, 252, 255, 255, 255]
117        );
118        assert_eq!(req, read::<Request>(&out).unwrap());
119    }
120
121    #[test]
122    fn attr_size() {
123        let list = InputStyleList {
124            styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA],
125        };
126
127        assert_eq!(list.size(), 8);
128
129        let attr = Attribute {
130            id: 0,
131            value: write_to_vec(list),
132        };
133
134        assert_eq!(attr.size(), 12);
135    }
136
137    #[test]
138    fn im_reply() {
139        let req = Request::GetImValuesReply {
140            input_method_id: 3,
141            im_attributes: vec![Attribute {
142                id: 0,
143                value: write_to_vec(InputStyleList {
144                    styles: vec![InputStyle::PREEDIT_POSITION | InputStyle::STATUS_AREA],
145                }),
146            }],
147        };
148
149        let out = write_to_vec(&req);
150        assert_eq!(req.size(), out.len());
151
152        let new_req = read(&out).unwrap();
153
154        assert_eq!(req, new_req);
155    }
156
157    #[test]
158    fn spot_attr() {
159        let value = [4, 0, 4, 0, 0, 0, 0, 0];
160
161        let attr = read::<Attribute>(&value).unwrap();
162
163        assert_eq!(attr.id, 4);
164        assert_eq!(read::<Point>(&attr.value).unwrap(), Point { x: 0, y: 0 });
165    }
166
167    #[test]
168    fn read_error() {
169        let req: Request = read(&[
170            20, 0, 7, 0, 2, 0, 1, 0, 3, 0, 2, 0, 16, 0, 0, 0, 105, 110, 118, 97, 108, 105, 100, 32,
171            105, 109, 32, 115, 116, 121, 108, 101,
172        ])
173        .unwrap();
174
175        assert_eq!(
176            req,
177            Request::Error {
178                input_method_id: 2,
179                input_context_id: 1,
180                flag: ErrorFlag::INPUT_METHOD_ID_VALID | ErrorFlag::INPUT_CONTEXT_ID_VALID,
181                code: ErrorCode::BadStyle,
182                detail: "invalid im style".into(),
183            }
184        );
185    }
186
187    #[test]
188    fn write_get_im_values() {
189        let req = Request::GetImValues {
190            input_method_id: 1,
191            im_attributes: vec![0],
192        };
193
194        let out = write_to_vec(&req);
195
196        assert_eq!(out.len(), req.size());
197    }
198
199    #[test]
200    fn write_forward_event() {
201        let req = Request::ForwardEvent {
202            input_method_id: 0,
203            input_context_id: 0,
204            flag: ForwardEventFlag::empty(),
205            serial_number: 0,
206            xev: unsafe { std::mem::zeroed() },
207        };
208        assert_eq!(req.size(), 4 + 8 + 32);
209
210        let out = write_to_vec(&req);
211        assert!(out.starts_with(b"\x3c\x00\x0a\x00"));
212    }
213
214    #[test]
215    fn write_create_ic() {
216        let req = Request::CreateIc {
217            input_method_id: 2,
218            ic_attributes: Vec::new(),
219        };
220        let out = write_to_vec(&req);
221        assert_eq!(out, b"\x32\x00\x01\x00\x02\x00\x00\x00");
222    }
223
224    #[test]
225    fn write_connect_reply() {
226        let req = Request::ConnectReply {
227            server_minor_protocol_version: 0,
228            server_major_protocol_version: 1,
229        };
230        let out = write_to_vec(&req);
231        assert_eq!(out, b"\x02\x00\x01\x00\x01\x00\x00\x00");
232    }
233
234    const OPEN_REPLY: &[u8] = b"\x1f\x00\x59\x00\x01\x00\x18\x00\x00\x00\x0a\x00\x0f\x00\x71\x75\x65\x72\x79\x49\x6e\x70\x75\x74\x53\x74\x79\x6c\x65\x00\x00\x00\x44\x01\x00\x00\x01\x00\x03\x00\x0a\x00\x69\x6e\x70\x75\x74\x53\x74\x79\x6c\x65\x02\x00\x05\x00\x0c\x00\x63\x6c\x69\x65\x6e\x74\x57\x69\x6e\x64\x6f\x77\x00\x00\x03\x00\x05\x00\x0b\x00\x66\x6f\x63\x75\x73\x57\x69\x6e\x64\x6f\x77\x00\x00\x00\x04\x00\x03\x00\x0c\x00\x66\x69\x6c\x74\x65\x72\x45\x76\x65\x6e\x74\x73\x00\x00\x05\x00\xff\x7f\x11\x00\x70\x72\x65\x65\x64\x69\x74\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x06\x00\xff\x7f\x10\x00\x73\x74\x61\x74\x75\x73\x41\x74\x74\x72\x69\x62\x75\x74\x65\x73\x00\x00\x07\x00\x0d\x00\x07\x00\x66\x6f\x6e\x74\x53\x65\x74\x00\x00\x00\x08\x00\x0b\x00\x04\x00\x61\x72\x65\x61\x00\x00\x09\x00\x0b\x00\x0a\x00\x61\x72\x65\x61\x4e\x65\x65\x64\x65\x64\x0a\x00\x03\x00\x08\x00\x63\x6f\x6c\x6f\x72\x4d\x61\x70\x00\x00\x0b\x00\x03\x00\x0b\x00\x73\x74\x64\x43\x6f\x6c\x6f\x72\x4d\x61\x70\x00\x00\x00\x0c\x00\x03\x00\x0a\x00\x66\x6f\x72\x65\x67\x72\x6f\x75\x6e\x64\x0d\x00\x03\x00\x0a\x00\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x0e\x00\x03\x00\x10\x00\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x50\x69\x78\x6d\x61\x70\x00\x00\x0f\x00\x0c\x00\x0c\x00\x73\x70\x6f\x74\x4c\x6f\x63\x61\x74\x69\x6f\x6e\x00\x00\x10\x00\x03\x00\x09\x00\x6c\x69\x6e\x65\x53\x70\x61\x63\x65\x00\x11\x00\x00\x00\x15\x00\x73\x65\x70\x61\x72\x61\x74\x6f\x72\x6f\x66\x4e\x65\x73\x74\x65\x64\x4c\x69\x73\x74\x00";
235
236    fn open_reply_value() -> Request {
237        Request::OpenReply {
238            input_method_id: 1,
239            im_attrs: vec![Attr {
240                id: 0,
241                ty: AttrType::Style,
242                name: AttributeName::QueryInputStyle,
243            }],
244            ic_attrs: vec![
245                Attr {
246                    id: 1,
247                    ty: AttrType::Long,
248                    name: AttributeName::InputStyle,
249                },
250                Attr {
251                    id: 2,
252                    ty: AttrType::Window,
253                    name: AttributeName::ClientWindow,
254                },
255                Attr {
256                    id: 3,
257                    ty: AttrType::Window,
258                    name: AttributeName::FocusWindow,
259                },
260                Attr {
261                    id: 4,
262                    ty: AttrType::Long,
263                    name: AttributeName::FilterEvents,
264                },
265                Attr {
266                    id: 5,
267                    ty: AttrType::NestedList,
268                    name: AttributeName::PreeditAttributes,
269                },
270                Attr {
271                    id: 6,
272                    ty: AttrType::NestedList,
273                    name: AttributeName::StatusAttributes,
274                },
275                Attr {
276                    id: 7,
277                    ty: AttrType::XFontSet,
278                    name: AttributeName::FontSet,
279                },
280                Attr {
281                    id: 8,
282                    ty: AttrType::XRectangle,
283                    name: AttributeName::Area,
284                },
285                Attr {
286                    id: 9,
287                    ty: AttrType::XRectangle,
288                    name: AttributeName::AreaNeeded,
289                },
290                Attr {
291                    id: 10,
292                    ty: AttrType::Long,
293                    name: AttributeName::ColorMap,
294                },
295                Attr {
296                    id: 11,
297                    ty: AttrType::Long,
298                    name: AttributeName::StdColorMap,
299                },
300                Attr {
301                    id: 12,
302                    ty: AttrType::Long,
303                    name: AttributeName::Foreground,
304                },
305                Attr {
306                    id: 13,
307                    ty: AttrType::Long,
308                    name: AttributeName::Background,
309                },
310                Attr {
311                    id: 14,
312                    ty: AttrType::Long,
313                    name: AttributeName::BackgroundPixmap,
314                },
315                Attr {
316                    id: 15,
317                    ty: AttrType::XPoint,
318                    name: AttributeName::SpotLocation,
319                },
320                Attr {
321                    id: 16,
322                    ty: AttrType::Long,
323                    name: AttributeName::LineSpace,
324                },
325                Attr {
326                    id: 17,
327                    ty: AttrType::Separator,
328                    name: AttributeName::SeparatorofNestedList,
329                },
330            ],
331        }
332    }
333
334    #[test]
335    fn read_open_reply() {
336        assert_eq!(read::<Request>(OPEN_REPLY).unwrap(), open_reply_value());
337    }
338
339    #[test]
340    fn size_open_reply() {
341        assert_eq!(open_reply_value().size(), OPEN_REPLY.len());
342    }
343
344    #[test]
345    fn write_open_reply() {
346        let value = open_reply_value();
347        let out = write_to_vec(&value);
348        assert_eq!(OPEN_REPLY.len(), out.len());
349        assert_eq!(OPEN_REPLY, out);
350        let new: Request = read(&out).unwrap();
351        assert_eq!(value, new);
352    }
353}