001    package com.skype.util;
002    
003    
004    import java.util.Arrays;
005    
006    
007    public class BaseX
008    {
009    
010        public BaseX(String s, boolean flag, char c)
011        {
012            for(bits = 1; 1 << bits < s.length(); bits++);
013            if(1 << bits != s.length())
014                throw new IllegalArgumentException("The size of the encoding alphabet is not a power of 2");
015            block = 8 / gcd(8, bits);
016            chars = s.toCharArray();
017            min = max = -1;
018            if(flag)
019            {
020                addMinMax(s);
021                values = new int[(max - min) + 1];
022                Arrays.fill(values, -1);
023                addChars(s);
024            } else
025            {
026                addMinMax(s.toUpperCase());
027                addMinMax(s.toLowerCase());
028                values = new int[(max - min) + 1];
029                Arrays.fill(values, -1);
030                addChars(s.toUpperCase());
031                addChars(s.toLowerCase());
032            }
033            if(c >= min && c <= max && values[c - min] != -1)
034            {
035                throw new IllegalArgumentException("The padding character appears in the encoding alphabet");
036            } else
037            {
038                pad = c;
039                return;
040            }
041        }
042    
043        private void addMinMax(String s)
044        {
045            for(int i = 0; i < s.length(); i++)
046            {
047                int j = s.codePointAt(i);
048                if(min == -1 || min > j)
049                    min = j;
050                if(max == -1 || max < j)
051                    max = j;
052            }
053    
054        }
055    
056        private void addChars(String s)
057        {
058            for(int i = 0; i < s.length(); i++)
059            {
060                int j = s.codePointAt(i) - min;
061                if(values[j] != -1 && values[j] != i)
062                    throw new IllegalArgumentException("Duplicate characters in the encoding alphapbet");
063                values[j] = i;
064            }
065    
066        }
067    
068        public StringBuffer encode(byte abyte0[], String s, int i)
069        {
070            if(s == null)
071            {
072                i = 0;
073            } else
074            {
075                for(int j = 0; j < s.length(); j++)
076                {
077                    int l = s.codePointAt(j);
078                    if(l >= min && l <= max && values[l - min] != -1)
079                        throw new IllegalArgumentException("The separator contains characters from the encoding alphabet");
080                }
081    
082            }
083            int k = ((8 * abyte0.length + bits) - 1) / bits;
084            k = (((k + block) - 1) / block) * block;
085            if(i > 0)
086                k += ((k - 1) / i) * s.length();
087            StringBuffer stringbuffer = new StringBuffer(k);
088            int i1 = 0;
089            int j1 = 0;
090            int k1 = 0;
091            int l1 = 0;
092            int i2 = (1 << bits) - 1;
093            for(; bits * i1 < 8 * abyte0.length; i1++)
094            {
095                if(i > 0 && i1 > 0 && i1 % i == 0)
096                    stringbuffer.append(s);
097                for(; l1 < bits; l1 += 8)
098                {
099                    byte byte0 = j1 >= abyte0.length ? 0 : abyte0[j1];
100                    j1++;
101                    k1 = k1 << 8 | byte0 & 0xff;
102                }
103    
104                stringbuffer.append(chars[k1 >>> l1 - bits & i2]);
105                l1 -= bits;
106            }
107    
108            for(; i1 % block != 0; i1++)
109            {
110                if(i > 0 && i1 > 0 && i1 % i == 0)
111                    stringbuffer.append(s);
112                stringbuffer.append(pad);
113            }
114    
115            return stringbuffer;
116        }
117    
118        public byte[] decode(String s)
119        {
120            byte abyte0[] = new byte[(s.length() * bits) / 8];
121            int i = 0;
122            int j = 0;
123            int k = 0;
124            int l = 0;
125            do
126            {
127                if(j >= s.length())
128                    break;
129                int i1 = s.codePointAt(j);
130                j++;
131                if(i1 >= min && i1 <= max)
132                {
133                    i1 = values[i1 - min];
134                    if(i1 != -1)
135                    {
136                        k = k << bits | i1;
137                        l += bits;
138                        while(l >= 8) 
139                        {
140                            abyte0[i] = (byte)(k >>> l - 8 & 0xff);
141                            l -= 8;
142                            i++;
143                        }
144                    }
145                }
146            } while(true);
147            if(i < abyte0.length)
148            {
149                byte abyte1[] = abyte0;
150                abyte0 = new byte[i];
151                System.arraycopy(abyte1, 0, abyte0, 0, i);
152            }
153            return abyte0;
154        }
155    
156        private static int gcd(int i, int j)
157        {
158            i = Math.abs(i);
159            j = Math.abs(j);
160            int k;
161            for(; i > 0; i = k)
162            {
163                k = j % i;
164                j = i;
165            }
166    
167            return j;
168        }
169        
170        private char chars[];
171        private int values[];
172        private int min;
173        private int max;
174        private int bits;
175        private int block;
176        private char pad;
177    }