6 #include "xmlrpc-c/girerr.hpp"
9 #include "xmlrpc-c/base64.hpp"
12 using namespace xmlrpc_c;
17 char const table_a2b_base64[] = {
18 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
19 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
20 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
21 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */
22 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
23 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
24 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
25 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
28 char const base64Pad('=');
29 size_t const base64MaxChunkSize(57);
30 // Max binary chunk size (76 character line)
31 #define BASE64_LINE_SZ 128 /* Buffer size for a single line. */
33 unsigned char const table_b2a_base64[] =
34 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
42 bitBuffer() : bitsInBuffer(0) {};
45 shiftIn8Bits(unsigned char const newBits) {
46 // Shift in 8 bits to the right end of the buffer
48 this->buffer = (this->buffer << 8) | newBits;
49 this->bitsInBuffer += 8;
51 assert(this->bitsInBuffer <= 12);
55 shiftIn6Bits(unsigned char const newBits) {
56 // Shift in 6 bits to the right end of the buffer
58 this->buffer = (this->buffer << 6) | newBits;
59 this->bitsInBuffer += 6;
61 assert(this->bitsInBuffer <= 12);
65 shiftOut6Bits(unsigned char * const outputP) {
66 // Shift out 6 bits from the left end of the buffer
68 assert(bitsInBuffer >= 6);
70 *outputP = (this->buffer >> (this->bitsInBuffer - 6)) & 0x3f;
71 this->bitsInBuffer -= 6;
75 shiftOut8Bits(unsigned char * const outputP) {
76 // Shift out 8 bits from the left end of the buffer
78 assert(bitsInBuffer >= 8);
80 *outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0x3f;
81 this->bitsInBuffer -= 8;
85 shiftOutResidue(unsigned char * const outputP) {
86 // Shift out the residual 2 or 4 bits, padded on the right with 0
89 while (this->bitsInBuffer < 6) {
91 this->bitsInBuffer += 2;
94 this->shiftOut6Bits(outputP);
99 assert(bitsInBuffer < 8);
101 this->bitsInBuffer = 0;
111 unsigned int bitsInBuffer;
119 encodeChunk(vector<unsigned char> const& bytes,
120 size_t const lineStart,
121 size_t const chunkSize,
122 string * const outputP) {
125 // A buffer in which we accumulate bits (up to 12 bits)
126 // until we have enough (6) for a base64 character.
128 // I suppose this would be more efficient with an iterator on
129 // 'bytes' and/or *outputP. I'd have to find out how to use one.
131 for (size_t linePos = 0; linePos < chunkSize; ++linePos) {
132 // Shift the data into our buffer
133 buffer.shiftIn8Bits(bytes[lineStart + linePos]);
135 // Encode any complete 6 bit groups
136 while (buffer.bitCount() >= 6) {
137 unsigned char theseBits;
138 buffer.shiftOut6Bits(&theseBits);
139 outputP->append(1, table_b2a_base64[theseBits]);
142 if (buffer.bitCount() > 0) {
143 // Handle residual bits in the buffer
144 unsigned char theseBits;
145 buffer.shiftOutResidue(&theseBits);
147 outputP->append(1, table_b2a_base64[theseBits]);
149 // Pad to a multiple of 4 characters (24 bits)
150 assert(outputP->length() % 4 > 0);
151 outputP->append(4-outputP->length() % 4, base64Pad);
153 assert(outputP->length() % 4 == 0);
160 base64FromBytes(vector<unsigned char> const& bytes,
161 newlineCtl const newlineCtl) {
165 if (bytes.size() == 0) {
166 if (newlineCtl == NEWLINE_YES)
171 // It would be good to preallocate retval. Need to look up
173 for (size_t chunkStart = 0;
174 chunkStart < bytes.size();
175 chunkStart += base64MaxChunkSize) {
177 size_t const chunkSize(
178 min(base64MaxChunkSize, bytes.size() - chunkStart));
180 encodeChunk(bytes, chunkStart, chunkSize, &retval);
182 if (newlineCtl == NEWLINE_YES)
183 // Append a courtesy crlf
192 vector<unsigned char>
193 bytesFromBase64(string const& base64) {
195 vector<unsigned char> retval;
199 npad = 0; // No pad characters seen yet
201 for (unsigned int cursor = 0; cursor < base64.length(); ++cursor) {
202 char const thisChar(base64[cursor] & 0x7f);
204 if (thisChar == '\r' || thisChar == '\n' || thisChar == ' ') {
205 // ignore this punctuation
207 if (thisChar == base64Pad) {
208 // This pad character is here to synchronize a chunk to
209 // a multiple of 24 bits (4 base64 characters; 3 bytes).
210 buffer.discardResidue();
212 unsigned int const tableIndex(thisChar);
213 if (table_a2b_base64[tableIndex] == -1)
214 throwf("Contains non-base64 character "
215 "with ASCII code 0x%02x", thisChar);
217 buffer.shiftIn6Bits(table_a2b_base64[tableIndex]);
219 if (buffer.bitCount() >= 8) {
220 unsigned char thisByte;
221 buffer.shiftOut8Bits(&thisByte);
222 retval.push_back(thisByte);
228 if (buffer.bitCount() > 0)
229 throwf("Not a multiple of 4 characters");