KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > security > utils > Base64


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package com.sun.org.apache.xml.internal.security.utils;
18
19
20
21 import java.io.BufferedReader JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.StringReader JavaDoc;
26 import java.math.BigInteger JavaDoc;
27
28 import javax.xml.parsers.DocumentBuilder JavaDoc;
29 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
30
31 import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
32 import org.w3c.dom.Document JavaDoc;
33 import org.w3c.dom.Element JavaDoc;
34 import org.w3c.dom.Node JavaDoc;
35 import org.w3c.dom.Text JavaDoc;
36 import org.xml.sax.InputSource JavaDoc;
37
38
39 /**
40  * Implementation of MIME's Base64 encoding and decoding conversions.
41  * Optimized code. (raw version taken from oreilly.jonathan.util,
42  * and currently com.sun.org.apache.xerces.internal.ds.util.Base64)
43  *
44  * @author Raul Benito(Of the xerces copy, and little adaptations).
45  * @author Anli Shundi
46  * @author Christian Geuer-Pollmann
47  * @see <A HREF="ftp://ftp.isi.edu/in-notes/rfc2045.txt">RFC 2045</A>
48  * @see com.sun.org.apache.xml.internal.security.transforms.implementations.TransformBase64Decode
49  */

50 public class Base64 {
51
52    /** {@link java.util.logging} logging facility */
53     static java.util.logging.Logger JavaDoc log =
54         java.util.logging.Logger.getLogger(Base64.class.getName());
55
56
57    /** Field BASE64DEFAULTLENGTH */
58    public static final int BASE64DEFAULTLENGTH = 76;
59
60    /** Field _base64length */
61    static int _base64length = Base64.BASE64DEFAULTLENGTH;
62
63    private Base64() {
64      // we don't allow instantiation
65
}
66
67    /**
68     * Returns a byte-array representation of a <code>{@link BigInteger}<code>.
69     * No sign-bit is outputed.
70     *
71     * <b>N.B.:</B> <code>{@link BigInteger}<code>'s toByteArray
72     * retunrs eventually longer arrays because of the leading sign-bit.
73     *
74     * @param big <code>BigInteger<code> to be converted
75     * @param bitlen <code>int<code> the desired length in bits of the representation
76     * @return a byte array with <code>bitlen</code> bits of <code>big</code>
77     */

78    static byte[] getBytes(BigInteger JavaDoc big, int bitlen) {
79     
80       //round bitlen
81
bitlen = ((bitlen + 7) >> 3) << 3;
82
83       if (bitlen < big.bitLength()) {
84          throw new IllegalArgumentException JavaDoc(I18n
85             .translate("utils.Base64.IllegalBitlength"));
86       }
87
88       byte[] bigBytes = big.toByteArray();
89
90       if (((big.bitLength() % 8) != 0)
91               && (((big.bitLength() / 8) + 1) == (bitlen / 8))) {
92          return bigBytes;
93       }
94
95          // some copying needed
96
int startSrc = 0; // no need to skip anything
97
int bigLen = bigBytes.length; //valid length of the string
98

99          if ((big.bitLength() % 8) == 0) { // correct values
100
startSrc = 1; // skip sign bit
101

102             bigLen--; // valid length of the string
103
}
104
105          int startDst = bitlen / 8 - bigLen; //pad with leading nulls
106
byte[] resizedBytes = new byte[bitlen / 8];
107
108          System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen);
109
110          return resizedBytes;
111       
112    }
113
114    /**
115     * Encode in Base64 the given <code>{@link BigInteger}<code>.
116     *
117     * @param big
118     * @return String with Base64 encoding
119     */

120    public static String JavaDoc encode(BigInteger JavaDoc big) {
121       return encode(getBytes(big, big.bitLength()));
122    }
123
124    /**
125     * Returns a byte-array representation of a <code>{@link BigInteger}<code>.
126     * No sign-bit is outputed.
127     *
128     * <b>N.B.:</B> <code>{@link BigInteger}<code>'s toByteArray
129     * retunrs eventually longer arrays because of the leading sign-bit.
130     *
131     * @param big <code>BigInteger<code> to be converted
132     * @param bitlen <code>int<code> the desired length in bits of the representation
133     * @return a byte array with <code>bitlen</code> bits of <code>big</code>
134     */

