You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
478 lines
10 KiB
478 lines
10 KiB
15 years ago
|
//=============================================================================
|
||
|
// 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
|