Skip to content

Commit 09a4135

Browse files
authored
refactor: inline quick-xml::escape::escape (#53)
* refactor: inline quick-xml::escape::escape * don't use it in examples either
1 parent f32f183 commit 09a4135

6 files changed

Lines changed: 82 additions & 36 deletions

File tree

.changes/drop-quickxml.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
tauri-winrt-notification: patch
3+
---
4+
5+
Drop quick-xml dependency.

Cargo.lock

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ rust-version = "1.74"
1818
default-target = "x86_64-pc-windows-msvc"
1919

2020
[dependencies]
21-
quick-xml = "0.38"
2221
thiserror = "2"
2322
windows-version = "0.1"
2423

examples/without_library.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ use windows::{
1717

1818
pub use windows::core::{Error, HSTRING};
1919

20+
// In a real project you'd use quick-xml::escape::escape
21+
#[path = "../src/xml_escape.rs"]
22+
mod xml_escape;
23+
2024
fn main() {
2125
do_toast().expect("not sure if this is actually failable");
2226
// this is a hack to workaround toasts not showing up if the application closes too quickly
@@ -42,7 +46,7 @@ fn do_toast() -> windows::core::Result<()> {
4246
<audio src="ms-winsoundevent:Notification.SMS" />
4347
<!-- <audio silent="true" /> -->
4448
</toast>"#,
45-
quick_xml::escape::escape(Path::new("C:\\path_to_image_in_toast.jpg").display().to_string()),
49+
xml_escape::escape(Path::new("C:\\path_to_image_in_toast.jpg").display().to_string()),
4650
))).expect("the xml is malformed");
4751

4852
// Create the toast and attach event listeners

src/lib.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
//! * <https://softwareengineering.stackexchange.com/questions/222339/using-the-system-tray-notification-area-app-in-windows-7>
3232
//!
3333
//! For actions look at <https://docs.microsoft.com/en-us/dotnet/api/microsoft.toolkit.uwp.notifications.toastactionscustom?view=win-comm-toolkit-dotnet-7.0>
34+
35+
mod xml_escape;
36+
3437
use windows::{
3538
core::{IInspectable, Interface},
3639
Data::Xml::Dom::XmlDocument,
@@ -356,10 +359,7 @@ impl Toast {
356359
/// Will be white.
357360
/// Supports Unicode ✓
358361
pub fn title(mut self, content: &str) -> Toast {
359-
self.title = format!(
360-
r#"<text id="1">{}</text>"#,
361-
&quick_xml::escape::escape(content)
362-
);
362+
self.title = format!(r#"<text id="1">{}</text>"#, xml_escape::escape(content));
363363
self
364364
}
365365

@@ -368,10 +368,7 @@ impl Toast {
368368
/// Will be grey.
369369
/// Supports Unicode ✓
370370
pub fn text1(mut self, content: &str) -> Toast {
371-
self.line1 = format!(
372-
r#"<text id="2">{}</text>"#,
373-
&quick_xml::escape::escape(content)
374-
);
371+
self.line1 = format!(r#"<text id="2">{}</text>"#, xml_escape::escape(content));
375372
self
376373
}
377374

@@ -380,10 +377,7 @@ impl Toast {
380377
/// Will be grey.
381378
/// Supports Unicode ✓
382379
pub fn text2(mut self, content: &str) -> Toast {
383-
self.line2 = format!(
384-
r#"<text id="3">{}</text>"#,
385-
&quick_xml::escape::escape(content)
386-
);
380+
self.line2 = format!(r#"<text id="3">{}</text>"#, xml_escape::escape(content));
387381
self
388382
}
389383

@@ -427,8 +421,8 @@ impl Toast {
427421
r#"{}<image placement="appLogoOverride" {} src="file:///{}" alt="{}" />"#,
428422
self.images,
429423
crop_type_attr,
430-
quick_xml::escape::escape(source.display().to_string()),
431-
quick_xml::escape::escape(alt_text)
424+
xml_escape::escape(source.display().to_string()),
425+
xml_escape::escape(alt_text)
432426
);
433427
self
434428
} else {
@@ -445,8 +439,8 @@ impl Toast {
445439
self.images = format!(
446440
r#"{}<image placement="Hero" src="file:///{}" alt="{}" />"#,
447441
self.images,
448-
quick_xml::escape::escape(source.display().to_string()),
449-
quick_xml::escape::escape(alt_text)
442+
xml_escape::escape(source.display().to_string()),
443+
xml_escape::escape(alt_text)
450444
);
451445
self
452446
} else {
@@ -467,8 +461,8 @@ impl Toast {
467461
self.images = format!(
468462
r#"{}<image id="1" src="file:///{}" alt="{}" />"#,
469463
self.images,
470-
quick_xml::escape::escape(source.display().to_string()),
471-
quick_xml::escape::escape(alt_text)
464+
xml_escape::escape(source.display().to_string()),
465+
xml_escape::escape(alt_text)
472466
);
473467
self
474468
}

src/xml_escape.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2022-2022 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
// Copied from https://github.com/tafia/quick-xml/blob/master/src/escape.rs
6+
7+
use std::{borrow::Cow, fmt::Write};
8+
9+
pub fn escape<'a>(raw: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
10+
let escape_chars = |ch| matches!(ch, b'<' | b'>' | b'&' | b'\'' | b'\"');
11+
let raw = raw.into();
12+
let bytes = raw.as_bytes();
13+
let mut escaped = None;
14+
let mut iter = bytes.iter();
15+
let mut pos = 0;
16+
while let Some(i) = iter.position(|&b| escape_chars(b)) {
17+
if escaped.is_none() {
18+
escaped = Some(String::with_capacity(raw.len()));
19+
}
20+
let escaped = escaped.as_mut().expect("initialized");
21+
let new_pos = pos + i;
22+
// SAFETY: It should fail only on OOM
23+
escape_char(escaped, &raw, pos, new_pos).unwrap();
24+
pos = new_pos + 1;
25+
}
26+
27+
if let Some(mut escaped) = escaped {
28+
if let Some(raw) = raw.get(pos..) {
29+
// SAFETY: It should fail only on OOM
30+
escaped.write_str(raw).unwrap();
31+
}
32+
Cow::Owned(escaped)
33+
} else {
34+
raw
35+
}
36+
}
37+
38+
fn escape_char<W>(writer: &mut W, value: &str, from: usize, to: usize) -> std::fmt::Result
39+
where
40+
W: Write,
41+
{
42+
writer.write_str(&value[from..to])?;
43+
match value.as_bytes()[to] {
44+
b'<' => writer.write_str("&lt;")?,
45+
b'>' => writer.write_str("&gt;")?,
46+
b'\'' => writer.write_str("&apos;")?,
47+
b'&' => writer.write_str("&amp;")?,
48+
b'"' => writer.write_str("&quot;")?,
49+
50+
// This set of escapes handles characters that should be escaped
51+
// in elements of xs:lists, because those characters works as
52+
// delimiters of list elements
53+
b'\t' => writer.write_str("&#9;")?,
54+
b'\n' => writer.write_str("&#10;")?,
55+
b'\r' => writer.write_str("&#13;")?,
56+
b' ' => writer.write_str("&#32;")?,
57+
_ => unreachable!("Only '<', '>','\', '&', '\"', '\\t', '\\r', '\\n', and ' ' are escaped"),
58+
}
59+
Ok(())
60+
}

0 commit comments

Comments
 (0)