Make \v and \x switchable

Previously, serde_jsonrc always accepted non-standard \v and \x
JSON escapes. With this change, this is now switchable.

Bug: 1069271
Change-Id: Id0c9379115a865c96fa36f2a6bdf65c17a464959
diff --git a/src/de.rs b/src/de.rs
index c892017..45ada2e 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -82,13 +82,13 @@
 impl<'a> Deserializer<read::SliceRead<'a>> {
     /// Creates a JSON deserializer from a `&[u8]`.
     pub fn from_slice(bytes: &'a [u8]) -> Self {
-        Deserializer::new(read::SliceRead::new(bytes, false, false))
+        Deserializer::new(read::SliceRead::new(bytes, false, false, false, false))
     }
 
     /// Creates a JSON deserializer from a `&[u8]`,
     /// providing some flexibility for some non-standard JSON options.
-    pub fn from_slice_with_options(bytes: &'a [u8], replace_invalid_characters: bool, allow_control_characters_in_string: bool) -> Self {
-        Deserializer::new(read::SliceRead::new(bytes, replace_invalid_characters, allow_control_characters_in_string))
+    pub fn from_slice_with_options(bytes: &'a [u8], replace_invalid_characters: bool, allow_control_characters_in_string: bool, allow_v_escapes: bool, allow_x_escapes: bool) -> Self {
+        Deserializer::new(read::SliceRead::new(bytes, replace_invalid_characters, allow_control_characters_in_string, allow_v_escapes, allow_x_escapes))
     }
 }
 
@@ -2475,7 +2475,7 @@
 where
     T: de::Deserialize<'a>,
 {
-    from_trait(read::SliceRead::new(v, false, false))
+    from_trait(read::SliceRead::new(v, false, false, false, false))
 }
 
 /// Deserialize an instance of type `T` from a string of JSON text.
diff --git a/src/read.rs b/src/read.rs
index 1900c6e..a877fcc 100644
--- a/src/read.rs
+++ b/src/read.rs
@@ -100,6 +100,12 @@
 
     /// Whether we should replace invalid unicode characters with \u{fffd}.
     fn replace_invalid_unicode(&self) -> bool;
+
+    /// Allow \v escapes
+    fn allow_v_escapes(&self) -> bool;
+
+    /// Allow \x escapes
+    fn allow_x_escapes(&self) -> bool;
 }
 
 pub struct Position {
@@ -297,6 +303,8 @@
     index: usize,
     replace_invalid_characters: bool,
     allow_control_characters_in_string: bool,
+    allow_x_escapes: bool,
+    allow_v_escapes: bool,
     #[cfg(feature = "raw_value")]
     raw_buffering_start_index: usize,
 }
@@ -393,6 +401,14 @@
         false
     }
 
+    fn allow_x_escapes(&self) -> bool {
+        false
+    }
+
+    fn allow_v_escapes(&self) -> bool {
+        false
+    }
+
     #[inline]
     fn next(&mut self) -> Result<Option<u8>> {
         match self.ch.take() {
@@ -539,7 +555,7 @@
 
 impl<'a> SliceRead<'a> {
     /// Create a JSON input source to read from a slice of bytes.
-    pub fn new(slice: &'a [u8], replace_invalid_characters: bool, allow_control_characters_in_string: bool) -> Self {
+    pub fn new(slice: &'a [u8], replace_invalid_characters: bool, allow_control_characters_in_string: bool, allow_v_escapes: bool, allow_x_escapes: bool) -> Self {
         #[cfg(not(feature = "raw_value"))]
         {
             SliceRead {
@@ -547,6 +563,8 @@
                 index: 0,
                 replace_invalid_characters,
                 allow_control_characters_in_string,
+                allow_v_escapes,
+                allow_x_escapes,
             }
         }
         #[cfg(feature = "raw_value")]
@@ -556,6 +574,8 @@
                 index: 0,
                 replace_invalid_characters,
                 allow_control_characters_in_string,
+                allow_v_escapes,
+                allow_x_escapes,
                 raw_buffering_start_index: 0,
             }
         }
@@ -644,6 +664,14 @@
         self.replace_invalid_characters
     }
 
+    fn allow_x_escapes(&self) -> bool {
+        self.allow_x_escapes
+    }
+
+    fn allow_v_escapes(&self) -> bool {
+        self.allow_v_escapes
+    }
+
     #[inline]
     fn next(&mut self) -> Result<Option<u8>> {
         // `Ok(self.slice.get(self.index).map(|ch| { self.index += 1; *ch }))`
@@ -772,7 +800,7 @@
         #[cfg(not(feature = "raw_value"))]
         {
             StrRead {
-                delegate: SliceRead::new(s.as_bytes(), false, false),
+                delegate: SliceRead::new(s.as_bytes(), false, false, false, false),
             }
         }
         #[cfg(feature = "raw_value")]
@@ -792,6 +820,14 @@
         false
     }
 
+    fn allow_x_escapes(&self) -> bool {
+        false
+    }
+
+    fn allow_v_escapes(&self) -> bool {
+        false
+    }
+
     #[inline]
     fn next(&mut self) -> Result<Option<u8>> {
         self.delegate.next()
@@ -945,8 +981,8 @@
         b'n' => scratch.push(b'\n'),
         b'r' => scratch.push(b'\r'),
         b't' => scratch.push(b'\t'),
-        b'v' => scratch.push(b'\x0b'),
-        b'x' => {
+        b'v' if read.allow_v_escapes() => scratch.push(b'\x0b'),
+        b'x' if read.allow_x_escapes() => {
             let c: u32 = tri!(read.decode_hex_escape(2)).into();
             let c = match char::from_u32(c) {
                 Some(c) => c,
diff --git a/tests/invalid_characters.rs b/tests/invalid_characters.rs
index ffd5936..3d4ecab 100644
--- a/tests/invalid_characters.rs
+++ b/tests/invalid_characters.rs
@@ -8,7 +8,7 @@
 use serde::de::Deserialize;
 
 fn from_slice_with_unicode_substitution(s: &[u8]) -> Result<Value, Error> {
-    let mut de = Deserializer::new(SliceRead::new(s, true, false));
+    let mut de = Deserializer::new(SliceRead::new(s, true, false, false, false));
     Deserialize::deserialize(&mut de)
 }