mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-02-28 19:16:09 +08:00
1240 lines
29 KiB
C++
1240 lines
29 KiB
C++
//
|
|
// 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 <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#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<base64str_count;i++)
|
|
{
|
|
w = base64str[i];
|
|
if ( w < 32 || w > 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<char*>(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<const char*>(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;
|
|
}
|