001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
018    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    
022    import java.io.ObjectInputStream;
023    import java.io.ObjectOutputStream;
024    
025    /**
026     * @author Brian Wing Shun Chan
027     */
028    public class Base64 {
029    
030            protected static char getChar(int sixbit) {
031                    if (sixbit >= 0 && sixbit <= 25) {
032                            return (char)(65 + sixbit);
033                    }
034    
035                    if (sixbit >= 26 && sixbit <= 51) {
036                            return (char)(97 + (sixbit - 26));
037                    }
038    
039                    if (sixbit >= 52 && sixbit <= 61) {
040                            return (char)(48 + (sixbit - 52));
041                    }
042    
043                    if (sixbit == 62) {
044                            return CharPool.PLUS;
045                    }
046    
047                    return sixbit != 63 ? CharPool.QUESTION : CharPool.SLASH;
048            }
049    
050            protected static int getValue(char c) {
051                    if ((c >= CharPool.UPPER_CASE_A) && (c <= CharPool.UPPER_CASE_Z)) {
052                            return c - 65;
053                    }
054    
055                    if ((c >= CharPool.LOWER_CASE_A) && (c <= CharPool.LOWER_CASE_Z)) {
056                            return (c - 97) + 26;
057                    }
058    
059                    if (c >= CharPool.NUMBER_0 && c <= CharPool.NUMBER_9) {
060                            return (c - 48) + 52;
061                    }
062    
063                    if (c == CharPool.PLUS) {
064                            return 62;
065                    }
066    
067                    if (c == CharPool.SLASH) {
068                            return 63;
069                    }
070    
071                    return c != CharPool.EQUAL ? -1 : 0;
072            }
073    
074            public static String encode(byte raw[]) {
075                    return encode(raw, 0, raw.length);
076            }
077    
078            public static String encode(byte raw[], int offset, int length) {
079                    int lastIndex = Math.min(raw.length, offset + length);
080    
081                    StringBuilder sb = new StringBuilder(
082                            ((lastIndex - offset) / 3 + 1) * 4);
083    
084                    for (int i = offset; i < lastIndex; i += 3) {
085                            sb.append(encodeBlock(raw, i, lastIndex));
086                    }
087    
088                    return sb.toString();
089            }
090    
091            protected static char[] encodeBlock(byte raw[], int offset, int lastIndex) {
092                    int block = 0;
093                    int slack = lastIndex - offset - 1;
094                    int end = slack < 2 ? slack : 2;
095    
096                    for (int i = 0; i <= end; i++) {
097                            byte b = raw[offset + i];
098    
099                            int neuter = b >= 0 ? ((int) (b)) : b + 256;
100                            block += neuter << 8 * (2 - i);
101                    }
102    
103                    char base64[] = new char[4];
104    
105                    for (int i = 0; i < 4; i++) {
106                            int sixbit = block >>> 6 * (3 - i) & 0x3f;
107                            base64[i] = getChar(sixbit);
108                    }
109    
110                    if (slack < 1) {
111                            base64[2] = CharPool.EQUAL;
112                    }
113    
114                    if (slack < 2) {
115                            base64[3] = CharPool.EQUAL;
116                    }
117    
118                    return base64;
119            }
120    
121            public static byte[] decode(String base64) {
122                    if (Validator.isNull(base64)) {
123                            return new byte[0];
124                    }
125    
126                    int pad = 0;
127    
128                    for (int i = base64.length() - 1; base64.charAt(i) == CharPool.EQUAL;
129                                    i--) {
130    
131                            pad++;
132                    }
133    
134                    int length = (base64.length() * 6) / 8 - pad;
135                    byte raw[] = new byte[length];
136                    int rawindex = 0;
137    
138                    for (int i = 0; i < base64.length(); i += 4) {
139                            int block = (getValue(base64.charAt(i)) << 18) +
140                                                    (getValue(base64.charAt(i + 1)) << 12) +
141                                                    (getValue(base64.charAt(i + 2)) << 6) +
142                                                    getValue(base64.charAt(i + 3));
143    
144                            for (int j = 0; j < 3 && rawindex + j < raw.length; j++) {
145                                    raw[rawindex + j] = (byte)(block >> 8 * (2 - j) & 0xff);
146                            }
147    
148                            rawindex += 3;
149                    }
150    
151                    return raw;
152            }
153    
154            public static String fromURLSafe(String base64) {
155                    return StringUtil.replace(
156                            base64,
157                            new String[] {
158                                    StringPool.MINUS,
159                                    StringPool.STAR,
160                                    StringPool.UNDERLINE
161                            },
162                            new String[] {
163                                    StringPool.PLUS,
164                                    StringPool.EQUAL,
165                                    StringPool.SLASH
166                            });
167            }
168    
169            public static String objectToString(Object o) {
170                    if (o == null) {
171                            return null;
172                    }
173    
174                    UnsyncByteArrayOutputStream ubaos = new UnsyncByteArrayOutputStream(
175                            32000);
176    
177                    try {
178                            ObjectOutputStream os = new ObjectOutputStream(ubaos);
179    
180                            os.flush();
181                            os.writeObject(o);
182                            os.flush();
183                    }
184                    catch (Exception e) {
185                            _log.error(e, e);
186                    }
187    
188                    return encode(ubaos.unsafeGetByteArray(), 0, ubaos.size());
189            }
190    
191            public static Object stringToObject(String s) {
192                    return _stringToObject(s, null, false);
193            }
194    
195            public static Object stringToObject(String s, ClassLoader classLoader) {
196                    return _stringToObject(s, classLoader, false);
197            }
198    
199            public static Object stringToObjectSilent(String s) {
200                    return _stringToObject(s, null, true);
201            }
202    
203            public static Object stringToObjectSilent(
204                    String s, ClassLoader classLoader) {
205    
206                    return _stringToObject(s, classLoader, true);
207            }
208    
209            public static String toURLSafe(String base64) {
210                    return StringUtil.replace(
211                            base64,
212                            new String[] {
213                                    StringPool.PLUS,
214                                    StringPool.EQUAL,
215                                    StringPool.SLASH
216                            },
217                            new String[] {
218                                    StringPool.MINUS,
219                                    StringPool.STAR,
220                                    StringPool.UNDERLINE
221                            });
222            }
223    
224            private static Object _stringToObject(
225                    String s, ClassLoader classLoader, boolean silent) {
226    
227                    if (s == null) {
228                            return null;
229                    }
230    
231                    byte bytes[] = decode(s);
232    
233                    UnsyncByteArrayInputStream ubais = new UnsyncByteArrayInputStream(
234                            bytes);
235    
236                    try {
237                            ObjectInputStream is = null;
238    
239                            if (classLoader == null) {
240                                    is = new ObjectInputStream(ubais);
241                            }
242                            else {
243                                    is = new ClassLoaderObjectInputStream(ubais, classLoader);
244                            }
245    
246                            return is.readObject();
247                    }
248                    catch (Exception e) {
249                            if (!silent) {
250                                    _log.error(e, e);
251                            }
252                    }
253    
254                    return null;
255            }
256    
257            private static Log _log = LogFactoryUtil.getLog(Base64.class);
258    
259    }