strigi/src/streams
base64inputstream.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "base64inputstream.h"
00021
00022 #include <cstring>
00023
00024 using namespace std;
00025 using namespace Strigi;
00026
00027
00028
00029
00030
00031 class Base64InputStream::Private {
00032 public:
00033 Base64InputStream* const p;
00034 InputStream* input;
00035 const char* pos, * pend;
00036 int32_t bits;
00037 int32_t nleft;
00038 char bytestodo;
00039 char char_count;
00040
00041 Private(Base64InputStream* p, InputStream* i);
00042 bool moreData();
00043 int32_t fillBuffer(char* start, int32_t space);
00044 };
00045
00046
00047 const unsigned char alphabet[]
00048 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00049 bool inalphabet[256];
00050 unsigned char decoder[133];
00051 bool initializedAlphabet = false;
00052 void initialize();
00053 string decode(const char* in, string::size_type length);
00054
00055
00056 void
00057 initialize() {
00058 if (!initializedAlphabet) {
00059 initializedAlphabet = true;
00060
00061 for (int i=64; i<256; ++i) {
00062 inalphabet[i] = 0;
00063 }
00064 for (int i=0; i<64; ++i) {
00065 inalphabet[alphabet[i]] = true;
00066 decoder[alphabet[i]] = i;
00067 }
00068 }
00069 }
00070
00071 Base64InputStream::Base64InputStream(InputStream* i)
00072 :p(new Private(this, i))
00073 {
00074 }
00075
00076 Base64InputStream::~Base64InputStream() {
00077 delete p;
00078 }
00079 Base64InputStream::Private::Private(Base64InputStream* bi, InputStream* i)
00080 :p(bi), input(i) {
00081 initialize();
00082 nleft = 0;
00083 char_count = 0;
00084 bits = 0;
00085 bytestodo = 0;
00086 pos = pend = 0;
00087 }
00088 bool
00089 Base64InputStream::Private::moreData() {
00090 if (pos == pend) {
00091 int32_t nread = input->read(pos, 1, 0);
00092 if (nread < -1) {
00093 p->m_status = Error;
00094 p->m_error = input->error();
00095 input = 0;
00096 return false;
00097 }
00098 if (nread <= 0) {
00099 input = 0;
00100 return false;
00101 }
00102 pend = pos + nread;
00103 }
00104 return true;
00105 }
00106 int32_t
00107 Base64InputStream::fillBuffer(char* start, int32_t space) {
00108 return p->fillBuffer(start, space);
00109 }
00110 int32_t
00111 Base64InputStream::Private::fillBuffer(char* start, int32_t space) {
00112 if (input == 0 && bytestodo == 0) return -1;
00113
00114 if (bytestodo) {
00115 switch (bytestodo) {
00116 case 3:
00117 *start = bits >> 16;
00118 break;
00119 case 2:
00120 *start = (bits >> 8) & 0xff;
00121 break;
00122 case 1:
00123 *start = bits & 0xff;
00124 bits = 0;
00125 char_count = 0;
00126 break;
00127 }
00128 bytestodo--;
00129 return 1;
00130 }
00131 const char* end = start + space;
00132 char* p = start;
00133 int32_t nwritten = 0;
00134 while (moreData()) {
00135 unsigned char c = *pos++;
00136
00137 if (c == '=') {
00138 if (char_count == 2) {
00139 bytestodo = 1;
00140 bits >>= 10;
00141 } else if (char_count == 3) {
00142 bytestodo = 2;
00143 bits >>= 8;
00144 }
00145 input = 0;
00146 break;
00147 }
00148
00149 if (!inalphabet[c]) {
00150 continue;
00151 }
00152 bits += decoder[c];
00153 char_count++;
00154 if (char_count == 4) {
00155 if (p >= end) {
00156 bytestodo = 3;
00157 break;
00158 }
00159 *p++ = bits >> 16;
00160 if (p >= end) {
00161 bytestodo = 2;
00162 nwritten++;
00163 break;
00164 }
00165 *p++ = (bits >> 8) & 0xff;
00166 if (p >= end) {
00167 bytestodo = 1;
00168 nwritten += 2;
00169 break;
00170 }
00171 *p++ = bits & 0xff;
00172 bits = 0;
00173 char_count = 0;
00174 nwritten += 3;
00175 } else {
00176 bits <<= 6;
00177 }
00178 }
00179 if (nwritten == 0 && input == 0 && bytestodo == 0) {
00180
00181 nwritten = -1;
00182 }
00183 return nwritten;
00184 }
00185 string
00186 Base64InputStream::decode(const char* in, string::size_type length) {
00187 initialize();
00188 string d;
00189 if (length%4) return d;
00190 initialize();
00191 int32_t words = length/4;
00192 d.reserve(words*3);
00193 const unsigned char* c = (const unsigned char*)in;
00194 const unsigned char* e = c + length;
00195 if (in[length-1] == '=') {
00196 e -= 4;
00197 }
00198 char k, l, b[3];
00199 for (; c < e; c += 4) {
00200 if (inalphabet[c[0]] && inalphabet[c[1]] && inalphabet[c[2]]
00201 && inalphabet[c[3]]) {
00202 k = decoder[c[1]];
00203 l = decoder[c[2]];
00204 b[0] = (decoder[c[0]] << 2) + (k >> 4);
00205 b[1] = (k << 4) + (l >> 2);
00206 b[2] = (l << 6) + (decoder[c[3]]);
00207 d.append(b, 3);
00208 } else {
00209 return string();
00210 }
00211 }
00212 if (in[length-2] == '=') {
00213 if (inalphabet[c[0]] && inalphabet[c[1]]) {
00214 b[0] = (decoder[c[0]] << 2)+((decoder[c[1]] >> 4));
00215 d.append(b, 1);
00216 } else {
00217 return string();
00218 }
00219 } else if (in[length-1] == '=') {
00220 if (inalphabet[c[0]] && inalphabet[c[1]] && inalphabet[c[2]]) {
00221 k = decoder[c[1]];
00222 b[0] = (decoder[c[0]] << 2) + (k >> 4);
00223 b[1] = (k << 4) + (decoder[c[2]] >> 2);
00224 d.append(b, 2);
00225 } else {
00226 return string();
00227 }
00228 }
00229 return d;
00230 }