00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "qca_textfilter.h"
00023
00024 namespace QCA {
00025
00026
00027
00028
00029 TextFilter::TextFilter(Direction dir)
00030 {
00031 setup(dir);
00032 }
00033
00034 void TextFilter::setup(Direction dir)
00035 {
00036 _dir = dir;
00037 }
00038
00039 Direction TextFilter::direction() const
00040 {
00041 return _dir;
00042 }
00043
00044 MemoryRegion TextFilter::encode(const MemoryRegion &a)
00045 {
00046 setup(Encode);
00047 return process(a);
00048 }
00049
00050 MemoryRegion TextFilter::decode(const MemoryRegion &a)
00051 {
00052 setup(Decode);
00053 return process(a);
00054 }
00055
00056 QString TextFilter::arrayToString(const MemoryRegion &a)
00057 {
00058 return QString::fromLatin1(encode(a).toByteArray());
00059 }
00060
00061 MemoryRegion TextFilter::stringToArray(const QString &s)
00062 {
00063 if(s.isEmpty())
00064 return MemoryRegion();
00065 return decode(s.toLatin1());
00066 }
00067
00068 QString TextFilter::encodeString(const QString &s)
00069 {
00070 return arrayToString(s.toUtf8());
00071 }
00072
00073 QString TextFilter::decodeString(const QString &s)
00074 {
00075 return QString::fromUtf8(stringToArray(s).toByteArray());
00076 }
00077
00078
00079
00080
00081 static int enhex(uchar c)
00082 {
00083 if(c < 10)
00084 return c + '0';
00085 else if(c < 16)
00086 return c - 10 + 'a';
00087 else
00088 return -1;
00089 }
00090
00091 static int dehex(char c)
00092 {
00093 if(c >= 'a' && c <= 'f')
00094 return c - 'a' + 10;
00095 else if(c >= 'A' && c <= 'F')
00096 return c - 'A' + 10;
00097 else if(c >= '0' && c <= '9')
00098 return c - '0';
00099 else
00100 return -1;
00101 }
00102
00103 Hex::Hex(Direction dir)
00104 :TextFilter(dir)
00105 {
00106 clear();
00107 }
00108
00109 void Hex::clear()
00110 {
00111 partial = false;
00112 _ok = true;
00113 }
00114
00115 MemoryRegion Hex::update(const MemoryRegion &m)
00116 {
00117 QByteArray a = m.toByteArray();
00118 if(_dir == Encode)
00119 {
00120 QByteArray out(a.size() * 2, 0);
00121 int at = 0;
00122 int c;
00123 for(int n = 0; n < (int)a.size(); ++n)
00124 {
00125 uchar lo = (uchar)a[n] & 0x0f;
00126 uchar hi = (uchar)a[n] >> 4;
00127 c = enhex(hi);
00128 if(c == -1)
00129 {
00130 _ok = false;
00131 break;
00132 }
00133 out[at++] = (char)c;
00134 c = enhex(lo);
00135 if(c == -1)
00136 {
00137 _ok = false;
00138 break;
00139 }
00140 out[at++] = (char)c;
00141 }
00142 if(!_ok)
00143 return MemoryRegion();
00144
00145 return out;
00146 }
00147 else
00148 {
00149 uchar lo = 0;
00150 uchar hi = 0;
00151 bool flag = false;
00152 if(partial)
00153 {
00154 hi = val;
00155 flag = true;
00156 }
00157
00158 QByteArray out(a.size() / 2, 0);
00159 int at = 0;
00160 int c;
00161 for(int n = 0; n < (int)a.size(); ++n)
00162 {
00163 c = dehex((char)a[n]);
00164 if(c == -1)
00165 {
00166 _ok = false;
00167 break;
00168 }
00169 if(flag)
00170 {
00171 lo = (uchar)c;
00172 uchar full = ((hi & 0x0f) << 4) + (lo & 0x0f);
00173 out[at++] = full;
00174 flag = false;
00175 }
00176 else
00177 {
00178 hi = (uchar)c;
00179 flag = true;
00180 }
00181 }
00182 if(!_ok)
00183 return MemoryRegion();
00184
00185 if(flag)
00186 {
00187 val = hi;
00188 partial = true;
00189 }
00190 return out;
00191 }
00192 }
00193
00194 MemoryRegion Hex::final()
00195 {
00196 if(partial)
00197 _ok = false;
00198 return MemoryRegion();
00199 }
00200
00201 bool Hex::ok() const
00202 {
00203 return _ok;
00204 }
00205
00206
00207
00208
00209 Base64::Base64(Direction dir)
00210 :TextFilter(dir)
00211 {
00212 _lb_enabled = false;
00213 _lb_column = 76;
00214 }
00215
00216 void Base64::clear()
00217 {
00218 partial.resize(0);
00219 _ok = true;
00220 col = 0;
00221 }
00222
00223 bool Base64::lineBreaksEnabled() const
00224 {
00225 return _lb_enabled;
00226 }
00227
00228 int Base64::lineBreaksColumn() const
00229 {
00230 return _lb_column;
00231 }
00232
00233 void Base64::setLineBreaksEnabled(bool b)
00234 {
00235 _lb_enabled = b;
00236 }
00237
00238 void Base64::setLineBreaksColumn(int column)
00239 {
00240 if(column > 0)
00241 _lb_column = column;
00242 else
00243 _lb_column = 76;
00244 }
00245
00246 static QByteArray b64encode(const QByteArray &s)
00247 {
00248 int i;
00249 int len = s.size();
00250 static char tbl[] =
00251 "ABCDEFGH"
00252 "IJKLMNOP"
00253 "QRSTUVWX"
00254 "YZabcdef"
00255 "ghijklmn"
00256 "opqrstuv"
00257 "wxyz0123"
00258 "456789+/"
00259 "=";
00260 int a, b, c;
00261
00262 QByteArray p((len + 2) / 3 * 4, 0);
00263 int at = 0;
00264 for(i = 0; i < len; i += 3)
00265 {
00266 a = ((unsigned char)s[i] & 3) << 4;
00267 if(i + 1 < len)
00268 {
00269 a += (unsigned char)s[i + 1] >> 4;
00270 b = ((unsigned char)s[i + 1] & 0xf) << 2;
00271 if(i + 2 < len)
00272 {
00273 b += (unsigned char)s[i + 2] >> 6;
00274 c = (unsigned char)s[i + 2] & 0x3f;
00275 }
00276 else
00277 c = 64;
00278 }
00279 else
00280 b = c = 64;
00281
00282 p[at++] = tbl[(unsigned char)s[i] >> 2];
00283 p[at++] = tbl[a];
00284 p[at++] = tbl[b];
00285 p[at++] = tbl[c];
00286 }
00287 return p;
00288 }
00289
00290 static QByteArray b64decode(const QByteArray &s, bool *ok)
00291 {
00292
00293
00294
00295
00296 static char tbl[] =
00297 {
00298 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00299 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00300 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
00301 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1,
00302 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
00303 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
00304 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
00305 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
00306 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00307 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00308 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00309 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00310 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00311 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00312 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00313 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
00314 };
00315
00316
00317 QByteArray p;
00318 *ok = true;
00319
00320
00321 int len = s.size();
00322 if(len % 4)
00323 {
00324 *ok = false;
00325 return p;
00326 }
00327
00328 p.resize(len / 4 * 3);
00329
00330 int i;
00331 int at = 0;
00332
00333 int a, b, c, d;
00334 c = d = 0;
00335
00336 for(i = 0; i < len; i += 4)
00337 {
00338 a = tbl[(int)s[i]];
00339 b = tbl[(int)s[i + 1]];
00340 c = tbl[(int)s[i + 2]];
00341 d = tbl[(int)s[i + 3]];
00342 if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0))
00343 {
00344 p.resize(0);
00345 *ok = false;
00346 return p;
00347 }
00348 p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03);
00349 p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F);
00350 p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F);
00351 }
00352
00353 if(c & 64)
00354 p.resize(at - 2);
00355 else if(d & 64)
00356 p.resize(at - 1);
00357
00358 return p;
00359 }
00360
00361 static int findLF(const QByteArray &in, int offset)
00362 {
00363 for(int n = offset; n < in.size(); ++n)
00364 {
00365 if(in[n] == '\n')
00366 return n;
00367 }
00368 return -1;
00369 }
00370
00371 static QByteArray insert_linebreaks(const QByteArray &s, int *col, int lfAt)
00372 {
00373 QByteArray out = s;
00374
00375 int needed = (out.size() + *col) / lfAt;
00376 if(needed > 0)
00377 {
00378 int firstlen = lfAt - *col;
00379 int at = firstlen + (lfAt * (needed - 1));
00380 int lastlen = out.size() - at;
00381
00382
00383
00384
00385 out.resize(out.size() + needed);
00386
00387
00388 for(int n = 0; n < needed; ++n)
00389 {
00390 char *p = out.data() + at;
00391 int len;
00392 if(n == 0)
00393 len = lastlen;
00394 else
00395 len = lfAt;
00396 memmove(p + needed - n, p, len);
00397 p[needed - n - 1] = '\n';
00398 at -= lfAt;
00399 }
00400
00401 *col = lastlen;
00402 }
00403 else
00404 *col += out.size();
00405
00406 return out;
00407 }
00408
00409 static QByteArray remove_linebreaks(const QByteArray &s)
00410 {
00411 QByteArray out = s;
00412
00413 int removed = 0;
00414 int at = findLF(out, 0);
00415 while(at != -1)
00416 {
00417 int next = findLF(out, at + 1);
00418 int len;
00419 if(next != -1)
00420 len = next - at;
00421 else
00422 len = out.size() - at;
00423
00424 if(len > 1)
00425 {
00426 char *p = out.data() + at;
00427 memmove(p - removed, p + 1, len - 1);
00428 }
00429 ++removed;
00430 at = next;
00431 }
00432 out.resize(out.size() - removed);
00433
00434 return out;
00435 }
00436
00437 static void appendArray(QByteArray *a, const QByteArray &b)
00438 {
00439 a->append(b);
00440 }
00441
00442 MemoryRegion Base64::update(const MemoryRegion &m)
00443 {
00444 QByteArray in;
00445 if(_dir == Decode && _lb_enabled)
00446 in = remove_linebreaks(m.toByteArray());
00447 else
00448 in = m.toByteArray();
00449
00450 if(in.isEmpty())
00451 return MemoryRegion();
00452
00453 int chunk;
00454 if(_dir == Encode)
00455 chunk = 3;
00456 else
00457 chunk = 4;
00458
00459 int size = partial.size() + in.size();
00460 if(size < chunk)
00461 {
00462 appendArray(&partial, in);
00463 return MemoryRegion();
00464 }
00465
00466 int eat = size % chunk;
00467
00468
00469 QByteArray s(partial.size() + in.size() - eat, 0);
00470 memcpy(s.data(), partial.data(), partial.size());
00471 memcpy(s.data() + partial.size(), in.data(), in.size() - eat);
00472
00473 partial.resize(eat);
00474 memcpy(partial.data(), in.data() + in.size() - eat, eat);
00475
00476 if(_dir == Encode)
00477 {
00478 if(_lb_enabled)
00479 return insert_linebreaks(b64encode(s), &col, _lb_column);
00480 else
00481 return b64encode(s);
00482 }
00483 else
00484 {
00485 bool ok;
00486 QByteArray out = b64decode(s, &ok);
00487 if(!ok)
00488 _ok = false;
00489 return out;
00490 }
00491 }
00492
00493 MemoryRegion Base64::final()
00494 {
00495 if(_dir == Encode)
00496 {
00497 if(_lb_enabled)
00498 return insert_linebreaks(b64encode(partial), &col, _lb_column);
00499 else
00500 return b64encode(partial);
00501 }
00502 else
00503 {
00504 bool ok;
00505 QByteArray out = b64decode(partial, &ok);
00506 if(!ok)
00507 _ok = false;
00508 return out;
00509 }
00510 }
00511
00512 bool Base64::ok() const
00513 {
00514 return _ok;
00515 }
00516
00517 }