693 lines
36 KiB
C++
693 lines
36 KiB
C++
// ==========================================================================
|
||
// Class Specification : COXUUDecoder
|
||
// ==========================================================================
|
||
|
||
// Header file : oxuudec.cpp
|
||
|
||
// Version: 9.3
|
||
|
||
// This software along with its related components, documentation and files ("The Libraries")
|
||
// is ?1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
||
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
||
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
||
// to obtain this file, or directly from our office. For a copy of the license governing
|
||
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
||
|
||
// ///////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "stdafx.h" // standard MFC include
|
||
#include "oxuudec.h" // file header
|
||
#include "afxpriv.h" // for CMirrorFile
|
||
|
||
#include <io.h>
|
||
#include <direct.h>
|
||
#include <ctype.h>
|
||
|
||
#ifdef _DEBUG
|
||
#undef THIS_FILE
|
||
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
#endif
|
||
|
||
IMPLEMENT_DYNAMIC(COXUUDecoder, CObject)
|
||
|
||
#define new DEBUG_NEW
|
||
|
||
#include "OXUUDRet.h"
|
||
|
||
/////////////////////////////////////////////////////////////////////////////
|
||
// Definition of static members
|
||
|
||
// Data members -------------------------------------------------------------
|
||
// protected:
|
||
|
||
// private:
|
||
|
||
// Member functions ---------------------------------------------------------
|
||
// public:
|
||
|
||
COXUUDecoder::COXUUDecoder()
|
||
: m_buf(m_bufa),
|
||
m_bufm1(m_bufb),
|
||
m_bufm2(m_bufc),
|
||
m_bufm3(m_bufd),
|
||
m_goodbuf(-1),
|
||
m_goodbufm1(-1),
|
||
m_goodbufm2(-1),
|
||
m_goodbufm3(-1),
|
||
m_bSkipIfExists(FALSE)
|
||
{
|
||
}
|
||
|
||
BOOL COXUUDecoder::IsUUEncodedFile(const char* EncodedFilNam)
|
||
{
|
||
CStdioFile EncodedFile;
|
||
|
||
if (!EncodedFile.Open((LPCTSTR)EncodedFilNam, CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite))
|
||
return FALSE;
|
||
|
||
m_buf[0] = 0; /* tells extractuu to search for begin line */
|
||
int res = ExtractUU(&EncodedFile, NULL);
|
||
|
||
m_buf[0] = 0; // Reset Buffer
|
||
EncodedFile.Close();
|
||
|
||
return (res == 0);
|
||
}
|
||
|
||
HRESULT COXUUDecoder::UUDecodeFile(const char* EncodedFilNam, const char* pszDir /* = NULL */,
|
||
CStringArray* pTargetFiles /* = NULL */)
|
||
{
|
||
HRESULT hr;
|
||
CStdioFile EncodedFile;
|
||
CStringArray TempTargetFiles;
|
||
CStringArray* pTrgtFiles = pTargetFiles;
|
||
if (pTargetFiles == NULL)
|
||
pTrgtFiles = new CStringArray;
|
||
|
||
if (!EncodedFile.Open((LPCTSTR)EncodedFilNam, CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite))
|
||
return (HRESULT)MSG_UUDEC_OPEN_ENCODED_ERROR;
|
||
|
||
hr = UUDecodeFile(&EncodedFile, pszDir, pTrgtFiles, &TempTargetFiles);
|
||
|
||
EncodedFile.Close();
|
||
|
||
// Examine the TempTargetFiles array to see whether there are some temporary files created
|
||
// that have to be renamed
|
||
for (int i = 0; i < TempTargetFiles.GetSize(); i++)
|
||
{
|
||
if (!TempTargetFiles.GetAt(i).IsEmpty() && pTrgtFiles != NULL)
|
||
{
|
||
CFile::Remove(pTrgtFiles->GetAt(i));
|
||
CFile::Rename(TempTargetFiles.GetAt(i), pTrgtFiles->GetAt(i));
|
||
}
|
||
}
|
||
delete pTrgtFiles;
|
||
|
||
return hr;
|
||
}
|
||
|
||
HRESULT COXUUDecoder::UUDecodeFile(CStdioFile* pEncodFil, const char* pszDir,
|
||
CStringArray* pTargetFiles, CStringArray* pTempTargetFiles)
|
||
{
|
||
ASSERT_VALID(pEncodFil);
|
||
|
||
HRESULT hr=NULL;
|
||
|
||
#ifdef WIN32
|
||
CMirrorFile TargetFile;
|
||
#else
|
||
CFile TargetFile;
|
||
#endif
|
||
|
||
CString sTargetName, sTempTargetName;
|
||
char targetfile[256]; /* 255 chars max length of a pathname */
|
||
|
||
int res,success,errors; /* gp result, success and error counters */
|
||
int amode; /* "begin xxx" where xxx is amode, for chmod() */
|
||
int nTargetIndex(-1); // index of the encoding part in a multiple encoded file
|
||
|
||
errors = 0;
|
||
success = 0;
|
||
res = 0;
|
||
amode = -1;
|
||
targetfile[0] = 0;
|
||
|
||
while (res < 3)
|
||
{ /* 0 success, 1 error, 2 begin before end, 3 eof seen */
|
||
if (res < 2)
|
||
{ /* skip this if buf[] already contains begin line */
|
||
m_buf[0] = 0; /* tells extractuu to search for begin line */
|
||
res = ExtractUU(pEncodFil, NULL);
|
||
nTargetIndex++;
|
||
}
|
||
|
||
/*
|
||
* here if we have res==2 then we must be recovering from a
|
||
* begin before end error on the previous pass, recycling buf[],
|
||
* the extractuu() above couldn't have generated a res==2 because
|
||
* it's looking for a begin so it must have come from the one below
|
||
*/
|
||
if (res == 0 || res == 2)
|
||
{
|
||
#if _MSC_VER >= 1400
|
||
if (sscanf_s(m_buf, "begin %d %255s", &amode, targetfile) != 2)
|
||
#else
|
||
if (sscanf(m_buf, "begin %d %255s", &amode, targetfile) != 2)
|
||
#endif
|
||
{
|
||
res = 1;
|
||
goto badfilename;
|
||
}
|
||
|
||
// Renaming target when Stringarray has new target name
|
||
sTargetName.Empty();
|
||
if (pTargetFiles != NULL)
|
||
if (pTargetFiles->GetSize() > nTargetIndex)
|
||
sTargetName = pTargetFiles->GetAt(nTargetIndex);
|
||
|
||
if (sTargetName.IsEmpty())
|
||
if (pszDir != NULL)
|
||
sTargetName = CString(pszDir) + CString("\\") + CString(targetfile);
|
||
else
|
||
sTargetName = targetfile;
|
||
else
|
||
TRACE1("renaming target to \"%s\"\n", sTargetName);
|
||
|
||
/* check for file existance */
|
||
sTempTargetName = sTargetName;
|
||
#if _MSC_VER >= 1400
|
||
if (_access((LPCSTR)(LPCTSTR)sTargetName, 0) == 0)
|
||
#else
|
||
if (access((LPCSTR)(LPCTSTR)sTargetName, 0) == 0)
|
||
#endif
|
||
{ /* it exists */
|
||
if (m_bSkipIfExists)
|
||
{ /* quietly skip without counting as error */
|
||
TRACE1("Skipped, file exists : %s\n", sTargetName);
|
||
res = 0;
|
||
if (pTargetFiles != NULL)
|
||
pTargetFiles->SetAtGrow(nTargetIndex, sTargetName);
|
||
|
||
goto badfilename1;
|
||
}
|
||
|
||
/* check if file has write access */
|
||
CFileStatus status;
|
||
pEncodFil->GetStatus(status);
|
||
|
||
if (sTargetName != status.m_szFullName &&
|
||
#if _MSC_VER >= 1400
|
||
_access((LPCSTR)(LPCTSTR)sTargetName, 2) != 0)
|
||
#else
|
||
access((LPCSTR)(LPCTSTR)sTargetName, 2) != 0)
|
||
#endif
|
||
{ /* write not allowed */
|
||
TRACE1("\"%s\" ", sTargetName);
|
||
TRACE(_T("Skipped, file exists write protected.\n"));
|
||
res = 1;
|
||
hr = (HRESULT)MSG_UUDEC_WRITING_OF_A_FILE_FAILED;
|
||
goto badfilename;
|
||
}
|
||
|
||
// get the directory for a temporary file
|
||
sTempTargetName.Empty();
|
||
#ifdef WIN32
|
||
TCHAR szPath[_MAX_PATH];
|
||
GetTempPath(_MAX_PATH, szPath);
|
||
|
||
//let's create a temporary file name
|
||
GetTempFileName(szPath, _T("OXTEMP"), 0,
|
||
sTempTargetName.GetBuffer(_MAX_PATH+1));
|
||
#else
|
||
//let's create a temporary file name
|
||
::GetTempFileName(0, _T("OXTEMP"), 0,
|
||
sTempTargetName.GetBuffer(_MAX_PATH+1));
|
||
#endif
|
||
sTempTargetName.ReleaseBuffer();
|
||
pTempTargetFiles->SetAtGrow(nTargetIndex, sTempTargetName);
|
||
|
||
/* we determined that the file is ok to overwrite */
|
||
TRACE1("updating \"%s\"\n",targetfile);
|
||
}
|
||
|
||
/* Create the new decoded file */
|
||
if (pszDir != NULL)
|
||
#if _MSC_VER >= 1400
|
||
_mkdir(pszDir);
|
||
#else
|
||
mkdir(pszDir);
|
||
#endif
|
||
if (!TargetFile.Open(sTempTargetName, CFile:: modeCreate | CFile::modeWrite | CFile::typeBinary))
|
||
{
|
||
TRACE2("%s\"%s\"\n", "fatal: can't open target file ", sTempTargetName);
|
||
res = 3;
|
||
hr = (HRESULT)MSG_UUDEC_WRITING_OF_A_FILE_FAILED;
|
||
goto badfilename;
|
||
}
|
||
|
||
/* m_buf[] contains begin line, this tells extractuu to decode */
|
||
/* rather than search for the next begin line */
|
||
res = ExtractUU(pEncodFil, &TargetFile);
|
||
|
||
TargetFile.Close();
|
||
|
||
if (res > 0)
|
||
{
|
||
TRACE1("trying to delete \"%s\"\n", sTargetName);
|
||
#if _MSC_VER >= 1400
|
||
if (_unlink((LPCSTR)(LPCTSTR)sTargetName) != 0)
|
||
#else
|
||
if (unlink((LPCSTR)(LPCTSTR)sTargetName) != 0)
|
||
#endif
|
||
TRACE1("error deleting \"%s\"\n",sTargetName);
|
||
}
|
||
else
|
||
{
|
||
if (pTargetFiles != NULL)
|
||
pTargetFiles->SetAtGrow(nTargetIndex, sTargetName);
|
||
}
|
||
}
|
||
|
||
badfilename:
|
||
if (res == 0)
|
||
success++;
|
||
|
||
badfilename1:
|
||
if (res == 1 || res == 2)
|
||
errors++;
|
||
} /* <-- end of while (res<3) { ... */
|
||
|
||
if (errors != 0)
|
||
return (hr);
|
||
|
||
return (HRESULT)MSG_UUDEC_SUCCESS;
|
||
}
|
||
|
||
#ifdef _DEBUG
|
||
void COXUUDecoder::Dump(CDumpContext& dc) const
|
||
{
|
||
CObject::Dump(dc);
|
||
}
|
||
|
||
void COXUUDecoder::AssertValid() const
|
||
{
|
||
CObject::AssertValid();
|
||
}
|
||
#endif
|
||
|
||
COXUUDecoder::~COXUUDecoder()
|
||
{
|
||
}
|
||
|
||
// protected:
|
||
void COXUUDecoder::FixEOLN(char buf[], int n)
|
||
// --- In : buf[] : buffer to be examined
|
||
// n : length of buffer
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : This subroutine strips all <cr> and <lf> from the end of buf[]
|
||
// This is done because a lot of Internet-News newbies don't know how to
|
||
// uuencode their files properly.
|
||
// Standard unix uudecode programs usually puke if there is a ^M in the line.
|
||
{
|
||
size_t len,nn;
|
||
int done;
|
||
|
||
if (n < 1)
|
||
return;
|
||
|
||
nn = (size_t)n - 1;
|
||
len = strlen(buf);
|
||
if (nn < len)
|
||
len = n;
|
||
|
||
done=0;
|
||
while (len>0 && !done)
|
||
{
|
||
switch (buf[len-1])
|
||
{
|
||
case '\r':
|
||
len--;
|
||
|
||
break;
|
||
case '\n':
|
||
len--;
|
||
|
||
break;
|
||
case ' ':
|
||
if (len > 61)
|
||
len--;
|
||
else
|
||
done = 1;
|
||
|
||
break;
|
||
default:
|
||
done = 1;
|
||
}
|
||
}
|
||
|
||
buf[len] = '\0';
|
||
return;
|
||
}
|
||
|
||
|
||
BOOL COXUUDecoder::GetLongLine(char* s, int n, CStdioFile* pFile)
|
||
// --- In : s : buffer to store read line
|
||
// n : max length of line to read
|
||
// pFile : the encoded file
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : This subroutine is just like the standard fgets() except smarter.
|
||
// When lines in the stream are longer than the buffer size, the line gets
|
||
// truncated and the stream is purged until the actual <lf> is seen.
|
||
// This works just like the Pascal readln(f,stringvar)
|
||
{
|
||
char buf[32];
|
||
char* result;
|
||
size_t nn;
|
||
|
||
TRY
|
||
{
|
||
result = (LPSTR)pFile->ReadString((LPTSTR)s, n);
|
||
|
||
if (n < 2 || result == NULL)
|
||
return FALSE;
|
||
|
||
nn = (size_t)n - 1;
|
||
if (strlen(s) == nn && s[n-2] != '\n')
|
||
{
|
||
while (pFile->ReadString((LPTSTR)buf, sizeof(buf)))
|
||
if (strlen(buf) + 1 < sizeof(buf) || buf[sizeof(buf) - 2] == '\n')
|
||
break;
|
||
}
|
||
|
||
FixEOLN(s, n);
|
||
}
|
||
CATCH(CFileException, e)
|
||
{
|
||
return FALSE;
|
||
}
|
||
END_CATCH
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
int COXUUDecoder::IsGoodBuf(char buf[], int n)
|
||
// --- In : buf[] : buffer to examine
|
||
// n : length of buffer
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : This subroutine checks buf to see if it looks like
|
||
// a standard uuencode line and returns a number for best guess.
|
||
//
|
||
// returned values are one of the following...
|
||
// 0) unknown, possibly text or short last line
|
||
// 1) "begin 644 filename" type of line
|
||
// 2) "M..." etc., main body line, short last line is not detected as 2
|
||
// 3) "`" or " ", this is usually the 2nd from last line in a uuencode
|
||
// 4) "end", usually last line of a uuencode
|
||
//
|
||
// n is the size of buf[]
|
||
|
||
{
|
||
size_t len,nn;
|
||
|
||
len = strlen(buf);
|
||
nn = (size_t)n - 1;
|
||
if (nn < len)
|
||
len = nn;
|
||
|
||
if (len == 61 && buf[0] == 'M')
|
||
return(2);
|
||
|
||
if (len > 10 && strncmp(buf, "begin ", 6) == 0 && isdigit(buf[6]) &&
|
||
isdigit(buf[7]) && isdigit(buf[8]))
|
||
return(1);
|
||
|
||
if (len >= 1 && (buf[0] == ' ' || buf[0] == '`'))
|
||
return(3);
|
||
|
||
if (len >= 3 && strncmp(buf, "end", 3) == 0)
|
||
return(4);
|
||
|
||
return(0);
|
||
}
|
||
|
||
int COXUUDecoder::UUD1Line(CFile* pFile, char buf[])
|
||
// --- In : pFile : file to write to
|
||
// buf : buffer contaning encode chars
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : uudecode 1 line, assumes buf[] is a valid uuencoded line
|
||
// if test=1 then range check every character decoded, a little slower!
|
||
// return 0 if no error
|
||
// return 1 if general error
|
||
// return 2 if illegal character (only when test=1)
|
||
{
|
||
int len,b,i,j;
|
||
size_t l;
|
||
unsigned char c0, c1, x, *from, *to;
|
||
static unsigned char binbuf[45];
|
||
static const unsigned char c[3][4] = { /* used by slow decoder below */
|
||
{2, 4, 6 , 0 },
|
||
{4, 2, 0 , 0 },
|
||
{0x03, 0x0f, 0x3f, 0 }
|
||
};
|
||
|
||
len = (int)buf[0] - 0x20; /* first char on line is # 8 bit bytes to decode */
|
||
l = strlen((const char*)buf);
|
||
b = 0;
|
||
/* this is the FAST! decoder for the main body lines */
|
||
TRY
|
||
{
|
||
if (len == 45 && l >= 61)
|
||
{
|
||
from = (unsigned char*)&buf[1];
|
||
to = binbuf;
|
||
while ( b < len)
|
||
{
|
||
if (*from < ' ' || *from > '`')
|
||
return(2);
|
||
*(to++) = (unsigned char)(((*from - 0x20) << 2) | (((*(from + 1) - 0x20) >> 4) & 0x03));
|
||
from++;
|
||
if (*from < ' ' || *from > '`')
|
||
return(2);
|
||
*(to++) = (unsigned char)(((*from - 0x20) << 4) | (((*(from + 1) - 0x20) >> 2) & 0x0f));
|
||
from++;
|
||
if (*from < ' ' || *from > '`')
|
||
return(2);
|
||
*(to++) = (unsigned char)(((*from - 0x20) << 6) | (( *(from + 1) - 0x20 ) & 0x3f));
|
||
from++;
|
||
if (*from < ' ' || *from > '`')
|
||
return(2);
|
||
from++;
|
||
b = b + 3;
|
||
}
|
||
|
||
pFile->Write(binbuf, len);
|
||
|
||
return(0);
|
||
}
|
||
|
||
if (len < 1 || len > 45)
|
||
{
|
||
return(2);
|
||
}
|
||
while (b < len)
|
||
{ /* this is the slow decoder for the last short line */
|
||
i = b % 3;
|
||
j = b * 4 / 3 + 1;
|
||
if ((size_t)j < l)
|
||
c0 = buf[j];
|
||
else
|
||
c0 = ' ';
|
||
|
||
if ((size_t)j + 1 < l)
|
||
c1 = buf[j + 1];
|
||
else
|
||
c1 = ' ';
|
||
|
||
if (c0 < ' ' || c0 > '`' || c1 < ' ' || c1 > '`')
|
||
return(2);
|
||
|
||
x = (unsigned char)(((c0 - 0x20) << c[0][i]) + (((c1 - 0x20) >> c[1][i]) & c[2][i]));
|
||
|
||
pFile->Write(&x, 1);
|
||
|
||
b++;
|
||
}
|
||
}
|
||
CATCH(CFileException, e)
|
||
{
|
||
return(1);
|
||
}
|
||
END_CATCH
|
||
|
||
return(0);
|
||
}
|
||
|
||
void COXUUDecoder::rotatebufs()
|
||
{
|
||
char* temp;
|
||
|
||
temp = m_bufm3;
|
||
m_bufm3 = m_bufm2;
|
||
m_bufm2 = m_bufm1;
|
||
m_bufm1 = m_buf;
|
||
m_buf = temp;
|
||
|
||
m_buf[0] = 0;
|
||
|
||
m_goodbufm3 = m_goodbufm2;
|
||
m_goodbufm2 = m_goodbufm1;
|
||
m_goodbufm1 = m_goodbuf;
|
||
m_goodbuf = -1;
|
||
}
|
||
|
||
void COXUUDecoder::clearmbufs()
|
||
{
|
||
m_bufm3[0] = 0;
|
||
m_bufm2[0] = 0;
|
||
m_bufm1[0] = 0;
|
||
m_goodbufm3 = -1;
|
||
m_goodbufm2 = -1;
|
||
m_goodbufm1 = -1;
|
||
}
|
||
|
||
int COXUUDecoder::ExtractUU(CStdioFile* pfrom, /* pointer to input file*/
|
||
CFile* pTo) /* pointer to output file*/
|
||
// --- In : pfrom : file to read from
|
||
// pTo : file to write to
|
||
// --- Out :
|
||
// --- Returns :
|
||
// --- Effect : This is the main extract subroutine.
|
||
// buf[] is used in the event that a new "begin" is encountered
|
||
// before the ending of the previous uuencoding. This is an error
|
||
// condition and to keep from messing up the next uudecode which is
|
||
// probably ok, this begin line is stuffed into the buf[] for
|
||
// the next pass through extractuu().
|
||
// returned values...
|
||
// 0=success
|
||
// 1=error
|
||
// 2=begin line encountered before end line decoded
|
||
// 3=eof seen
|
||
{
|
||
int amode,res;
|
||
char fn[BUFSIZE];
|
||
|
||
if (strlen(m_buf) == 0)
|
||
{
|
||
retry:
|
||
m_goodbuf = 0;
|
||
while (GetLongLine(m_buf, BUFSIZE, pfrom))
|
||
if ((m_goodbuf = IsGoodBuf(m_buf, BUFSIZE)) == 1)
|
||
break;
|
||
|
||
if (m_goodbuf != 1)
|
||
return(3); /* indicate eof seen */
|
||
|
||
#if _MSC_VER >= 1400
|
||
if (sscanf_s(m_buf, "begin %d %80s", &amode, fn) != 2)
|
||
#else
|
||
if (sscanf(m_buf, "begin %d %80s", &amode, fn) != 2)
|
||
#endif
|
||
goto retry;
|
||
|
||
return(0);
|
||
}
|
||
|
||
/* here when begin line was found and is in buf[], now do decoding */
|
||
clearmbufs(); /* clear back history buffers */
|
||
m_goodbuf = 1; /* assume begin line is in buf[] */
|
||
if (IsGoodBuf(m_buf, BUFSIZE) != m_goodbuf)
|
||
{
|
||
return(1);
|
||
}
|
||
|
||
rotatebufs();
|
||
while (GetLongLine(m_buf, BUFSIZE, pfrom))
|
||
{
|
||
m_goodbuf = IsGoodBuf(m_buf, BUFSIZE);
|
||
if (m_goodbufm1 == 2 && (m_goodbuf == 2 || m_goodbufm2 == 2 || m_goodbufm2 == 1))
|
||
if ((res = UUD1Line(pTo, m_bufm1)) != 0)
|
||
return(1);
|
||
|
||
if (m_goodbuf == 1)
|
||
return(2);
|
||
|
||
/* end detected...logic for what to do with 3rd from last line bufm2
|
||
* (for relax=0 or 1)
|
||
*
|
||
* ignore this end | decode line bufm2 | just exit, already decoded
|
||
* (m2) (m3) | (m2) (m3) | (m2) (m3) <-- goodbuf
|
||
* ----------------+-------------------+---------------------------
|
||
* 0 0 | 0 1 | 1 x
|
||
* 0 3 | 0 2 | 2 1
|
||
* 0 4 | 2 0 | 2 2
|
||
* 2 3 | |
|
||
* 2 4 | |
|
||
* 3 x | |
|
||
* 4 x | |
|
||
*/
|
||
if (m_goodbuf == 4 && m_goodbufm1 == 3)
|
||
{ /* end sequence seen */
|
||
if (m_goodbufm2 == 1)
|
||
return(0);
|
||
if ((m_goodbufm2 == 0 && (m_goodbufm3 == 0 || m_goodbufm3 >= 3)) ||
|
||
(m_goodbufm2 >= 3) || (m_goodbufm2 == 2 && m_goodbufm3 >= 3))
|
||
goto nextline;
|
||
|
||
if ((m_goodbufm2 == 0 && (m_goodbufm3 == 1 || m_goodbufm3 == 2)) ||
|
||
(m_goodbufm2 == 2 && m_goodbufm3 == 0))
|
||
{
|
||
if ((res = UUD1Line(pTo, m_bufm2)) != 0)
|
||
return(1);
|
||
}
|
||
|
||
return(0);
|
||
}
|
||
|
||
/* end detected...logic for what to do with 2nd from last line bufm1
|
||
* (for relax=1)
|
||
*
|
||
* ignore this end | decode line bufm2 | just exit, already decoded
|
||
* (m1) (m2) | (m1) (m2) | (m1) (m2) <-- goodbuf
|
||
* ----------------+-------------------+---------------------------
|
||
* 0 0 | 0 1 | 1 x
|
||
* 0 3 | 0 2 | 2 1
|
||
* 0 4 | 2 0 | 2 2
|
||
* 2 3 | |
|
||
* 2 4 | |
|
||
* 3 x | |
|
||
* 4 x | |
|
||
*/
|
||
if (m_goodbuf == 4)
|
||
{ /* end sequence seen */
|
||
if (m_goodbufm1 == 1)
|
||
return(0);
|
||
|
||
if ((m_goodbufm1 == 0 && (m_goodbufm2 == 0 || m_goodbufm2 >= 3)) ||
|
||
(m_goodbufm1 >= 3) || (m_goodbufm1 == 2 && m_goodbufm2 >= 3))
|
||
goto nextline;
|
||
|
||
if ((m_goodbufm1 == 0 && (m_goodbufm2 == 1 || m_goodbufm2 == 2)) ||
|
||
(m_goodbufm1 == 2 && m_goodbufm2 == 0))
|
||
{
|
||
if ((res = UUD1Line(pTo, m_bufm1)) != 0)
|
||
return(1);
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
nextline:
|
||
rotatebufs();
|
||
}
|
||
|
||
if (m_goodbufm1 == 2 && (m_goodbufm2 == 1 || m_goodbufm2 == 2))
|
||
res = UUD1Line(pTo, m_bufm1);
|
||
|
||
return(3); /* indicate end of input file */
|
||
}
|
||
|
||
// private:
|
||
// ==========================================================================
|