// // Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// #include "opennurbs.h" #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif ////////////////////////////////////////////////////////////////////////////////////////// // // ON_DecodeBase64 // ON_DecodeBase64::ON_DecodeBase64() { Begin(); } ON_DecodeBase64::~ON_DecodeBase64() { Begin(); } void ON_DecodeBase64::Begin() { m_decode_count = 0; m_output_count = 0; memset(m_output,0,512); m_status = 0; m_cache_count = 0; m_cache[0] = 0; m_cache[1] = 0; m_cache[2] = 0; m_cache[3] = 0; } bool ON_DecodeBase64::End() { if ( 0 != m_status ) { if ( 3 == m_status || 4 == m_status ) { if ( 0 != m_output_count ) SetError(); // all output should have been flushed else m_status = 5; // finished } else if ( 1 != m_status ) SetError(); } else { if ( m_output_count > 0 ) { Output(); m_output_count = 0; } m_status = 5; // finished } m_output_count = 0; memset(m_output,0,512); return ( 1 != m_status ); } void ON_DecodeBase64::SetError() { // unrecoverable error ON_ERROR("ON_DecodeBase64::Decode - error"); m_status = 1; } const bool ON_DecodeBase64::Error() const { return (1 == m_status); } void ON_DecodeBase64::DecodeHelper1() { // Send the last byte of decoded output when the // last 4 bytes of the base64 encoded string are "**==" // This function is called at most one time to // decode the last base 64 quartet into the final // byte of output. union { ON__INT32 i; unsigned char b[4]; } u; m_status = 0; if ( m_output_count >= 512 ) { Output(); m_output_count = 0; } u.i = 4*m_cache[0] + m_cache[1]/16; m_output[m_output_count++] = u.b[0]; Output(); m_output_count = 0; } void ON_DecodeBase64::DecodeHelper2() { // Send the last 2 bytes of decoded output when the // last 4 bytes of base64 encoded string are "***=". // This function is called at most one time to // decode the last base 64 quartet into the final // two bytes of output. union { ON__INT32 i; unsigned char b[4]; } u; m_status = 0; if ( m_output_count >= 511 ) { Output(); m_output_count = 0; } u.i = 1024*m_cache[0] + 16*m_cache[1] + m_cache[2]/4; m_output[m_output_count++] = u.b[1]; m_output[m_output_count++] = u.b[0]; Output(); m_output_count = 0; } const char* ON_DecodeBase64::Decode(const char* base64str) { union { ON__INT32 i; unsigned char b[4]; } u; ON__INT32 i; unsigned char* outbuf; //#if defined(_DEBUG) // if ( m_cache_count < 0 // || m_cache_count >= 4 // || m_cache_count != (m_decode_count % 4) // ) // { // // algorithm error // SetError(); // return 0; // } //#endif if ( m_status ) { // rarely executed code if ( 1 == m_status ) { return 0; } if ( base64str ) { i = *base64str; if (i >= 65 && i <= 90) i = 1; else if (i >= 97 && i <= 122) i = 1; else if (i >= 48 && i <= 57) i = 1; else if ('+' == i) i = 1; else if ('/' == i) i = 1; else if ('=' == i) i = -1; else { return 0; } if ( 2 != m_status || -1 != m_cache[2] ) { SetError(); return 0; } if ( -1 != i ) { // base64 encoded strings are parsed in groups of 4 characters. // When we enter this part of the Decode function, m_status is // either 1 (error occured earlier) or 2. // A 2 means the previous character we parsed was the 3rd // of the group and it was an equal sign. In this case, the // the 4th character in the group must be an equal sign and // the group encodes a single byte. SetError(); return 0; } } } if (!base64str) return 0; outbuf = m_output+m_output_count; for(;;) { while ( m_cache_count < 4 ) { // base 64 encodes 3 bytes as a 4 digit base 64 number. // The base 64 "digits" are A-z,a-z,0-9,+ and /. The // values of these "digits" are listed below. // 'A' -> 0 // ... // 'Z' -> 25 // 'a' -> 26 // ... // 'z' -> 51 // '0' -> 52 // ... // '9' -> 61 // '+' -> 62 // '/' -> 63 // '=' padding used to encode the last one or two bytes // If the 3rd and 4th characters in the quartet are // equal signs, the quartet represents a single byte // as a 2 digit base 64 number. // If the 4th character in the quartet is an equal sign, // the quartet represents two bytes as a 3 digit // base 64 number. i = *base64str++; if (i >= 65 && i <= 90) i -= 65; else if (i >= 97 && i <= 122) i -= 71; else if (i >= 48 && i <= 57) i += 4; else if ('+' == i) i = 62; else if ('/' == i) i = 63; else if ('=' == i) { if ( m_cache_count < 2 ) { // An equal sign cannot be the 1rst or 2nd character // in a 4 character block SetError(); return 0; } if ( 2 == m_cache_count ) { // This equal sign is the 3rd character. The next // character must also be an = sign or the input is // not valid. m_status = 2; } else // 3 == m_cache_count { // This equal sign is the 4th character. // This must be the last encoded character. if ( -1 == m_cache[2] ) { // block ends with 2 equal signs // and will decode into a single byte m_status = 3; m_cache[m_cache_count++] = -1; m_decode_count++; DecodeHelper1(); return base64str; } else { // block ends with 1 equal sign and will // decode into 2 bytes. m_status = 4; m_cache[m_cache_count++] = -1; m_decode_count++; DecodeHelper2(); return base64str; } } i = -1; } else { // end of valid portion of this base64str return (base64str-1); } m_cache[m_cache_count++] = i; m_decode_count++; } m_cache_count = 0; // 3 bytes of output if ( m_output_count >= 510 ) { Output(); m_output_count = 0; outbuf = m_output; } u.i = m_cache[3] + 64*(m_cache[2] + 64*(m_cache[1] + 64*m_cache[0])); *outbuf++ = u.b[2]; *outbuf++ = u.b[1]; *outbuf++ = u.b[0]; m_output_count += 3; } //return 0; } const char* ON_DecodeBase64::Decode(const char* base64str, size_t base64str_count) { char* sEnd; const char* p; char s[1025]; if ( 0 == base64str ) return 0; sEnd = s + 1024; *sEnd = 0; while ( base64str_count >= 1024 ) { memcpy(s,base64str,1024); p = Decode(s); if ( 0 == p ) return 0; if ( p != sEnd ) { return base64str + (p - s); } base64str += 1024; base64str_count -= 1024; } if ( base64str_count > 0 ) { memcpy(s,base64str,base64str_count); s[base64str_count]=0; p = Decode(s); if ( 0 == p ) return 0; base64str += (p - s); } return base64str; } const wchar_t* ON_DecodeBase64::Decode(const wchar_t* base64str) { const wchar_t* p; wchar_t w; if ( 0 == base64str ) return 0; p = base64str; for(;;) { w = *p++; if ( w < 32 || w > 122 ) break; } return Decode(base64str,p-base64str); } const wchar_t* ON_DecodeBase64::Decode(const wchar_t* base64str, size_t base64str_count) { char* sEnd; const char* p; char s[1025]; size_t i; wchar_t w; if ( 0 == base64str ) return 0; sEnd = s + 1024; *sEnd = 0; while ( base64str_count >= 1024 ) { for(i=0;i<1024;i++) { w = base64str[i]; if ( w < 32 || w > 122 ) { s[i] = 0; break; } s[i] = (char)w; } p = Decode(s); if ( 0 == p ) return 0; if ( p != sEnd ) { return base64str + (p - s); } base64str += 1024; base64str_count -= 1024; } if ( base64str_count > 0 ) { for(i=0;i 122 ) { s[i] = 0; break; } s[i] = (char)w; } s[i] = 0; p = Decode(s); if ( 0 == p ) return 0; base64str += (p - s); } return base64str; } // virtual void ON_DecodeBase64::Output() { // default does nothing. } /* ////////////////////////////////////////////////////////////////////////////////////////// // // ON_EncodeBase64 // ON_EncodeBase64::ON_EncodeBase64() { Begin(); } ON_EncodeBase64::~ON_EncodeBase64() { Begin(); } //vitrual void ON_EncodeBase64::Output() { // The default does nothing - override this function // if you want to do something useful with the output. } void ON_EncodeBase64::Begin() { m_encode_count = 0; m_output_count = 0; memset(m_output,0,80); m_unused2 = 0; m_input_count = 0; memset(m_input,0,64); } void ON_EncodeBase64::EncodeHelper1(const unsigned char* inbuf, char* outbuf ) { // base64 encode the final byte of input into 4 bytes of outbuf. unsigned char c; c = (*inbuf >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (*inbuf & 3) << 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; *outbuf++ = '='; *outbuf = '='; } void ON_EncodeBase64::EncodeHelper2(const unsigned char* inbuf, char* outbuf ) { // base64 encode the final 2 bytes of input into 4 bytes of outbuf. unsigned char b, c; b = *inbuf++; c = (b >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 3) << 4; b = *inbuf; c |= (b & 0xF0) >> 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 0x0F) << 2; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; *outbuf = '='; } void ON_EncodeBase64::EncodeHelper3(const unsigned char* inbuf, char* outbuf ) { // base64 encode 3 bytes from inbuf into 4 bytes of outbuf. unsigned char b, c; b = *inbuf++; c = (b >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 3) << 4; b = *inbuf++; c |= (b & 0xF0) >> 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 0x0F) << 2; b = *inbuf++; c |= (b&0xC0) >> 6; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; b &= 0x3F; if ( b < 26 ) b += 65; else if ( b < 52 ) b += 71; else if ( b < 62 ) b -= 4; else b = (b&1) ? '/' : '+'; *outbuf++ = b; } void ON_EncodeBase64::EncodeHelper57(const unsigned char* inbuf ) { // base64 encode 57 bytes from inbuf and put results in m_output[] // // Encoding 57 input bytes creates 76 output bytes and 76 // is the maximum line length for base64 encoding. char* outbuf = m_output; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeHelper3(inbuf,outbuf); memset(outbuf+4,0,4); m_encode_count += 57; } void ON_EncodeBase64::Encode( const void* buffer, size_t sizeof_buffer ) { // code is designed for speed unsigned int sz; const unsigned char* inbuf; if ( sizeof_buffer <= 0 || !buffer ) return; if ( m_input_count ) { // residual input left from the previous call to Encode() sz = 57 - m_input_count; if ( sizeof_buffer < sz ) { // still don't have 57 bytes of input memcpy(m_input+m_input_count,buffer,sizeof_buffer); m_input_count += ((int)sizeof_buffer); // safe cast - sizeof_buffer < 57 return; } // m_input[] has 57 bytes - encode it memcpy(m_input+m_input_count,buffer,sz); EncodeHelper57(m_input); m_output_count = 76; m_input_count = 0; Output(); if ( sizeof_buffer == sz ) { // no input left m_output_count = 0; *m_output = 0; return; } // deal with remaining input buffer = ((const unsigned char*)buffer + sz); sizeof_buffer -= sz; } m_output_count = 76; inbuf = (const unsigned char*)buffer; while(sizeof_buffer >= 57 ) { // encode 57 bytes in m_input_count[] EncodeHelper57(inbuf); Output(); inbuf += 57; sizeof_buffer -= 57; } if ( sizeof_buffer ) { // store what's left of the input in m_input[] memcpy(m_input,inbuf,sizeof_buffer); m_input_count = (int)sizeof_buffer; // safe cast - sizeof_buffer < 57 } m_output_count = 0; *m_output = 0; } void ON_EncodeBase64::End() { const unsigned char* inbuf; char* outbuf; m_output_count = 0; if ( m_input_count > 0 ) { // flush rest of input inbuf = m_input; outbuf = m_output; while ( m_input_count >= 3 ) { EncodeHelper3(inbuf,outbuf); inbuf += 3; outbuf += 4; m_input_count -= 3; m_output_count += 4; m_encode_count += 3; } if ( 1 == m_input_count ) { // 1 byte of input left EncodeHelper1(inbuf,outbuf); outbuf += 4; m_output_count += 4; m_encode_count++; } else if ( 2 == m_input_count ) { // 2 bytes of input left EncodeHelper2(inbuf,outbuf); outbuf += 4; m_output_count += 4; m_encode_count += 2; } memset(outbuf,0,80-m_output_count); m_input_count = 0; Output(); m_output_count = 0; } *m_output = 0; } */ ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ON_Base64EncodeStream::ON_Base64EncodeStream() : m_out_callback_function(0) , m_out_callback_context(0) , m_in_size(0) , m_out_size(0) , m_in_crc(0) , m_out_crc(0) , m_implementation(0) , m_reserved(0) {} ON_Base64EncodeStream::~ON_Base64EncodeStream() { if ( 0 != m_implementation ) { onfree(m_implementation); m_implementation = 0; } } void ON_Base64EncodeStream::ErrorHandler() { // place holder for error handing ON_ERROR("ON_UncompressStream error"); } class ON_Base64EncodeImplementation { public: // input waiting to be encoded // At most 56 bytes can be waiting to be processed in m_in_buffer[]. // m_in_buffer[] is full when it has 57 bytes. ON__UINT32 m_in_buffer_size; unsigned char m_in_buffer[64]; // When the output stream handler is called, m_out_buffer[] // is a null terminated string with 4 to 76 characters of // base64 encoded output. char m_out_buffer[80]; }; bool ON_Base64EncodeStream::Begin() { if ( 0 != m_implementation ) { onfree(m_implementation); m_implementation = 0; } // zero these because the same instance of an // ON_UncompressStream class may be used multiple times. m_in_size = 0; m_out_size = 0; m_in_crc = 0; m_out_crc = 0; ON_Base64EncodeImplementation* imp = (ON_Base64EncodeImplementation*)onmalloc(sizeof(*imp)); memset(imp,0,sizeof(*imp)); m_implementation = imp; return true; } static void EncodeBase64Helper1(const unsigned char* inbuf, char* outbuf ) { // base64 encode the final byte of input into 4 bytes of outbuf. unsigned char c; c = (*inbuf >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (*inbuf & 3) << 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; *outbuf++ = '='; *outbuf = '='; } static void EncodeBase64Helper2(const unsigned char* inbuf, char* outbuf ) { // base64 encode the final 2 bytes of input into 4 bytes of outbuf. unsigned char b, c; b = *inbuf++; c = (b >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 3) << 4; b = *inbuf; c |= (b & 0xF0) >> 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 0x0F) << 2; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; *outbuf = '='; } static void EncodeBase64Helper3(const unsigned char* inbuf, char* outbuf ) { // base64 encode 3 bytes from inbuf into 4 bytes of outbuf. unsigned char b, c; b = *inbuf++; c = (b >> 2); if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 3) << 4; b = *inbuf++; c |= (b & 0xF0) >> 4; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; c = (b & 0x0F) << 2; b = *inbuf++; c |= (b&0xC0) >> 6; if ( c < 26 ) c += 65; else if ( c < 52 ) c += 71; else if ( c < 62 ) c -= 4; else c = (c&1) ? '/' : '+'; *outbuf++ = c; b &= 0x3F; if ( b < 26 ) b += 65; else if ( b < 52 ) b += 71; else if ( b < 62 ) b -= 4; else b = (b&1) ? '/' : '+'; *outbuf++ = b; } static void EncodeBase64Helper57(const unsigned char* inbuf, char* outbuf ) { // base64 encode 57 bytes from inbuf and put results in m_output[] // // Encoding 57 input bytes creates 76 output bytes and 76 // is the maximum line length for base64 encoding. EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); inbuf += 3; outbuf += 4; EncodeBase64Helper3(inbuf,outbuf); outbuf[4] = 0; } bool ON_Base64EncodeStream::In( ON__UINT64 in_buffer_size, const void* in_buffer ) { if ( in_buffer_size <= 0 ) return true; if ( 0 == m_implementation ) { ErrorHandler(); return false; } if ( 0 == in_buffer ) { ErrorHandler(); return false; } bool rc = false; ON__UINT32 crc1; ON__UINT32 sz; ON_Base64EncodeImplementation* imp = (ON_Base64EncodeImplementation*)m_implementation; if ( imp->m_in_buffer_size > 0 ) { // residual input left from the previous call to In() sz = 57 - imp->m_in_buffer_size; if ( in_buffer_size < sz ) { // still don't have sizeof(imp->m_in_buffer_size) bytes of input sz = (ON__UINT32)in_buffer_size; // cast is safe because in_buffer_size < sizeof(imp->m_in_buffer_size) <= 8192 memcpy( imp->m_in_buffer + imp->m_in_buffer_size, in_buffer, sz ); imp->m_in_buffer_size += sz; return true; } memcpy( imp->m_in_buffer + imp->m_in_buffer_size, in_buffer, sz ); in_buffer = ((const unsigned char*)in_buffer) + sz; in_buffer_size -= sz; EncodeBase64Helper57(imp->m_in_buffer,imp->m_out_buffer); imp->m_in_buffer_size = 0; crc1 = ON_CRC32(m_out_crc,76,imp->m_out_buffer); rc = ( 0 != m_out_callback_function ) ? m_out_callback_function(m_out_callback_context,76,imp->m_out_buffer) : Out(m_out_callback_context,76,imp->m_out_buffer); if ( !rc ) { onfree(m_implementation); m_implementation = 0; return false; } m_in_crc = ON_CRC32(m_in_crc,57,imp->m_in_buffer); m_in_size += 57; m_out_crc = crc1; m_out_size += 76; } while(in_buffer_size >= 57 ) { // base 64 encode 57 input bytes to create 76 output bytes EncodeBase64Helper57((const unsigned char*)in_buffer,imp->m_out_buffer); crc1 = ON_CRC32(m_out_crc,76,imp->m_out_buffer); rc = ( 0 != m_out_callback_function ) ? m_out_callback_function(m_out_callback_context,76,imp->m_out_buffer) : Out(m_out_callback_context,76,imp->m_out_buffer); if ( !rc ) { onfree(m_implementation); m_implementation = 0; return false; } m_in_crc = ON_CRC32(m_in_crc,57,in_buffer); m_in_size += 57; m_out_crc = crc1; m_out_size += 76; in_buffer = ((const unsigned char*)in_buffer) + 57; in_buffer_size -= 57; } if ( in_buffer_size > 0 ) { // store what's left of the input in imp->m_in_buffer[] memcpy(imp->m_in_buffer,in_buffer,(size_t)in_buffer_size); } imp->m_in_buffer_size = (ON__UINT32)in_buffer_size; // safe cast - sizeof_buffer < 57 return true; } bool ON_Base64EncodeStream::End() { if ( 0 == m_implementation ) { ErrorHandler(); return false; } bool rc = true; ON_Base64EncodeImplementation* imp = (ON_Base64EncodeImplementation*)m_implementation; if ( imp->m_in_buffer_size > 0 ) { // residual input left from the final call to In() const unsigned char* in_buffer = imp->m_in_buffer; ON__UINT32 in_buffer_size = imp->m_in_buffer_size; ON__UINT32 out_buffer_size = 0; while ( in_buffer_size >= 3 ) { EncodeBase64Helper3( in_buffer, &imp->m_out_buffer[out_buffer_size] ); in_buffer += 3; out_buffer_size += 4; in_buffer_size -= 3; } if ( 1 == in_buffer_size ) { // 1 byte of input left EncodeBase64Helper1(in_buffer,&imp->m_out_buffer[out_buffer_size]); out_buffer_size += 4; } else if ( 2 == in_buffer_size ) { // 2 bytes of input left EncodeBase64Helper2(in_buffer,&imp->m_out_buffer[out_buffer_size]); out_buffer_size += 4; } imp->m_out_buffer[out_buffer_size] = 0; ON__UINT32 crc1 = ON_CRC32(m_out_crc,out_buffer_size,imp->m_out_buffer); rc = ( 0 != m_out_callback_function ) ? m_out_callback_function(m_out_callback_context,out_buffer_size,imp->m_out_buffer) : Out(m_out_callback_context,out_buffer_size,imp->m_out_buffer); if ( rc ) { m_in_crc = ON_CRC32(m_in_crc,imp->m_in_buffer_size,imp->m_in_buffer); m_in_size += imp->m_in_buffer_size; m_out_crc = crc1; m_out_size += out_buffer_size; } } onfree(m_implementation); m_implementation = 0; return rc; } bool ON_Base64EncodeStream::Out( void*, ON__UINT32, const char* ) { // default base 64 encoded stream handler does nothing. return true; } bool ON_Base64EncodeStream::SetCallback( ON_StreamCallbackFunction out_callback_function, void* out_callback_context ) { m_out_callback_function = out_callback_function; m_out_callback_context = out_callback_context; return true; } ON_StreamCallbackFunction ON_Base64EncodeStream::CallbackFunction() const { return m_out_callback_function; } void* ON_Base64EncodeStream::CallbackContext() const { return m_out_callback_context; } ON__UINT64 ON_Base64EncodeStream::InSize() const { return m_in_size; } ON__UINT64 ON_Base64EncodeStream::OutSize() const { return m_out_size; } ON__UINT32 ON_Base64EncodeStream::InCRC() const { return m_in_crc; } ON__UINT32 ON_Base64EncodeStream::OutCRC() const { return m_out_crc; } // ON_Base64 static const int DecodeTab[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, }; static bool ReadEncodedByte(int& pos, const wchar_t* wsz, ON__UINT8& byteOut) { wchar_t w = wsz[pos]; if (w >= 128) w = 128; // Will fail validation. byteOut = ON__UINT8(w); while (byteOut != 0) { pos++; // Check that the byte is a valid Base64 character. // The Base64 specification requires garbled data to be ignored. if ((byteOut < 128) && (DecodeTab[byteOut] >= 0)) return true; // Move on to the next byte and keep trying. w = wsz[pos]; if (w >= 128) w = 128; // Will fail validation. byteOut = ON__UINT8(w); } return false; // End of data. } size_t ON_Base64::Decode(const wchar_t* wszBase64in, void* pvBufferOut, size_t maxLength) // Static. { auto* pBufferOut = static_cast(pvBufferOut); ON__UINT32 uBytesWritten = 0; int iResultSize = 3; ON__UINT8 a = 0, b = 0, c = 0, d = 0, aResult[3] = { 0 }; int pos = 0; while (ReadEncodedByte(pos, wszBase64in, a)) { ReadEncodedByte(pos, wszBase64in, b); ReadEncodedByte(pos, wszBase64in, c); ReadEncodedByte(pos, wszBase64in, d); if ('=' == d) // Handle padding character(s). { iResultSize = ('=' == c) ? 1 : 2; } if (pBufferOut != nullptr) { const auto val = (ON__UINT32)((DecodeTab[a] << 18) | (DecodeTab[b] << 12) | (DecodeTab[c] << 6) | DecodeTab[d]); aResult[0] = (ON__UINT8)((val & 0xFF0000) >> 16); aResult[1] = (ON__UINT8)((val & 0x00FF00) >> 8); aResult[2] = (ON__UINT8)((val)); memcpy(pBufferOut, aResult, iResultSize); pBufferOut += iResultSize; uBytesWritten += iResultSize; if (size_t(uBytesWritten) >= maxLength) break; } else { uBytesWritten += iResultSize; } } return size_t(uBytesWritten); } static const wchar_t* EncodeTab = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; bool ON_Base64::Encode(const void* pvBufferIn, size_t bufNumBytes, ON_wString& sBase64Out, bool bAppend) // Static. { // Base64 is about 133% of the data size. Use 150% plus 4 for padding. const auto bigBufNumBytes = (bufNumBytes * 150) / 100 + 4; const int iExistingLen = bAppend ? sBase64Out.Length() : 0; const auto outNumBytes = size_t(iExistingLen) + bigBufNumBytes; auto* start = sBase64Out.SetLength(outNumBytes); if (nullptr == start) return false; auto* out = start + iExistingLen; const auto* p = static_cast(pvBufferIn); const char* pEnd = p + bufNumBytes; ON__UINT8 a = 0, b = 0, c = 0; while (p < pEnd) { out[2] = out[3] = L'='; a = *p++; out[0] = EncodeTab[a >> 2]; a = ON__UINT8((a & 0x03) << 4); if (p < pEnd) { b = *p++; out[1] = EncodeTab[a | (b >> 4)]; b = ON__UINT8((b & 0x0F) << 2); if (p < pEnd) { c = *p++; out[2] = EncodeTab[b | (c >> 6)]; out[3] = EncodeTab[c & 0x3F]; } else { out[2] = EncodeTab[b]; } } else { out[1] = EncodeTab[a]; } out += 4; } *out = 0; const auto realLength = out - start; sBase64Out.SetLength(realLength); return true; }