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}