-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* start working on livesplit logic * split export implementation * update documentation * clean up * update docs * more clean up
- Loading branch information
1 parent
6ef1fd3
commit e42b82d
Showing
27 changed files
with
577 additions
and
120 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use std::borrow::Cow; | ||
|
||
macro_rules! escape { | ||
($escaped:ident, $bytes:literal, $s:ident, $i:ident, $len:literal) => { | ||
match &mut $escaped { | ||
None => { | ||
let mut vec = Vec::with_capacity($s.len() + $len); | ||
vec.extend_from_slice(&$s.as_bytes()[0..$i]); | ||
vec.extend_from_slice($bytes); | ||
$escaped = Some(vec); | ||
} | ||
Some(vec) => vec.extend_from_slice($bytes), | ||
} | ||
}; | ||
} | ||
|
||
/// Escapes a string for XML. | ||
/// | ||
/// This function escapes the following characters: | ||
/// - `&` becomes `&` | ||
/// - `<` becomes `<` | ||
/// - `>` becomes `>` | ||
/// - `"` becomes `"` | ||
/// - `'` becomes `'` | ||
pub fn xml_escape(s: &str) -> Cow<str> { | ||
// An ASCII byte always represent a ASCII character | ||
// so it is safe to treat the input as bytes | ||
let mut escaped = None; | ||
for (i, b) in s.bytes().enumerate() { | ||
match b { | ||
b'&' => { | ||
escape!(escaped, b"&", s, i, 5); | ||
} | ||
b'<' => { | ||
escape!(escaped, b"<", s, i, 5); | ||
} | ||
b'>' => { | ||
escape!(escaped, b">", s, i, 5); | ||
} | ||
b'\'' => { | ||
escape!(escaped, b"'", s, i, 5); | ||
} | ||
b'"' => { | ||
escape!(escaped, b""", s, i, 5); | ||
} | ||
_ => { | ||
if let Some(vec) = &mut escaped { | ||
vec.push(b); | ||
} | ||
} | ||
} | ||
} | ||
match escaped { | ||
Some(vec) => Cow::Owned(String::from_utf8(vec).unwrap()), | ||
None => Cow::Borrowed(s), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
fn no_escape() { | ||
let input = "This is a test."; | ||
let expected = Cow::Borrowed(input); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
|
||
#[test] | ||
fn no_escape_unicode() { | ||
let input = "\u{0926}This is a test."; | ||
let expected = Cow::Borrowed(input); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
|
||
#[test] | ||
fn escape_amp() { | ||
let input = "\u{4f60}&\u{597d}& Chips"; | ||
let expected: Cow<str> = Cow::Owned(String::from("\u{4f60}&\u{597d}& Chips")); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
|
||
#[test] | ||
fn escape_lt_gt() { | ||
let input = "2 < 3 and 3 > 2"; | ||
let expected: Cow<str> = Cow::Owned(String::from("2 < 3 and 3 > 2")); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
|
||
#[test] | ||
fn escape_quotes() { | ||
let input = r#"She said, "Hello, world!""#; | ||
let expected: Cow<str> = Cow::Owned(String::from("She said, "Hello, world!"")); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
|
||
#[test] | ||
fn escape_apos() { | ||
let input = "It's a sunny day"; | ||
let expected: Cow<str> = Cow::Owned(String::from("It's a sunny day")); | ||
let escaped = xml_escape(input); | ||
assert_eq!(escaped, expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use std::io; | ||
use std::io::Write; | ||
|
||
use base64::Engine; | ||
use flate2::write::GzEncoder; | ||
use flate2::Compression; | ||
|
||
use crate::macros::derive_wasm; | ||
|
||
/// The data in the export | ||
#[derive(Debug, Clone)] | ||
#[derive_wasm] | ||
#[serde(tag = "type", content = "data")] | ||
pub enum ExpoBlob { | ||
/// UTF-8 text | ||
Text(String), | ||
/// Binary data encoded in base64 | ||
Base64(String), | ||
/// Binary data gzipped and encoded in base64 | ||
Base64Gzip(String), | ||
} | ||
|
||
impl ExpoBlob { | ||
/// Create a blob from UTF-8 string | ||
pub fn from_utf8(s: String) -> Self { | ||
Self::Text(s) | ||
} | ||
|
||
/// Create a blob from binary data, uncompressed | ||
/// | ||
/// Useful if the binary data is small or is already compressed | ||
pub fn from_bytes(b: &[u8]) -> Self { | ||
let encoded = base64::engine::general_purpose::STANDARD.encode(b); | ||
Self::Base64(encoded) | ||
} | ||
|
||
/// Create a blob from binary data, compressed with gzip format | ||
pub fn from_bytes_gzipped(b: Vec<u8>) -> io::Result<Self> { | ||
let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); | ||
encoder.write_all(&b)?; | ||
let bytes = encoder.finish()?; | ||
Ok(Self::from_bytes(&bytes)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.