001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.coder;
020
021import java.text.StringCharacterIterator;
022
023/**
024 * Unix Coding for java
025 */
026public final class UUCoder {
027
028    /**
029     * encodes a byte array to a String
030     * @param barr
031     * @return encoded String
032     */
033    public static String encode(byte barr[]) {
034        StringBuilder rtn = new StringBuilder();
035        int len = barr.length;
036        int read = 0;
037        boolean stop = false;
038        byte b = 0;
039        int offset = 0;
040        
041        do {
042            int left=len-read;
043            if(left==0) stop=true;
044            
045            if(left<=45) b=(byte)left;
046            else b=45;
047            
048            rtn.append(_enc(b));
049            for(int i = 0; i < b; i += 3) {
050                if(len - offset < 3) {
051                    byte padding[] = new byte[3];
052                    for(int z = 0; offset + z < len; z++) padding[z] = barr[offset + z];
053                    encodeBytes(padding, 0, rtn);
054                } else {
055                    encodeBytes(barr, offset, rtn);
056                }
057                offset += 3;
058            }
059
060            rtn.append('\n');
061            read += b;
062            if(b < 45) stop=true;
063        } 
064        while(!stop);
065        return rtn.toString();
066    }
067
068    /**
069     * decodes back a String to a byte array
070     * @param b
071     * @return decoded byte array
072     */
073    public static byte[] decode(String str) throws CoderException {
074        byte out[] = new byte[str.length()];
075        int len = 0;
076        int offset = 0;
077        //int current = 0;
078        byte b = 0;
079        boolean stop = false;
080        StringCharacterIterator it = new StringCharacterIterator(str);
081        do {
082            b = _dec(it.current());
083            it.next();
084            if(b>45) throw new CoderException("can't decode string ["+str+"]");
085            if(b<45) stop=true;
086            len += b;
087            for(; b > 0; b -= 3) {
088                decodeChars(it, out, offset);
089                offset += 3;
090            }
091            it.next();
092        } 
093        while(!stop);
094        byte rtn[] = new byte[len];
095        for(int i = 0; i < len; i++)
096            rtn[i] = out[i];
097
098        return rtn;
099    }
100
101    private static void encodeBytes(byte in[], int off, StringBuilder out) {
102        out.append(_enc((byte)(in[off] >>> 2)));
103        out.append(_enc((byte)(in[off] << 4 & 0x30 | in[off + 1] >>> 4 & 0xf)));
104        out.append(_enc((byte)(in[off + 1] << 2 & 0x3c | in[off + 2] >>> 6 & 3)));
105        out.append(_enc((byte)(in[off + 2] & 0x3f)));
106    }
107
108    private static void decodeChars(StringCharacterIterator it, byte out[], int off) {
109        byte b1 = _dec(it.current());
110        byte b2 = _dec(it.next());
111        byte b3 = _dec(it.next());
112        byte b4 = _dec(it.next());
113        it.next();
114        byte b5 = (byte)(b1 << 2 | b2 >> 4);
115        byte b6 = (byte)(b2 << 4 | b3 >> 2);
116        byte b7 = (byte)(b3 << 6 | b4);
117        out[off] = b5;
118        out[off + 1] = b6;
119        out[off + 2] = b7;
120    }
121
122    private static char _enc(byte c) {
123        return (char)((c & 0x3f) + 32);
124    }
125
126    private static byte _dec(char c) {
127        return (byte)(c - 32 & 0x3f);
128    }
129}