135    public static byte[] encode(BigInteger JavaDoc big, int bitlen) {
136
137       //round bitlen
138
bitlen = ((bitlen + 7) >> 3) << 3;
139
140       if (bitlen < big.bitLength()) {
141          throw new IllegalArgumentException JavaDoc(I18n
142             .translate("utils.Base64.IllegalBitlength"));
143       }
144
145       byte[] bigBytes = big.toByteArray();
146
147       if (((big.bitLength() % 8) != 0)
148               && (((big.bitLength() / 8) + 1) == (bitlen / 8))) {
149          return bigBytes;
150       }
151
152          // some copying needed
153
int startSrc = 0; // no need to skip anything
154
int bigLen = bigBytes.length; //valid length of the string
155

156          if ((big.bitLength() % 8) == 0) { // correct values
157
startSrc = 1; // skip sign bit
158

159             bigLen--; // valid length of the string
160
}
161
162          int startDst = bitlen / 8 - bigLen; //pad with leading nulls
163
byte[] resizedBytes = new byte[bitlen / 8];
164
165          System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen);
166
167          return resizedBytes;
168       
169    }
170
171    /**
172     * Method decodeBigIntegerFromElement
173     *
174     * @param element
175     * @return the biginter obtained from the node
176     * @throws Base64DecodingException
177     */

178    public static BigInteger JavaDoc decodeBigIntegerFromElement(Element JavaDoc element) throws Base64DecodingException
179    {
180       return new BigInteger JavaDoc(1, Base64.decode(element));
181    }
182
183    /**
184     * Method decodeBigIntegerFromText
185     *
186     * @param text
187     * @return the biginter obtained from the text node
188     * @throws Base64DecodingException
189     */

190    public static BigInteger JavaDoc decodeBigIntegerFromText(Text JavaDoc text) throws Base64DecodingException
191    {
192       return new BigInteger JavaDoc(1, Base64.decode(text.getData()));
193    }
194
195    /**
196     * This method takes an (empty) Element and a BigInteger and adds the
197     * base64 encoded BigInteger to the Element.
198     *
199     * @param element
200     * @param biginteger
201     */

202    public static void fillElementWithBigInteger(Element JavaDoc element,
203            BigInteger JavaDoc biginteger) {
204
205       String JavaDoc encodedInt = encode(biginteger);
206
207       if (encodedInt.length() > 76) {
208          encodedInt = "\n" + encodedInt + "\n";
209       }
210
211       Document JavaDoc doc = element.getOwnerDocument();
212       Text JavaDoc text = doc.createTextNode(encodedInt);
213
214       element.appendChild(text);
215    }
216
217    /**
218     * Method decode
219     *
220     * Takes the <CODE>Text</CODE> children of the Element and interprets
221     * them as input for the <CODE>Base64.decode()</CODE> function.
222     *
223     * @param element
224     * @return the byte obtained of the decoding the element
225     * $todo$ not tested yet
226     * @throws Base64DecodingException
227     */

228    public static byte[] decode(Element JavaDoc element) throws Base64DecodingException {
229
230       Node JavaDoc sibling = element.getFirstChild();
231       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
232
233       while (sibling!=null) {
234          if (sibling.getNodeType() == Node.TEXT_NODE) {
235             Text JavaDoc t = (Text JavaDoc) sibling;
236
237             sb.append(t.getData());
238          }
239          sibling=sibling.getNextSibling();
240       }
241
242       return decode(sb.toString());
243    }
244
245    /**
246     * Method encodeToElement
247     *
248     * @param doc
249     * @param localName
250     * @param bytes
251     * @return an Element with the base64 encoded in the text.
252     *
253     */

254    public static Element JavaDoc encodeToElement(Document JavaDoc doc, String JavaDoc localName,
255                                          byte[] bytes) {
256
257       Element JavaDoc el = XMLUtils.createElementInSignatureSpace(doc, localName);
258       Text JavaDoc text = doc.createTextNode(encode(bytes));
259
260       el.appendChild(text);
261
262       return el;
263    }
264
265    /**
266     * Method decode
267     *
268     *
269     * @param base64
270     * @return the UTF bytes of the base64
271     * @throws Base64DecodingException
272     *
273     */

