|
|
#include <string.h> |
|
|
|
|
|
#include "xmlrpc_config.h" |
|
|
|
|
|
#include "bool.h" |
|
|
#include "xmlrpc-c/util_int.h" |
|
|
#include "int.h" |
|
|
#include "xmlrpc-c/base64_int.h" |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
xmlrpc_base64Encode(const char * const chars, |
|
|
char * const base64) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char tbl[64] = { |
|
|
'A','B','C','D','E','F','G','H', |
|
|
'I','J','K','L','M','N','O','P', |
|
|
'Q','R','S','T','U','V','W','X', |
|
|
'Y','Z','a','b','c','d','e','f', |
|
|
'g','h','i','j','k','l','m','n', |
|
|
'o','p','q','r','s','t','u','v', |
|
|
'w','x','y','z','0','1','2','3', |
|
|
'4','5','6','7','8','9','+','/' |
|
|
}; |
|
|
|
|
|
unsigned int i; |
|
|
uint32_t length; |
|
|
char * p; |
|
|
const char * s; |
|
|
|
|
|
length = strlen(chars); |
|
|
s = &chars[0]; |
|
|
p = &base64[0]; |
|
|
|
|
|
for (i = 0; i < length; i += 3) { |
|
|
*p++ = tbl[s[0] >> 2]; |
|
|
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; |
|
|
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; |
|
|
*p++ = tbl[s[2] & 0x3f]; |
|
|
s += 3; |
|
|
} |
|
|
|
|
|
|
|
|
if (i == length + 1) |
|
|
*(p - 1) = '='; |
|
|
else if (i == length + 2) |
|
|
*(p - 1) = *(p - 2) = '='; |
|
|
|
|
|
|
|
|
*p = '\0'; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CRLF "\015\012" |
|
|
#define CR '\015' |
|
|
#define LF '\012' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char table_a2b_base64[] = { |
|
|
-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 |
|
|
}; |
|
|
|
|
|
#define BASE64_PAD '=' |
|
|
#define BASE64_MAXBIN 57 |
|
|
#define BASE64_LINE_SZ 128 |
|
|
|
|
|
static unsigned char const table_b2a_base64[] = |
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
|
|
|
|
|
|
|
|
|
|
|
static xmlrpc_mem_block * |
|
|
base64Encode(xmlrpc_env * const envP, |
|
|
const unsigned char * const binData, |
|
|
size_t const binLen, |
|
|
bool const wantNewlines) { |
|
|
|
|
|
size_t chunkStart, chunkLeft; |
|
|
unsigned char * asciiData; |
|
|
int leftbits; |
|
|
unsigned char thisCh; |
|
|
unsigned int leftchar; |
|
|
xmlrpc_mem_block * outputP; |
|
|
unsigned char lineBuffer[BASE64_LINE_SZ]; |
|
|
const unsigned char * cursor; |
|
|
|
|
|
|
|
|
outputP = xmlrpc_mem_block_new(envP, 0); |
|
|
XMLRPC_FAIL_IF_FAULT(envP); |
|
|
|
|
|
|
|
|
if (binLen == 0) { |
|
|
if (wantNewlines) |
|
|
XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, CRLF, 2); |
|
|
goto cleanup; |
|
|
} |
|
|
|
|
|
|
|
|
for (chunkStart = 0, cursor = &binData[0]; |
|
|
chunkStart < binLen; |
|
|
chunkStart += BASE64_MAXBIN) { |
|
|
|
|
|
|
|
|
asciiData = &lineBuffer[0]; |
|
|
chunkLeft = binLen - chunkStart; |
|
|
if (chunkLeft > BASE64_MAXBIN) |
|
|
chunkLeft = BASE64_MAXBIN; |
|
|
leftbits = 0; |
|
|
leftchar = 0; |
|
|
|
|
|
for(; chunkLeft > 0; --chunkLeft, ++cursor) { |
|
|
|
|
|
leftchar = (leftchar << 8) | *cursor; |
|
|
leftbits += 8; |
|
|
|
|
|
|
|
|
while (leftbits >= 6) { |
|
|
thisCh = (leftchar >> (leftbits-6)) & 0x3f; |
|
|
leftbits -= 6; |
|
|
*asciiData++ = table_b2a_base64[thisCh]; |
|
|
} |
|
|
} |
|
|
if (leftbits == 2) { |
|
|
*asciiData++ = table_b2a_base64[(leftchar&3) << 4]; |
|
|
*asciiData++ = BASE64_PAD; |
|
|
*asciiData++ = BASE64_PAD; |
|
|
} else if (leftbits == 4) { |
|
|
*asciiData++ = table_b2a_base64[(leftchar&0xf) << 2]; |
|
|
*asciiData++ = BASE64_PAD; |
|
|
} |
|
|
|
|
|
|
|
|
if (wantNewlines) { |
|
|
*asciiData++ = CR; |
|
|
*asciiData++ = LF; |
|
|
} |
|
|
|
|
|
|
|
|
XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, lineBuffer, |
|
|
asciiData - &lineBuffer[0]); |
|
|
XMLRPC_FAIL_IF_FAULT(envP); |
|
|
} |
|
|
|
|
|
cleanup: |
|
|
if (envP->fault_occurred) { |
|
|
if (outputP) |
|
|
xmlrpc_mem_block_free(outputP); |
|
|
return NULL; |
|
|
} |
|
|
return outputP; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_mem_block * |
|
|
xmlrpc_base64_encode(xmlrpc_env * const envP, |
|
|
const unsigned char * const binData, |
|
|
size_t const binLen) { |
|
|
|
|
|
return base64Encode(envP, binData, binLen, true); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_mem_block * |
|
|
xmlrpc_base64_encode_without_newlines(xmlrpc_env * const envP, |
|
|
const unsigned char * const binData, |
|
|
size_t const binLen) { |
|
|
|
|
|
return base64Encode(envP, binData, binLen, false); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xmlrpc_mem_block * |
|
|
xmlrpc_base64_decode(xmlrpc_env * const envP, |
|
|
const char * const asciiData, |
|
|
size_t const acsiiLen) { |
|
|
|
|
|
unsigned char * binData; |
|
|
int leftbits; |
|
|
unsigned char thisCh; |
|
|
unsigned int leftchar; |
|
|
size_t npad; |
|
|
size_t binLen, bufferSize; |
|
|
xmlrpc_mem_block * outputP; |
|
|
const char * nextCharP; |
|
|
size_t remainingLen; |
|
|
|
|
|
|
|
|
|
|
|
bufferSize = ((acsiiLen + 3) / 4) * 3; |
|
|
outputP = xmlrpc_mem_block_new(envP, bufferSize); |
|
|
XMLRPC_FAIL_IF_FAULT(envP); |
|
|
|
|
|
|
|
|
leftbits = 0; |
|
|
leftchar = 0; |
|
|
npad = 0; |
|
|
binData = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, outputP); |
|
|
binLen = 0; |
|
|
|
|
|
for (remainingLen = acsiiLen, nextCharP = asciiData; |
|
|
remainingLen > 0; |
|
|
--remainingLen, ++nextCharP) { |
|
|
|
|
|
|
|
|
thisCh = (*nextCharP & 0x7f); |
|
|
if (thisCh == '\r' || thisCh == '\n' || thisCh == ' ') |
|
|
continue; |
|
|
if (thisCh == BASE64_PAD) |
|
|
++npad; |
|
|
thisCh = table_a2b_base64[(*nextCharP) & 0x7f]; |
|
|
|
|
|
|
|
|
if (thisCh == (unsigned char) -1) |
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
leftchar = (leftchar << 6) | (thisCh); |
|
|
leftbits += 6; |
|
|
if (leftbits >= 8) { |
|
|
leftbits -= 8; |
|
|
XMLRPC_ASSERT(binLen < bufferSize); |
|
|
*binData++ = (leftchar >> leftbits) & 0xFF; |
|
|
leftchar &= ((1 << leftbits) - 1); |
|
|
++binLen; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (leftbits) |
|
|
XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, "Incorrect Base64 padding"); |
|
|
|
|
|
|
|
|
if (npad > binLen || npad > 2) |
|
|
XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, "Malformed Base64 data"); |
|
|
|
|
|
|
|
|
binLen -= npad; |
|
|
XMLRPC_MEMBLOCK_RESIZE(char, envP, outputP, binLen); |
|
|
XMLRPC_ASSERT(!envP->fault_occurred); |
|
|
|
|
|
cleanup: |
|
|
if (envP->fault_occurred) { |
|
|
if (outputP) |
|
|
xmlrpc_mem_block_free(outputP); |
|
|
return NULL; |
|
|
} |
|
|
return outputP; |
|
|
} |
|
|
|