290 lines
6.8 KiB
C++
290 lines
6.8 KiB
C++
//
|
|
// VMime library (http://vmime.sourceforge.net)
|
|
// Copyright (C) 2002-2004 Vincent Richard <vincent@vincent-richard.net>
|
|
//
|
|
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
//
|
|
|
|
#include "encoderUUE.hpp"
|
|
#include "parserHelpers.hpp"
|
|
|
|
|
|
namespace vmime
|
|
{
|
|
|
|
|
|
encoderUUE::encoderUUE()
|
|
{
|
|
getProperties()["mode"] = 644;
|
|
getProperties()["filename"] = "no_name";
|
|
getProperties()["maxlinelength"] = 46;
|
|
}
|
|
|
|
|
|
const std::vector <string> encoderUUE::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 const unsigned char UUENCODE(const unsigned char c)
|
|
{
|
|
return ((c & 077) + ' ');
|
|
}
|
|
|
|
// Single character decoding
|
|
static inline const unsigned char UUDECODE(const unsigned char c)
|
|
{
|
|
return ((c - ' ') & 077);
|
|
}
|
|
|
|
|
|
const utility::stream::size_type encoderUUE::encode(utility::inputStream& in, utility::outputStream& out)
|
|
{
|
|
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;
|
|
|
|
// 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];
|
|
|
|
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 = (unsigned char) inBuffer[i];
|
|
const unsigned char c2 = (unsigned char) inBuffer[i + 1];
|
|
const unsigned char c3 = (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;
|
|
}
|
|
|
|
out << "end\r\n";
|
|
total += 5;
|
|
|
|
return (total);
|
|
}
|
|
|
|
|
|
const utility::stream::size_type encoderUUE::decode(utility::inputStream& in, utility::outputStream& out)
|
|
{
|
|
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;
|
|
|
|
bool stop = false;
|
|
|
|
std::fill(inBuffer, inBuffer + sizeof(inBuffer), 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, (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' &&
|
|
isspace(inBuffer[4]))
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (c != '\n')
|
|
{
|
|
// OOPS! Weird line. Don't try to decode more...
|
|
return (total);
|
|
}
|
|
|
|
// Parse filename and mode
|
|
if (count > 0)
|
|
{
|
|
buffer[count] = '\0';
|
|
|
|
utility::stream::value_type* p = buffer;
|
|
|
|
while (*p && isspace(*p)) ++p;
|
|
|
|
utility::stream::value_type* modeStart = buffer;
|
|
|
|
while (*p && !isspace(*p)) ++p;
|
|
|
|
getResults()["mode"] = string(modeStart, p);
|
|
|
|
while (*p && 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;
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// Read encoded data
|
|
if (in.read(inBuffer + inPos, inLength - inPos) != inLength - inPos)
|
|
{
|
|
// Premature end of data
|
|
break;
|
|
}
|
|
|
|
// Decode data
|
|
for (utility::stream::size_type i = 0, j = 0 ; i < inLength ; i += 4, j += 3)
|
|
{
|
|
const unsigned char c1 = (unsigned char) inBuffer[i];
|
|
const unsigned char c2 = (unsigned char) inBuffer[i + 1];
|
|
const unsigned char c3 = (unsigned char) inBuffer[i + 2];
|
|
const unsigned char c4 = (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);
|
|
}
|
|
|
|
return (total);
|
|
}
|
|
|
|
|
|
} // vmime
|