1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
use crate::ENCODED_LENGTH_OVERFLOWS; /// Checks if the char needs to be encoded. Alpha-numeric chars and chars in non-specials do not /// need to be encoded. All other chars need to be encoded. /// /// ``` /// use enc::percent::needs_encoding; /// /// let ns: &[u8] = &[b'_']; /// /// // Encoding Not Needed /// assert!(!needs_encoding(b'A', ns)); /// assert!(!needs_encoding(b'Z', ns)); /// assert!(!needs_encoding(b'a', ns)); /// assert!(!needs_encoding(b'z', ns)); /// assert!(!needs_encoding(b'0', ns)); /// assert!(!needs_encoding(b'9', ns)); /// assert!(!needs_encoding(b'_', ns)); /// /// // Encoding Needed /// assert!(needs_encoding(b'A' - 1, ns)); /// assert!(needs_encoding(b'Z' + 1, ns)); /// assert!(needs_encoding(b'a' - 1, ns)); /// assert!(needs_encoding(b'z' + 1, ns)); /// assert!(needs_encoding(b'0' - 1, ns)); /// assert!(needs_encoding(b'9' + 1, ns)); /// assert!(needs_encoding(b'_' - 1, ns)); /// assert!(needs_encoding(b'_' + 1, ns)); /// ``` pub fn needs_encoding(c: u8, non_specials: &[u8]) -> bool { !c.is_ascii_alphanumeric() && !non_specials.contains(&c) } /// Gets the length of the encoded data given the length of the data and the number of chars that /// need to be percent encoded. /// /// # Panics /// This function will panic if the length of the encoded data overflows usize. fn encoded_length_usize(len: usize, count: usize) -> usize { let extra: usize = count.checked_mul(2).expect(ENCODED_LENGTH_OVERFLOWS); len.checked_add(extra).expect(ENCODED_LENGTH_OVERFLOWS) } #[cfg(test)] mod encoded_length_usize_tests { #[test] fn test_encoded_length_usize() { assert_eq!(super::encoded_length_usize(0, 0), 0); assert_eq!(super::encoded_length_usize(1, 1), 3); assert_eq!(super::encoded_length_usize(3, 2), 7); } #[test] #[should_panic] fn test_encoded_length_usize_panics1() { super::encoded_length_usize(0, (std::usize::MAX / 2) + 1); } #[test] #[should_panic] fn test_encoded_length_usize_panics2() { super::encoded_length_usize(std::usize::MAX - 1, 1); } } /// Gets the length of the encoded data. This function is consistent with the encode function. /// /// # Panics /// This function will panic if the length of the encoded data overflows usize. /// /// ``` /// use enc::percent::encoded_length; /// /// let ns: &[u8] = &[b'_']; /// /// assert_eq!(encoded_length(&[b'a'], ns), 1); /// assert_eq!(encoded_length(&[b'a', b'_'], ns), 2); /// assert_eq!(encoded_length(&[b'a', b'_', b'_' + 1], ns), 5); /// assert_eq!(encoded_length(&[b'a', b'_', b'_' + 1, b'_' - 1], ns), 8); /// ``` pub fn encoded_length(data: &[u8], non_specials: &[u8]) -> usize { let count: usize = data.iter() .filter(|r| needs_encoding(**r, non_specials)) .count(); encoded_length_usize(data.len(), count) } /// Encodes the data into the target. Returns the length of the encoded data. This function is /// consistent with the encoded_length function. /// /// # Panics /// This function will panic if the target has insufficient space for the encoded data. /// /// ``` /// use enc::percent::encode; /// /// let target: &mut [u8] = &mut [0u8; 6]; /// let ns: &[u8] = &[b'_']; /// /// assert_eq!(encode(&[0u8; 0], ns, target), 0); /// /// assert_eq!(encode(&[b'a'], ns, target), 1); /// assert_eq!(target[..1], [b'a']); /// /// assert_eq!(encode(&[b'a', b'_', 0u8], ns, target), 5); /// assert_eq!(target[..5], [b'a', b'_', b'%', b'0', b'0']); /// /// ``` pub fn encode(data: &[u8], non_specials: &[u8], target: &mut [u8]) -> usize { let mut t: usize = 0; for r in data.iter() { let c: u8 = *r; if needs_encoding(c, non_specials) { target[t] = b'%'; t += 1; let e: [u8; 2] = crate::hex::encode_byte_upper(c); target[t] = e[0]; t += 1; target[t] = e[1]; t += 1; } else { target[t] = c; t += 1; } } t } #[cfg(test)] mod tests { #[test] #[should_panic] fn test_encode_lower_panics() { super::encode(&[b'a', b'a' - 1], &[b'_'], &mut [0u8; 3]); } }