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

KDE's Doxygen guidelines are available online.