punycode.rs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // Copyright 2013 The rust-url developers.
  2. //
  3. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  4. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  5. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  6. // option. This file may not be copied, modified, or distributed
  7. // except according to those terms.
  8. //! Punycode ([RFC 3492](http://tools.ietf.org/html/rfc3492)) implementation.
  9. //!
  10. //! Since Punycode fundamentally works on unicode code points,
  11. //! `encode` and `decode` take and return slices and vectors of `char`.
  12. //! `encode_str` and `decode_to_string` provide convenience wrappers
  13. //! that convert from and to Rust’s UTF-8 based `str` and `String` types.
  14. use alloc::{string::String, vec::Vec};
  15. use core::char;
  16. use core::u32;
  17. // Bootstring parameters for Punycode
  18. static BASE: u32 = 36;
  19. static T_MIN: u32 = 1;
  20. static T_MAX: u32 = 26;
  21. static SKEW: u32 = 38;
  22. static DAMP: u32 = 700;
  23. static INITIAL_BIAS: u32 = 72;
  24. static INITIAL_N: u32 = 0x80;
  25. static DELIMITER: char = '-';
  26. #[inline]
  27. fn adapt(mut delta: u32, num_points: u32, first_time: bool) -> u32 {
  28. delta /= if first_time { DAMP } else { 2 };
  29. delta += delta / num_points;
  30. let mut k = 0;
  31. while delta > ((BASE - T_MIN) * T_MAX) / 2 {
  32. delta /= BASE - T_MIN;
  33. k += BASE;
  34. }
  35. k + (((BASE - T_MIN + 1) * delta) / (delta + SKEW))
  36. }
  37. /// Convert Punycode to an Unicode `String`.
  38. ///
  39. /// This is a convenience wrapper around `decode`.
  40. #[inline]
  41. pub fn decode_to_string(input: &str) -> Option<String> {
  42. decode(input).map(|chars| chars.into_iter().collect())
  43. }
  44. /// Convert Punycode to Unicode.
  45. ///
  46. /// Return None on malformed input or overflow.
  47. /// Overflow can only happen on inputs that take more than
  48. /// 63 encoded bytes, the DNS limit on domain name labels.
  49. pub fn decode(input: &str) -> Option<Vec<char>> {
  50. Some(Decoder::default().decode(input).ok()?.collect())
  51. }
  52. #[derive(Default)]
  53. pub(crate) struct Decoder {
  54. insertions: Vec<(usize, char)>,
  55. }
  56. impl Decoder {
  57. /// Split the input iterator and return a Vec with insertions of encoded characters
  58. pub(crate) fn decode<'a>(&'a mut self, input: &'a str) -> Result<Decode<'a>, ()> {
  59. self.insertions.clear();
  60. // Handle "basic" (ASCII) code points.
  61. // They are encoded as-is before the last delimiter, if any.
  62. let (base, input) = match input.rfind(DELIMITER) {
  63. None => ("", input),
  64. Some(position) => (
  65. &input[..position],
  66. if position > 0 {
  67. &input[position + 1..]
  68. } else {
  69. input
  70. },
  71. ),
  72. };
  73. if !base.is_ascii() {
  74. return Err(());
  75. }
  76. let base_len = base.len();
  77. let mut length = base_len as u32;
  78. let mut code_point = INITIAL_N;
  79. let mut bias = INITIAL_BIAS;
  80. let mut i = 0;
  81. let mut iter = input.bytes();
  82. loop {
  83. let previous_i = i;
  84. let mut weight = 1;
  85. let mut k = BASE;
  86. let mut byte = match iter.next() {
  87. None => break,
  88. Some(byte) => byte,
  89. };
  90. // Decode a generalized variable-length integer into delta,
  91. // which gets added to i.
  92. loop {
  93. let digit = match byte {
  94. byte @ b'0'..=b'9' => byte - b'0' + 26,
  95. byte @ b'A'..=b'Z' => byte - b'A',
  96. byte @ b'a'..=b'z' => byte - b'a',
  97. _ => return Err(()),
  98. } as u32;
  99. if digit > (u32::MAX - i) / weight {
  100. return Err(()); // Overflow
  101. }
  102. i += digit * weight;
  103. let t = if k <= bias {
  104. T_MIN
  105. } else if k >= bias + T_MAX {
  106. T_MAX
  107. } else {
  108. k - bias
  109. };
  110. if digit < t {
  111. break;
  112. }
  113. if weight > u32::MAX / (BASE - t) {
  114. return Err(()); // Overflow
  115. }
  116. weight *= BASE - t;
  117. k += BASE;
  118. byte = match iter.next() {
  119. None => return Err(()), // End of input before the end of this delta
  120. Some(byte) => byte,
  121. };
  122. }
  123. bias = adapt(i - previous_i, length + 1, previous_i == 0);
  124. if i / (length + 1) > u32::MAX - code_point {
  125. return Err(()); // Overflow
  126. }
  127. // i was supposed to wrap around from length+1 to 0,
  128. // incrementing code_point each time.
  129. code_point += i / (length + 1);
  130. i %= length + 1;
  131. let c = match char::from_u32(code_point) {
  132. Some(c) => c,
  133. None => return Err(()),
  134. };
  135. // Move earlier insertions farther out in the string
  136. for (idx, _) in &mut self.insertions {
  137. if *idx >= i as usize {
  138. *idx += 1;
  139. }
  140. }
  141. self.insertions.push((i as usize, c));
  142. length += 1;
  143. i += 1;
  144. }
  145. self.insertions.sort_by_key(|(i, _)| *i);
  146. Ok(Decode {
  147. base: base.chars(),
  148. insertions: &self.insertions,
  149. inserted: 0,
  150. position: 0,
  151. len: base_len + self.insertions.len(),
  152. })
  153. }
  154. }
  155. pub(crate) struct Decode<'a> {
  156. base: core::str::Chars<'a>,
  157. pub(crate) insertions: &'a [(usize, char)],
  158. inserted: usize,
  159. position: usize,
  160. len: usize,
  161. }
  162. impl<'a> Iterator for Decode<'a> {
  163. type Item = char;
  164. fn next(&mut self) -> Option<Self::Item> {
  165. loop {
  166. match self.insertions.get(self.inserted) {
  167. Some((pos, c)) if *pos == self.position => {
  168. self.inserted += 1;
  169. self.position += 1;
  170. return Some(*c);
  171. }
  172. _ => {}
  173. }
  174. if let Some(c) = self.base.next() {
  175. self.position += 1;
  176. return Some(c);
  177. } else if self.inserted >= self.insertions.len() {
  178. return None;
  179. }
  180. }
  181. }
  182. fn size_hint(&self) -> (usize, Option<usize>) {
  183. let len = self.len - self.position;
  184. (len, Some(len))
  185. }
  186. }
  187. impl<'a> ExactSizeIterator for Decode<'a> {
  188. fn len(&self) -> usize {
  189. self.len - self.position
  190. }
  191. }
  192. /// Convert an Unicode `str` to Punycode.
  193. ///
  194. /// This is a convenience wrapper around `encode`.
  195. #[inline]
  196. pub fn encode_str(input: &str) -> Option<String> {
  197. let mut buf = String::with_capacity(input.len());
  198. encode_into(input.chars(), &mut buf).ok().map(|()| buf)
  199. }
  200. /// Convert Unicode to Punycode.
  201. ///
  202. /// Return None on overflow, which can only happen on inputs that would take more than
  203. /// 63 encoded bytes, the DNS limit on domain name labels.
  204. pub fn encode(input: &[char]) -> Option<String> {
  205. let mut buf = String::with_capacity(input.len());
  206. encode_into(input.iter().copied(), &mut buf)
  207. .ok()
  208. .map(|()| buf)
  209. }
  210. pub(crate) fn encode_into<I>(input: I, output: &mut String) -> Result<(), ()>
  211. where
  212. I: Iterator<Item = char> + Clone,
  213. {
  214. // Handle "basic" (ASCII) code points. They are encoded as-is.
  215. let (mut input_length, mut basic_length) = (0, 0);
  216. for c in input.clone() {
  217. input_length += 1;
  218. if c.is_ascii() {
  219. output.push(c);
  220. basic_length += 1;
  221. }
  222. }
  223. if basic_length > 0 {
  224. output.push('-')
  225. }
  226. let mut code_point = INITIAL_N;
  227. let mut delta = 0;
  228. let mut bias = INITIAL_BIAS;
  229. let mut processed = basic_length;
  230. while processed < input_length {
  231. // All code points < code_point have been handled already.
  232. // Find the next larger one.
  233. let min_code_point = input
  234. .clone()
  235. .map(|c| c as u32)
  236. .filter(|&c| c >= code_point)
  237. .min()
  238. .unwrap();
  239. if min_code_point - code_point > (u32::MAX - delta) / (processed + 1) {
  240. return Err(()); // Overflow
  241. }
  242. // Increase delta to advance the decoder’s <code_point,i> state to <min_code_point,0>
  243. delta += (min_code_point - code_point) * (processed + 1);
  244. code_point = min_code_point;
  245. for c in input.clone() {
  246. let c = c as u32;
  247. if c < code_point {
  248. delta = delta.checked_add(1).ok_or(())?;
  249. }
  250. if c == code_point {
  251. // Represent delta as a generalized variable-length integer:
  252. let mut q = delta;
  253. let mut k = BASE;
  254. loop {
  255. let t = if k <= bias {
  256. T_MIN
  257. } else if k >= bias + T_MAX {
  258. T_MAX
  259. } else {
  260. k - bias
  261. };
  262. if q < t {
  263. break;
  264. }
  265. let value = t + ((q - t) % (BASE - t));
  266. output.push(value_to_digit(value));
  267. q = (q - t) / (BASE - t);
  268. k += BASE;
  269. }
  270. output.push(value_to_digit(q));
  271. bias = adapt(delta, processed + 1, processed == basic_length);
  272. delta = 0;
  273. processed += 1;
  274. }
  275. }
  276. delta += 1;
  277. code_point += 1;
  278. }
  279. Ok(())
  280. }
  281. #[inline]
  282. fn value_to_digit(value: u32) -> char {
  283. match value {
  284. 0..=25 => (value as u8 + b'a') as char, // a..z
  285. 26..=35 => (value as u8 - 26 + b'0') as char, // 0..9
  286. _ => panic!(),
  287. }
  288. }