diff options
Diffstat (limited to 'src/utility/encoder')
-rw-r--r-- | src/utility/encoder/b64Encoder.cpp | 308 | ||||
-rw-r--r-- | src/utility/encoder/binaryEncoder.cpp | 39 | ||||
-rw-r--r-- | src/utility/encoder/defaultEncoder.cpp | 73 | ||||
-rw-r--r-- | src/utility/encoder/eightBitEncoder.cpp | 39 | ||||
-rw-r--r-- | src/utility/encoder/encoder.cpp | 76 | ||||
-rw-r--r-- | src/utility/encoder/encoderFactory.cpp | 113 | ||||
-rw-r--r-- | src/utility/encoder/qpEncoder.cpp | 472 | ||||
-rw-r--r-- | src/utility/encoder/sevenBitEncoder.cpp | 39 | ||||
-rw-r--r-- | src/utility/encoder/uuEncoder.cpp | 331 |
9 files changed, 1490 insertions, 0 deletions
diff --git a/src/utility/encoder/b64Encoder.cpp b/src/utility/encoder/b64Encoder.cpp new file mode 100644 index 00000000..c4ba2b39 --- /dev/null +++ b/src/utility/encoder/b64Encoder.cpp @@ -0,0 +1,308 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/b64Encoder.hpp" +#include "vmime/parserHelpers.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +b64Encoder::b64Encoder() +{ +} + + +const std::vector <string> b64Encoder::getAvailableProperties() const +{ + std::vector <string> list(encoder::getAvailableProperties()); + + list.push_back("maxlinelength"); + + return (list); +} + + +// 7-bits alphabet used to encode binary data +const unsigned char b64Encoder::sm_alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +const unsigned char b64Encoder::sm_decodeMap[256] = +{ + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x00 - 0x0f + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x10 - 0x1f + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f, // 0x20 - 0x2f + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0x3d,0xff,0xff, // 0x30 - 0x3f + 0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, // 0x40 - 0x4f + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff, // 0x50 - 0x5f + 0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, // 0x60 - 0x6f + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff, // 0x70 - 0x7f + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x80 - 0x8f + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x90 - 0x9f + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xa0 - 0xaf + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xb0 - 0xbf + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xc0 - 0xcf + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xd0 - 0xdf + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xe0 - 0xef + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xf0 - 0xff +}; + +#ifndef VMIME_BUILDING_DOC + #define B64_WRITE(s, x, l) s.write(reinterpret_cast <utility::stream::value_type*>(x), l) +#endif // VMIME_BUILDING_DOC + + + +utility::stream::size_type b64Encoder::encode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + const int propMaxLineLength = getProperties().getProperty <int>("maxlinelength", -1); + + const bool cutLines = (propMaxLineLength != -1); + const int maxLineLength = std::min(propMaxLineLength, 76); + + // Process data + utility::stream::value_type buffer[65536]; + utility::stream::size_type bufferLength = 0; + utility::stream::size_type bufferPos = 0; + + unsigned char bytes[3]; + unsigned char output[4]; + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + int curCol = 0; + + if (progress) + progress->start(0); + + while (bufferPos < bufferLength || !in.eof()) + { + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + if (bufferLength == 0) + break; + } + + // Get 3 bytes of data + int count = 0; + + while (count < 3 && bufferPos < bufferLength) + bytes[count++] = buffer[bufferPos++]; + + while (count < 3) + { + // There may be more data in the next chunk... + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + if (bufferLength == 0) + break; + } + + while (count < 3 && bufferPos < bufferLength) + bytes[count++] = buffer[bufferPos++]; + } + + // Encode data + switch (count) + { + case 1: + + output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2]; + output[1] = sm_alphabet[(bytes[0] & 0x03) << 4]; + output[2] = sm_alphabet[64]; // padding + output[3] = sm_alphabet[64]; // padding + + break; + + case 2: + + output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2]; + output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)]; + output[2] = sm_alphabet[(bytes[1] & 0x0F) << 2]; + output[3] = sm_alphabet[64]; // padding + + break; + + default: + case 3: + + output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2]; + output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)]; + output[2] = sm_alphabet[((bytes[1] & 0x0F) << 2) | ((bytes[2] & 0xC0) >> 6)]; + output[3] = sm_alphabet[(bytes[2] & 0x3F)]; + + break; + } + + // Write encoded data to output stream + B64_WRITE(out, output, 4); + + inTotal += count; + total += 4; + curCol += 4; + + if (cutLines && curCol >= maxLineLength - 2 /* \r\n */ - 4 /* next bytes */) + { + out.write("\r\n", 2); + curCol = 0; + } + + if (progress) + progress->progress(inTotal, inTotal); + } + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +utility::stream::size_type b64Encoder::decode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + // Process the data + char buffer[16384]; + int bufferLength = 0; + int bufferPos = 0; + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + unsigned char bytes[4]; + unsigned char output[3]; + + if (progress) + progress->start(0); + + while (bufferPos < bufferLength || !in.eof()) + { + bytes[0] = '='; + bytes[1] = '='; + bytes[2] = '='; + bytes[3] = '='; + + // Need to get more data? + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + // No more data + if (bufferLength == 0) + break; + } + + // 4 bytes of input provide 3 bytes of output, so + // get the next 4 bytes from the input stream. + int count = 0; + + while (count < 4 && bufferPos < bufferLength) + { + const unsigned char c = buffer[bufferPos++]; + + if (!parserHelpers::isSpace(c)) + bytes[count++] = c; + } + + if (count != 4) + { + while (count < 4 && !in.eof()) + { + // Data continues on the next chunk + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + while (count < 4 && bufferPos < bufferLength) + { + const unsigned char c = buffer[bufferPos++]; + + if (!parserHelpers::isSpace(c)) + bytes[count++] = c; + } + } + } + + // Decode the bytes + unsigned char c1 = bytes[0]; + unsigned char c2 = bytes[1]; + + if (c1 == '=' || c2 == '=') // end + break; + + output[0] = static_cast <unsigned char>((sm_decodeMap[c1] << 2) | ((sm_decodeMap[c2] & 0x30) >> 4)); + + c1 = bytes[2]; + + if (c1 == '=') // end + { + B64_WRITE(out, output, 1); + total += 1; + break; + } + + output[1] = static_cast <unsigned char>(((sm_decodeMap[c2] & 0xf) << 4) | ((sm_decodeMap[c1] & 0x3c) >> 2)); + + c2 = bytes[3]; + + if (c2 == '=') // end + { + B64_WRITE(out, output, 2); + total += 2; + break; + } + + output[2] = static_cast <unsigned char>(((sm_decodeMap[c1] & 0x03) << 6) | sm_decodeMap[c2]); + + B64_WRITE(out, output, 3); + total += 3; + inTotal += count; + + if (progress) + progress->progress(inTotal, inTotal); + } + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/binaryEncoder.cpp b/src/utility/encoder/binaryEncoder.cpp new file mode 100644 index 00000000..2bc77d27 --- /dev/null +++ b/src/utility/encoder/binaryEncoder.cpp @@ -0,0 +1,39 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/binaryEncoder.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +binaryEncoder::binaryEncoder() +{ +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/defaultEncoder.cpp b/src/utility/encoder/defaultEncoder.cpp new file mode 100644 index 00000000..db833c85 --- /dev/null +++ b/src/utility/encoder/defaultEncoder.cpp @@ -0,0 +1,73 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/defaultEncoder.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +defaultEncoder::defaultEncoder() +{ +} + + +utility::stream::size_type defaultEncoder::encode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + // No encoding performed + utility::stream::size_type res = 0; + + if (progress) + res = utility::bufferedStreamCopy(in, out, 0, progress); + else + res = utility::bufferedStreamCopy(in, out); + + return res; +} + + +utility::stream::size_type defaultEncoder::decode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + // No decoding performed + utility::stream::size_type res = 0; + + if (progress) + res = utility::bufferedStreamCopy(in, out, 0, progress); + else + res = utility::bufferedStreamCopy(in, out); + + return res; +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/eightBitEncoder.cpp b/src/utility/encoder/eightBitEncoder.cpp new file mode 100644 index 00000000..88f07bc4 --- /dev/null +++ b/src/utility/encoder/eightBitEncoder.cpp @@ -0,0 +1,39 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/eightBitEncoder.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +eightBitEncoder::eightBitEncoder() +{ +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/encoder.cpp b/src/utility/encoder/encoder.cpp new file mode 100644 index 00000000..893ed4fc --- /dev/null +++ b/src/utility/encoder/encoder.cpp @@ -0,0 +1,76 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/encoder.hpp" +#include "vmime/exception.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +encoder::encoder() +{ +} + + +encoder::~encoder() +{ +} + + +const propertySet& encoder::getProperties() const +{ + return (m_props); +} + + +propertySet& encoder::getProperties() +{ + return (m_props); +} + + +const propertySet& encoder::getResults() const +{ + return (m_results); +} + + +propertySet& encoder::getResults() +{ + return (m_results); +} + + +const std::vector <string> encoder::getAvailableProperties() const +{ + std::vector <string> list; + return (list); +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/encoderFactory.cpp b/src/utility/encoder/encoderFactory.cpp new file mode 100644 index 00000000..9d7c1070 --- /dev/null +++ b/src/utility/encoder/encoderFactory.cpp @@ -0,0 +1,113 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/encoderFactory.hpp" +#include "vmime/exception.hpp" + +#include "vmime/utility/encoder/b64Encoder.hpp" +#include "vmime/utility/encoder/qpEncoder.hpp" +#include "vmime/utility/encoder/uuEncoder.hpp" +#include "vmime/utility/encoder/binaryEncoder.hpp" +#include "vmime/utility/encoder/sevenBitEncoder.hpp" +#include "vmime/utility/encoder/eightBitEncoder.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +encoderFactory::encoderFactory() +{ + // Register some default encoders + registerName <b64Encoder>("base64"); + registerName <qpEncoder>("quoted-printable"); + registerName <uuEncoder>("uuencode"); + registerName <sevenBitEncoder>("7bit"); + registerName <eightBitEncoder>("8bit"); + registerName <binaryEncoder>("binary"); +} + + +encoderFactory::~encoderFactory() +{ +} + + +encoderFactory* encoderFactory::getInstance() +{ + static encoderFactory instance; + return (&instance); +} + + +ref <encoder> encoderFactory::create(const string& name) +{ + return (getEncoderByName(name)->create()); +} + + +const ref <const encoderFactory::registeredEncoder> encoderFactory::getEncoderByName(const string& name) const +{ + const string lcName(utility::stringUtils::toLower(name)); + + for (std::vector <ref <registeredEncoder> >::const_iterator it = m_encoders.begin() ; + it != m_encoders.end() ; ++it) + { + if ((*it)->getName() == lcName) + return (*it); + } + + throw exceptions::no_encoder_available(name); +} + + +int encoderFactory::getEncoderCount() const +{ + return (m_encoders.size()); +} + + +const ref <const encoderFactory::registeredEncoder> encoderFactory::getEncoderAt(const int pos) const +{ + return (m_encoders[pos]); +} + + +const std::vector <ref <const encoderFactory::registeredEncoder> > encoderFactory::getEncoderList() const +{ + std::vector <ref <const registeredEncoder> > res; + + for (std::vector <ref <registeredEncoder> >::const_iterator it = m_encoders.begin() ; + it != m_encoders.end() ; ++it) + { + res.push_back(*it); + } + + return (res); +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/qpEncoder.cpp b/src/utility/encoder/qpEncoder.cpp new file mode 100644 index 00000000..737d488a --- /dev/null +++ b/src/utility/encoder/qpEncoder.cpp @@ -0,0 +1,472 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/qpEncoder.hpp" +#include "vmime/parserHelpers.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +qpEncoder::qpEncoder() +{ +} + + +const std::vector <string> qpEncoder::getAvailableProperties() const +{ + std::vector <string> list(encoder::getAvailableProperties()); + + list.push_back("maxlinelength"); + + list.push_back("text"); // if set, '\r' and '\n' are not hex-encoded. + // WARNING! You should not use this for binary data! + + list.push_back("rfc2047"); // for header fields encoding (RFC #2047) + + return (list); +} + + + +// Encoding table +const unsigned char qpEncoder::sm_hexDigits[] = "0123456789ABCDEF"; + +// Decoding table +const unsigned char qpEncoder::sm_hexDecodeTable[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +#ifndef VMIME_BUILDING_DOC + +#define QP_ENCODE_HEX(x) \ + outBuffer[outBufferPos] = '='; \ + outBuffer[outBufferPos + 1] = sm_hexDigits[x >> 4]; \ + outBuffer[outBufferPos + 2] = sm_hexDigits[x & 0xF]; \ + outBufferPos += 3; \ + curCol += 3; + +#define QP_WRITE(s, x, l) s.write(reinterpret_cast <utility::stream::value_type*>(x), l) + +#endif // VMIME_BUILDING_DOC + + +utility::stream::size_type qpEncoder::encode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + const string::size_type propMaxLineLength = + getProperties().getProperty <string::size_type>("maxlinelength", static_cast <string::size_type>(-1)); + + const bool rfc2047 = getProperties().getProperty <bool>("rfc2047", false); + const bool text = getProperties().getProperty <bool>("text", false); // binary mode by default + + const bool cutLines = (propMaxLineLength != static_cast <string::size_type>(-1)); + const string::size_type maxLineLength = std::min(propMaxLineLength, static_cast <string::size_type>(74)); + + // Process the data + char buffer[16384]; + int bufferLength = 0; + int bufferPos = 0; + + string::size_type curCol = 0; + + unsigned char outBuffer[16384]; + int outBufferPos = 0; + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + if (progress) + progress->start(0); + + while (bufferPos < bufferLength || !in.eof()) + { + // Flush current output buffer + if (outBufferPos + 6 >= static_cast <int>(sizeof(outBuffer))) + { + QP_WRITE(out, outBuffer, outBufferPos); + + total += outBufferPos; + outBufferPos = 0; + } + + // Need to get more data? + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + // No more data + if (bufferLength == 0) + break; + } + + // Get the next char and encode it + const unsigned char c = static_cast <unsigned char>(buffer[bufferPos++]); + + switch (c) + { + case '.': + { + if (!rfc2047 && curCol == 0) + { + // If a '.' appears at the beginning of a line, we encode it to + // to avoid problems with SMTP servers... ("\r\n.\r\n" means the + // end of data transmission). + QP_ENCODE_HEX('.') + continue; + } + + outBuffer[outBufferPos++] = '.'; + ++curCol; + break; + } + case ' ': + { + // RFC-2047, Page 5, 4.2. The "Q" encoding: + // << The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be + // represented as "_" (underscore, ASCII 95.). >> + if (rfc2047) + { + outBuffer[outBufferPos++] = '_'; + ++curCol; + } + else + { + // Need to get more data? + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + } + + // Spaces cannot appear at the end of a line. So, encode the space. + if (bufferPos >= bufferLength || + (buffer[bufferPos] == '\r' || buffer[bufferPos] == '\n')) + { + QP_ENCODE_HEX(' '); + } + else + { + outBuffer[outBufferPos++] = ' '; + ++curCol; + } + } + + break; + } + case '\t': + { + QP_ENCODE_HEX(c) + break; + } + case '\r': + case '\n': + { + // Text mode (where using CRLF or LF or ... does not + // care for a new line...) + if (text) + { + outBuffer[outBufferPos++] = c; + ++curCol; + } + // Binary mode (where CR and LF bytes are important!) + else + { + QP_ENCODE_HEX(c) + } + + break; + } + case '=': + { + QP_ENCODE_HEX('=') + break; + } + // RFC-2047 'especials' characters + case ',': + case ';': + case ':': + case '_': + case '@': + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + { + if (rfc2047) + { + QP_ENCODE_HEX(c) + } + else + { + outBuffer[outBufferPos++] = c; + ++curCol; + } + + break; + } + /* + Rule #2: (Literal representation) Octets with decimal values of 33 + through 60 inclusive, and 62 through 126, inclusive, MAY be + represented as the ASCII characters which correspond to those + octets (EXCLAMATION POINT through LESS THAN, and GREATER THAN + through TILDE, respectively). + */ + default: + { + //if ((c >= 33 && c <= 60) || (c >= 62 && c <= 126)) + if (c >= 33 && c <= 126 && c != 61 && c != 63) + { + outBuffer[outBufferPos++] = c; + ++curCol; + } + // Other characters: '=' + hexadecimal encoding + else + { + QP_ENCODE_HEX(c) + } + + break; + } + + } + + // Soft line break : "=\r\n" + if (cutLines && curCol >= maxLineLength - 1) + { + outBuffer[outBufferPos] = '='; + outBuffer[outBufferPos + 1] = '\r'; + outBuffer[outBufferPos + 2] = '\n'; + + outBufferPos += 3; + curCol = 0; + } + + ++inTotal; + + if (progress) + progress->progress(inTotal, inTotal); + } + + // Flush remaining output buffer + if (outBufferPos != 0) + { + QP_WRITE(out, outBuffer, outBufferPos); + total += outBufferPos; + } + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +utility::stream::size_type qpEncoder::decode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + // Process the data + const bool rfc2047 = getProperties().getProperty <bool>("rfc2047", false); + + char buffer[16384]; + int bufferLength = 0; + int bufferPos = 0; + + unsigned char outBuffer[16384]; + int outBufferPos = 0; + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + while (bufferPos < bufferLength || !in.eof()) + { + // Flush current output buffer + if (outBufferPos >= static_cast <int>(sizeof(outBuffer))) + { + QP_WRITE(out, outBuffer, outBufferPos); + + total += outBufferPos; + outBufferPos = 0; + } + + // Need to get more data? + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + + // No more data + if (bufferLength == 0) + break; + } + + // Decode the next sequence (hex-encoded byte or printable character) + unsigned char c = static_cast <unsigned char>(buffer[bufferPos++]); + + ++inTotal; + + switch (c) + { + case '=': + { + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + } + + if (bufferPos < bufferLength) + { + c = static_cast <unsigned char>(buffer[bufferPos++]); + + ++inTotal; + + switch (c) + { + // Ignore soft line break ("=\r\n" or "=\n") + case '\r': + + // Read one byte more + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + } + + if (bufferPos < bufferLength) + { + ++bufferPos; + ++inTotal; + } + + break; + + case '\n': + + break; + + // Hex-encoded char + default: + { + // We need another byte... + if (bufferPos >= bufferLength) + { + bufferLength = in.read(buffer, sizeof(buffer)); + bufferPos = 0; + } + + if (bufferPos < bufferLength) + { + const unsigned char next = static_cast <unsigned char>(buffer[bufferPos++]); + + ++inTotal; + + const unsigned char value = static_cast <unsigned char> + (sm_hexDecodeTable[c] * 16 + sm_hexDecodeTable[next]); + + outBuffer[outBufferPos++] = value; + } + else + { + // Premature end-of-data + } + + break; + } + + } + } + else + { + // Premature end-of-data + } + + break; + } + case '_': + { + if (rfc2047) + { + // RFC-2047, Page 5, 4.2. The "Q" encoding: + // << Note that the "_" always represents hexadecimal 20, even if the SPACE + // character occupies a different code position in the character set in use. >> + outBuffer[outBufferPos++] = 0x20; + break; + } + + // no break here... + } + default: + { + outBuffer[outBufferPos++] = c; + } + + } + + if (progress) + progress->progress(inTotal, inTotal); + } + + // Flush remaining output buffer + if (outBufferPos != 0) + { + QP_WRITE(out, outBuffer, outBufferPos); + total += outBufferPos; + } + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/sevenBitEncoder.cpp b/src/utility/encoder/sevenBitEncoder.cpp new file mode 100644 index 00000000..812afa90 --- /dev/null +++ b/src/utility/encoder/sevenBitEncoder.cpp @@ -0,0 +1,39 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/sevenBitEncoder.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +sevenBitEncoder::sevenBitEncoder() +{ +} + + +} // encoder +} // utility +} // vmime diff --git a/src/utility/encoder/uuEncoder.cpp b/src/utility/encoder/uuEncoder.cpp new file mode 100644 index 00000000..0e72599b --- /dev/null +++ b/src/utility/encoder/uuEncoder.cpp @@ -0,0 +1,331 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2008 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include "vmime/utility/encoder/uuEncoder.hpp" +#include "vmime/parserHelpers.hpp" + + +namespace vmime { +namespace utility { +namespace encoder { + + +uuEncoder::uuEncoder() +{ + getProperties()["mode"] = 644; + getProperties()["filename"] = "no_name"; + getProperties()["maxlinelength"] = 46; +} + + +const std::vector <string> uuEncoder::getAvailableProperties() const +{ + std::vector <string> list(encoder::getAvailableProperties()); + + list.push_back("maxlinelength"); + + list.push_back("mode"); + list.push_back("filename"); + + return (list); +} + + +// This is the character encoding function to make a character printable +static inline unsigned char UUENCODE(const unsigned char c) +{ + return ((c & 077) + ' '); +} + +// Single character decoding +static inline unsigned char UUDECODE(const unsigned char c) +{ + return ((c - ' ') & 077); +} + + +utility::stream::size_type uuEncoder::encode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + const string propFilename = getProperties().getProperty <string>("filename", ""); + const string propMode = getProperties().getProperty <string>("mode", "644"); + + const string::size_type maxLineLength = + std::min(getProperties().getProperty <string::size_type>("maxlinelength", 46), + static_cast <string::size_type>(46)); + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + // Output the prelude text ("begin [mode] [filename]") + out << "begin"; + + if (!propFilename.empty()) + { + out << " " << propMode << " " << propFilename; + total += 2 + propMode.length() + propFilename.length(); + } + + out << "\r\n"; + total += 7; + + // Process the data + utility::stream::value_type inBuffer[64]; + utility::stream::value_type outBuffer[64]; + + if (progress) + progress->start(0); + + while (!in.eof()) + { + // Process up to 45 characters per line + std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0); + + const utility::stream::size_type inLength = in.read(inBuffer, maxLineLength - 1); + + outBuffer[0] = UUENCODE(inLength); // Line length + + utility::stream::size_type j = 1; + + for (utility::stream::size_type i = 0 ; i < inLength ; i += 3, j += 4) + { + const unsigned char c1 = static_cast <unsigned char>(inBuffer[i]); + const unsigned char c2 = static_cast <unsigned char>(inBuffer[i + 1]); + const unsigned char c3 = static_cast <unsigned char>(inBuffer[i + 2]); + + outBuffer[j] = UUENCODE(c1 >> 2); + outBuffer[j + 1] = UUENCODE((c1 << 4) & 060 | (c2 >> 4) & 017); + outBuffer[j + 2] = UUENCODE((c2 << 2) & 074 | (c3 >> 6) & 03); + outBuffer[j + 3] = UUENCODE(c3 & 077); + } + + outBuffer[j] = '\r'; + outBuffer[j + 1] = '\n'; + + out.write(outBuffer, j + 2); + + total += j + 2; + inTotal += inLength; + + if (progress) + progress->progress(inTotal, inTotal); + } + + out << "end\r\n"; + total += 5; + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +utility::stream::size_type uuEncoder::decode(utility::inputStream& in, + utility::outputStream& out, utility::progressListener* progress) +{ + in.reset(); // may not work... + + // Process the data + utility::stream::value_type inBuffer[64]; + utility::stream::value_type outBuffer[64]; + + utility::stream::size_type total = 0; + utility::stream::size_type inTotal = 0; + + bool stop = false; + + std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0); + + if (progress) + progress->start(0); + + while (!stop && !in.eof()) + { + // Get the line length + utility::stream::value_type lengthChar; + + if (in.read(&lengthChar, 1) == 0) + break; + + const utility::stream::size_type outLength = UUDECODE(lengthChar); + const utility::stream::size_type inLength = + std::min((outLength * 4) / 3, static_cast <utility::stream::size_type>(64)); + utility::stream::value_type inPos = 0; + + switch (lengthChar) + { + case ' ': + case '\t': + case '\r': + case '\n': + { + // Ignore + continue; + } + case 'b': + { + // Read 5 characters more to check for begin ("begin ...\r\n" or "begin ...\n") + inPos = in.read(inBuffer, 5); + + if (inPos == 5 && + inBuffer[0] == 'e' && + inBuffer[1] == 'g' && + inBuffer[2] == 'i' && + inBuffer[3] == 'n' && + parserHelpers::isSpace(inBuffer[4])) + { + inTotal += 5; + + utility::stream::value_type c = 0; + + utility::stream::size_type count = 0; + utility::stream::value_type buffer[512]; + + while (count < sizeof(buffer) - 1 && in.read(&c, 1) == 1) + { + if (c == '\n') + break; + + buffer[count++] = c; + } + + inTotal += count; + + if (c != '\n') + { + // OOPS! Weird line. Don't try to decode more... + + if (progress) + progress->stop(inTotal); + + return (total); + } + + // Parse filename and mode + if (count > 0) + { + buffer[count] = '\0'; + + utility::stream::value_type* p = buffer; + + while (*p && parserHelpers::isSpace(*p)) ++p; + + utility::stream::value_type* modeStart = buffer; + + while (*p && !parserHelpers::isSpace(*p)) ++p; + + getResults()["mode"] = string(modeStart, p); + + while (*p && parserHelpers::isSpace(*p)) ++p; + + utility::stream::value_type* filenameStart = buffer; + + while (*p && !(*p == '\r' || *p == '\n')) ++p; + + getResults()["filename"] = string(filenameStart, p); + } + // No filename or mode specified + else + { + getResults()["filename"] = "untitled"; + getResults()["mode"] = 644; + } + + continue; + } + + break; + } + case 'e': + { + // Read 3 characters more to check for end ("end\r\n" or "end\n") + inPos = in.read(inBuffer, 3); + + if (inPos == 3 && + inBuffer[0] == 'n' && + inBuffer[1] == 'd' && + (inBuffer[2] == '\r' || inBuffer[2] == '\n')) + { + stop = true; + inTotal += 3; + continue; + } + + break; + } + + } + + // Read encoded data + if (in.read(inBuffer + inPos, inLength - inPos) != inLength - inPos) + { + // Premature end of data + break; + } + + inTotal += (inLength - inPos); + + // Decode data + for (utility::stream::size_type i = 0, j = 0 ; i < inLength ; i += 4, j += 3) + { + const unsigned char c1 = static_cast <unsigned char>(inBuffer[i]); + const unsigned char c2 = static_cast <unsigned char>(inBuffer[i + 1]); + const unsigned char c3 = static_cast <unsigned char>(inBuffer[i + 2]); + const unsigned char c4 = static_cast <unsigned char>(inBuffer[i + 3]); + + const utility::stream::size_type n = + std::min(inLength - i, static_cast <utility::stream::size_type>(3)); + + switch (n) + { + default: + case 3: outBuffer[j + 2] = UUDECODE(c3) << 6 | UUDECODE(c4); + case 2: outBuffer[j + 1] = UUDECODE(c2) << 4 | UUDECODE(c3) >> 2; + case 1: outBuffer[j] = UUDECODE(c1) << 2 | UUDECODE(c2) >> 4; + case 0: break; + } + + total += n; + } + + out.write(outBuffer, outLength); + + std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0); + + if (progress) + progress->progress(inTotal, inTotal); + } + + if (progress) + progress->stop(inTotal); + + return (total); +} + + +} // encoder +} // utility +} // vmime |