punycode.rs 9.7 KB

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