punycode.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright 2013 Simon Sapin.
  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. use std::u32;
  9. use std::char;
  10. use std::ascii::Ascii;
  11. use std::ascii::AsciiStr;
  12. static BASE: u32 = 36;
  13. static T_MIN: u32 = 1;
  14. static T_MAX: u32 = 26;
  15. static SKEW: u32 = 38;
  16. static DAMP: u32 = 700;
  17. static INITIAL_BIAS: u32 = 72;
  18. static INITIAL_N: u32 = 0x80;
  19. static DELIMITER: char = '-';
  20. #[inline]
  21. fn adapt(mut delta: u32, num_points: u32, first_time: bool) -> u32 {
  22. delta /= if first_time { DAMP } else { 2 };
  23. delta += delta / num_points;
  24. let mut k = 0;
  25. while delta > ((BASE - T_MIN) * T_MAX) / 2 {
  26. delta /= BASE - T_MIN;
  27. k += BASE;
  28. }
  29. k + (((BASE - T_MIN + 1) * delta) / (delta + SKEW))
  30. }
  31. pub fn decode(input: &[Ascii]) -> Option<~str> {
  32. // XXX when upgrading to rust with as_str_ascii(),
  33. // just replace the first to_str_ascii() (do not copy)
  34. // and add .to_owned() after the second (do copy.)
  35. let (mut output, input) = match input.to_str_ascii().rfind(DELIMITER) {
  36. None => (~"", input),
  37. Some(position) => (
  38. input.slice_to(position).to_str_ascii(),
  39. if position > 0 { input.slice_from(position + 1) } else { input }
  40. )
  41. };
  42. let mut n = INITIAL_N;
  43. let mut bias = INITIAL_BIAS;
  44. let mut i = 0;
  45. let mut iter = input.iter();
  46. loop {
  47. let previous_i = i;
  48. let mut weight = 1;
  49. let mut k = BASE;
  50. let mut ascii = match iter.next() {
  51. None => break,
  52. Some(ascii) => ascii,
  53. };
  54. loop {
  55. let digit = match ascii.to_byte() {
  56. byte @ 0x30 .. 0x39 => byte - 0x30 + 26, // 0..9
  57. byte @ 0x41 .. 0x5A => byte - 0x41, // A..Z
  58. byte @ 0x61 .. 0x7A => byte - 0x61, // a..z
  59. _ => return None
  60. } as u32;
  61. if digit > (u32::max_value - i) / weight {
  62. return None // Malformed input would cause integer overflow
  63. }
  64. i += digit * weight;
  65. let t = if k <= bias { T_MIN }
  66. else if k >= bias + T_MAX { T_MAX }
  67. else { k - bias };
  68. if digit < t {
  69. break
  70. }
  71. if weight > u32::max_value / (BASE - t) {
  72. return None // Malformed input would cause integer overflow
  73. }
  74. weight *= BASE - t;
  75. k += BASE;
  76. ascii = match iter.next() {
  77. None => return None, // End of input before the end of this delta
  78. Some(ascii) => ascii,
  79. };
  80. }
  81. let length = output.len() as u32;
  82. bias = adapt(i - previous_i, length + 1, previous_i == 0);
  83. if i / (length + 1) > u32::max_value - n {
  84. return None // Malformed input would cause integer overflow
  85. }
  86. n += i / (length + 1);
  87. i %= length + 1;
  88. let c = match char::from_u32(n) {
  89. Some(c) => c,
  90. None => return None
  91. };
  92. insert(&mut output, c, i as uint);
  93. }
  94. Some(output)
  95. }
  96. #[inline]
  97. fn insert(string: &mut ~str, to_insert: char, position: uint) {
  98. let mut new_string = string.slice_to(position).to_owned();
  99. new_string.push_char(to_insert);
  100. new_string.push_str(string.slice_from(position));
  101. *string = new_string;
  102. }