274    public static byte[] decode(byte[] base64) throws Base64DecodingException {
275          return decodeInternal(base64);
276    }
277
278
279
280    /**
281     * Encode a byte array and fold lines at the standard 76th character.
282     *
283     * @param binaryData <code>byte[]<code> to be base64 encoded
284     * @return the <code>String<code> with encoded data
285     */

286    public static String JavaDoc encode(byte[] binaryData) {
287         return encode(binaryData,BASE64DEFAULTLENGTH);
288    }
289    
290    /**
291     * Base64 decode the lines from the reader and return an InputStream
292     * with the bytes.
293     *
294     *
295     * @param reader
296     * @return InputStream with the decoded bytes
297     * @exception IOException passes what the reader throws
298     * @throws IOException
299     * @throws Base64DecodingException
300     */

301    public static byte[] decode(BufferedReader JavaDoc reader)
302            throws IOException JavaDoc, Base64DecodingException {
303
304       UnsyncByteArrayOutputStream baos = new UnsyncByteArrayOutputStream();
305       String JavaDoc line;
306
307       while (null != (line = reader.readLine())) {
308          byte[] bytes = decode(line);
309
310          baos.write(bytes);
311       }
312
313       return baos.toByteArray();
314    }
315
316    /**
317     * Method main
318     *
319     *
320     * @param args
321     *
322     * @throws Exception
323     */

324    public static void main(String JavaDoc[] args) throws Exception JavaDoc {
325
326       DocumentBuilderFactory JavaDoc docBuilderFactory =
327          DocumentBuilderFactory.newInstance();
328       DocumentBuilder JavaDoc docBuilder = docBuilderFactory.newDocumentBuilder();
329       String JavaDoc testString1 =
330          "<container><base64 value=\"Should be 'Hallo'\">SGFsbG8=</base64></container>";
331       InputSource JavaDoc inputSource = new InputSource JavaDoc(new StringReader JavaDoc(testString1));
332       Document JavaDoc doc = docBuilder.parse(inputSource);
333       Element JavaDoc base64Elem =
334          (Element JavaDoc) doc.getDocumentElement().getChildNodes().item(0);
335
336       System.out.println(new String JavaDoc(decode(base64Elem)));
337    }
338    static private final int BASELENGTH = 255;
339    static private final int LOOKUPLENGTH = 64;
340    static private final int TWENTYFOURBITGROUP = 24;
341    static private final int EIGHTBIT = 8;
342    static private final int SIXTEENBIT = 16;
343    static private final int FOURBYTE = 4;
344    static private final int SIGN = -128;
345    static private final char PAD = '=';
346    static private final boolean fDebug = false;
347    static final private byte [] base64Alphabet = new byte[BASELENGTH];
348    static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
349
350    static {
351
352        for (int i = 0; i<BASELENGTH; i++) {
353            base64Alphabet[i] = -1;
354        }
355        for (int i = 'Z'; i >= 'A'; i--) {
356            base64Alphabet[i] = (byte) (i-'A');
357        }
358        for (int i = 'z'; i>= 'a'; i--) {
359            base64Alphabet[i] = (byte) ( i-'a' + 26);
360        }
361
362        for (int i = '9'; i >= '0'; i--) {
363            base64Alphabet[i] = (byte) (i-'0' + 52);
364        }
365
366        base64Alphabet['+'] = 62;
367        base64Alphabet['/'] = 63;
368
369        for (int i = 0; i<=25; i++)
370            lookUpBase64Alphabet[i] = (char)('A'+i);
371
372        for (int i = 26, j = 0; i<=51; i++, j++)
373            lookUpBase64Alphabet[i] = (char)('a'+ j);
374
375        for (int i = 52, j = 0; i<=61; i++, j++)
376            lookUpBase64Alphabet[i] = (char)('0' + j);
377        lookUpBase64Alphabet[62] = '+';
378        lookUpBase64Alphabet[63] = '/';
379
380    }
381
382    protected static final boolean isWhiteSpace(byte octect) {
383        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
384    }
385
386    protected static final boolean isPad(byte octect) {
387        return (octect == PAD);
388    }
389
390
391    /**
392     * Encodes hex octects into Base64
393     *
394     * @param binaryData Array containing binaryData
395     * @return Encoded Base64 array
396     */

397    /**
398     * Encode a byte array in Base64 format and return an optionally
399     * wrapped line.
400     *
401     * @param binaryData <code>byte[]</code> data to be encoded
402     * @param length <code>int<code> length of wrapped lines; No wrapping if less than 4.
403     * @return a <code>String</code> with encoded data
404     */

