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

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