001 /**
002 *
003 * Copyright 2003-2004 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