KCodecs

kcodecsuuencode.cpp
Go to the documentation of this file.
1 /* -*- c++ -*-
2  SPDX-FileCopyrightText: 2002 Marc Mutz <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
17 #include "kcodecsuuencode.h"
18 
19 #include <QDebug>
20 
21 #include <cassert>
22 
23 using namespace KCodecs;
24 
25 namespace KCodecs
26 {
27 
28 class UUDecoder : public Decoder
29 {
30  uint mStepNo;
31  uchar mAnnouncedOctetCount; // (on current line)
32  uchar mCurrentOctetCount; // (on current line)
33  uchar mOutbits;
34  bool mLastWasCRLF : 1;
35  bool mSawBegin : 1; // whether we already saw ^begin...
36  uint mIntoBeginLine : 3; // count #chars we compared against "begin" 0..5
37  bool mSawEnd : 1; // whether we already saw ^end...
38  uint mIntoEndLine : 2; // count #chars we compared against "end" 0..3
39 
40  void searchForBegin(const char *&scursor, const char *const send);
41 
42 protected:
43  friend class UUCodec;
44  UUDecoder(Codec::NewlineType newline = Codec::NewlineLF)
45  : Decoder(newline)
46  , mStepNo(0)
47  , mAnnouncedOctetCount(0)
48  , mCurrentOctetCount(0)
49  , mOutbits(0)
50  , mLastWasCRLF(true)
51  , mSawBegin(false)
52  , mIntoBeginLine(0)
53  , mSawEnd(false)
54  , mIntoEndLine(0)
55  {}
56 
57 public:
58  virtual ~UUDecoder() {}
59 
60  bool decode(const char *&scursor, const char *const send,
61  char *&dcursor, const char *const dend) override;
62  // ### really needs no finishing???
63  bool finish(char *&dcursor, const char *const dend) override
64  {
65  Q_UNUSED(dcursor);
66  Q_UNUSED(dend);
67  return true;
68  }
69 };
70 
71 Encoder *UUCodec::makeEncoder(NewlineType newline) const
72 {
73  Q_UNUSED(newline)
74  return nullptr; // encoding not supported
75 }
76 
77 Decoder *UUCodec::makeDecoder(NewlineType newline) const
78 {
79  return new UUDecoder(newline);
80 }
81 
82 /********************************************************/
83 /********************************************************/
84 /********************************************************/
85 
86 void UUDecoder::searchForBegin(const char *&scursor, const char *const send)
87 {
88  static const char begin[] = "begin\n";
89  static const uint beginLength = 5; // sic!
90 
91  assert(!mSawBegin || mIntoBeginLine > 0);
92 
93  while (scursor != send) {
94  uchar ch = *scursor++;
95  if (ch == begin[mIntoBeginLine]) {
96  if (mIntoBeginLine < beginLength) {
97  // found another char
98  ++mIntoBeginLine;
99  if (mIntoBeginLine == beginLength) {
100  mSawBegin = true; // "begin" complete, now search the next \n...
101  }
102  } else { // mIntoBeginLine == beginLength
103  // found '\n': begin line complete
104  mLastWasCRLF = true;
105  mIntoBeginLine = 0;
106  return;
107  }
108  } else if (mSawBegin) {
109  // OK, skip stuff until the next \n
110  } else {
111  //qWarning() << "UUDecoder: garbage before \"begin\", resetting parser";
112  mIntoBeginLine = 0;
113  }
114  }
115 
116 }
117 
118 // uuencoding just shifts all 6-bit octets by 32 (SP/' '), except NUL,
119 // which gets mapped to 0x60
120 static inline uchar uuDecode(uchar c)
121 {
122  return (c - ' ') // undo shift and
123  & 0x3F; // map 0x40 (0x60-' ') to 0...
124 }
125 
126 bool UUDecoder::decode(const char *&scursor, const char *const send,
127  char *&dcursor, const char *const dend)
128 {
129  // First, check whether we still need to find the "begin" line:
130  if (!mSawBegin || mIntoBeginLine != 0) {
131  searchForBegin(scursor, send);
132  } else if (mSawEnd) {
133  // or if we are past the end line:
134  scursor = send; // do nothing anymore...
135  return true;
136  }
137 
138  while (dcursor != dend && scursor != send) {
139  uchar ch = *scursor++;
140  uchar value;
141 
142  // Check whether we need to look for the "end" line:
143  if (mIntoEndLine > 0) {
144  static const char end[] = "end";
145  static const uint endLength = 3;
146 
147  if (ch == end[mIntoEndLine]) {
148  ++mIntoEndLine;
149  if (mIntoEndLine == endLength) {
150  mSawEnd = true;
151  scursor = send; // shortcut to the end
152  return true;
153  }
154  continue;
155  } else {
156  //qWarning() << "UUDecoder: invalid line octet count looks like \"end\" (mIntoEndLine ="
157  // << mIntoEndLine << ")!";
158  mIntoEndLine = 0;
159  // fall through...
160  }
161  }
162 
163  // Normal parsing:
164 
165  // The first char of a line is an encoding of the length of the
166  // current line. We simply ignore it:
167  if (mLastWasCRLF) {
168  // reset char-per-line counter:
169  mLastWasCRLF = false;
170  mCurrentOctetCount = 0;
171 
172  // try to decode the chars-on-this-line announcement:
173  if (ch == 'e') { // maybe the beginning of the "end"? ;-)
174  mIntoEndLine = 1;
175  } else if (ch > 0x60) {
176  // ### invalid line length char: what shall we do??
177  } else if (ch > ' ') {
178  mAnnouncedOctetCount = uuDecode(ch);
179  } else if (ch == '\n') {
180  mLastWasCRLF = true; // oops, empty line
181  }
182 
183  continue;
184  }
185 
186  // try converting ch to a 6-bit value:
187  if (ch > 0x60) {
188  continue; // invalid char
189  } else if (ch > ' ') {
190  value = uuDecode(ch);
191  } else if (ch == '\n') { // line end
192  mLastWasCRLF = true;
193  continue;
194  } else {
195  continue;
196  }
197 
198  // add the new bits to the output stream and flush full octets:
199  switch (mStepNo) {
200  case 0:
201  mOutbits = value << 2;
202  break;
203  case 1:
204  if (mCurrentOctetCount < mAnnouncedOctetCount) {
205  *dcursor++ = (char)(mOutbits | value >> 4);
206  }
207  ++mCurrentOctetCount;
208  mOutbits = value << 4;
209  break;
210  case 2:
211  if (mCurrentOctetCount < mAnnouncedOctetCount) {
212  *dcursor++ = (char)(mOutbits | value >> 2);
213  }
214  ++mCurrentOctetCount;
215  mOutbits = value << 6;
216  break;
217  case 3:
218  if (mCurrentOctetCount < mAnnouncedOctetCount) {
219  *dcursor++ = (char)(mOutbits | value);
220  }
221  ++mCurrentOctetCount;
222  mOutbits = 0;
223  break;
224  default:
225  assert(0);
226  }
227  mStepNo = (mStepNo + 1) % 4;
228 
229  // check whether we ran over the announced octet count for this line:
230  if (mCurrentOctetCount == mAnnouncedOctetCount + 1) {
231  // qWarning()
232  // << "UUDecoder: mismatch between announced ("
233  // << mAnnouncedOctetCount << ") and actual line octet count!";
234  }
235 
236  }
237 
238  // return false when caller should call us again:
239  return scursor == send;
240 } // UUDecoder::decode()
241 
242 } // namespace KCodecs
This file is part of the API for handling MIME data and defines a uuencode Codec class.
Decoder * makeDecoder(NewlineType newline=Codec::NewlineLF) const override
A class representing the UUEncode codec.
A wrapper class for the most commonly used encoding and decoding algorithms.
Definition: kcodecs.cpp:49
Encoder * makeEncoder(NewlineType newline=Codec::NewlineLF) const override
Stateful encoder class.
Definition: kcodecs.h:695
Stateful CTE decoder class.
Definition: kcodecs.h:638
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 19 2021 22:45:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.