405     public static String JavaDoc encode(byte[] binaryData,int length) {
406         
407         if (length<4) {
408             length=Integer.MAX_VALUE;
409         }
410
411        if (binaryData == null)
412            return null;
413
414        int lengthDataBits = binaryData.length*EIGHTBIT;
415        if (lengthDataBits == 0) {
416            return "";
417        }
418        
419        int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP;
420        int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP;
421        int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets;
422        int quartesPerLine = length/4;
423        int numberLines = (numberQuartet-1)/quartesPerLine;
424        char encodedData[] = null;
425
426        encodedData = new char[numberQuartet*4+numberLines];
427
428        byte k=0, l=0, b1=0,b2=0,b3=0;
429
430        int encodedIndex = 0;
431        int dataIndex = 0;
432        int i = 0;
433        if (fDebug) {
434            System.out.println("number of triplets = " + numberTriplets );
435        }
436
437        for (int line = 0; line < numberLines; line++) {
438            for (int quartet = 0; quartet < 19; quartet++) {
439                b1 = binaryData[dataIndex++];
440                b2 = binaryData[dataIndex++];
441                b3 = binaryData[dataIndex++];
442
443                if (fDebug) {
444                    System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
445                }
446
447                l = (byte)(b2 & 0x0f);
448                k = (byte)(b1 & 0x03);
449
450                byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
451
452                byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
453                byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
454
455                if (fDebug) {
456                    System.out.println( "val2 = " + val2 );
457                    System.out.println( "k4 = " + (k<<4));
458                    System.out.println( "vak = " + (val2 | (k<<4)));
459                }
460
461                encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
462                encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
463                encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
464                encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
465
466                i++;
467            }
468             encodedData[encodedIndex++] = 0xa;
469        }
470
471        for (; i<numberTriplets; i++) {
472            b1 = binaryData[dataIndex++];
473            b2 = binaryData[dataIndex++];
474            b3 = binaryData[dataIndex++];
475
476            if (fDebug) {
477                System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
478            }
479
480            l = (byte)(b2 & 0x0f);
481            k = (byte)(b1 & 0x03);
482
483            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
484
485            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
486            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
487
488            if (fDebug) {
489                System.out.println( "val2 = " + val2 );
490                System.out.println( "k4 = " + (k<<4));
491                System.out.println( "vak = " + (val2 | (k<<4)));
492            }
493
494            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
495            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
496            encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
497            encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
498        }
499
500        // form integral number of 6-bit groups
501
if (fewerThan24bits == EIGHTBIT) {
502            b1 = binaryData[dataIndex];
503            k = (byte) ( b1 &0x03 );
504            if (fDebug) {
505                System.out.println("b1=" + b1);
506                System.out.println("b1<<2 = " + (b1>>2) );
507            }
508            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
509            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
510            encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
511            encodedData[encodedIndex++] = PAD;
512            encodedData[encodedIndex++] = PAD;
513        } else if (fewerThan24bits == SIXTEENBIT) {
514            b1 = binaryData[dataIndex];
515            b2 = binaryData[dataIndex +1 ];
516            l = ( byte ) ( b2 &0x0f );
517            k = ( byte ) ( b1 &0x03 );
518
519            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
520            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
521
522            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
523            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
524            encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
525            encodedData[encodedIndex++] = PAD;
526        }
527
528        //encodedData[encodedIndex] = 0xa;
529

530        return new String JavaDoc(encodedData);
531    }
532
533    /**
534     * Decodes Base64 data into octects
535     *
536     * @param encoded Byte array containing Base64 data
537     * @return Array containind decoded data.
538     * @throws Base64DecodingException
539     */

