)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
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: