001    package railo.runtime.coder;
002    
003    import java.text.StringCharacterIterator;
004    
005    /**
006     * Unix Coding for java
007     */
008    public final class UUCoder {
009    
010        /**
011         * encodes a byte array to a String
012         * @param barr
013         * @return encoded String
014         */
015        public static String encode(byte barr[]) {
016            StringBuffer rtn = new StringBuffer();
017            int len = barr.length;
018            int read = 0;
019            boolean stop = false;
020            byte b = 0;
021            int offset = 0;
022            
023            do {
024                int left=len-read;
025                if(left==0) stop=true;
026                
027                if(left<=45) b=(byte)left;
028                else b=45;
029                
030                rtn.append(_enc(b));
031                for(int i = 0; i < b; i += 3) {
032                    if(len - offset < 3) {
033                        byte padding[] = new byte[3];
034                        for(int z = 0; offset + z < len; z++) padding[z] = barr[offset + z];
035                        encodeBytes(padding, 0, rtn);
036                    } else {
037                        encodeBytes(barr, offset, rtn);
038                    }
039                    offset += 3;
040                }
041    
042                rtn.append('\n');
043                read += b;
044                if(b < 45) stop=true;
045            } 
046            while(!stop);
047            return rtn.toString();
048        }
049    
050        /**
051         * decodes back a String to a byte array
052         * @param b
053         * @return decoded byte array
054         */
055        public static byte[] decode(String str) throws CoderException {
056            byte out[] = new byte[str.length()];
057            int len = 0;
058            int offset = 0;
059            //int current = 0;
060            byte b = 0;
061            boolean stop = false;
062            StringCharacterIterator it = new StringCharacterIterator(str);
063            do {
064                b = _dec(it.current());
065                it.next();
066                if(b>45) throw new CoderException("can't decode string ["+str+"]");
067                if(b<45) stop=true;
068                len += b;
069                for(; b > 0; b -= 3) {
070                    decodeChars(it, out, offset);
071                    offset += 3;
072                }
073                it.next();
074            } 
075            while(!stop);
076            byte rtn[] = new byte[len];
077            for(int i = 0; i < len; i++)
078                rtn[i] = out[i];
079    
080            return rtn;
081        }
082    
083        private static void encodeBytes(byte in[], int off, StringBuffer out) {
084            out.append(_enc((byte)(in[off] >>> 2)));
085            out.append(_enc((byte)(in[off] << 4 & 0x30 | in[off + 1] >>> 4 & 0xf)));
086            out.append(_enc((byte)(in[off + 1] << 2 & 0x3c | in[off + 2] >>> 6 & 3)));
087            out.append(_enc((byte)(in[off + 2] & 0x3f)));
088        }
089    
090        private static void decodeChars(StringCharacterIterator it, byte out[], int off) {
091            byte b1 = _dec(it.current());
092            byte b2 = _dec(it.next());
093            byte b3 = _dec(it.next());
094            byte b4 = _dec(it.next());
095            it.next();
096            byte b5 = (byte)(b1 << 2 | b2 >> 4);
097            byte b6 = (byte)(b2 << 4 | b3 >> 2);
098            byte b7 = (byte)(b3 << 6 | b4);
099            out[off] = b5;
100            out[off + 1] = b6;
101            out[off + 2] = b7;
102        }
103    
104        private static char _enc(byte c) {
105            return (char)((c & 0x3f) + 32);
106        }
107    
108        private static byte _dec(char c) {
109            return (byte)(c - 32 & 0x3f);
110        }
111    }