mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-23 12:42:02 +00:00
merged new xmlrpc-c revision 1472 from https://xmlrpc-c.svn.sourceforge.net/svnroot/xmlrpc-c/trunk
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8545 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
#include "xmlrpc-c/girerr.hpp"
|
||||
using girerr::error;
|
||||
using girerr::throwf;
|
||||
#include "xmlrpc-c/base64.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace xmlrpc_c;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
char const 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, /* Note PAD->0 */
|
||||
-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
|
||||
};
|
||||
|
||||
char const base64Pad('=');
|
||||
size_t const base64MaxChunkSize(57);
|
||||
// Max binary chunk size (76 character line)
|
||||
#define BASE64_LINE_SZ 128 /* Buffer size for a single line. */
|
||||
|
||||
unsigned char const table_b2a_base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
class bitBuffer {
|
||||
public:
|
||||
bitBuffer() : bitsInBuffer(0) {};
|
||||
|
||||
void
|
||||
shiftIn8Bits(unsigned char const newBits) {
|
||||
// Shift in 8 bits to the right end of the buffer
|
||||
|
||||
this->buffer = (this->buffer << 8) | newBits;
|
||||
this->bitsInBuffer += 8;
|
||||
|
||||
assert(this->bitsInBuffer <= 12);
|
||||
}
|
||||
|
||||
void
|
||||
shiftIn6Bits(unsigned char const newBits) {
|
||||
// Shift in 6 bits to the right end of the buffer
|
||||
|
||||
this->buffer = (this->buffer << 6) | newBits;
|
||||
this->bitsInBuffer += 6;
|
||||
|
||||
assert(this->bitsInBuffer <= 12);
|
||||
}
|
||||
|
||||
void
|
||||
shiftOut6Bits(unsigned char * const outputP) {
|
||||
// Shift out 6 bits from the left end of the buffer
|
||||
|
||||
assert(bitsInBuffer >= 6);
|
||||
|
||||
*outputP = (this->buffer >> (this->bitsInBuffer - 6)) & 0x3f;
|
||||
this->bitsInBuffer -= 6;
|
||||
}
|
||||
|
||||
void
|
||||
shiftOut8Bits(unsigned char * const outputP) {
|
||||
// Shift out 8 bits from the left end of the buffer
|
||||
|
||||
assert(bitsInBuffer >= 8);
|
||||
|
||||
*outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0x3f;
|
||||
this->bitsInBuffer -= 8;
|
||||
}
|
||||
|
||||
void
|
||||
shiftOutResidue(unsigned char * const outputP) {
|
||||
// Shift out the residual 2 or 4 bits, padded on the right with 0
|
||||
// to 6 bits.
|
||||
|
||||
while (this->bitsInBuffer < 6) {
|
||||
this->buffer <<= 2;
|
||||
this->bitsInBuffer += 2;
|
||||
}
|
||||
|
||||
this->shiftOut6Bits(outputP);
|
||||
}
|
||||
|
||||
void
|
||||
discardResidue() {
|
||||
assert(bitsInBuffer < 8);
|
||||
|
||||
this->bitsInBuffer = 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
bitCount() {
|
||||
return bitsInBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int buffer;
|
||||
unsigned int bitsInBuffer;
|
||||
};
|
||||
|
||||
|
||||
namespace xmlrpc_c {
|
||||
|
||||
|
||||
static void
|
||||
encodeChunk(vector<unsigned char> const& bytes,
|
||||
size_t const lineStart,
|
||||
size_t const chunkSize,
|
||||
string * const outputP) {
|
||||
|
||||
bitBuffer buffer;
|
||||
// A buffer in which we accumulate bits (up to 12 bits)
|
||||
// until we have enough (6) for a base64 character.
|
||||
|
||||
// I suppose this would be more efficient with an iterator on
|
||||
// 'bytes' and/or *outputP. I'd have to find out how to use one.
|
||||
|
||||
for (size_t linePos = 0; linePos < chunkSize; ++linePos) {
|
||||
// Shift the data into our buffer
|
||||
buffer.shiftIn8Bits(bytes[lineStart + linePos]);
|
||||
|
||||
// Encode any complete 6 bit groups
|
||||
while (buffer.bitCount() >= 6) {
|
||||
unsigned char theseBits;
|
||||
buffer.shiftOut6Bits(&theseBits);
|
||||
outputP->append(1, table_b2a_base64[theseBits]);
|
||||
}
|
||||
}
|
||||
if (buffer.bitCount() > 0) {
|
||||
// Handle residual bits in the buffer
|
||||
unsigned char theseBits;
|
||||
buffer.shiftOutResidue(&theseBits);
|
||||
|
||||
outputP->append(1, table_b2a_base64[theseBits]);
|
||||
|
||||
// Pad to a multiple of 4 characters (24 bits)
|
||||
assert(outputP->length() % 4 > 0);
|
||||
outputP->append(4-outputP->length() % 4, base64Pad);
|
||||
} else {
|
||||
assert(outputP->length() % 4 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
string
|
||||
base64FromBytes(vector<unsigned char> const& bytes,
|
||||
newlineCtl const newlineCtl) {
|
||||
|
||||
string retval;
|
||||
|
||||
if (bytes.size() == 0) {
|
||||
if (newlineCtl == NEWLINE_YES)
|
||||
retval = "\r\n";
|
||||
else
|
||||
retval = "";
|
||||
} else {
|
||||
// It would be good to preallocate retval. Need to look up
|
||||
// how to do that.
|
||||
for (size_t chunkStart = 0;
|
||||
chunkStart < bytes.size();
|
||||
chunkStart += base64MaxChunkSize) {
|
||||
|
||||
size_t const chunkSize(
|
||||
min(base64MaxChunkSize, bytes.size() - chunkStart));
|
||||
|
||||
encodeChunk(bytes, chunkStart, chunkSize, &retval);
|
||||
|
||||
if (newlineCtl == NEWLINE_YES)
|
||||
// Append a courtesy crlf
|
||||
retval += "\r\n";
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vector<unsigned char>
|
||||
bytesFromBase64(string const& base64) {
|
||||
|
||||
vector<unsigned char> retval;
|
||||
bitBuffer buffer;
|
||||
unsigned int npad;
|
||||
|
||||
npad = 0; // No pad characters seen yet
|
||||
|
||||
for (unsigned int cursor = 0; cursor < base64.length(); ++cursor) {
|
||||
char const thisChar(base64[cursor] & 0x7f);
|
||||
|
||||
if (thisChar == '\r' || thisChar == '\n' || thisChar == ' ') {
|
||||
// ignore this punctuation
|
||||
} else {
|
||||
if (thisChar == base64Pad) {
|
||||
// This pad character is here to synchronize a chunk to
|
||||
// a multiple of 24 bits (4 base64 characters; 3 bytes).
|
||||
buffer.discardResidue();
|
||||
} else {
|
||||
unsigned int const tableIndex(thisChar);
|
||||
if (table_a2b_base64[tableIndex] == -1)
|
||||
throwf("Contains non-base64 character "
|
||||
"with ASCII code 0x%02x", thisChar);
|
||||
|
||||
buffer.shiftIn6Bits(table_a2b_base64[tableIndex]);
|
||||
|
||||
if (buffer.bitCount() >= 8) {
|
||||
unsigned char thisByte;
|
||||
buffer.shiftOut8Bits(&thisByte);
|
||||
retval.push_back(thisByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.bitCount() > 0)
|
||||
throwf("Not a multiple of 4 characters");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
} //namespace
|
||||
Reference in New Issue
Block a user