diff options
Diffstat (limited to 'mimelib/uuencode.cpp')
-rw-r--r-- | mimelib/uuencode.cpp | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/mimelib/uuencode.cpp b/mimelib/uuencode.cpp new file mode 100644 index 000000000..bbd3c8563 --- /dev/null +++ b/mimelib/uuencode.cpp @@ -0,0 +1,477 @@ +//============================================================================= +// File: uuencode.cpp +// Contents: Definitions for DwUuencode +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// +// Copyright (c) 1996, 1997 Douglas W. Sauder +// All rights reserved. +// +// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT, +// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF +// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER +// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT +// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, +// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +//============================================================================= + +#define DW_IMPLEMENTATION + +#include <mimelib/config.h> +#include <mimelib/debug.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <mimelib/uuencode.h> +#include <config.h> + +#if defined(DW_TESTING_UUENCODE) +#include <stdlib.h> +#include <time.h> +#include <iostream> +#include <fstream> +#endif + + +DwUuencode::DwUuencode() +{ + memset(mFileName, 0, sizeof(mFileName)); + mMode = 0644; +} + + +DwUuencode::~DwUuencode() +{ +} + + +void DwUuencode::SetFileName(const char* aName) +{ + size_t n = sizeof(mFileName); + strlcpy(mFileName, aName, n); + mFileName[n-1] = 0; // Superfluous +} + + +const char* DwUuencode::FileName() const +{ + return mFileName; +} + + +void DwUuencode::SetFileMode(DwUint16 aMode) +{ + mMode = aMode; +} + + +DwUint16 DwUuencode::FileMode() const +{ + return mMode; +} + + +void DwUuencode::SetBinaryChars(const DwString& aStr) +{ + mBinaryChars = aStr; +} + + +const DwString& DwUuencode::BinaryChars() const +{ + return mBinaryChars; +} + + +void DwUuencode::SetAsciiChars(const DwString& aStr) +{ + mAsciiChars = aStr; +} + + +const DwString& DwUuencode::AsciiChars() const +{ + return mAsciiChars; +} + + +#define ENC(c) ((char) ((c) ? ((c) & 0x3F) + ' ' : 96 )) + + +void DwUuencode::Encode() +{ + // Get input buffer + + size_t binLen = mBinaryChars.length(); + const char* binBuf = mBinaryChars.data(); + size_t binPos = 0; + + // Allocate buffer for binary chars + + size_t ascSize = (binLen+2)/3*4 + + ((binLen+44)/45+1)*(strlen(DW_EOL)+1) + + strlen(mFileName) + + 13 + 2*strlen(DW_EOL) + + 100; + DwString ascStr(ascSize, (char)0); + char* ascBuf = (char*)ascStr.data(); + size_t ascPos = 0; + + // Write the "begin" line + + snprintf(ascBuf, ascSize, "begin %o %s" DW_EOL, mMode, mFileName); + ascPos = strlen(ascBuf); + + // Encode the binary chars + + while (ascPos < ascSize) { + int numBinChars = binLen - binPos; + numBinChars = (numBinChars <= 45) ? numBinChars : 45; + ascBuf[ascPos++] = ENC(numBinChars); + if (numBinChars == 0) { + strcpy(&ascBuf[ascPos], DW_EOL); + ascPos += strlen(DW_EOL); + break; + } + int bin, asc; + int binCharsDone = 0; + while (binCharsDone <= numBinChars - 3) { + + bin = binBuf[binPos++]; + asc = (bin & 0xFC) >> 2; + ascBuf[ascPos++] = ENC(asc); + + asc = (bin & 0x03) << 4; + bin = binBuf[binPos++]; + asc |= (bin & 0xF0) >> 4; + ascBuf[ascPos++] = ENC(asc); + + asc = (bin & 0x0F) << 2; + bin = binBuf[binPos++]; + asc |= (bin & 0xC0) >> 6; + ascBuf[ascPos++] = ENC(asc); + + asc = bin & 0x3F; + ascBuf[ascPos++] = ENC(asc); + + binCharsDone += 3; + } + + if (binCharsDone < numBinChars) { + int binCharsLeft = numBinChars - binCharsDone; + switch (binCharsLeft) { + + case 1: + bin = binBuf[binPos++]; + asc = (bin & 0xFC) >> 2; + ascBuf[ascPos++] = ENC(asc); + + asc = (bin & 0x03) << 4; + ascBuf[ascPos++] = ENC(asc); + + ascBuf[ascPos++] = 96; + ascBuf[ascPos++] = 96; + break; + + case 2: + bin = binBuf[binPos++]; + asc = (bin & 0xFC) >> 2; + ascBuf[ascPos++] = ENC(asc); + + asc = (bin & 0x03) << 4; + bin = binBuf[binPos++]; + asc |= (bin & 0xF0) >> 4; + ascBuf[ascPos++] = ENC(asc); + + asc = (bin & 0x0F) << 2; + ascBuf[ascPos++] = ENC(asc); + + ascBuf[ascPos++] = 96; + break; + + default: + break; + } + } + + strcpy(&ascBuf[ascPos], DW_EOL); + ascPos += strlen(DW_EOL); + } + + // Write the "end" line + + strcpy(&ascBuf[ascPos], "end" DW_EOL); + ascPos += 3 + strlen(DW_EOL); + ascBuf[ascPos] = 0; + + mAsciiChars.assign(ascStr, 0, ascPos); +} + + +#define DEC(c) (((c) - ' ') & 0x3F) + + +int DwUuencode::Decode() +{ + int retVal = -1; + + // Get input buffer + + size_t ascLen = mAsciiChars.length(); + const char* ascBuf = mAsciiChars.data(); + size_t ascPos = 0; + + // Allocate destination buffer + + size_t binSize = (ascLen+3)/4*3; + mBinaryChars.reserve(binSize); + + // Look for "begin " at beginning of buffer + + if (ascPos + 6 <= ascLen && + strncmp(&ascBuf[ascPos], "begin ", 6) == 0) { + + ascPos += 6; + } + else { + + // Find "\nbegin " or "\rbegin " + + while (ascPos < ascLen) { + int ch = ascBuf[ascPos++] & 0xff; + switch (ch) { + case '\n': + case '\r': + if (ascPos + 6 <= ascLen && + strncmp(&ascBuf[ascPos], "begin ", 6) == 0) { + + ascPos += 6; + goto LOOP_EXIT_1; + } + break; + default: + break; + } + } + } +LOOP_EXIT_1: + + // Get mode + + mMode = 0; + while (ascPos < ascLen && isdigit(ascBuf[ascPos])) { + mMode <<= 3; + mMode += (DwUint16) (ascBuf[ascPos++] - '0'); + } + + // Get file name + + while (ascPos < ascLen && + (ascBuf[ascPos] == ' ' || ascBuf[ascPos] == '\t')) { + + ++ascPos; + } + size_t p1 = 0; + while (ascPos < ascLen && p1 < sizeof(mFileName)-1 && + !isspace(ascBuf[ascPos])) { + + mFileName[p1++] = ascBuf[ascPos++]; + } + mFileName[p1] = 0; + + // Advance to beginning of next line + + while (ascPos < ascLen) { + int ch = ascBuf[ascPos++]; + switch (ch) { + case '\n': + goto LOOP_EXIT_2; + case '\r': + if (ascPos < ascLen && ascBuf[ascPos] == '\n') { + ++ascPos; + } + goto LOOP_EXIT_2; + default: + break; + } + } +LOOP_EXIT_2: + + // Decode chars + + while (ascPos < ascLen) { + int asc, bin; + + // Get number of binary chars in this line + + asc = ascBuf[ascPos++] & 0xff; + size_t numBinChars = DEC(asc); + if (numBinChars == 0) { + break; + } + + // Decode this line + + size_t binCharsEaten = 0; + while (binCharsEaten <= numBinChars - 3 && ascPos <= ascLen - 4) { + + asc = ascBuf[ascPos++] & 0xff; + bin = (DEC(asc) & 0x3F) << 2; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x30) >> 4; + mBinaryChars.append((size_t) 1, (char) bin); + + bin = (DEC(asc) & 0x0F) << 4; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x3C) >> 2; + mBinaryChars.append((size_t) 1, (char) bin); + + bin = (DEC(asc) & 0x03) << 6; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x3F); + mBinaryChars.append((size_t) 1, (char) bin); + + binCharsEaten += 3; + } + + // Special case if number of binary chars is not divisible by 3 + + if (binCharsEaten < numBinChars) { + int binCharsLeft = numBinChars - binCharsEaten; + switch (binCharsLeft) { + case 2: + if (ascPos >= ascLen) + break; + asc = ascBuf[ascPos++] & 0xff; + bin = (DEC(asc) & 0x3F) << 2; + if (ascPos >= ascLen) + break; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x30) >> 4; + mBinaryChars.append((size_t) 1, (char) bin); + + bin = (DEC(asc) & 0x0F) << 4; + if (ascPos >= ascLen) + break; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x3C) >> 2; + mBinaryChars.append((size_t) 1, (char) bin); + break; + case 1: + if (ascPos >= ascLen) + break; + asc = ascBuf[ascPos++] & 0xff; + bin = (DEC(asc) & 0x3F) << 2; + if (ascPos >= ascLen) + break; + asc = ascBuf[ascPos++] & 0xff; + bin |= (DEC(asc) & 0x30) >> 4; + mBinaryChars.append((size_t) 1, (char) bin); + break; + default: + break; + } + } + + // Advance to beginning of next line + + while (ascPos < ascLen) { + int ch = ascBuf[ascPos++]; + switch (ch) { + case '\n': + goto LOOP_EXIT_3; + case '\r': + if (ascPos < ascLen && + ascBuf[ascPos] == '\n') { + + ++ascPos; + } + goto LOOP_EXIT_3; + default: + break; + } + } +LOOP_EXIT_3: + ; + } + while (ascPos < ascLen) { + int ch = ascBuf[ascPos++]; + switch (ch) { + case '\n': + goto LOOP_EXIT_4; + case '\r': + if (ascPos < ascLen && + ascBuf[ascPos] == '\n') { + + ++ascPos; + } + goto LOOP_EXIT_4; + default: + break; + } + } +LOOP_EXIT_4: + if (ascPos + 3 <= ascLen && + strncmp(&ascBuf[ascPos], "end", 3) == 0) { + + retVal = 0; + } + return retVal; +} + + +#if defined(DW_TESTING_UUENCODE) + +// Test harness for DwUudecode + +int main(int argc, char** argv) +{ + srand(time(0)); + DwString binStr; + binStr.reserve(5000); + char ch; + int i; + for (i=0; i < 4000; ++i) { + ch = rand()/(double)RAND_MAX*256; + binStr += (char) ch; + } + for ( ; i < 4100; ++i) { + binStr += (char) 0; + } + DwUuencode uu; + uu.SetFileName("Testfile.dat"); + uu.SetMode(0600); + uu.SetBinaryChars(binStr); + uu.Encode(); + DwString asciiStr = uu.AsciiChars(); + // std::ofstream out("test.out", ios::out|ios::binary); + std::ofstream out("test.out", ios::out); + out << asciiStr; + + DwUuencode uu1; + uu1.SetAsciiChars(uu.AsciiChars()); + uu1.Decode(); + + size_t n = uu1.BinaryChars().length(); + const char* b1 = binStr.data(); + const char* b2 = uu1.BinaryChars().data(); + int bad = 0; + for (i=0; i < n; ++i) { + if (b1[i] != b2[i]) { + cout << "Binary chars not equal at position " << i << "\n"; + bad = 1; + break; + } + } + if (! bad) { + cout << "A-okay\n"; + } + return 0; +} + +#endif |