/*========================================================================= Program: Visualization Toolkit Module: vtkBase64Utilities.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkBase64Utilities.h" #include "vtkObjectFactory.h" #include //------------------------------------------------------------------------------ vtkStandardNewMacro(vtkBase64Utilities); //------------------------------------------------------------------------------ void vtkBase64Utilities::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ static const unsigned char vtkBase64UtilitiesEncodeTable[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; //------------------------------------------------------------------------------ inline static unsigned char vtkBase64UtilitiesEncodeChar(unsigned char c) { assert(c < 65); return vtkBase64UtilitiesEncodeTable[c]; } //------------------------------------------------------------------------------ void vtkBase64Utilities::EncodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char* o0, unsigned char* o1, unsigned char* o2, unsigned char* o3) { *o0 = vtkBase64UtilitiesEncodeChar((i0 >> 2) & 0x3F); *o1 = vtkBase64UtilitiesEncodeChar(((i0 << 4) & 0x30) | ((i1 >> 4) & 0x0F)); *o2 = vtkBase64UtilitiesEncodeChar(((i1 << 2) & 0x3C) | ((i2 >> 6) & 0x03)); *o3 = vtkBase64UtilitiesEncodeChar(i2 & 0x3F); } //------------------------------------------------------------------------------ void vtkBase64Utilities::EncodePair(unsigned char i0, unsigned char i1, unsigned char* o0, unsigned char* o1, unsigned char* o2, unsigned char* o3) { *o0 = vtkBase64UtilitiesEncodeChar((i0 >> 2) & 0x3F); *o1 = vtkBase64UtilitiesEncodeChar(((i0 << 4) & 0x30) | ((i1 >> 4) & 0x0F)); *o2 = vtkBase64UtilitiesEncodeChar(((i1 << 2) & 0x3C)); *o3 = '='; } //------------------------------------------------------------------------------ void vtkBase64Utilities::EncodeSingle( unsigned char i0, unsigned char* o0, unsigned char* o1, unsigned char* o2, unsigned char* o3) { *o0 = vtkBase64UtilitiesEncodeChar((i0 >> 2) & 0x3F); *o1 = vtkBase64UtilitiesEncodeChar(((i0 << 4) & 0x30)); *o2 = '='; *o3 = '='; } //------------------------------------------------------------------------------ unsigned long vtkBase64Utilities::Encode( const unsigned char* input, unsigned long length, unsigned char* output, int mark_end) { const unsigned char* ptr = input; const unsigned char* end = input + length; unsigned char* optr = output; // Encode complete triplet while ((end - ptr) >= 3) { vtkBase64Utilities::EncodeTriplet( ptr[0], ptr[1], ptr[2], &optr[0], &optr[1], &optr[2], &optr[3]); ptr += 3; optr += 4; } // Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. if (end - ptr == 2) { vtkBase64Utilities::EncodePair(ptr[0], ptr[1], &optr[0], &optr[1], &optr[2], &optr[3]); optr += 4; } // Encodes a 1-byte ending into 2 bytes and 2 pad bytes else if (end - ptr == 1) { vtkBase64Utilities::EncodeSingle(ptr[0], &optr[0], &optr[1], &optr[2], &optr[3]); optr += 4; } // Do we need to mark the end else if (mark_end) { optr[0] = optr[1] = optr[2] = optr[3] = '='; optr += 4; } return optr - output; } //------------------------------------------------------------------------------ static const unsigned char vtkBase64UtilitiesDecodeTable[256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, // 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, // 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // //------------------------------------- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // }; //------------------------------------------------------------------------------ inline static unsigned char vtkBase64UtilitiesDecodeChar(unsigned char c) { return vtkBase64UtilitiesDecodeTable[c]; } //------------------------------------------------------------------------------ int vtkBase64Utilities::DecodeTriplet(unsigned char i0, unsigned char i1, unsigned char i2, unsigned char i3, unsigned char* o0, unsigned char* o1, unsigned char* o2) { unsigned char d0, d1, d2, d3; d0 = vtkBase64UtilitiesDecodeChar(i0); d1 = vtkBase64UtilitiesDecodeChar(i1); d2 = vtkBase64UtilitiesDecodeChar(i2); d3 = vtkBase64UtilitiesDecodeChar(i3); // Make sure all characters were valid if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) { return 0; } // Decode the 3 bytes *o0 = ((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03); *o1 = ((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F); *o2 = ((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F); // Return the number of bytes actually decoded if (i2 == '=') { return 1; } if (i3 == '=') { return 2; } return 3; } //------------------------------------------------------------------------------ size_t vtkBase64Utilities::DecodeSafely( const unsigned char* input, size_t inputLen, unsigned char* output, size_t outputLen) { assert(input); assert(output); // Nonsense small input or no space for any output if ((inputLen < 4) || (outputLen == 0)) { return 0; } // Consume 4 ASCII chars of input at a time, until less than 4 left size_t inIdx = 0, outIdx = 0; while (inIdx <= inputLen - 4) { // Decode 4 ASCII characters into 0, 1, 2, or 3 bytes unsigned char o0, o1, o2; int bytesDecoded = vtkBase64Utilities::DecodeTriplet( input[inIdx + 0], input[inIdx + 1], input[inIdx + 2], input[inIdx + 3], &o0, &o1, &o2); assert((bytesDecoded >= 0) && (bytesDecoded <= 3)); if ((bytesDecoded >= 1) && (outIdx < outputLen)) { output[outIdx++] = o0; } if ((bytesDecoded >= 2) && (outIdx < outputLen)) { output[outIdx++] = o1; } if ((bytesDecoded >= 3) && (outIdx < outputLen)) { output[outIdx++] = o2; } // If fewer than 3 bytes resulted from decoding (in this pass), // then the input stream has nothing else decodable, so end. if (bytesDecoded < 3) { return outIdx; } // Consumed a whole 4 of input and got 3 bytes of output, continue inIdx += 4; assert(bytesDecoded == 3); } return outIdx; }