Clover coverage report - Maven Clover report
Coverage timestamp: Sun Aug 20 2006 04:01:04 PDT
file stats: LOC: 552   Methods: 10
NCLOC: 379   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Base64Encoder.java 50% 65.7% 90% 62.7%
coverage coverage
 1    /**
 2    *
 3    * Copyright 2003-2004 The Apache Software Foundation
 4    *
 5    * Licensed under the Apache License, Version 2.0 (the "License");
 6    * you may not use this file except in compliance with the License.
 7    * You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    */
 17   
 18    package org.apache.geronimo.mail.util;
 19   
 20    import java.io.IOException;
 21    import java.io.InputStream;
 22    import java.io.OutputStream;
 23    import java.io.PrintStream;
 24   
 25    public class Base64Encoder
 26    implements Encoder
 27    {
 28    protected final byte[] encodingTable =
 29    {
 30    (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
 31    (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
 32    (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
 33    (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
 34    (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
 35    (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
 36    (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
 37    (byte)'v',
 38    (byte)'w', (byte)'x', (byte)'y', (byte)'z',
 39    (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
 40    (byte)'7', (byte)'8', (byte)'9',
 41    (byte)'+', (byte)'/'
 42    };
 43   
 44    protected byte padding = (byte)'=';
 45   
 46    /*
 47    * set up the decoding table.
 48    */
 49    protected final byte[] decodingTable = new byte[256];
 50   
 51  11 protected void initialiseDecodingTable()
 52    {
 53  11 for (int i = 0; i < encodingTable.length; i++)
 54    {
 55  704 decodingTable[encodingTable[i]] = (byte)i;
 56    }
 57    }
 58   
 59  11 public Base64Encoder()
 60    {
 61  11 initialiseDecodingTable();
 62    }
 63   
 64    /**
 65    * encode the input data producing a base 64 output stream.
 66    *
 67    * @return the number of bytes produced.
 68    */
 69  42 public int encode(
 70    byte[] data,
 71    int off,
 72    int length,
 73    OutputStream out)
 74    throws IOException
 75    {
 76  42 int modulus = length % 3;
 77  42 int dataLength = (length - modulus);
 78  42 int a1, a2, a3;
 79   
 80  42 for (int i = off; i < off + dataLength; i += 3)
 81    {
 82  256 a1 = data[i] & 0xff;
 83  256 a2 = data[i + 1] & 0xff;
 84  256 a3 = data[i + 2] & 0xff;
 85   
 86  256 out.write(encodingTable[(a1 >>> 2) & 0x3f]);
 87  256 out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
 88  256 out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
 89  256 out.write(encodingTable[a3 & 0x3f]);
 90    }
 91   
 92    /*
 93    * process the tail end.
 94    */
 95  42 int b1, b2, b3;
 96  42 int d1, d2;
 97   
 98  42 switch (modulus)
 99    {
 100  40 case 0: /* nothing left to do */
 101  40 break;
 102  1 case 1:
 103  1 d1 = data[off + dataLength] & 0xff;
 104  1 b1 = (d1 >>> 2) & 0x3f;
 105  1 b2 = (d1 << 4) & 0x3f;
 106   
 107  1 out.write(encodingTable[b1]);
 108  1 out.write(encodingTable[b2]);
 109  1 out.write(padding);
 110  1 out.write(padding);
 111  1 break;
 112  1 case 2:
 113  1 d1 = data[off + dataLength] & 0xff;
 114  1 d2 = data[off + dataLength + 1] & 0xff;
 115   
 116  1 b1 = (d1 >>> 2) & 0x3f;
 117  1 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
 118  1 b3 = (d2 << 2) & 0x3f;
 119   
 120  1 out.write(encodingTable[b1]);
 121  1 out.write(encodingTable[b2]);
 122  1 out.write(encodingTable[b3]);
 123  1 out.write(padding);
 124  1 break;
 125    }
 126   
 127  42 return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
 128    }
 129   
 130  1062 private boolean ignore(
 131    char c)
 132    {
 133  1062 return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
 134    }
 135   
 136    /**
 137    * decode the base 64 encoded byte data writing it to the given output stream,
 138    * whitespace characters will be ignored.
 139    *
 140    * @return the number of bytes produced.
 141    */
 142  2 public int decode(
 143    byte[] data,
 144    int off,
 145    int length,
 146    OutputStream out)
 147    throws IOException
 148    {
 149  2 byte[] bytes;
 150  2 byte b1, b2, b3, b4;
 151  2 int outLen = 0;
 152   
 153  2 int end = off + length;
 154   
 155  2 while (end > 0)
 156    {
 157  2 if (!ignore((char)data[end - 1]))
 158    {
 159  2 break;
 160    }
 161   
 162  0 end--;
 163    }
 164   
 165  2 int i = off;
 166  2 int finish = end - 4;
 167   
 168  2 while (i < finish)
 169    {
 170  10 while ((i < finish) && ignore((char)data[i]))
 171    {
 172  0 i++;
 173    }
 174   
 175  10 b1 = decodingTable[data[i++]];
 176   
 177  10 while ((i < finish) && ignore((char)data[i]))
 178    {
 179  0 i++;
 180    }
 181   
 182  10 b2 = decodingTable[data[i++]];
 183   
 184  10 while ((i < finish) && ignore((char)data[i]))
 185    {
 186  0 i++;
 187    }
 188   
 189  10 b3 = decodingTable[data[i++]];
 190   
 191  10 while ((i < finish) && ignore((char)data[i]))
 192    {
 193  0 i++;
 194    }
 195   
 196  10 b4 = decodingTable[data[i++]];
 197   
 198  10 out.write((b1 << 2) | (b2 >> 4));
 199  10 out.write((b2 << 4) | (b3 >> 2));
 200  10 out.write((b3 << 6) | b4);
 201   
 202  10 outLen += 3;
 203    }
 204   
 205  2 if (data[end - 2] == padding)
 206    {
 207  0 b1 = decodingTable[data[end - 4]];
 208  0 b2 = decodingTable[data[end - 3]];
 209   
 210  0 out.write((b1 << 2) | (b2 >> 4));
 211   
 212  0 outLen += 1;
 213    }
 214  2 else if (data[end - 1] == padding)
 215    {
 216  2 b1 = decodingTable[data[end - 4]];
 217  2 b2 = decodingTable[data[end - 3]];
 218  2 b3 = decodingTable[data[end - 2]];
 219   
 220  2 out.write((b1 << 2) | (b2 >> 4));
 221  2 out.write((b2 << 4) | (b3 >> 2));
 222   
 223  2 outLen += 2;
 224    }
 225    else
 226    {
 227  0 b1 = decodingTable[data[end - 4]];
 228  0 b2 = decodingTable[data[end - 3]];
 229  0 b3 = decodingTable[data[end - 2]];
 230  0 b4 = decodingTable[data[end - 1]];
 231   
 232  0 out.write((b1 << 2) | (b2 >> 4));
 233  0 out.write((b2 << 4) | (b3 >> 2));
 234  0 out.write((b3 << 6) | b4);
 235   
 236  0 outLen += 3;
 237    }
 238   
 239  2 return outLen;
 240    }
 241   
 242    /**
 243    * decode the base 64 encoded String data writing it to the given output stream,
 244    * whitespace characters will be ignored.
 245    *
 246    * @return the number of bytes produced.
 247    */
 248  0 public int decode(
 249    String data,
 250    OutputStream out)
 251    throws IOException
 252    {
 253  0 byte[] bytes;
 254  0 byte b1, b2, b3, b4;
 255  0 int length = 0;
 256   
 257  0 int end = data.length();
 258   
 259  0 while (end > 0)
 260    {
 261  0 if (!ignore(data.charAt(end - 1)))
 262    {
 263  0 break;
 264    }
 265   
 266  0 end--;
 267    }
 268   
 269  0 int i = 0;
 270  0 int finish = end - 4;
 271   
 272  0 while (i < finish)
 273    {
 274  0 while ((i < finish) && ignore(data.charAt(i)))
 275    {
 276  0 i++;
 277    }
 278   
 279  0 b1 = decodingTable[data.charAt(i++)];
 280   
 281  0 while ((i < finish) && ignore(data.charAt(i)))
 282    {
 283  0 i++;
 284    }
 285  0 b2 = decodingTable[data.charAt(i++)];
 286   
 287  0 while ((i < finish) && ignore(data.charAt(i)))
 288    {
 289  0 i++;
 290    }
 291  0 b3 = decodingTable[data.charAt(i++)];
 292   
 293  0 while ((i < finish) && ignore(data.charAt(i)))
 294    {
 295  0 i++;
 296    }
 297  0 b4 = decodingTable[data.charAt(i++)];
 298   
 299  0 out.write((b1 << 2) | (b2 >> 4));
 300  0 out.write((b2 << 4) | (b3 >> 2));
 301  0 out.write((b3 << 6) | b4);
 302   
 303  0 length += 3;
 304    }
 305   
 306  0 if (data.charAt(end - 2) == padding)
 307    {
 308  0 b1 = decodingTable[data.charAt(end - 4)];
 309  0 b2 = decodingTable[data.charAt(end - 3)];
 310   
 311  0 out.write((b1 << 2) | (b2 >> 4));
 312   
 313  0 length += 1;
 314    }
 315  0 else if (data.charAt(end - 1) == padding)
 316    {
 317  0 b1 = decodingTable[data.charAt(end - 4)];
 318  0 b2 = decodingTable[data.charAt(end - 3)];
 319  0 b3 = decodingTable[data.charAt(end - 2)];
 320   
 321  0 out.write((b1 << 2) | (b2 >> 4));
 322  0 out.write((b2 << 4) | (b3 >> 2));
 323   
 324  0 length += 2;
 325    }
 326    else
 327    {
 328  0 b1 = decodingTable[data.charAt(end - 4)];
 329  0 b2 = decodingTable[data.charAt(end - 3)];
 330  0 b3 = decodingTable[data.charAt(end - 2)];
 331  0 b4 = decodingTable[data.charAt(end - 1)];
 332   
 333  0 out.write((b1 << 2) | (b2 >> 4));
 334  0 out.write((b2 << 4) | (b3 >> 2));
 335  0 out.write((b3 << 6) | b4);
 336   
 337  0 length += 3;
 338    }
 339   
 340  0 return length;
 341    }
 342   
 343    /**
 344    * decode the base 64 encoded byte data writing it to the provided byte array buffer.
 345    *
 346    * @return the number of bytes produced.
 347    */
 348  4 public int decode(byte[] data, int off, int length, byte[] out) throws IOException
 349    {
 350  4 byte[] bytes;
 351  4 byte b1, b2, b3, b4;
 352  4 int outLen = 0;
 353   
 354  4 int end = off + length;
 355   
 356  4 while (end > 0)
 357    {
 358  4 if (!ignore((char)data[end - 1]))
 359    {
 360  4 break;
 361    }
 362   
 363  0 end--;
 364    }
 365   
 366  4 int i = off;
 367  4 int finish = end - 4;
 368   
 369  4 while (i < finish)
 370    {
 371  254 while ((i < finish) && ignore((char)data[i]))
 372    {
 373  0 i++;
 374    }
 375   
 376  254 b1 = decodingTable[data[i++]];
 377   
 378  254 while ((i < finish) && ignore((char)data[i]))
 379    {
 380  0 i++;
 381    }
 382   
 383  254 b2 = decodingTable[data[i++]];
 384   
 385  254 while ((i < finish) && ignore((char)data[i]))
 386    {
 387  0 i++;
 388    }
 389   
 390  254 b3 = decodingTable[data[i++]];
 391   
 392  254 while ((i < finish) && ignore((char)data[i]))
 393    {
 394  0 i++;
 395    }
 396   
 397  254 b4 = decodingTable[data[i++]];
 398   
 399  254 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
 400  254 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
 401  254 out[outLen++] = (byte)((b3 << 6) | b4);
 402    }
 403   
 404  4 if (data[end - 2] == padding)
 405    {
 406  1 b1 = decodingTable[data[end - 4]];
 407  1 b2 = decodingTable[data[end - 3]];
 408   
 409  1 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
 410    }
 411  3 else if (data[end - 1] == padding)
 412    {
 413  1 b1 = decodingTable[data[end - 4]];
 414  1 b2 = decodingTable[data[end - 3]];
 415  1 b3 = decodingTable[data[end - 2]];
 416   
 417  1 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
 418  1 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
 419    }
 420    else
 421    {
 422  2 b1 = decodingTable[data[end - 4]];
 423  2 b2 = decodingTable[data[end - 3]];
 424  2 b3 = decodingTable[data[end - 2]];
 425  2 b4 = decodingTable[data[end - 1]];
 426   
 427  2 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
 428  2 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
 429  2 out[outLen++] = (byte)((b3 << 6) | b4);
 430    }
 431   
 432  4 return outLen;
 433    }
 434   
 435    /**
 436    * Test if a character is a valid Base64 encoding character. This
 437    * must be either a valid digit or the padding character ("=").
 438    *
 439    * @param ch The test character.
 440    *
 441    * @return true if this is valid in Base64 encoded data, false otherwise.
 442    */
 443  1056 public boolean isValidBase64(int ch) {
 444    // 'A' has the value 0 in the decoding table, so we need a special one for that
 445  1056 return ch == padding || ch == 'A' || decodingTable[ch] != 0;
 446    }
 447   
 448   
 449    /**
 450    * Perform RFC-2047 word encoding using Base64 data encoding.
 451    *
 452    * @param in The source for the encoded data.
 453    * @param charset The charset tag to be added to each encoded data section.
 454    * @param out The output stream where the encoded data is to be written.
 455    * @param fold Controls whether separate sections of encoded data are separated by
 456    * linebreaks or whitespace.
 457    *
 458    * @exception IOException
 459    */
 460  2 public void encodeWord(InputStream in, String charset, OutputStream out, boolean fold) throws IOException
 461    {
 462  2 PrintStream writer = new PrintStream(out);
 463   
 464    // encoded words are restricted to 76 bytes, including the control adornments.
 465  2 int limit = 76 - 7 - charset.length();
 466  2 boolean firstLine = true;
 467  2 StringBuffer encodedString = new StringBuffer(76);
 468   
 469  2 while (true) {
 470    // encode the next segment.
 471  4 encode(in, encodedString, limit);
 472    // if we're out of data, nothing will be encoded.
 473  4 if (encodedString.length() == 0) {
 474  2 break;
 475    }
 476   
 477    // if we have more than one segment, we need to insert separators. Depending on whether folding
 478    // was requested, this is either a blank or a linebreak.
 479  2 if (!firstLine) {
 480  0 if (fold) {
 481  0 writer.print("\r\n");
 482    }
 483    else {
 484  0 writer.print(" ");
 485    }
 486    }
 487   
 488    // add the encoded word header
 489  2 writer.print("=?");
 490  2 writer.print(charset);
 491  2 writer.print("?B?");
 492    // the data
 493  2 writer.print(encodedString.toString());
 494    // and the word terminator.
 495  2 writer.print("?=");
 496  2 writer.flush();
 497   
 498    // reset our string buffer for the next segment.
 499  2 encodedString.setLength(0);
 500    }
 501    }
 502   
 503    /**
 504    * encode the input data producing a base 64 output stream.
 505    *
 506    * @return the number of bytes produced.
 507    */
 508  4 public void encode(InputStream in, StringBuffer out, int limit) throws IOException
 509    {
 510  4 int count = limit / 4;
 511  4 byte [] inBuffer = new byte[3];
 512   
 513  14 while (count-- > 0) {
 514   
 515  14 int readCount = in.read(inBuffer);
 516    // did we get a full triplet? that's an easy encoding.
 517  14 if (readCount == 3) {
 518  10 int a1 = inBuffer[0] & 0xff;
 519  10 int a2 = inBuffer[1] & 0xff;
 520  10 int a3 = inBuffer[2] & 0xff;
 521   
 522  10 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
 523  10 out.append((char)encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
 524  10 out.append((char)encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
 525  10 out.append((char)encodingTable[a3 & 0x3f]);
 526   
 527    }
 528  4 else if (readCount <= 0) {
 529    // eof condition, don'e entirely.
 530  2 return;
 531    }
 532  2 else if (readCount == 1) {
 533  0 int a1 = inBuffer[0] & 0xff;
 534  0 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
 535  0 out.append((char)encodingTable[(a1 << 4) & 0x3f]);
 536  0 out.append((char)padding);
 537  0 out.append((char)padding);
 538  0 return;
 539    }
 540  2 else if (readCount == 2) {
 541  2 int a1 = inBuffer[0] & 0xff;
 542  2 int a2 = inBuffer[1] & 0xff;
 543   
 544  2 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
 545  2 out.append((char)encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
 546  2 out.append((char)encodingTable[(a2 << 2) & 0x3f]);
 547  2 out.append((char)padding);
 548  2 return;
 549    }
 550    }
 551    }
 552    }