540    public final static byte[] decode(String JavaDoc encoded) throws Base64DecodingException {
541
542        if (encoded == null)
543            return null;
544
545        return decodeInternal(encoded.getBytes());
546    }
547    protected final static byte[] decodeInternal(byte[] base64Data) throws Base64DecodingException {
548        // remove white spaces
549
int len = removeWhiteSpace(base64Data);
550        
551        if (len%FOURBYTE != 0) {
552            throw new Base64DecodingException("decoding.divisible.four");
553            //should be divisible by four
554
}
555
556        int numberQuadruple = (len/FOURBYTE );
557
558        if (numberQuadruple == 0)
559            return new byte[0];
560
561        byte decodedData[] = null;
562        byte b1=0,b2=0,b3=0, b4=0;
563
564
565        int i = 0;
566        int encodedIndex = 0;
567        int dataIndex = 0;
568        
569        //decodedData = new byte[ (numberQuadruple)*3];
570
dataIndex=(numberQuadruple-1)*4;
571        encodedIndex=(numberQuadruple-1)*3;
572        //first last bits.
573
b1 = base64Alphabet[base64Data[dataIndex++]];
574        b2 = base64Alphabet[base64Data[dataIndex++]];
575        if ((b1==-1) || (b2==-1)) {
576                 throw new Base64DecodingException("decoding.general");//if found "no data" just return null
577
}
578
579         
580         byte d3,d4;
581         b3 = base64Alphabet[d3=base64Data[dataIndex++]];
582         b4 = base64Alphabet[d4=base64Data[dataIndex++]];
583         if ((b3==-1 ) || (b4==-1) ) {
584             //Check if they are PAD characters
585
if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
586
if ((b2 & 0xf) != 0)//last 4 bits should be zero
587
throw new Base64DecodingException("decoding.general");
588                 decodedData = new byte[ encodedIndex + 1 ];
589                 decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ;
590             } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
591
if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
592
throw new Base64DecodingException("decoding.general");
593                 decodedData = new byte[ encodedIndex + 2 ];
594                 decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 );
595                 decodedData[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
596             } else {
597                 throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
598
}
599         } else {
600             //No PAD e.g 3cQl
601
decodedData = new byte[encodedIndex+3];
602             decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
603             decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
604             decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
605         }
606         encodedIndex=0;
607         dataIndex=0;
608        //the begin
609
for (i=numberQuadruple-1; i>0; i--) {
610            b1 = base64Alphabet[base64Data[dataIndex++]];
611            b2 = base64Alphabet[base64Data[dataIndex++]];
612            b3 = base64Alphabet[base64Data[dataIndex++]];
613            b4 = base64Alphabet[base64Data[dataIndex++]];
614
615            if ( (b1==-1) ||
616                 (b2==-1) ||
617                 (b3==-1) ||
618                 (b4==-1) ) {
619                throw new Base64DecodingException("decoding.general");//if found "no data" just return null
620
}
621                        
622            decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
623            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
624            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
625        }
626        return decodedData;
627    }
628    
629    /**
630     * Decodes Base64 data into outputstream
631     *
632     * @param base64Data Byte array containing Base64 data
633     * @param os the outputstream
634     * @throws IOException
635     * @throws Base64DecodingException
636     */

