KCodecs

kcodecs.cpp
1 /*
2  SPDX-FileCopyrightText: 2000-2001 Dawit Alemayehu <[email protected]>
3  SPDX-FileCopyrightText: 2001 Rik Hemsley (rikkus) <[email protected]>
4  SPDX-FileCopyrightText: 2001-2002 Marc Mutz <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 
8  RFC 1321 "MD5 Message-Digest Algorithm" Copyright (C) 1991-1992. // krazy:exclude=copyright
9  RSA Data Security, Inc. Created 1991. All rights reserved.
10 
11  The KMD5 class is based on a C++ implementation of
12  "RSA Data Security, Inc. MD5 Message-Digest Algorithm" by
13  Mordechai T. Abzug, Copyright (c) 1995. This implementation // krazy:exclude=copyright
14  passes the test-suite as defined in RFC 1321.
15 
16  The encoding and decoding utilities in KCodecs with the exception of
17  quoted-printable are based on the java implementation in HTTPClient
18  package by Ronald Tschalär Copyright (C) 1996-1999. // krazy:exclude=copyright
19 
20  The quoted-printable codec as described in RFC 2045, section 6.7. is by
21  Rik Hemsley (C) 2001.
22 */
23 
24 #include "kcodecs.h"
25 #include "kcharsets.h"
26 #include "kcodecs_debug.h"
27 #include "kcodecs_p.h"
28 #include "kcodecsbase64.h"
29 #include "kcodecsidentity.h"
30 #include "kcodecsqp.h"
31 #include "kcodecsuuencode.h"
32 
33 #include <QMutex>
34 
35 #include <cassert>
36 #include <cstring>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include <QDebug>
42 #include <QHash>
43 #include <QTextCodec>
44 
45 #if defined(Q_OS_WIN)
46 #define strncasecmp _strnicmp
47 #endif
48 
49 namespace KCodecs
50 {
51 static QList<QByteArray> charsetCache;
52 
53 QByteArray cachedCharset(const QByteArray &name)
54 {
55  auto it = std::find_if(charsetCache.cbegin(), charsetCache.cend(), [&name](const QByteArray &charset) {
56  return qstricmp(name.data(), charset.data()) == 0;
57  });
58  if (it != charsetCache.cend()) {
59  return *it;
60  }
61 
62  charsetCache.append(name.toUpper());
63  return charsetCache.last();
64 }
65 
66 namespace CodecNames
67 {
68 QByteArray utf8()
69 {
70  return QByteArrayLiteral("UTF-8");
71 }
72 }
73 
74 Q_REQUIRED_RESULT
75 QByteArray updateEncodingCharset(const QByteArray &currentCharset, const QByteArray &nextCharset)
76 {
77  if (!nextCharset.isEmpty()) {
78  if (currentCharset.isEmpty()) {
79  return nextCharset;
80  }
81  if (currentCharset != nextCharset) {
82  // only one charset per string supported, so change to superset charset UTF-8,
83  // which should cover any possible chars
84  return CodecNames::utf8();
85  }
86  }
87  return currentCharset;
88 }
89 
90 } // namespace KCodecs
91 
92 /******************************** KCodecs ********************************/
93 
95 {
96  Codec *codec = Codec::codecForName("quoted-printable");
97  return codec->encode(in, useCRLF ? Codec::NewlineCRLF : Codec::NewlineLF);
98 }
99 
100 void KCodecs::quotedPrintableEncode(const QByteArray &in, QByteArray &out, bool useCRLF)
101 {
102  out = quotedPrintableEncode(in, useCRLF ? Codec::NewlineCRLF : Codec::NewlineLF);
103 }
104 
106 {
107  Codec *codec = Codec::codecForName("quoted-printable");
108  return codec->decode(in);
109 }
110 
112 {
113  out = quotedPrintableDecode(in);
114 }
115 
117 {
118  Codec *codec = Codec::codecForName("base64");
119  return codec->encode(in);
120 }
121 
122 #if KCODECS_BUILD_DEPRECATED_SINCE(5, 5)
123 QByteArray KCodecs::base64Encode(const QByteArray &in, bool insertLFs)
124 {
125  Q_UNUSED(insertLFs);
126  return base64Encode(in);
127 }
128 #endif
129 
130 void KCodecs::base64Encode(const QByteArray &in, QByteArray &out, bool insertLFs)
131 {
132  Q_UNUSED(insertLFs);
133  out = base64Encode(in);
134 }
135 
137 {
138  Codec *codec = Codec::codecForName("base64");
139  return codec->decode(in);
140 }
141 
143 {
144  out = base64Decode(in);
145 }
146 
147 #if KCODECS_BUILD_DEPRECATED_SINCE(5, 56)
149 {
150  Codec *codec = Codec::codecForName("x-uuencode");
151  return codec->encode(in);
152 }
153 #endif
154 
155 #if KCODECS_BUILD_DEPRECATED_SINCE(5, 56)
157 {
158  out = uuencode(in);
159 }
160 #endif
161 
163 {
164  Codec *codec = Codec::codecForName("x-uuencode");
165  return codec->decode(in);
166 }
167 
169 {
170  out = uudecode(in);
171 }
172 
173 //@cond PRIVATE
174 
175 namespace KCodecs
176 {
177 // parse the encoded-word (scursor points to after the initial '=')
178 bool parseEncodedWord(const char *&scursor,
179  const char *const send,
180  QString *result,
181  QByteArray *language,
182  QByteArray *usedCS,
183  const QByteArray &defaultCS,
184  CharsetOption charsetOption)
185 {
186  assert(result);
187  assert(language);
188 
189  // make sure the caller already did a bit of the work.
190  assert(*(scursor - 1) == '=');
191 
192  //
193  // STEP 1:
194  // scan for the charset/language portion of the encoded-word
195  //
196 
197  char ch = *scursor++;
198 
199  if (ch != '?') {
200  // qCDebug(KCODECS_LOG) << "first";
201  // qCDebug(KCODECS_LOG) << "Premature end of encoded word";
202  return false;
203  }
204 
205  // remember start of charset (ie. just after the initial "=?") and
206  // language (just after the first '*') fields:
207  const char *charsetStart = scursor;
208  const char *languageStart = nullptr;
209 
210  // find delimiting '?' (and the '*' separating charset and language
211  // tags, if any):
212  for (; scursor != send; scursor++) {
213  if (*scursor == '?') {
214  break;
215  } else if (*scursor == '*' && languageStart == nullptr) {
216  languageStart = scursor + 1;
217  }
218  }
219 
220  // not found? can't be an encoded-word!
221  if (scursor == send || *scursor != '?') {
222  // qCDebug(KCODECS_LOG) << "second";
223  // qCDebug(KCODECS_LOG) << "Premature end of encoded word";
224  return false;
225  }
226 
227  // extract the language information, if any (if languageStart is 0,
228  // language will be null, too):
229  QByteArray maybeLanguage(languageStart, scursor - languageStart);
230  // extract charset information (keep in mind: the size given to the
231  // ctor is one off due to the \0 terminator):
232  QByteArray maybeCharset(charsetStart, (languageStart ? languageStart - 1 : scursor) - charsetStart);
233 
234  //
235  // STEP 2:
236  // scan for the encoding portion of the encoded-word
237  //
238 
239  // remember start of encoding (just _after_ the second '?'):
240  scursor++;
241  const char *encodingStart = scursor;
242 
243  // find next '?' (ending the encoding tag):
244  for (; scursor != send; scursor++) {
245  if (*scursor == '?') {
246  break;
247  }
248  }
249 
250  // not found? Can't be an encoded-word!
251  if (scursor == send || *scursor != '?') {
252  // qCDebug(KCODECS_LOG) << "third";
253  // qCDebug(KCODECS_LOG) << "Premature end of encoded word";
254  return false;
255  }
256 
257  // extract the encoding information:
258  QByteArray maybeEncoding(encodingStart, scursor - encodingStart);
259 
260  // qCDebug(KCODECS_LOG) << "parseEncodedWord: found charset == \"" << maybeCharset
261  // << "\"; language == \"" << maybeLanguage
262  // << "\"; encoding == \"" << maybeEncoding << "\"";
263 
264  //
265  // STEP 3:
266  // scan for encoded-text portion of encoded-word
267  //
268 
269  // remember start of encoded-text (just after the third '?'):
270  scursor++;
271  const char *encodedTextStart = scursor;
272 
273  // find the '?=' sequence (ending the encoded-text):
274  for (; scursor != send; scursor++) {
275  if (*scursor == '?') {
276  if (scursor + 1 != send) {
277  if (*(scursor + 1) != '=') { // We expect a '=' after the '?', but we got something else; ignore
278  // qCDebug(KCODECS_LOG) << "Stray '?' in q-encoded word, ignoring this.";
279  continue;
280  } else { // yep, found a '?=' sequence
281  scursor += 2;
282  break;
283  }
284  } else { // The '?' is the last char, but we need a '=' after it!
285  // qCDebug(KCODECS_LOG) << "Premature end of encoded word";
286  return false;
287  }
288  }
289  }
290 
291  if (*(scursor - 2) != '?' || *(scursor - 1) != '=' || scursor < encodedTextStart + 2) {
292  // qCDebug(KCODECS_LOG) << "Premature end of encoded word";
293  return false;
294  }
295 
296  // set end sentinel for encoded-text:
297  const char *const encodedTextEnd = scursor - 2;
298 
299  //
300  // STEP 4:
301  // setup decoders for the transfer encoding and the charset
302  //
303 
304  // try if there's a codec for the encoding found:
305  Codec *codec = Codec::codecForName(maybeEncoding);
306  if (!codec) {
307  // qCDebug(KCODECS_LOG) << "Unknown encoding" << maybeEncoding;
308  return false;
309  }
310 
311  // get an instance of a corresponding decoder:
312  Decoder *dec = codec->makeDecoder();
313  assert(dec);
314 
315  // try if there's a (text)codec for the charset found:
316  bool matchOK = false;
317  QByteArray cs;
318  QTextCodec *textCodec = nullptr;
319  if (charsetOption == KCodecs::ForceDefaultCharset || maybeCharset.isEmpty()) {
320  textCodec = KCharsets::charsets()->codecForName(QLatin1String(defaultCS), matchOK);
321  cs = cachedCharset(defaultCS);
322  } else {
323  textCodec = KCharsets::charsets()->codecForName(QLatin1String(maybeCharset), matchOK);
324  if (!matchOK) { // no suitable codec found => use default charset
325  textCodec = KCharsets::charsets()->codecForName(QLatin1String(defaultCS), matchOK);
326  cs = cachedCharset(defaultCS);
327  } else {
328  cs = cachedCharset(maybeCharset);
329  }
330  }
331  if (usedCS) {
332  *usedCS = updateEncodingCharset(*usedCS, cs);
333  }
334 
335  if (!matchOK || !textCodec) {
336  // qCDebug(KCODECS_LOG) << "Unknown charset" << maybeCharset;
337  delete dec;
338  return false;
339  };
340 
341  // qCDebug(KCODECS_LOG) << "mimeName(): \"" << textCodec->name() << "\"";
342 
343  // allocate a temporary buffer to store the 8bit text:
344  int encodedTextLength = encodedTextEnd - encodedTextStart;
345  QByteArray buffer;
346  buffer.resize(codec->maxDecodedSizeFor(encodedTextLength));
347  char *bbegin = buffer.data();
348  char *bend = bbegin + buffer.length();
349 
350  //
351  // STEP 5:
352  // do the actual decoding
353  //
354 
355  if (!dec->decode(encodedTextStart, encodedTextEnd, bbegin, bend)) {
356  qWarning() << codec->name() << "codec lies about its maxDecodedSizeFor(" << encodedTextLength << ")\nresult may be truncated";
357  }
358 
359  *result = textCodec->toUnicode(buffer.data(), bbegin - buffer.data());
360 
361  // qCDebug(KCODECS_LOG) << "result now: \"" << result << "\"";
362  // cleanup:
363  delete dec;
364  *language = maybeLanguage;
365 
366  return true;
367 }
368 
369 } // namespace KCodecs
370 
371 //@endcond
372 
374 {
375  QByteArray usedCS;
376  return decodeRFC2047String(msg.toUtf8(), &usedCS, CodecNames::utf8(), NoOption);
377 }
378 
379 QString KCodecs::decodeRFC2047String(const QByteArray &src, QByteArray *usedCS, const QByteArray &defaultCS, CharsetOption charsetOption)
380 {
381  QByteArray result;
382  QByteArray spaceBuffer;
383  const char *scursor = src.constData();
384  const char *send = scursor + src.length();
385  bool onlySpacesSinceLastWord = false;
386  if (usedCS) {
387  usedCS->clear();
388  }
389 
390  while (scursor != send) {
391  // space
392  if (isspace(*scursor) && onlySpacesSinceLastWord) {
393  spaceBuffer += *scursor++;
394  continue;
395  }
396 
397  // possible start of an encoded word
398  if (*scursor == '=') {
399  QByteArray language;
400  QString decoded;
401  ++scursor;
402  const char *start = scursor;
403  if (parseEncodedWord(scursor, send, &decoded, &language, usedCS, defaultCS, charsetOption)) {
404  result += decoded.toUtf8();
405  onlySpacesSinceLastWord = true;
406  spaceBuffer.clear();
407  } else {
408  if (onlySpacesSinceLastWord) {
409  result += spaceBuffer;
410  onlySpacesSinceLastWord = false;
411  }
412  result += '=';
413  scursor = start; // reset cursor after parsing failure
414  }
415  continue;
416  } else {
417  // unencoded data
418  if (onlySpacesSinceLastWord) {
419  result += spaceBuffer;
420  onlySpacesSinceLastWord = false;
421  }
422  result += *scursor;
423  ++scursor;
424  }
425  }
426  // If there are any chars that couldn't be decoded in UTF-8,
427  // fallback to local codec
428  const QString tryUtf8 = QString::fromUtf8(result);
429  if (tryUtf8.contains(QChar(0xFFFD))) {
431  if (usedCS) {
432  *usedCS = updateEncodingCharset(*usedCS, cachedCharset(codec->name()));
433  }
434  return codec->toUnicode(result);
435  } else {
436  return tryUtf8;
437  }
438 }
439 
441 {
442  QByteArray result;
443  int start = 0;
444  int end = 0;
445  bool nonAscii = false;
446  bool ok = true;
447  bool useQEncoding = false;
448 
449  // fromLatin1() is safe here, codecForName() uses toLatin1() internally
450  const QTextCodec *codec = KCharsets::charsets()->codecForName(QString::fromLatin1(charset), ok);
451 
452  QByteArray usedCS;
453  if (!ok) {
454  // no codec available => try local8Bit and hope the best ;-)
455  codec = QTextCodec::codecForLocale();
456  usedCS = codec->name();
457  } else {
458  Q_ASSERT(codec);
459  if (charset.isEmpty()) {
460  usedCS = codec->name();
461  } else {
462  usedCS = charset;
463  }
464  }
465 
467  QByteArray encoded8Bit = codec->fromUnicode(src.constData(), src.length(), &converterState);
468  if (converterState.invalidChars > 0) {
469  usedCS = CodecNames::utf8();
470  codec = QTextCodec::codecForName(usedCS);
471  encoded8Bit = codec->fromUnicode(src);
472  }
473 
474  if (usedCS.contains("8859-")) { // use "B"-Encoding for non iso-8859-x charsets
475  useQEncoding = true;
476  }
477 
478  uint encoded8BitLength = encoded8Bit.length();
479  for (unsigned int i = 0; i < encoded8BitLength; i++) {
480  if (encoded8Bit[i] == ' ') { // encoding starts at word boundaries
481  start = i + 1;
482  }
483 
484  // encode escape character, for japanese encodings...
485  if (((signed char)encoded8Bit[i] < 0) || (encoded8Bit[i] == '\033')) {
486  end = start; // non us-ascii char found, now we determine where to stop encoding
487  nonAscii = true;
488  break;
489  }
490  }
491 
492  if (nonAscii) {
493  while ((end < encoded8Bit.length()) && (encoded8Bit[end] != ' ')) {
494  // we encode complete words
495  end++;
496  }
497 
498  for (int x = end; x < encoded8Bit.length(); x++) {
499  if (((signed char)encoded8Bit[x] < 0) || (encoded8Bit[x] == '\033')) {
500  end = x; // we found another non-ascii word
501 
502  while ((end < encoded8Bit.length()) && (encoded8Bit[end] != ' ')) {
503  // we encode complete words
504  end++;
505  }
506  }
507  }
508 
509  result = encoded8Bit.left(start) + "=?" + usedCS;
510 
511  if (useQEncoding) {
512  result += "?Q?";
513 
514  char hexcode; // "Q"-encoding implementation described in RFC 2047
515  for (int i = start; i < end; i++) {
516  const char c = encoded8Bit[i];
517  if (c == ' ') { // make the result readable with not MIME-capable readers
518  result += '_';
519  } else {
520  if (((c >= 'a') && (c <= 'z')) || // paranoid mode, encode *all* special chars to avoid problems
521  ((c >= 'A') && (c <= 'Z')) || // with "From" & "To" headers
522  ((c >= '0') && (c <= '9'))) {
523  result += c;
524  } else {
525  result += '='; // "stolen" from KMail ;-)
526  hexcode = ((c & 0xF0) >> 4) + 48;
527  if (hexcode >= 58) {
528  hexcode += 7;
529  }
530  result += hexcode;
531  hexcode = (c & 0x0F) + 48;
532  if (hexcode >= 58) {
533  hexcode += 7;
534  }
535  result += hexcode;
536  }
537  }
538  }
539  } else {
540  result += "?B?" + encoded8Bit.mid(start, end - start).toBase64();
541  }
542 
543  result += "?=";
544  result += encoded8Bit.right(encoded8Bit.length() - end);
545  } else {
546  result = encoded8Bit;
547  }
548 
549  return result;
550 }
551 
552 /******************************************************************************/
553 /* KCodecs::Codec */
554 
555 // global list of KCodecs::Codec's
556 //@cond PRIVATE
557 namespace
558 {
559 static QHash<QByteArray, KCodecs::Codec *> *allCodecs = nullptr;
560 Q_GLOBAL_STATIC(QMutex, dictLock)
561 
562 static void createCodecs()
563 {
564  // all->insert( "7bit", new KCodecs::SevenBitCodec() );
565  // all->insert( "8bit", new KCodecs::EightBitCodec() );
566  allCodecs->insert("base64", new KCodecs::Base64Codec());
567  allCodecs->insert("quoted-printable", new KCodecs::QuotedPrintableCodec());
568  allCodecs->insert("b", new KCodecs::Rfc2047BEncodingCodec());
569  allCodecs->insert("q", new KCodecs::Rfc2047QEncodingCodec());
570  allCodecs->insert("x-kmime-rfc2231", new KCodecs::Rfc2231EncodingCodec());
571  allCodecs->insert("x-uuencode", new KCodecs::UUCodec());
572  // all->insert( "binary", new KCodecs::BinaryCodec() );
573 }
574 
575 static void cleanupCodecs()
576 {
577  qDeleteAll(*allCodecs);
578  delete allCodecs;
579  allCodecs = nullptr;
580 }
581 
582 }
583 //@endcond
584 
586 {
587  const QByteArray ba(name);
588  return codecForName(ba);
589 }
590 
592 {
593  QMutexLocker locker(dictLock()); // protect "allCodecs"
594  if (!allCodecs) {
595  allCodecs = new QHash<QByteArray, Codec *>();
596  qAddPostRoutine(cleanupCodecs);
597  createCodecs();
598  }
599  QByteArray lowerName = name.toLower();
600  Codec *codec = (*allCodecs).value(lowerName);
601 
602  if (!codec) {
603  qWarning() << "Unknown codec \"" << name << "\" requested!";
604  }
605 
606  return codec;
607 }
608 
609 bool KCodecs::Codec::encode(const char *&scursor, const char *const send, char *&dcursor, const char *const dend, NewlineType newline) const
610 {
611  // get an encoder:
612  std::unique_ptr<Encoder> enc(makeEncoder(newline));
613  if (!enc) {
614  qWarning() << "makeEncoder failed for" << name();
615  return false;
616  }
617 
618  // encode and check for output buffer overflow:
619  while (!enc->encode(scursor, send, dcursor, dend)) {
620  if (dcursor == dend) {
621  return false; // not enough space in output buffer
622  }
623  }
624 
625  // finish and check for output buffer overflow:
626  while (!enc->finish(dcursor, dend)) {
627  if (dcursor == dend) {
628  return false; // not enough space in output buffer
629  }
630  }
631 
632  return true; // successfully encoded.
633 }
634 
635 QByteArray KCodecs::Codec::encode(const QByteArray &src, NewlineType newline) const
636 {
637  // allocate buffer for the worst case:
638  QByteArray result;
639  result.resize(maxEncodedSizeFor(src.size(), newline));
640 
641  // set up iterators:
642  QByteArray::ConstIterator iit = src.begin();
643  QByteArray::ConstIterator iend = src.end();
644  QByteArray::Iterator oit = result.begin();
645  QByteArray::ConstIterator oend = result.end();
646 
647  // encode
648  if (!encode(iit, iend, oit, oend, newline)) {
649  qCritical() << name() << "codec lies about it's mEncodedSizeFor()";
650  }
651 
652  // shrink result to actual size:
653  result.truncate(oit - result.begin());
654 
655  return result;
656 }
657 
658 QByteArray KCodecs::Codec::decode(const QByteArray &src, NewlineType newline) const
659 {
660  // allocate buffer for the worst case:
661  QByteArray result;
662  result.resize(maxDecodedSizeFor(src.size(), newline));
663 
664  // set up iterators:
665  QByteArray::ConstIterator iit = src.begin();
666  QByteArray::ConstIterator iend = src.end();
667  QByteArray::Iterator oit = result.begin();
668  QByteArray::ConstIterator oend = result.end();
669 
670  // decode
671  if (!decode(iit, iend, oit, oend, newline)) {
672  qCritical() << name() << "codec lies about it's maxDecodedSizeFor()";
673  }
674 
675  // shrink result to actual size:
676  result.truncate(oit - result.begin());
677 
678  return result;
679 }
680 
681 bool KCodecs::Codec::decode(const char *&scursor, const char *const send, char *&dcursor, const char *const dend, NewlineType newline) const
682 {
683  // get a decoder:
684  std::unique_ptr<Decoder> dec(makeDecoder(newline));
685  assert(dec);
686 
687  // decode and check for output buffer overflow:
688  while (!dec->decode(scursor, send, dcursor, dend)) {
689  if (dcursor == dend) {
690  return false; // not enough space in output buffer
691  }
692  }
693 
694  // finish and check for output buffer overflow:
695  while (!dec->finish(dcursor, dend)) {
696  if (dcursor == dend) {
697  return false; // not enough space in output buffer
698  }
699  }
700 
701  return true; // successfully encoded.
702 }
703 
704 /******************************************************************************/
705 /* KCodecs::Encoder */
706 
707 KCodecs::EncoderPrivate::EncoderPrivate(Codec::NewlineType newline)
708  : outputBufferCursor(0)
709  , newline(newline)
710 {
711 }
712 
713 KCodecs::Encoder::Encoder(Codec::NewlineType newline)
714  : d(new KCodecs::EncoderPrivate(newline))
715 {
716 }
717 
718 KCodecs::Encoder::~Encoder() = default;
719 
720 bool KCodecs::Encoder::write(char ch, char *&dcursor, const char *const dend)
721 {
722  if (dcursor != dend) {
723  // if there's space in the output stream, write there:
724  *dcursor++ = ch;
725  return true;
726  } else {
727  // else buffer the output:
728  if (d->outputBufferCursor >= maxBufferedChars) {
729  qCritical() << "KCodecs::Encoder: internal buffer overflow!";
730  } else {
731  d->outputBuffer[d->outputBufferCursor++] = ch;
732  }
733  return false;
734  }
735 }
736 
737 // write as much as possible off the output buffer. Return true if
738 // flushing was complete, false if some chars could not be flushed.
739 bool KCodecs::Encoder::flushOutputBuffer(char *&dcursor, const char *const dend)
740 {
741  int i;
742  // copy output buffer to output stream:
743  for (i = 0; dcursor != dend && i < d->outputBufferCursor; ++i) {
744  *dcursor++ = d->outputBuffer[i];
745  }
746 
747  // calculate the number of missing chars:
748  int numCharsLeft = d->outputBufferCursor - i;
749  // push the remaining chars to the begin of the buffer:
750  if (numCharsLeft) {
751  ::memmove(d->outputBuffer, d->outputBuffer + i, numCharsLeft);
752  }
753  // adjust cursor:
754  d->outputBufferCursor = numCharsLeft;
755 
756  return !numCharsLeft;
757 }
758 
759 bool KCodecs::Encoder::writeCRLF(char *&dcursor, const char *const dend)
760 {
761  if (d->newline == Codec::NewlineCRLF) {
762  write('\r', dcursor, dend);
763  }
764  return write('\n', dcursor, dend);
765 }
766 
767 /******************************************************************************/
768 /* KCodecs::Decoder */
769 
770 KCodecs::DecoderPrivate::DecoderPrivate(Codec::NewlineType newline)
771  : newline(newline)
772 {
773 }
774 
775 KCodecs::Decoder::Decoder(Codec::NewlineType newline)
776  : d(new KCodecs::DecoderPrivate(newline))
777 {
778 }
779 
780 KCodecs::Decoder::~Decoder() = default;
void append(const T &value)
QByteArray right(int len) const const
QByteArray fromUnicode(const QString &str) const const
const QChar * constData() const const
QString toUpper() const const
Defines the UUCodec class.
QString fromUtf8(const char *str, int size)
A class representing the codec for QuotedPrintable as specified in RFC2045 (section 6....
Definition: kcodecsqp.h:42
A class representing the codec for RFC2231.
Definition: kcodecsqp.h:169
KCODECS_EXPORT QString decodeRFC2047String(const QString &text)
Decodes string text according to RFC2047, i.e., the construct =?charset?[qb]?encoded?...
Definition: kcodecs.cpp:373
@ ForceDefaultCharset
No special option.
Definition: kcodecs.h:293
Q_SCRIPTABLE Q_NOREPLY void start()
KCODECS_EXPORT QByteArray uudecode(const QByteArray &in)
Decodes the given data using the uudecode algorithm.
Definition: kcodecs.cpp:162
QByteArray toBase64(QByteArray::Base64Options options) const const
QTextCodec * codecForName(const QString &name) const
Provided for compatibility.
Definition: kcharsets.cpp:712
void clear()
Defines the Base64Codec and Rfc2047BEncodingCodec classes.
QHash::iterator insert(const Key &key, const T &value)
QTextCodec * codecForLocale()
QByteArray::iterator begin()
CharsetOption
Charset options for RFC2047 encoder.
Definition: kcodecs.h:291
virtual ~Encoder()
Destroys the encoder.
virtual const char * name() const =0
Returns the name of the encoding.
QByteArray mid(int pos, int len) const const
QByteArray toUtf8() const const
int length() const const
QTextCodec * codecForName(const QByteArray &name)
KCODECS_EXPORT QByteArray base64Encode(const QByteArray &in)
Encodes the given data using the base64 algorithm.
Definition: kcodecs.cpp:116
A class representing the UUEncode codec.
Defines the classes QuotedPrintableCodec, Rfc2047QEncodingCodec, and Rfc2231EncodingCodec.
QTextStream & dec(QTextStream &stream)
QList::const_iterator cend() const const
virtual bool encode(const char *&scursor, const char *const send, char *&dcursor, const char *const dend, NewlineType newline=NewlineLF) const
Convenience wrapper that can be used for small chunks of data when you can provide a large enough buf...
Definition: kcodecs.cpp:609
KCODECS_EXPORT QByteArray base64Decode(const QByteArray &in)
Decodes the given data that was encoded using the base64 algorithm.
Definition: kcodecs.cpp:136
KCODECS_EXPORT QByteArray encodeRFC2047String(const QString &src, const QByteArray &charset)
Encodes string src according to RFC2047 using charset charset.
Definition: kcodecs.cpp:440
KCODECS_EXPORT QByteArray quotedPrintableEncode(const QByteArray &in, bool useCRLF=true)
Encodes the given data using the quoted-printable algorithm.
Definition: kcodecs.cpp:94
bool contains(char ch) const const
T & last()
QString toLower() const const
QByteArray left(int len) const const
bool isEmpty() const const
bool flushOutputBuffer(char *&dcursor, const char *const dend)
Writes characters from the output buffer to the output stream.
Definition: kcodecs.cpp:739
bool writeCRLF(char *&dcursor, const char *const dend)
Convenience function.
Definition: kcodecs.cpp:759
void resize(int size)
KCODECS_EXPORT QByteArray uuencode(const QByteArray &in)
Encodes the given data using the uuencode algorithm.
Definition: kcodecs.cpp:148
static KCharsets * charsets()
The global charset manager.
Definition: kcharsets.cpp:843
const char * constData() const const
virtual ~Decoder()
Destroys the decoder.
QString fromLatin1(const char *str, int size)
virtual bool decode(const char *&scursor, const char *const send, char *&dcursor, const char *const dend, NewlineType newline=NewlineLF) const
Convenience wrapper that can be used for small chunks of data when you can provide a large enough buf...
Definition: kcodecs.cpp:681
QList::const_iterator cbegin() const const
Encoder(Codec::NewlineType newline=Codec::NewlineLF)
Protected constructor.
Definition: kcodecs.cpp:713
A class representing the codec for the Q encoding as specified in RFC2047Q.
Definition: kcodecsqp.h:107
A class representing the codec for the B encoding as specified in RFC2047B.
const KIMAP_EXPORT QString decodeRFC2047String(const QString &str)
Decodes string text according to RFC2047, i.e., the construct =?charset?[qb]?encoded?...
Definition: kcodecs.cpp:373
A wrapper class for the most commonly used encoding and decoding algorithms.
Definition: kcodecs.cpp:49
bool write(char ch, char *&dcursor, const char *const dend)
Writes character ch to the output stream or the output buffer, depending on whether or not the output...
Definition: kcodecs.cpp:720
int size() const const
int length() const const
An abstract base class of codecs for common mail transfer encodings.
Definition: kcodecs.h:387
Decoder(Codec::NewlineType newline=Codec::NewlineLF)
Protected constructor.
Definition: kcodecs.cpp:775
void truncate(int pos)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
A class representing the codec for Base64 as specified in RFC2045.
Definition: kcodecsbase64.h:48
QString toUnicode(const QByteArray &a) const const
KCODECS_EXPORT QByteArray quotedPrintableDecode(const QByteArray &in)
Decodes a quoted-printable encoded data.
Definition: kcodecs.cpp:105
Definition: kcodecs.h:29
QByteArray::iterator end()
static Codec * codecForName(const char *name)
Returns a codec associated with the specified name.
Definition: kcodecs.cpp:585
char * data()
virtual QByteArray name() const const=0
Defines the classes IdentityCodec, SevenBitCodec, EightBitCodec, and BinaryCodec.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sun Nov 27 2022 04:02:30 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.