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