summaryrefslogtreecommitdiffstats
path: root/mimelib/uuencode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mimelib/uuencode.cpp')
-rw-r--r--mimelib/uuencode.cpp477
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