GME  13
Base64.cpp
Go to the documentation of this file.
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to You under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at
00008  * 
00009  *      http://www.apache.org/licenses/LICENSE-2.0
00010  * 
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 // ---------------------------------------------------------------------------
00019 //  Includes
00020 // ---------------------------------------------------------------------------
00021 #include <xercesc/util/Base64.hpp>
00022 #include <xercesc/util/XMLString.hpp>
00023 #include <xercesc/util/Janitor.hpp>
00024 #include <xercesc/internal/XMLReader.hpp>
00025 #include <xercesc/framework/MemoryManager.hpp>
00026 
00027 XERCES_CPP_NAMESPACE_BEGIN
00028 
00029 // ---------------------------------------------------------------------------
00030 //  constants
00031 // ---------------------------------------------------------------------------
00032 static const int BASELENGTH = 255;
00033 static const int FOURBYTE   = 4;
00034 
00035 // ---------------------------------------------------------------------------
00036 //  class data member
00037 // ---------------------------------------------------------------------------
00038 
00039 // the base64 alphabet according to definition in RFC 2045
00040 const XMLByte Base64::base64Alphabet[] = {
00041     chLatin_A, chLatin_B, chLatin_C, chLatin_D, chLatin_E,
00042     chLatin_F, chLatin_G, chLatin_H, chLatin_I, chLatin_J,
00043     chLatin_K, chLatin_L, chLatin_M, chLatin_N, chLatin_O,
00044     chLatin_P, chLatin_Q, chLatin_R, chLatin_S, chLatin_T,
00045     chLatin_U, chLatin_V, chLatin_W, chLatin_X, chLatin_Y, chLatin_Z,
00046     chLatin_a, chLatin_b, chLatin_c, chLatin_d, chLatin_e,
00047     chLatin_f, chLatin_g, chLatin_h, chLatin_i, chLatin_j,
00048     chLatin_k, chLatin_l, chLatin_m, chLatin_n, chLatin_o,
00049     chLatin_p, chLatin_q, chLatin_r, chLatin_s, chLatin_t,
00050     chLatin_u, chLatin_v, chLatin_w, chLatin_x, chLatin_y, chLatin_z,
00051     chDigit_0, chDigit_1, chDigit_2, chDigit_3, chDigit_4,
00052     chDigit_5, chDigit_6, chDigit_7, chDigit_8, chDigit_9,
00053     chPlus, chForwardSlash, chNull
00054 };
00055 
00056 // This is an inverse table for base64 decoding.  So, if
00057 // base64Alphabet[17] = 'R', then base64Inverse['R'] = 17.
00058 //
00059 // For characters not in base64Alphabet then
00060 // base64Inverse[ch] = 0xFF.
00061 const XMLByte Base64::base64Inverse[BASELENGTH] =
00062 {
00063     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00064     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00065     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F,
00066     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00067     0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
00068     0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00069     0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
00070     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00071     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00072     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00073     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00074     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00075     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00076     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00077     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
00078     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
00079 };
00080 
00081 const XMLByte Base64::base64Padding = chEqual;
00082 
00083 /***
00084  *
00085  * Memory Management Issue:
00086  *
00087  * . For memory allocated for result returned to caller (external memory), 
00088  *   the plugged memory manager is used if it is provided, otherwise global 
00089  *   new used to retain the pre-memory-manager behaviour.
00090  *
00091  * . For memory allocated for temperary buffer (internal memory), 
00092  *   XMLPlatformUtils::fgMemoryManager is used.
00093  *
00094  */
00095 
00096 static void* getExternalMemory(  MemoryManager* const allocator
00097                                , XMLSize_t const   sizeToAllocate)
00098 {
00099    return allocator ? allocator->allocate(sizeToAllocate)
00100        : ::operator new(sizeToAllocate);
00101 }
00102 
00103 /***
00104  * internal memory is deallocated by janitorArray
00105  */ 
00106 static void returnExternalMemory(  MemoryManager* const allocator
00107                                  , void*                buffer)
00108 {
00109     allocator ? allocator->deallocate(buffer)
00110         : ::operator delete(buffer);
00111 }
00112 
00138 // number of quadruplets per one line ( must be >1 and <19 )
00139 const unsigned int Base64::quadsPerLine = 15;
00140 
00141 XMLByte* Base64::encode(const XMLByte* const inputData
00142                       , const XMLSize_t      inputLength
00143                       , XMLSize_t*           outputLength                      
00144                       , MemoryManager* const memMgr)
00145 {
00146     if (!inputData || !outputLength)
00147         return 0;
00148 
00149     int quadrupletCount = ( (int)inputLength + 2 ) / 3;
00150     if (quadrupletCount == 0)
00151         return 0;
00152 
00153     // number of rows in encoded stream ( including the last one )
00154     int lineCount = ( quadrupletCount + quadsPerLine-1 ) / quadsPerLine;
00155 
00156     //
00157     // convert the triplet(s) to quadruplet(s)
00158     //
00159     XMLByte  b1, b2, b3, b4;  // base64 binary codes ( 0..63 )
00160 
00161     XMLSize_t inputIndex = 0;
00162     XMLSize_t outputIndex = 0;
00163     XMLByte *encodedData = (XMLByte*) getExternalMemory(memMgr, (quadrupletCount*FOURBYTE+lineCount+1) * sizeof(XMLByte));
00164 
00165     //
00166     // Process all quadruplet(s) except the last
00167     //
00168     int quad = 1;
00169     for (; quad <= quadrupletCount-1; quad++ )
00170     {
00171         // read triplet from the input stream
00172         split1stOctet( inputData[ inputIndex++ ], b1, b2 );
00173         split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
00174         split3rdOctet( inputData[ inputIndex++ ], b3, b4 );
00175 
00176         // write quadruplet to the output stream
00177         encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];
00178         encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
00179         encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
00180         encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];
00181 
00182         if (( quad % quadsPerLine ) == 0 )
00183             encodedData[ outputIndex++ ] = chLF;
00184     }
00185 
00186     //
00187     // process the last Quadruplet
00188     //
00189     // first octet is present always, process it
00190     split1stOctet( inputData[ inputIndex++ ], b1, b2 );
00191     encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];
00192 
00193     if( inputIndex < inputLength )
00194     {
00195         // second octet is present, process it
00196         split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
00197         encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
00198 
00199         if( inputIndex < inputLength )
00200         {
00201             // third octet present, process it
00202             // no PAD e.g. 3cQl
00203             split3rdOctet( inputData[ inputIndex++ ], b3, b4 );
00204             encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
00205             encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];
00206         }
00207         else
00208         {
00209             // third octet not present
00210             // one PAD e.g. 3cQ=
00211             encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
00212             encodedData[ outputIndex++ ] = base64Padding;
00213         }
00214     }
00215     else
00216     {
00217         // second octet not present
00218         // two PADs e.g. 3c==
00219         encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
00220         encodedData[ outputIndex++ ] = base64Padding;
00221         encodedData[ outputIndex++ ] = base64Padding;
00222     }
00223 
00224     // write out end of the last line
00225     encodedData[ outputIndex++ ] = chLF;
00226     // write out end of string
00227     encodedData[ outputIndex ] = 0;
00228 
00229     *outputLength = outputIndex;
00230 
00231     return encodedData;
00232 }
00233 
00234 //
00235 // delete the buffer allocated by decode() if
00236 // decoding is successfully done.
00237 //
00238 // In previous version, we use XMLString::strLen(decodedData)
00239 // to get the length, this will fail for test case containing
00240 // consequtive "A", such "AAFF", or "ab56AA56". Instead of
00241 // returning 3/6, we have 0 and 3, indicating that "AA", after
00242 // decoded, is interpreted as <null> by the strLen().
00243 //
00244 // Since decode() has track of length of the decoded data, we
00245 // will get this length from decode(), instead of strLen().
00246 //
00247 int Base64::getDataLength(const XMLCh*         const inputData
00248                         ,       MemoryManager* const manager
00249                         ,       Conformance          conform )
00250 
00251 {
00252     XMLSize_t retLen = 0;
00253     XMLByte* decodedData = decodeToXMLByte(inputData, &retLen, manager, conform);
00254 
00255     if ( !decodedData )
00256         return -1;
00257     else
00258     {
00259         returnExternalMemory(manager, decodedData);
00260         return (int)retLen;
00261     }
00262 }
00263 
00264 XMLByte* Base64::decode(const XMLByte*       const  inputData
00265                       ,       XMLSize_t*            decodedLength
00266                       ,       MemoryManager* const  memMgr
00267                       ,       Conformance           conform )
00268 {
00269     XMLByte* canRepInByte = 0;
00270     XMLByte* retStr = decode(
00271                               inputData
00272                             , decodedLength
00273                             , canRepInByte
00274                             , memMgr
00275                             , conform);
00276 
00277     /***
00278      * Release the canRepData
00279      */ 
00280     if (retStr)
00281         returnExternalMemory(memMgr, canRepInByte);
00282 
00283     return retStr;
00284 }
00285 
00286 
00287 XMLByte* Base64::decodeToXMLByte(const XMLCh*         const   inputData
00288                                 ,      XMLSize_t*             decodedLen
00289                                 ,      MemoryManager* const   memMgr
00290                                 ,      Conformance            conform )
00291 {
00292     if (!inputData || !*inputData)
00293         return 0;
00294 
00295     /***
00296      *  Move input data to a XMLByte buffer
00297      */
00298     XMLSize_t srcLen = XMLString::stringLen(inputData);
00299     XMLByte *dataInByte = (XMLByte*) getExternalMemory(memMgr, (srcLen+1) * sizeof(XMLByte));
00300     ArrayJanitor<XMLByte> janFill(dataInByte, memMgr ? memMgr : XMLPlatformUtils::fgMemoryManager);
00301 
00302     for (XMLSize_t i = 0; i < srcLen; i++)
00303         dataInByte[i] = (XMLByte)inputData[i];
00304 
00305     dataInByte[srcLen] = 0;
00306 
00307     /***
00308      * Forward to the actual decoding method to do the decoding
00309      */
00310     *decodedLen = 0;
00311     return decode(dataInByte, decodedLen, memMgr, conform);
00312 }
00313 
00314 /***
00315 * E2-54
00316 *
00317 * Canonical-base64Binary ::= (B64 B64 B64 B64)*((B64 B64 B16 '=')|(B64 B04 '=='))? 
00318 * B04                    ::= [AQgw]
00319 * B16                    ::= [AEIMQUYcgkosw048]
00320 * B64                    ::= [A-Za-z0-9+/] 
00321 *
00322 ***/
00323 XMLCh* Base64::getCanonicalRepresentation(const XMLCh*         const   inputData
00324                                         ,       MemoryManager* const   memMgr
00325                                         ,       Conformance            conform)
00326     
00327 {
00328     if (!inputData || !*inputData) 
00329         return 0;
00330 
00331     /***
00332      *  Move input data to a XMLByte buffer
00333      */
00334     XMLSize_t srcLen = XMLString::stringLen(inputData);
00335     XMLByte *dataInByte = (XMLByte*) getExternalMemory(memMgr, (srcLen+1) * sizeof(XMLByte));
00336     ArrayJanitor<XMLByte> janFill(dataInByte, memMgr ? memMgr : XMLPlatformUtils::fgMemoryManager);
00337 
00338     for (XMLSize_t i = 0; i < srcLen; i++)
00339         dataInByte[i] = (XMLByte)inputData[i];
00340 
00341     dataInByte[srcLen] = 0;
00342 
00343     /***
00344      * Forward to the actual decoding method to do the decoding
00345      */
00346     XMLSize_t decodedLength = 0;
00347     XMLByte*     canRepInByte = 0;
00348     XMLByte*     retStr = decode(
00349                               dataInByte
00350                             , &decodedLength
00351                             , canRepInByte
00352                             , memMgr
00353                             , conform);
00354 
00355     if (!retStr)
00356         return 0;
00357 
00358     /***
00359      * Move canonical representation to a XMLCh buffer to return
00360      */
00361     XMLSize_t canRepLen = XMLString::stringLen((char*)canRepInByte);
00362     XMLCh *canRepData = (XMLCh*) getExternalMemory(memMgr, (canRepLen + 1) * sizeof(XMLCh));
00363                
00364     for (XMLSize_t j = 0; j < canRepLen; j++)
00365         canRepData[j] = (XMLCh)canRepInByte[j];
00366 
00367     canRepData[canRepLen] = 0;
00368 
00369     /***
00370      * Release the memory allocated in the actual decoding method
00371      */ 
00372     returnExternalMemory(memMgr, retStr);
00373     returnExternalMemory(memMgr, canRepInByte);
00374 
00375     return canRepData;
00376 }
00377 // -----------------------------------------------------------------------
00378 //  Helper methods
00379 // -----------------------------------------------------------------------
00380 
00381 //
00382 // return 0(null) if invalid data found.
00383 // return the buffer containning decoded data otherwise
00384 // the caller is responsible for the de-allocation of the
00385 // buffer returned.
00386 //
00387 // temporary data, rawInputData, is ALWAYS released by this function.
00388 //
00389 
00390 /***
00391  *     E2-9
00392  *
00393  *     Base64Binary ::= S? B64quartet* B64final?
00394  *
00395  *     B64quartet   ::= B64 S? B64 S? B64 S? B64 S?
00396  *
00397  *     B64final     ::= B64 S? B04 S? '=' S? '=' S?
00398  *                    | B64 S? B64 S? B16 S? '=' S?
00399  *
00400  *     B04          ::= [AQgw]
00401  *     B16          ::= [AEIMQUYcgkosw048]
00402  *     B64          ::= [A-Za-z0-9+/]
00403  *
00404  *
00405  *     E2-54
00406  *
00407  *     Base64Binary  ::=  ((B64S B64S B64S B64S)*
00408  *                         ((B64S B64S B64S B64) |
00409  *                          (B64S B64S B16S '=') |
00410  *                          (B64S B04S '=' #x20? '=')))?
00411  *
00412  *     B64S         ::= B64 #x20?
00413  *     B16S         ::= B16 #x20?
00414  *     B04S         ::= B04 #x20?
00415  *
00416  *
00417  *     Note that this grammar requires the number of non-whitespace characters 
00418  *     in the lexical form to be a multiple of four, and for equals signs to 
00419  *     appear only at the end of the lexical form; strings which do not meet these 
00420  *     constraints are not legal lexical forms of base64Binary because they 
00421  *     cannot successfully be decoded by base64 decoders.
00422  * 
00423  *     Note: 
00424  *     The above definition of the lexical space is more restrictive than that given 
00425  *     in [RFC 2045] as regards whitespace -- this is not an issue in practice. Any 
00426  *     string compatible with the RFC can occur in an element or attribute validated 
00427  *     by this type, because the whiteSpace facet of this type is fixed to collapse, 
00428  *     which means that all leading and trailing whitespace will be stripped, and all 
00429  *     internal whitespace collapsed to single space characters, before the above grammar 
00430  *     is enforced.
00431  *
00432 */
00433 
00434 XMLByte* Base64::decode (   const XMLByte*        const   inputData
00435                           ,       XMLSize_t*              decodedLength
00436                           ,       XMLByte*&               canRepData
00437                           ,       MemoryManager*  const   memMgr
00438                           ,       Conformance             conform
00439                         )
00440 {
00441     if ((!inputData) || (!*inputData))
00442         return 0;
00443     
00444     //
00445     // remove all XML whitespaces from the base64Data
00446     //
00447     XMLSize_t inputLength = XMLString::stringLen( (const char*)inputData );
00448     XMLByte* rawInputData = (XMLByte*) getExternalMemory(memMgr, (inputLength+1) * sizeof(XMLByte));
00449     ArrayJanitor<XMLByte> jan(rawInputData, memMgr ? memMgr : XMLPlatformUtils::fgMemoryManager);
00450 
00451     XMLSize_t inputIndex = 0;
00452     XMLSize_t rawInputLength = 0;
00453     bool inWhiteSpace = false;
00454 
00455     switch (conform)
00456     {
00457     case Conf_RFC2045:
00458         while ( inputIndex < inputLength )
00459         {
00460             if (!XMLChar1_0::isWhitespace(inputData[inputIndex]))
00461             {
00462                 rawInputData[ rawInputLength++ ] = inputData[ inputIndex ];
00463             }
00464             // RFC2045 does not explicitly forbid more than ONE whitespace 
00465             // before, in between, or after base64 octects.
00466             // Besides, S? allows more than ONE whitespace as specified in the production 
00467             // [3]   S   ::=   (#x20 | #x9 | #xD | #xA)+
00468             // therefore we do not detect multiple ws
00469 
00470             inputIndex++;
00471         }
00472 
00473         break;
00474     case Conf_Schema:
00475         // no leading #x20
00476         if (chSpace == inputData[inputIndex])
00477             return 0;
00478 
00479         while ( inputIndex < inputLength )
00480         {
00481             if (chSpace != inputData[inputIndex])
00482             {
00483                 rawInputData[ rawInputLength++ ] = inputData[ inputIndex ];
00484                 inWhiteSpace = false;
00485             }
00486             else
00487             {
00488                 if (inWhiteSpace)
00489                     return 0; // more than 1 #x20 encountered
00490                 else
00491                     inWhiteSpace = true;
00492             }
00493 
00494             inputIndex++;
00495         }
00496 
00497         // no trailing #x20
00498         if (inWhiteSpace)
00499             return 0;
00500 
00501         break;
00502 
00503     default:
00504         break;
00505     }
00506 
00507     //now rawInputData contains canonical representation 
00508     //if the data is valid Base64
00509     rawInputData[ rawInputLength ] = 0;
00510 
00511     // the length of raw data should be divisible by four
00512     if (( rawInputLength % FOURBYTE ) != 0 )
00513         return 0;
00514 
00515     int quadrupletCount = (int)rawInputLength / FOURBYTE;
00516     if ( quadrupletCount == 0 )
00517         return 0;
00518 
00519     //
00520     // convert the quadruplet(s) to triplet(s)
00521     //
00522     XMLByte  d1, d2, d3, d4;  // base64 characters
00523     XMLByte  b1, b2, b3, b4;  // base64 binary codes ( 0..64 )
00524 
00525     XMLSize_t rawInputIndex  = 0;
00526     XMLSize_t outputIndex    = 0;
00527     XMLByte *decodedData = (XMLByte*) getExternalMemory(memMgr, (quadrupletCount*3+1) * sizeof(XMLByte));
00528 
00529     //
00530     // Process all quadruplet(s) except the last
00531     //
00532     int quad = 1;
00533     for (; quad <= quadrupletCount-1; quad++ )
00534     {
00535         // read quadruplet from the input stream
00536         if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
00537             !isData( (d2 = rawInputData[ rawInputIndex++ ]) ) ||
00538             !isData( (d3 = rawInputData[ rawInputIndex++ ]) ) ||
00539             !isData( (d4 = rawInputData[ rawInputIndex++ ]) ))
00540         {
00541             // if found "no data" just return NULL
00542             returnExternalMemory(memMgr, decodedData);
00543             return 0;
00544         }
00545 
00546         b1 = base64Inverse[ d1 ];
00547         b2 = base64Inverse[ d2 ];
00548         b3 = base64Inverse[ d3 ];
00549         b4 = base64Inverse[ d4 ];
00550 
00551         // write triplet to the output stream
00552         decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
00553         decodedData[ outputIndex++ ] = set2ndOctet(b2, b3);
00554         decodedData[ outputIndex++ ] = set3rdOctet(b3, b4);
00555     }
00556 
00557     //
00558     // process the last Quadruplet
00559     //
00560     // first two octets are present always, process them
00561     if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
00562         !isData( (d2 = rawInputData[ rawInputIndex++ ]) ))
00563     {
00564         // if found "no data" just return NULL
00565         returnExternalMemory(memMgr, decodedData);
00566         return 0;
00567     }
00568 
00569     b1 = base64Inverse[ d1 ];
00570     b2 = base64Inverse[ d2 ];
00571 
00572     // try to process last two octets
00573     d3 = rawInputData[ rawInputIndex++ ];
00574     d4 = rawInputData[ rawInputIndex++ ];
00575 
00576     if (!isData( d3 ) || !isData( d4 ))
00577     {
00578         // check if last two are PAD characters
00579         if (isPad( d3 ) && isPad( d4 ))
00580         {
00581             // two PAD e.g. 3c==
00582             if ((b2 & 0xf) != 0) // last 4 bits should be zero
00583             {
00584                 returnExternalMemory(memMgr, decodedData);
00585                 return 0;
00586             }
00587 
00588             decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
00589         }
00590         else if (!isPad( d3 ) && isPad( d4 ))
00591         {
00592             // one PAD e.g. 3cQ=
00593             b3 = base64Inverse[ d3 ];
00594             if (( b3 & 0x3 ) != 0 ) // last 2 bits should be zero
00595             {
00596                 returnExternalMemory(memMgr, decodedData);
00597                 return 0;
00598             }
00599 
00600             decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
00601             decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
00602         }
00603         else
00604         {
00605             // an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
00606             returnExternalMemory(memMgr, decodedData);
00607             return 0;
00608         }
00609     }
00610     else
00611     {
00612         // no PAD e.g 3cQl
00613         b3 = base64Inverse[ d3 ];
00614         b4 = base64Inverse[ d4 ];
00615         decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
00616         decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
00617         decodedData[ outputIndex++ ] = set3rdOctet( b3, b4 );
00618     }
00619 
00620     // write out the end of string
00621     decodedData[ outputIndex ] = 0;
00622     *decodedLength = outputIndex;
00623 
00624     //allow the caller to have access to the canonical representation
00625     jan.release(); 
00626     canRepData = rawInputData;
00627 
00628     return decodedData;
00629 }
00630 
00631 bool Base64::isData(const XMLByte& octet)
00632 {
00633     return (base64Inverse[octet]!=(XMLByte)-1);
00634 }
00635 
00636 XERCES_CPP_NAMESPACE_END