637    public final static void decode(byte[] base64Data,
638         OutputStream JavaDoc os) throws Base64DecodingException, IOException JavaDoc {
639     // remove white spaces
640
int len = removeWhiteSpace(base64Data);
641     
642     if (len%FOURBYTE != 0) {
643         throw new Base64DecodingException("decoding.divisible.four");
644         //should be divisible by four
645
}
646
647     int numberQuadruple = (len/FOURBYTE );
648
649     if (numberQuadruple == 0)
650         return;
651
652     //byte decodedData[] = null;
653
byte b1=0,b2=0,b3=0, b4=0;
654
655     int i = 0;
656
657     int dataIndex = 0;
658     
659     //the begin
660
for (i=numberQuadruple-1; i>0; i--) {
661         b1 = base64Alphabet[base64Data[dataIndex++]];
662         b2 = base64Alphabet[base64Data[dataIndex++]];
663         b3 = base64Alphabet[base64Data[dataIndex++]];
664         b4 = base64Alphabet[base64Data[dataIndex++]];
665         if ( (b1==-1) ||
666             (b2==-1) ||
667             (b3==-1) ||
668             (b4==-1) )
669          throw new Base64DecodingException("decoding.general");//if found "no data" just return null
670

671         
672
673         os.write((byte)( b1 <<2 | b2>>4 ) );
674         os.write((byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
675         os.write( (byte)( b3<<6 | b4 ));
676     }
677     b1 = base64Alphabet[base64Data[dataIndex++]];
678     b2 = base64Alphabet[base64Data[dataIndex++]];
679     
680     // first last bits.
681
if ((b1==-1) ||
682         (b2==-1) ){
683              throw new Base64DecodingException("decoding.general");//if found "no data" just return null
684
}
685
686      byte d3,d4;
687      b3= base64Alphabet[d3 = base64Data[dataIndex++]];
688      b4= base64Alphabet[d4 = base64Data[dataIndex++]];
689      if ((b3==-1 ) ||
690           (b4==-1) ) {//Check if they are PAD characters
691
if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
692
if ((b2 & 0xf) != 0)//last 4 bits should be zero
693
throw new Base64DecodingException("decoding.general");
694              os.write( (byte)( b1 <<2 | b2>>4 ) );
695          } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
696
if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
697
throw new Base64DecodingException("decoding.general");
698              os.write( (byte)( b1 <<2 | b2>>4 ));
699              os.write( (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
700          } else {
701              throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
702
}
703      } else {
704          //No PAD e.g 3cQl
705
os.write((byte)( b1 <<2 | b2>>4 ) );
706          os.write( (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
707          os.write((byte)( b3<<6 | b4 ));
708      }
709     return ;
710    }
711    
712    /**
713     * Decodes Base64 data into outputstream
714     *
715     * @param is containing Base64 data
716     * @param os the outputstream
717     * @throws IOException
718     * @throws Base64DecodingException
719     */

720    public final static void decode(InputStream JavaDoc is,
721         OutputStream JavaDoc os) throws Base64DecodingException, IOException JavaDoc {
722     //byte decodedData[] = null;
723
byte b1=0,b2=0,b3=0, b4=0;
724
725     int index=0;
726     byte []data=new byte[4];
727     int read;
728     //the begin
729
while ((read=is.read())>0) {
730         byte readed=(byte)read;
731         if (isWhiteSpace(readed)) {
732             continue;
733         }
734         if (isPad(readed)) {
735             data[index++]=readed;
736             if (index==3)
737                 data[index++]=(byte)is.read();
738             break;
739         }
740         
741         
742         if ((data[index++]=readed)==-1) {
743             throw new Base64DecodingException("decoding.general");//if found "no data" just return null
744
}
745         
746         if (index!=4) {
747             continue;
748         }
749         index=0;
750         b1 = base64Alphabet[data[0]];
751         b2 = base64Alphabet[data[1]];
752         b3 = base64Alphabet[data[2]];
753         b4 = base64Alphabet[data[3]];
754
755         os.write((byte)( b1 <<2 | b2>>4 ) );
756         os.write((byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
757         os.write( (byte)( b3<<6 | b4 ));
758     }
759     
760
761     byte d1=data[0],d2=data[1],d3=data[2], d4=data[3];
762     b1 = base64Alphabet[d1];
763     b2 = base64Alphabet[d2];
764     b3 = base64Alphabet[ d3 ];
765     b4 = base64Alphabet[ d4 ];
766      if ((b3==-1 ) ||
767          (b4==-1) ) {//Check if they are PAD characters
768
if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
769
if ((b2 & 0xf) != 0)//last 4 bits should be zero
770
throw new Base64DecodingException("decoding.general");
771              os.write( (byte)( b1 <<2 | b2>>4 ) );
772          } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
773
b3 = base64Alphabet[ d3 ];
774              if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
775
throw new Base64DecodingException("decoding.general");
776              os.write( (byte)( b1 <<2 | b2>>4 ));
777              os.write( (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
778          } else {
779              throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
780
}
781      } else {
782          //No PAD e.g 3cQl
783

784          os.write((byte)( b1 <<2 | b2>>4 ) );
785          os.write( (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ));
786          os.write((byte)( b3<<6 | b4 ));
787      }
788     
789     return ;
790    }
791    /**
792     * remove WhiteSpace from MIME containing encoded Base64 data.
793     *
794     * @param data the byte array of base64 data (with WS)
795     * @return the new length
796     */

797    protected static int removeWhiteSpace(byte[] data) {
798        if (data == null)
799            return 0;
800
801        // count characters that's not whitespace
802
int newSize = 0;
803        int len = data.length;
804        for (int i = 0; i < len; i++) {
805            byte dataS=data[i];
806            if (!isWhiteSpace(dataS))
807                data[newSize++] = dataS;
808        }
809        return newSize;
810    }
811 }
812
Popular Tags