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 public class XTextEncoder 026 implements Encoder 027 { 028 protected final byte[] encodingTable = 029 { 030 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', 031 (byte)'8', (byte)'9', (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F' 032 }; 033 034 /* 035 * set up the decoding table. 036 */ 037 protected final byte[] decodingTable = new byte[128]; 038 039 protected void initialiseDecodingTable() 040 { 041 for (int i = 0; i < encodingTable.length; i++) 042 { 043 decodingTable[encodingTable[i]] = (byte)i; 044 } 045 } 046 047 public XTextEncoder() 048 { 049 initialiseDecodingTable(); 050 } 051 052 /** 053 * encode the input data producing an XText output stream. 054 * 055 * @return the number of bytes produced. 056 */ 057 public int encode( 058 byte[] data, 059 int off, 060 int length, 061 OutputStream out) 062 throws IOException 063 { 064 int bytesWritten = 0; 065 066 for (int i = off; i < (off + length); i++) 067 { 068 int v = data[i] & 0xff; 069 // character tha must be encoded? Prefix with a '+' and encode in hex. 070 if (v < 33 || v > 126 || v == '+' || v == '+') { 071 out.write((byte)'+'); 072 out.write(encodingTable[(v >>> 4)]); 073 out.write(encodingTable[v & 0xf]); 074 bytesWritten += 3; 075 } 076 else { 077 // add unchanged. 078 out.write((byte)v); 079 bytesWritten++; 080 } 081 } 082 083 return bytesWritten; 084 } 085 086 087 /** 088 * decode the xtext encoded byte data writing it to the given output stream 089 * 090 * @return the number of bytes produced. 091 */ 092 public int decode( 093 byte[] data, 094 int off, 095 int length, 096 OutputStream out) 097 throws IOException 098 { 099 byte[] bytes; 100 byte b1, b2; 101 int outLen = 0; 102 103 int end = off + length; 104 105 int i = off; 106 while (i < end) 107 { 108 byte v = data[i++]; 109 // a plus is a hex character marker, need to decode a hex value. 110 if (v == '+') { 111 b1 = decodingTable[data[i++]]; 112 b2 = decodingTable[data[i++]]; 113 out.write((b1 << 4) | b2); 114 } 115 else { 116 // copied over unchanged. 117 out.write(v); 118 } 119 // always just one byte added 120 outLen++; 121 } 122 123 return outLen; 124 } 125 126 /** 127 * decode the xtext encoded String data writing it to the given output stream. 128 * 129 * @return the number of bytes produced. 130 */ 131 public int decode( 132 String data, 133 OutputStream out) 134 throws IOException 135 { 136 byte[] bytes; 137 byte b1, b2, b3, b4; 138 int length = 0; 139 140 int end = data.length(); 141 142 int i = 0; 143 while (i < end) 144 { 145 char v = data.charAt(i++); 146 if (v == '+') { 147 b1 = decodingTable[data.charAt(i++)]; 148 b2 = decodingTable[data.charAt(i++)]; 149 150 out.write((b1 << 4) | b2); 151 } 152 else { 153 out.write((byte)v); 154 } 155 length++; 156 } 157 158 return length; 159 } 160 } 161