escape.rs 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. use std::fmt::{self, Write};
  2. /// Escape a string to pass it into JavaScript.
  3. ///
  4. /// # Example
  5. ///
  6. /// ```rust,no_run
  7. /// # use web_view::WebView;
  8. /// # use std::mem;
  9. /// #
  10. /// # let mut view: WebView<()> = unsafe { mem::uninitialized() };
  11. /// #
  12. /// let string = "Hello, world!";
  13. ///
  14. /// // Calls the function callback with "Hello, world!" as its parameter.
  15. ///
  16. /// view.eval(&format!("callback({});", web_view::escape(string)));
  17. /// ```
  18. pub fn escape(string: &str) -> Escaper {
  19. Escaper(string)
  20. }
  21. // "All code points may appear literally in a string literal except for the
  22. // closing quote code points, U+005C (REVERSE SOLIDUS), U+000D (CARRIAGE
  23. // RETURN), U+2028 (LINE SEPARATOR), U+2029 (PARAGRAPH SEPARATOR), and U+000A
  24. // (LINE FEED)." - ES6 Specification
  25. pub struct Escaper<'a>(&'a str);
  26. const SPECIAL: &[char] = &[
  27. '\n', // U+000A (LINE FEED)
  28. '\r', // U+000D (CARRIAGE RETURN)
  29. '\'', // U+0027 (APOSTROPHE)
  30. '\\', // U+005C (REVERSE SOLIDUS)
  31. '\u{2028}', // U+2028 (LINE SEPARATOR)
  32. '\u{2029}', // U+2029 (PARAGRAPH SEPARATOR)
  33. ];
  34. impl<'a> fmt::Display for Escaper<'a> {
  35. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  36. let &Escaper(mut string) = self;
  37. f.write_char('\'')?;
  38. while !string.is_empty() {
  39. if let Some(i) = string.find(SPECIAL) {
  40. if i > 0 {
  41. f.write_str(&string[..i])?;
  42. }
  43. let mut chars = string[i..].chars();
  44. f.write_str(match chars.next().unwrap() {
  45. '\n' => "\\n",
  46. '\r' => "\\r",
  47. '\'' => "\\'",
  48. '\\' => "\\\\",
  49. '\u{2028}' => "\\u2028",
  50. '\u{2029}' => "\\u2029",
  51. _ => unreachable!(),
  52. })?;
  53. string = chars.as_str();
  54. } else {
  55. f.write_str(string)?;
  56. break;
  57. }
  58. }
  59. f.write_char('\'')?;
  60. Ok(())
  61. }
  62. }
  63. #[test]
  64. fn test() {
  65. let plain = "ABC \n\r' abc \\ \u{2028} \u{2029}123";
  66. let escaped = escape(plain).to_string();
  67. assert!(escaped == "'ABC \\n\\r\\' abc \\\\ \\u2028 \\u2029123'");
  68. }