شركة التطبيقات المتكاملة لتصميم النظم البرمجية الخاصة

Integrated Applications Programming Company

Skip Navigation LinksHome » Code Library » Punycode

Public general use code classes and xml files that we've compiled and used over the years:

Punycode support class.

   1:  using System;
   2:  using System.Text;
   3:   
   4:  namespace Ia.Cl.Model
   5:  {
   6:      ////////////////////////////////////////////////////////////////////////////
   7:   
   8:      /// <summary publish="true">
   9:      /// Punycode support class.
  10:      /// </summary>
  11:      /// <remarks> 
  12:      /// Copyright © 2001-2015 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
  13:      ///
  14:      /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
  15:      /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  16:      ///
  17:      /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  18:      /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  19:      /// 
  20:      /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
  21:      /// 
  22:      /// Copyright notice: This notice may not be removed or altered from any source distribution.
  23:      /// </remarks> 
  24:      public class Punycode
  25:      {
  26:          ////////////////////////////////////////////////////////////////////////////
  27:   
  28:          /*
  29:           * $Id: punycode.cs,v 1.3 2003/03/30 23:28:41 Mayuki Sawatari Exp $
  30:           *
  31:           * Punycode (RFC 3492) encoder/decoder implementation in C# with .NET Framework
  32:           *
  33:           * RFC 3492: IDNA Punycode
  34:           * http://www.ietf.org/rfc/rfc3492.txt
  35:           *
  36:           * Copyright (C) 2003 Mayuki Sawatari <mayuki@misuzilla.org>, All rights reserved.
  37:           *
  38:           * Redistribution and use in source and binary forms, with or without
  39:           * modification, are permitted provided that the following conditions
  40:           * are met:
  41:           * 1. Redistributions of source code must retain the above copyright
  42:           *    notice, this list of conditions and the following disclaimer.
  43:           * 2. Redistributions in binary form must reproduce the above copyright
  44:           *    notice, this list of conditions and the following disclaimer in the
  45:           *    documentation and/or other materials provided with the distribution.
  46:           *
  47:           * THIS LIBRARY IS PROVIDED BY THE MISUZILLA.ORG ``AS IS'' AND
  48:           * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49:           * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50:           * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  51:           * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  52:           * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  53:           * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  54:           * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  55:           * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  56:           * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  57:           * SUCH DAMAGE.
  58:           */
  59:   
  60:          /// <summary/>
  61:          public const string Prefix = "xn--";
  62:   
  63:          /// <summary/>
  64:          public static string Decode(string s)
  65:          {
  66:              if (s.StartsWith(Punycode.Prefix))
  67:                  return DecodeString(s.Substring(Punycode.Prefix.Length));
  68:              else
  69:                  return DecodeString(s);
  70:          }
  71:   
  72:          /// <summary/>
  73:          public static string Encode(string s)
  74:          {
  75:              return EncodeString(s).Insert(0, Punycode.Prefix).ToString();
  76:          }
  77:   
  78:          /// <summary/>
  79:          public static string EncodeWithoutPrefix(string s)
  80:          {
  81:              return EncodeString(s).ToString();
  82:          }
  83:   
  84:          /// <summary/>
  85:          private sealed class PunyParams
  86:          {
  87:              public const Int32 Base = 36;
  88:              public const Int32 Tmin = 1;
  89:              public const Int32 Tmax = 26;
  90:              public const Int32 Skew = 38;
  91:              public const Int32 Damp = 700;
  92:              public const Int32 InitialBias = 72;
  93:              public const Int32 InitialN = 0x80;
  94:              public const Int32 Delimiter = 0x2d;
  95:          }
  96:   
  97:          /// <summary/>
  98:          private static char DecodeDigit(Int32 cp)
  99:          {
 100:              return (char)(cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 :
 101:                  cp - 97 < 26 ? cp - 97 : PunyParams.Base);
 102:          }
 103:   
 104:          /// <summary/>
 105:          private static char EncodeDigit(Int32 d, Int32 flag)
 106:          {
 107:              return (char)(d + 22 + 75 * (d < 26 ? 1 : 0) - (flag << 5));
 108:          }
 109:   
 110:          /// <summary/>
 111:          private static StringBuilder EncodeString(string input)
 112:          {
 113:              StringBuilder output = new StringBuilder();
 114:              Int32 delta, bias, maxOut;
 115:              Int32 m, k, t, b, n, h, q, i;
 116:   
 117:   
 118:              maxOut = Int32.MaxValue;
 119:              n = PunyParams.InitialN;
 120:              bias = PunyParams.InitialBias;
 121:              delta = 0;
 122:   
 123:              for (i = 0; i < input.Length; i++)
 124:              {
 125:                  if (input[i] < 0x80)
 126:                  {
 127:                      if (maxOut - input.Length < 2) throw new PunycodeBigOutputException("punycode_big_output");
 128:                      output.Append(input[i]);
 129:                  }
 130:              }
 131:   
 132:              h = b = (Int32)output.Length;
 133:   
 134:              if (output.Length > 0)
 135:                  output.Append((char)PunyParams.Delimiter);
 136:   
 137:              /* Main encoding loop: */
 138:              while (h < input.Length)
 139:              {
 140:                  m = Int32.MaxValue;
 141:                  for (i = 0; i < input.Length; i++)
 142:                  {
 143:                      if (input[i] >= n && input[i] < m)
 144:                          m = input[i];
 145:                  }
 146:   
 147:                  if (m - n > (Int32.MaxValue - delta) / (h + 1))
 148:                      throw new PunycodeOverflowException("punycode_overflow");
 149:   
 150:                  delta += (char)(m - n) * (h + 1);
 151:                  n = m;
 152:   
 153:                  for (i = 0; i < input.Length; i++)
 154:                  {
 155:                      /* Punycode does not need to check whether input[j] is basic: */
 156:                      if (input[i] < n)
 157:                      {
 158:                          if (++delta == 0)
 159:                              throw new PunycodeOverflowException("punycode_overflow");
 160:                      }
 161:   
 162:                      if (input[i] == n)
 163:                      {
 164:                          /* Represent delta as a generalized variable-length integer: */
 165:                          for (q = delta, k = PunyParams.Base; ; k += PunyParams.Base)
 166:                          {
 167:                              t = (k <= bias) ?
 168:                                  PunyParams.Tmin :
 169:                                  (k >= bias + PunyParams.Tmax) ?
 170:                                      PunyParams.Tmax : k - bias;
 171:   
 172:                              if (q < t)
 173:                                  break;
 174:   
 175:                              output.Append(EncodeDigit(t + (q - t) % (PunyParams.Base - t), 0));
 176:                              q = (q - t) / (PunyParams.Base - t);
 177:                          }
 178:                          //output[outlen++] = EncodeDigit(q, case_flags && case_flags[j]);
 179:                          output.Append(EncodeDigit(q, 0)); // ignore case
 180:                          bias = (char)Adapt(delta, h + 1, h == b);
 181:                          delta = 0;
 182:                          ++h;
 183:                      }
 184:                  }
 185:                  ++delta; ++n;
 186:              }
 187:   
 188:              return output;
 189:          }
 190:   
 191:          private static Int32 Adapt(Int32 delta, Int32 numpoints, Boolean firsttime)
 192:          {
 193:              Int32 k;
 194:              delta = firsttime ? delta / PunyParams.Damp : delta >> 1; /* delta >> 1 --> delta / 2 */
 195:              delta += delta / numpoints;
 196:   
 197:              for (k = 0; delta > ((PunyParams.Base - PunyParams.Tmin) * PunyParams.Tmax) / 2; k += PunyParams.Base)
 198:              {
 199:                  delta /= (PunyParams.Base - PunyParams.Tmin);
 200:              }
 201:   
 202:              return k + ((PunyParams.Base - PunyParams.Tmin) + 1) * delta / (delta + PunyParams.Skew);
 203:          }
 204:   
 205:          private static string DecodeString(string input)
 206:          {
 207:              StringBuilder output = new StringBuilder();
 208:              Int32 n, outlen, i, bias, b, j, inl, oldi, w, k, digit, t;
 209:   
 210:              /* Initialize the state: */
 211:   
 212:              n = PunyParams.InitialN;
 213:              outlen = i = 0;
 214:              bias = PunyParams.InitialBias;
 215:   
 216:              /* Handle the basic code points:  Let b be the number of input code */
 217:              /* points before the last delimiter, or 0 if there is none, then    */
 218:              /* copy the first b code points to the output.                      */
 219:   
 220:              for (b = j = 0; j < input.Length; ++j)
 221:                  if (input[j] == PunyParams.Delimiter)
 222:                      b = j;
 223:   
 224:              if (b > Int32.MaxValue)
 225:                  throw new PunycodeBigOutputException("punycode_big_output");
 226:   
 227:              for (j = 0; j < b; ++j)
 228:              {
 229:                  //if (case_flags)
 230:                  //    case_flags[outlen] = flagged(input[j]);
 231:                  if (!(input[j] < 0x80))
 232:                      throw new PunycodeBadInputException("punycode_bad_input");
 233:                  outlen++;
 234:                  output.Append(input[j]);
 235:              }
 236:   
 237:              /* Main decoding loop:  Start just after the last delimiter if any  */
 238:              /* basic code points were copied; start at the beginning otherwise. */
 239:              for (inl = b > 0 ? b + 1 : 0; inl < input.Length; ++outlen)
 240:              {
 241:   
 242:                  for (oldi = i, w = 1, k = PunyParams.Base; ; k += PunyParams.Base)
 243:                  {
 244:                      if (inl >= input.Length)
 245:                          throw new PunycodeBadInputException(string.Format("{0} >= {1}", inl, input.Length));
 246:   
 247:                      digit = DecodeDigit(input[inl++]);
 248:   
 249:                      if (digit >= PunyParams.Base)
 250:                          throw new PunycodeBadInputException(string.Format("{0} >= {1}", digit, PunyParams.Base));
 251:                      if (digit > (Int32.MaxValue - i) / w)
 252:                          throw new PunycodeOverflowException(string.Format("{0} > ({1} - {2}) / {3}", digit, Int32.MaxValue, i, w));
 253:   
 254:                      i += digit * w;
 255:                      t = (k <= bias ? PunyParams.Tmin : (k >= bias + PunyParams.Tmax ? PunyParams.Tmax : k - bias));
 256:                      if (digit < t) break;
 257:   
 258:                      if (w > Int32.MaxValue / (PunyParams.Base - t))
 259:                          throw new PunycodeOverflowException("punycode_overflow");
 260:   
 261:                      w *= (PunyParams.Base - t);
 262:                  }
 263:   
 264:                  bias = Adapt(i - oldi, outlen + 1, oldi == 0);
 265:   
 266:                  /* i was supposed to wrap around from out+1 to 0,   */
 267:                  /* incrementing n each time, so we'll fix that now: */
 268:   
 269:                  if (i / (outlen + 1) > Int32.MaxValue - n)
 270:                      throw new PunycodeOverflowException("punycode_overflow");
 271:   
 272:                  n += i / (outlen + 1);
 273:                  i %= (outlen + 1);
 274:   
 275:                  /* Insert n at position i of the output: */
 276:                  if (outlen >= Int32.MaxValue)
 277:                      throw new PunycodeBigOutputException("punycode_big_output");
 278:                  //if (case_flags) {
 279:                  //memmove(case_flags + i + 1, case_flags + i, out - i);
 280:   
 281:                  /* Case of last character determines uppercase flag: */
 282:                  //case_flags[i] = flagged(input[inl - 1]);
 283:                  //}
 284:                  output.Insert(i, (char)n);
 285:                  i++;
 286:              }
 287:              return output.ToString();
 288:          }
 289:      }
 290:   
 291:      /// <summary/>
 292:      public class PunycodeBigOutputException : ApplicationException
 293:      {
 294:          /// <summary/>
 295:          public PunycodeBigOutputException(string s) : base(s) { }
 296:      }
 297:   
 298:      /// <summary/>
 299:      public class PunycodeBadInputException : ApplicationException
 300:      {
 301:          /// <summary/>
 302:          public PunycodeBadInputException(string s) : base(s) { }
 303:      }
 304:   
 305:      /// <summary/>
 306:      public class PunycodeOverflowException : ApplicationException
 307:      {
 308:          /// <summary/>
 309:          public PunycodeOverflowException(string s) : base(s) { }
 310:      }
 311:   
 312:      ////////////////////////////////////////////////////////////////////////////
 313:      ////////////////////////////////////////////////////////////////////////////
 314:  }
 315: