All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.abdera.i18n.text.Punycode Maven / Gradle / Ivy

There is a newer version: 1.1.3
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  The ASF licenses this file to You
 * under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 */
package org.apache.abdera.i18n.text;

import java.io.IOException;

/**
 * Implementation of the Punycode encoding scheme used by IDNA
 */
public final class Punycode {

    static final int base = 0x24; // 36
    static final int tmin = 0x01; // 1
    static final int tmax = 0x1A; // 26
    static final int skew = 0x26; // 38
    static final int damp = 0x02BC; // 700
    static final int initial_bias = 0x48; // 72
    static final int initial_n = 0x80; // 0x80
    static final int delimiter = 0x2D; // 0x2D

    Punycode() {
    }

    private static boolean basic(int cp) {
        return cp < 0x80;
    }

    private static boolean delim(int cp) {
        return cp == delimiter;
    }

    private static boolean flagged(int bcp) {
        return (bcp - 65) < 26;
    }

    private static int decode_digit(int cp) {
        return (cp - 48 < 10) ? cp - 22 : (cp - 65 < 26) ? cp - 65 : (cp - 97 < 26) ? cp - 97 : base;
    }

    private static int t(boolean c) {
        return (c) ? 1 : 0;
    }

    private static int encode_digit(int d, boolean upper) {
        return (d + 22 + 75 * t(d < 26)) - (t(upper) << 5);
    }

    private static int adapt(int delta, int numpoints, boolean firsttime) {
        int k;
        delta = (firsttime) ? delta / damp : delta >> 1;
        delta += delta / numpoints;
        for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) {
            delta /= base - tmin;
        }
        return k + (base - tmin + 1) * delta / (delta + skew);
    }

    public static String encode(char[] chars, boolean[] case_flags) throws IOException {
        StringBuilder buf = new StringBuilder();
        CodepointIterator ci = CodepointIterator.forCharArray(chars);
        int n, delta, h, b, bias, m, q, k, t;
        n = initial_n;
        delta = 0;
        bias = initial_bias;
        int i = -1;
        while (ci.hasNext()) {
            i = ci.next().getValue();
            if (basic(i)) {
                if (case_flags != null) {
                } else {
                    buf.append((char)i);
                }
            }
        }
        h = b = buf.length();
        if (b > 0)
            buf.append((char)delimiter);
        while (h < chars.length) {
            ci.position(0);
            i = -1;
            m = Integer.MAX_VALUE;
            while (ci.hasNext()) {
                i = ci.next().getValue();
                if (i >= n && i < m)
                    m = i;
            }
            if (m - n > (Integer.MAX_VALUE - delta) / (h + 1))
                throw new IOException("Overflow");
            delta += (m - n) * (h + 1);
            n = m;
            ci.position(0);
            i = -1;
            while (ci.hasNext()) {
                i = ci.next().getValue();
                if (i < n) {
                    if (++delta == 0)
                        throw new IOException("Overflow");
                }
                if (i == n) {
                    for (q = delta, k = base;; k += base) {
                        t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
                        if (q < t)
                            break;
                        buf.append((char)encode_digit(t + (q - t) % (base - t), false));
                        q = (q - t) / (base - t);
                    }
                    buf.append((char)encode_digit(q, (case_flags != null) ? case_flags[ci.position() - 1] : false));
                    bias = adapt(delta, h + 1, h == b);
                    delta = 0;
                    ++h;
                }
            }
            ++delta;
            ++n;
        }
        return buf.toString();
    }

    public static String encode(String s) {
        try {
            if (s == null)
                return null;
            return encode(s.toCharArray(), null).toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decode(String s) {
        try {
            if (s == null)
                return null;
            return decode(s.toCharArray(), null).toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decode(char[] chars, boolean[] case_flags) throws IOException {
        StringBuilder buf = new StringBuilder();
        int n, out, i, bias, b, j, in, oldi, w, k, digit, t;
        n = initial_n;
        out = i = 0;
        bias = initial_bias;
        for (b = j = 0; j < chars.length; ++j)
            if (delim(chars[j]))
                b = j;
        for (j = 0; j < b; ++j) {
            if (case_flags != null)
                case_flags[out] = flagged(chars[j]);
            if (!basic(chars[j]))
                throw new IOException("Bad Input");
            buf.append((char)chars[j]);
        }
        out = buf.length();
        for (in = (b > 0) ? b + 1 : 0; in < chars.length; ++out) {
            for (oldi = i, w = 1, k = base;; k += base) {
                if (in > chars.length)
                    throw new IOException("Bad input");
                digit = decode_digit(chars[in++]);
                if (digit >= base)
                    throw new IOException("Bad input");
                if (digit > (Integer.MAX_VALUE - i) / w)
                    throw new IOException("Overflow");
                i += digit * w;
                t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias;
                if (digit < t)
                    break;
                if (w > Integer.MAX_VALUE / (base - t))
                    throw new IOException("Overflow");
                w *= (base - t);
            }
            bias = adapt(i - oldi, out + 1, oldi == 0);
            if (i / (out + 1) > Integer.MAX_VALUE - n)
                throw new IOException("Overflow");
            n += i / (out + 1);
            i %= (out + 1);
            if (case_flags != null) {
                System.arraycopy( // not sure if this is right
                                 case_flags,
                                 i,
                                 case_flags,
                                 i + CharUtils.length(n),
                                 case_flags.length - i);
            }
            CharUtils.insert(buf, i++, n);
        }
        return buf.toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy