001 /** 002 * 003 * Copyright 2003-2006 The Apache Software Foundation 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.mail.util; 019 020 import java.io.IOException; 021 import java.io.OutputStream; 022 023 public class XTextEncoder 024 implements Encoder 025 { 026 protected final byte[] encodingTable = 027 { 028 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', 029 (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' 030 }; 031 032 /* 033 * set up the decoding table. 034 */ 035 protected final byte[] decodingTable = new byte[128]; 036 037 protected void initialiseDecodingTable() 038 { 039 for (int i = 0; i < encodingTable.length; i++) 040 { 041 decodingTable[encodingTable[i]] = (byte)i; 042 } 043 } 044 045 public XTextEncoder() 046 { 047 initialiseDecodingTable(); 048 } 049 050 /** 051 * encode the input data producing an XText output stream. 052 * 053 * @return the number of bytes produced. 054 */ 055 public int encode( 056 byte[] data, 057 int off, 058 int length, 059 OutputStream out) 060 throws IOException 061 { 062 int bytesWritten = 0; 063 064 for (int i = off; i < (off + length); i++) 065 { 066 int v = data[i] & 0xff; 067 // character tha must be encoded? Prefix with a '+' and encode in hex. 068 if (v < 33 || v > 126 || v == '+' || v == '+') { 069 out.write((byte)'+'); 070 out.write(encodingTable[(v >>> 4)]); 071 out.write(encodingTable[v & 0xf]); 072 bytesWritten += 3; 073 } 074 else { 075 // add unchanged. 076 out.write((byte)v); 077 bytesWritten++; 078 } 079 } 080 081 return bytesWritten; 082 } 083 084 085 /** 086 * decode the xtext encoded byte data writing it to the given output stream 087 * 088 * @return the number of bytes produced. 089 */ 090 public int decode( 091 byte[] data, 092 int off, 093 int length, 094 OutputStream out) 095 throws IOException 096 { 097 byte[] bytes; 098 byte b1, b2; 099 int outLen = 0; 100 101 int end = off + length; 102 103 int i = off; 104 while (i < end) 105 { 106 byte v = data[i++]; 107 // a plus is a hex character marker, need to decode a hex value. 108 if (v == '+') { 109 b1 = decodingTable[data[i++]]; 110 b2 = decodingTable[data[i++]]; 111 out.write((b1 << 4) | b2); 112 } 113 else { 114 // copied over unchanged. 115 out.write(v); 116 } 117 // always just one byte added 118 outLen++; 119 } 120 121 return outLen; 122 } 123 124 /** 125 * decode the xtext encoded String data writing it to the given output stream. 126 * 127 * @return the number of bytes produced. 128 */ 129 public int decode( 130 String data, 131 OutputStream out) 132 throws IOException 133 { 134 byte[] bytes; 135 byte b1, b2, b3, b4; 136 int length = 0; 137 138 int end = data.length(); 139 140 int i = 0; 141 while (i < end) 142 { 143 char v = data.charAt(i++); 144 if (v == '+') { 145 b1 = decodingTable[data.charAt(i++)]; 146 b2 = decodingTable[data.charAt(i++)]; 147 148 out.write((b1 << 4) | b2); 149 } 150 else { 151 out.write((byte)v); 152 } 153 length++; 154 } 155 156 return length; 157 } 158 } 159