001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   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   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: Radix64Codec.java,v $
023   Revision 1.5  2004/05/05 22:47:37  markl
024   comment block updates
025
026   Revision 1.4  2003/01/19 09:34:27  markl
027   Javadoc & comment header updates.
028
029   Revision 1.3  2001/03/12 02:18:28  markl
030   Source code cleanup.
031
032   Revision 1.2  1999/01/10 03:37:18  markl
033   added GPL header & RCS tag
034   ----------------------------------------------------------------------------
035*/
036
037package kiwi.text;
038
039/** This class implements a codec for the Radix-64 encoding scheme. For a
040  * high-level interface, see the <i>Radix64InputStream</i> and
041  * <i>Radix64OutputStream</i> filters in <b>kiwi.io</b>.
042  * <p>
043  * This codec implements Radix-64 as defined by the <i>PGP</i> software.
044  *
045  * @see kiwi.io.Radix64InputStream
046  * @see kiwi.io.Radix64OutputStream
047  *
048  * @author Mark Lindner
049  */
050
051public class Radix64Codec
052  {
053  private static final String radix64
054    = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
055  private static final byte pad = (byte)'=';
056
057  private Radix64Codec() {}
058
059  /** Determine if a byte is a valid Radix-64 encoding character; one of the
060   * characters: '+', '/', '=', '0' - '9', 'A' - 'Z', 'a' - 'z'.
061   *
062   * @param c The byte to test.
063   *
064   * @return <code>true</code> if <code>c</code> is a Radix-64 character,
065   * <code>false</code>
066   * otherwise.
067   */
068
069  public static final boolean isRadix64Character(byte c)
070    {
071    return((radix64.indexOf((char)c) != -1) || (c == pad));
072    }
073
074  /** Encode up to 3 bytes of binary data as 4 bytes of printable ASCII text.
075    *
076    * @param input A 3-byte long array of input.
077    * @param len The number of bytes (1, 2, or 3) that are significant in the
078    * input.
079    *
080    * @return A 4-byte array of printable characters that represent the
081    * Radix-64 encoding of the input. The output will include padding ('='
082    * characters) if not all 3 bytes of the input were significant.
083    */
084
085  public static final byte[] encode(byte input[], int len)
086    {
087    byte out[] = new byte[4];
088
089    // 3 bytes --> 4 bytes
090    // the highest order byte becomes the first radix-64 'digit'
091
092    int x = 0;
093    for(int i = 0; i < 3; i++)
094      {
095      if(i > 0) x <<= 8;
096      if(i < len)
097        x |= input[i];
098      }
099
100    for(int i = 0; i < 4; i++)
101      {
102      out[3 - i] = (byte)(radix64.charAt(x & 0x3F));
103      x >>>= 6;
104      }
105
106    if(len < 3) out[3] = pad;
107    if(len < 2) out[2] = pad;
108
109    return(out);
110    }
111
112  /** Decode 4 bytes of printable ASCII text into up to 3 bytes of binary data.
113    *
114    * @param input A 4-byte long array of input bytes.
115    * @param output A 3-byte long array in which up to 3 bytes of decoded
116    * output will be stored.
117    *
118    * @return The number of bytes decoded (1, 2, or 3).
119    */
120
121  public static final int decode(byte input[], byte output[])
122    {
123    int out = 0;
124    int len = 3;
125
126    if(input[3] == pad) len--;
127    if(input[2] == pad) len--;
128
129    for(int i = 0; i < 4; i++)
130      {
131      if(i > 0) out <<= 6;
132      out |= (byte)(radix64.indexOf((char)input[i]));
133      }
134
135    for(int i = 0; i < 3; i++)
136      {
137      if(i > 0) out >>>= 8;
138      output[2 - i] = (byte)(out & 0xFF);
139      }
140
141    return(len);
142    }
143  
144  }
145
146/* end of source file */