www.pudn.com > zmodemclass.zip > ZModemCore.cpp


//----------------------------------------------------------------------------- 
// project:		ZModem 
// author:		Frank Weiler, Genshagen, Germany 
// version:		0.91 
// date:		October 10, 2000 
// email:		frank@weilersplace.de 
// copyright:	This Software is OpenSource. 
// file:		ZModemCore.cpp 
// description:	A class that implements a basic ZModem protocol. 
//				Not all possible features are supported, especially 
//				no support for buffersizes greater than 1024. 
//				Sending data is done with 1024 buffersize, 
//				receiving is event-driven using overlapped I/O. 
//----------------------------------------------------------------------------- 
 
#include "stdafx.h" 
#include "ZModemCore.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
//----------------------------------------------------------------------------- 
// purpose:	construction 
// params:	howner			->	handle of the Owner Window 
//			hcomm			->	handle of the modem ressource, got from TAPI 
//			hcancelevent	->  handle of an event signaling user-break 
CZModemCore::CZModemCore(HWND howner,HANDLE hcomm,HANDLE hcancelevent) 
//----------------------------------------------------------------------------- 
{ 
	m_hOwner = howner; 
	m_hcomm = hcomm; 
	m_hCancelEvent = hcancelevent; 
	m_ZModemComm = new CZModemComm(m_hcomm,m_hCancelEvent); 
	m_ZModemFile = new CZModemFile(howner); 
	maxTx = ZMCORE_MAXTX; 
} 
 
//----------------------------------------------------------------------------- 
// purpose:	destruction 
CZModemCore::~CZModemCore() 
//----------------------------------------------------------------------------- 
{ 
	delete m_ZModemComm; 
	delete m_ZModemFile; 
} 
 
//----------------------------------------------------------------------------- 
// purpose:	sending files 
// params:	filelist	->	Array of filenames (full path) to send 
// returns:	success 
bool CZModemCore::Send(CStringArray* filelist) 
//----------------------------------------------------------------------------- 
{	//  
	bool fin=false,quit=false,ok=true; 
	int tries=0; 
	//  
	this->ResetAll(); 
	if(filelist == NULL) 
		return false; 
	if(filelist->GetSize() == 0) 
		return false; 
	m_Filelist = filelist; 
	bufTop = mainBuf + (sizeof mainBuf); 
	m_ZModemComm->ClearInbound();//clear all pending data from modem 
	sendrz();//send initialization string  
	while(ALLOK && !fin && (tries < 100)) 
	{ 
		quit=false; 
		sendZRQINIT();//send ZRQINIT 
		getZMHeader(); 
		if(ALLOK) 
		{ 
			switch(headerType) 
			{ 
				case ZCAN://canceled from other side 
				{ 
					TRACE("set error %s\n","ZMODEM_GOTZCAN"); 
					SetLastError(ZMODEM_GOTZCAN); 
					::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)ZMODEM_GOTZCAN,0L); 
					quit=true; 
					fin=true; 
					break; 
				} 
				case ZRINIT:// ok, let's communicate 
				{ 
            		TRACE("ZRINIT erhalten"); 
					//validate CRC-32-property and CANFX-property 
					static int Rxflags = 0377 & headerData[3]; 
					bcrc32 = (Rxflags & CANFC32) != 0; 
					bcanfdx = Rxflags & CANFDX; 
					TRACE("bcanfdx ist %s\n",bcanfdx ? "true" : "false"); 
					TRACE("bcrc32 ist %s\n",bcrc32 ? "true" : "false"); 
					// start sending all files 
					ok=sendFiles(); 
					fin=true; 
					break; 
				} 
				case ZCHALLENGE: 
				{ 
					TRACE("got ZCHALLENGE"); 
					sendZACK(); 
					break; 
				} 
				default: 
				{ 
					TRACE("got unexpected header"); 
					tries++; 
					break; 
				} 
			}//switch 
		}//if(ALLOK) 
		else 
		{ 
			DWORD err=GetLastError(); 
			if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) || 
				(err==ZMODEM_CRC32) || (err==ZMODEM_BADHEX)) 
			{ 
				::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)err,0L); 
				if(tries < 100) 
				{ 
					SetLastError(0); 
					tries++; 
				} 
			} 
		} 
	}//while(...) 
	// sendig is over, finish session 
	if(ALLOK) 
	{ 
		quit=false; 
		tries=0; 
		sendZFIN(); 
		while(ALLOK && !quit) 
		{ 
      		getZMHeader(); 
			if(ALLOK && (headerType == ZFIN)) 
         		quit=true;//other side has finish accepted 
			else 
			{ 
				if(tries < 100) 
				{ 
					SetLastError(0); 
					sendZFIN(); 
					tries++; 
				} 
			} 
		} 
		if(ALLOK) 
			sendOO();//over and out 
	} 
	return(quit && fin && ok); 
} 
 
//----------------------------------------------------------------------------- 
// purpose:	receiving files 
// params:	filelist	->	Array of filenames received 
//			receivedir	->  folder to save the received files 
// returns:	success 
bool CZModemCore::Receive(CStringArray* filelist,CString receivedir) 
//----------------------------------------------------------------------------- 
{	//  
	bool fin,quit; 
	int tries; 
	//  
	this->ResetAll(); 
	if(filelist == NULL) 
		return false; 
	if(filelist->GetSize() == 0) 
		return false; 
	m_Filelist = filelist; 
	if(!receivedir.IsEmpty()) 
		m_ZModemFile->SetReceivingDir(receivedir); 
	bufTop = mainBuf + (sizeof mainBuf); 
	m_ZModemComm->ClearInbound(); 
	skip = false; 
	fin = false; 
	while(ALLOK && !fin) 
	{ 
		sendZRINIT(); 
		quit = false; 
		tries = 0; 
		while(ALLOK && !quit) 
		{ 
			getZMHeader(); 
			if(ALLOK) 
			{ 
				if(headerType == ZFIN)//other side has finish signaled 
				{ 
					sendZFIN();//reply 
					getOO();//try to get over and out signal 
					quit = true; 
					fin = true; 
				} 
				else if(headerType == ZRQINIT) 
				{ 
					if(tries < 100) 
					{ 
						sendZRINIT(); 
						tries++; 
					} 
					else 
					{ 
						TRACE("set error %s\n","ZMODEM_INIT"); 
						SetLastError(ZMODEM_INIT); 
					} 
				} 
				else if(headerType == ZFILE)//file transfer signaled 
				{ 
					skip = false; 
					getFILEINFO();//extract the FILEINFO from data block 
					if(ALLOK) 
					{ 
						receiveFile();//receive current file 
						if(ALLOK) 
							m_Filelist->Add(m_ZModemFile->GetReceivedFileName()); 
						quit = true; 
					} 
					else if(GetLastError()==ZMODEM_CRC32) 
					{ 
						::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)ZMODEM_CRC32,0L); 
						if(tries < 100) 
						{ 
							SetLastError(0); 
							sendZRINIT(); 
							tries++; 
						} 
					} 
				} 
			} 
			else 
			{ 
				DWORD err=GetLastError(); 
				if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) || 
					(err==ZMODEM_CRC32) || (err==ZMODEM_BADHEX)) 
				{ 
					::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)err,0L); 
					if(tries < 100) 
					{ 
						SetLastError(0); 
						sendZRINIT(); 
						tries++; 
					} 
				} 
			} 
		} 
	} 
	Sleep(4000);//wait 4 seconds tu ensure that the other side really get our ZEOF  
	return(ALLOK); 
} 
 
// Layer 3 #################################################################### 
//----------------------------------------------------------------------------- 
void CZModemCore::ResetAll() 
//----------------------------------------------------------------------------- 
{ 
	ch = 0; 
	gotSpecial =0; 
	m_bWait = true; 
	gotHeader =0; 
	frameType =0; 
	headerType =0; 
	memset(headerData,0,4); 
	moreData=0; 
	memset(mainBuf,0,sizeof mainBuf); 
	bufPos = NULL; 
	bufTop = NULL; 
	goodOffset=0; 
	bytes=0; 
	bcrc32=false,bcanfdx=false; 
	skip=false; 
	m_ZModemFile->ResetAll(); 
	m_ZModemComm->ResetAll(); 
} 
 
//----------------------------------------------------------------------------- 
bool CZModemCore::sendFiles() 
//----------------------------------------------------------------------------- 
{	//  
	bool gotfile; 
	int count = 0; 
	int tries; 
	bool sent; 
	bool rw=true; 
	DWORD offset; 
	int i=0; 
	bool fileinfosent=false; 
	//  
	int nSize=m_Filelist->GetSize(); 
 
	while(ALLOK && ( i < nSize)) 
	{ 
		gotfile = m_ZModemFile->Open(m_Filelist->GetAt(i),OPEN_EXISTING); 
     	if(gotfile) 
        	TRACE("SendFiles filename %s",m_Filelist->GetAt(i)); 
		else 
      		break; 
		goodOffset = 0; 
		tries = 0; 
		sent = false; 
		while(ALLOK && (tries < 10) && !sent) 
		{ 
			if(!fileinfosent) 
			{ 
				sendZFILE(); 
				sendFILEINFO(); 
				fileinfosent=true; 
			}	 
			getZMHeader(); 
			if(ALLOK) 
			{ 
				if(headerType == ZRINIT) 
				{ 
            		TRACE("got ZRINIT"); 
					tries++; 
				} 
				else if (headerType == ZRPOS) 
				{ 
           			TRACE("got ZRPOS"); 
					offset=(headerData[3] << 24) | (headerData[2] << 16) | 
							 (headerData[1] << 8)  | headerData[0]; 
					m_ZModemFile->SetPos(offset); 
					goodOffset = offset; 
					rw=sendFile(); 
					sent = true; 
				} 
				else if(headerType == ZNAK)//nochmal senden 
				{ 
            		TRACE("got ZNAK"); 
					fileinfosent=false; 
				} 
				else if(headerType == ZSKIP)//bitte nächstes file 
				{ 
					TRACE("got ZSKIP"); 
            		sent=true; 
				} 
				else if(headerType== ZCRC) 
				{ 
					TRACE("got ZCRC, no action"); 
				} 
			} 
			else 
			{ 
				DWORD err=GetLastError(); 
				if(err==ZMODEM_TIMEOUT) 
				{ 
					SetLastError(0); 
				} 
				tries++; 
			} 
		} 
		m_ZModemFile->Finish(); 
		i++;//next file 
	} 
	return rw; 
} 
 
//----------------------------------------------------------------------------- 
bool CZModemCore::sendFile() 
//----------------------------------------------------------------------------- 
{	//  
	int tries = 0; 
	DWORD lastpos = 0; 
	DWORD newpos; 
	int state; 
	bool sentfile = false; 
	bool rw=true; 
	//  
	state = SM_SENDZDATA; 
	while(ALLOK && !sentfile) 
	{ 
		switch(state) 
		{ 
			case SM_SENDZDATA: 
			{ 
	       		moreData = 1; 
				int erg=m_ZModemFile->GetData(mainBuf,maxTx,&bytes); 
				if(erg==ZMODEMFILE_NOMOREDATA) 
				{ 
					state = SM_SENDZEOF; 
					moreData = 0; 
				} 
				else if(erg == ZMODEMFILE_OK) 
				{ 
					sendZDATA(); 
					state = SM_SENDDATA; 
				} 
				else//ZMODEMFILE_ERROR 
				{ 
					TRACE("set error ZMODEM_ERROR_FILE"); 
					SetLastError(ZMODEM_ERROR_FILE); 
				} 
				break; 
			} 
			case SM_SENDDATA: 
				while (ALLOK && (state == SM_SENDDATA)) 
				{ 
					sendData(); 
					getZMHeaderImmediate(); 
					DWORD err=GetLastError(); 
					if(ALLOK && (headerType == ZRPOS)) 
					{ 
						state = SM_ACTIONRPOS; 
					} 
					else 
					{ 
						DWORD err=GetLastError(); 
						if(err==ZMODEM_TIMEOUT)//got no header 
							SetLastError(0); 
						if(ALLOK) 
						{ 
							if(!moreData) 
							{ 
								state = SM_SENDZEOF; 
								break; 
							} 
							else 
								m_ZModemFile->GetData(mainBuf,maxTx,&bytes); 
						} 
					} 
				}//while 
				break; 
			case SM_ACTIONRPOS: 
				newpos=headerData[0] | (headerData[1] << 8) | 
						 (headerData[2] << 16) | (headerData[3] << 24); 
				TRACE("in SM_ACTIONRPOS\n"); 
#ifdef _DEBUG 
				char out[1000]; 
				wsprintf(out,"newpos: %lu",newpos); 
				TRACE(out); 
#endif 
				if(newpos <= lastpos) 
					tries++; 
				else 
					 tries = 0; 
				m_ZModemFile->SetPos(newpos); 
				::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,ZMODEM_POS,0L); 
				::PostMessage(m_hOwner,WM_USER_ZMODEMRPOS,newpos,0L); 
				goodOffset = newpos; 
				state = SM_SENDZDATA; 
				break; 
			case SM_SENDZEOF: 
				TRACE("in SM_SENDZEOF\n"); 
				sendZEOF(); 
				tries = 0; 
				state = SM_WAITZRINIT; 
				break; 
			case SM_WAITZRINIT: 
				TRACE("in SM_WAITZRINIT\n"); 
				getZMHeader(); 
				if(ALLOK && (headerType == ZRINIT)) 
					sentfile = true; 
				else if (ALLOK && (headerType == ZRPOS)) 
				{ 
					state = SM_ACTIONRPOS; 
				} 
				//erweitert ... 
				else if(ALLOK && (headerType == ZFERR)) 
				{ 
					TRACE("got ZFERR, finish sending"); 
					sentfile = true; 
					rw=false; 
				} 
				else if(ALLOK && (headerType == ZFIN)) 
				{ 
					TRACE("got ZFIN, finish sending"); 
					sentfile = true; 
				} 
				else 
				{ 
					tries++; 
					if(tries < 100) 
						SetLastError(0); 
				} 
				break; 
		}//switch 
	}//while 
	return rw; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::receiveFile() 
//----------------------------------------------------------------------------- 
{	//  
	bool quit; 
	int tries; 
	//  
	goodOffset = 0; 
	m_ZModemFile->OpenReceivingFile(&goodOffset,&skip); 
	if(skip) 
		sendZSKIP(); 
	else 
	{ 
		sendZRPOS(); 
		quit = false; 
		tries = 0; 
		while(ALLOK && !quit) 
		{ 
			getZMHeader(); 
			if(ALLOK) 
			{ 
				if(headerType == ZFILE) 
				{ 
					if(tries < 100) 
					{ 
						sendZRPOS(); 
						tries++; 
					} 
					else 
					{ 
						TRACE("set error %s\n","ZMODEM_POS"); 
						SetLastError(ZMODEM_POS); 
						::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,ZMODEM_POS,0L); 
					} 
				} 
				else if(headerType == ZDATA) 
				{ 
					receiveData(); 
					quit = true; 
				} 
			} 
			else 
			{ 
				DWORD err=GetLastError(); 
				if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) || 
					(err==ZMODEM_CRC32)) 
				{ 
              		PostMessage(m_hOwner,WM_USER_ZMODEMERROR,err,0L); 
					if(tries < 100) 
					{ 
						SetLastError(0); 
						sendZRPOS(); 
						tries++; 
					} 
				} 
			} 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::receiveData() 
//----------------------------------------------------------------------------- 
{	//  
	bool quit; 
	int tries; 
	//  
	quit = false; 
	tries = 0; 
	moreData = 1; 
	while(ALLOK && !quit) 
	{ 
		if(moreData) 
		{ 
			getData(); 
			if(ALLOK) 
			{ 
				m_ZModemFile->WriteData(mainBuf,(DWORD)(bufPos - mainBuf)); 
				tries = 0; 
			} 
		} 
		else 
		{ 
			getZMHeader(); 
			if(ALLOK) 
			{ 
				if(headerType == ZDATA) 
				{ 
					if(posMatch()) 
						moreData = 1; 
				} 
				else if (headerType == ZEOF) 
				{ 
					if (posMatch()) 
					{ 
						m_ZModemFile->Finish(); 
						quit = true; 
					} 
				} 
			} 
		} 
		if(!ALLOK) 
		{ 
			DWORD err=GetLastError(); 
			if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_LONGSP) || 
				(err==ZMODEM_CRCXM) || (err==ZMODEM_CRC32)) 
			{ 
				if(tries < 100) 
				{ 
					::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,err,0L); 
					SetLastError(0); 
					moreData = 0; 
					sendZRPOS(); 
					tries++; 
				} 
			} 
		} 
	} 
} 
 
// Layer 2 #################################################################### 
//----------------------------------------------------------------------------- 
void CZModemCore::getZMHeaderImmediate() 
//----------------------------------------------------------------------------- 
{ 
	m_bWait = false; 
	getZMHeader(); 
	m_bWait = true; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getZMHeader() 
//----------------------------------------------------------------------------- 
{	//  
	int count; 
	//  
	gotHeader = 0; 
	getNextCh(); 
	while(ALLOK && !gotHeader) 
	{ 
		while (ALLOK && (ch != ZPAD)) 
		{ 
			getNextCh(); 
		} 
		if(ALLOK) 
		{ 
			count = 1; 
			getNextCh(); 
			while (ALLOK && (ch == ZPAD)) 
			{ 
				count++; 
				getNextCh(); 
			} 
			if(ALLOK && (ch == ZDLE)) 
			{ 
				getNextCh(); 
				if(ALLOK) 
				{ 
					if (ch == ZBIN) 
					{ 
						frameType = ZBIN; 
						getBinaryHeader(); 
					} 
					else if (ch == ZBIN32) 
					{ 
						frameType = ZBIN32; 
						getBin32Header(); 
					} 
					else if ((ch == ZHEX) && (count >= 2)) 
					{ 
						frameType = ZHEX; 
						getHexHeader(); 
					} 
				} 
			} 
		} 
	} 
	if(gotHeader) 
	{ 
#ifdef _DEBUG 
		char out[1000]; 
		wsprintf(out,"headerdata 0: %u 1: %u 2: %u 3: %u",headerData[0], 
           			headerData[1],headerData[2],headerData[3]); 
		TRACE(out); 
#endif 
		;       
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getOO()		 
//----------------------------------------------------------------------------- 
{ 
	getNextCh(); 
	if(ALLOK) 
		getNextCh(); 
	DWORD err=GetLastError(); 
	if(!ALLOK && (err==ZMODEM_TIMEOUT)) 
	{ 
		TRACE("set error 0"); 
		SetLastError(0); 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getFILEINFO() 
//----------------------------------------------------------------------------- 
{	//  
	bool noproblem; 
	//  
	getData(); 
	if(ALLOK) 
	{ 
   		noproblem=m_ZModemFile->InitFromFILEINFO(mainBuf); 
		if(!noproblem) 
		{ 
			TRACE("set error ZMODEM_FILEDATA"); 
			SetLastError(ZMODEM_FILEDATA); 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZRINIT() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZRINIT; 
	headerData[0] = 0x00; 
	headerData[1] = 0x00; 
	headerData[2] = 0x00; 
	headerData[3] = CANOVIO | CANFDX | CANFC32; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZSKIP() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZSKIP; 
	headerData[0] = 0x00; 
	headerData[1] = 0x00; 
	headerData[2] = 0x00; 
	headerData[3] = 0x00; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZRPOS() 
//----------------------------------------------------------------------------- 
{	//  
	long templ; 
	//  
	frameType = ZHEX; 
	headerType = ZRPOS; 
	templ = goodOffset; 
	headerData[0] = (unsigned char)(templ & 0xff); 
	templ = templ >> 8; 
	headerData[1] = (unsigned char)(templ & 0xff); 
	templ = templ >> 8; 
	headerData[2] = (unsigned char)(templ & 0xff); 
	templ = templ >> 8; 
	headerData[3] = (unsigned char)(templ & 0xff); 
	m_ZModemComm->ClearInbound(); 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZFIN() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZFIN; 
	headerData[0] = 0x00; 
	headerData[1] = 0x00; 
	headerData[2] = 0x00; 
	headerData[3] = 0x00; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZEOF() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZEOF; 
	headerData[0] = (unsigned char)(goodOffset); 
	headerData[1] = (unsigned char)((goodOffset) >> 8); 
	headerData[2] = (unsigned char)((goodOffset) >> 16); 
	headerData[3] = (unsigned char)((goodOffset) >> 24); 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendrz() 
//----------------------------------------------------------------------------- 
{ 
	m_ZModemComm->WriteBlock("\x72\x7a\x0d",3); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZRQINIT() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZRQINIT; 
	headerData[0]=0x00; 
	headerData[1]=0x00; 
	headerData[2]=0x00; 
	headerData[3]=0x00; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZFILE() 
//----------------------------------------------------------------------------- 
{ 
	if(bcrc32) 
		frameType= ZBIN32; 
	else 
   		frameType= ZBIN; 
	headerType=ZFILE; 
	headerData[0]=0x00; 
	headerData[1]=0x00; 
	headerData[2]=0x00; 
	headerData[3]=0x00;//ZCBIN; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendFILEINFO() 
//----------------------------------------------------------------------------- 
{	//  
	unsigned char* buf;//buffer for FILEINFO 
	int cnt; 
	int x; 
	CRCXM crc; 
	CRC32 crc32; 
	//  
	buf = new unsigned char[500]; 
	memset(buf,0,500); 
	cnt = m_ZModemFile->MakeFileInfo(buf); 
	if(bcrc32) 
   		crc32Init(&crc32); 
	else 
   		crcxmInit(&crc); 
	for(x = 0; x < cnt; x++) 
	{ 
   		if(bcrc32) 
      		crc32Update(&crc32, buf[x]); 
		else 
			crcxmUpdate(&crc, buf[x]); 
	} 
	// add CRC 
	buf[cnt++] = ZDLE; 
	buf[cnt++] = ZCRCW; 
	if(bcrc32) 
		crc32Update(&crc32, ZCRCW); 
	else 
		crcxmUpdate(&crc, ZCRCW); 
	crc32 = ~crc32; 
 
	if(bcrc32) 
	{ 
		for(int i=4;--i>=0;) 
		{ 
			buf[cnt++]=(unsigned char)crc32; 
      		crc32 >>= 8; 
		} 
	} 
	else 
	{ 
		buf[cnt++] = (unsigned char)crcxmHighbyte(&crc); 
		buf[cnt++] = (unsigned char)crcxmLowbyte(&crc); 
	} 
	buf[cnt++] = 0x11; 
	m_ZModemComm->WriteBlock(buf,cnt); 
	delete[] buf; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZDATA() 
//----------------------------------------------------------------------------- 
{ 
	if(bcrc32) 
		frameType=ZBIN32; 
	else 
		frameType=ZBIN; 
	headerType=ZDATA; 
	headerData[0]=goodOffset & 0xff; 
	headerData[1]=(goodOffset >> 8) & 0xff; 
	headerData[2]=(goodOffset >> 16) & 0xff; 
	headerData[3]=(goodOffset >> 24) & 0xff; 
	sendHeader(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendOO() 
//----------------------------------------------------------------------------- 
{ 
	m_ZModemComm->WriteBlock("OO",2); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendZACK() 
//----------------------------------------------------------------------------- 
{ 
	frameType = ZHEX; 
	headerType = ZACK; 
/*	headerData[0] = is already filled, bouncing back 
	headerData[1] = 
	headerData[2] = 
	headerData[3] =*/ 
	sendHeader(); 
} 
 
// Layer 1 #################################################################### 
//----------------------------------------------------------------------------- 
void CZModemCore::sendHeader() 
//----------------------------------------------------------------------------- 
{ 
#ifdef _DEBUG 
	char out[1000]; 
	wsprintf(out,"sending frametype: %u headertyp: %u, headerdata 0: %u 1: %u 2: %u 3: %u", 
   			frameType,headerType,headerData[0],headerData[1],headerData[2],headerData[3]); 
	TRACE(out); 
#endif 
	switch(frameType) 
	{ 
		case ZHEX: 
			sendHexHeader(); 
			break; 
		case ZBIN: 
			sendBinHeader(); 
			break; 
		case ZBIN32: 
			sendBin32Header(); 
			break; 
		default: 
			TRACE("wrong headertype"); 
			break; 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendHexHeader() 
//----------------------------------------------------------------------------- 
{	//  
	CRCXM crc; 
	//  
	crcxmInit(&crc); 
	ch = ZPAD; 
	sendChar(); 
	sendChar(); 
	ch = ZDLE; 
	sendChar(); 
  	ch = frameType; 
    sendChar(); 
   	ch = headerType; 
    crcxmUpdate(&crc, ch); 
	sendHexChar(); 
   	ch = headerData[0]; 
	crcxmUpdate(&crc, ch); 
    sendHexChar(); 
   	ch = headerData[1]; 
    crcxmUpdate(&crc, ch); 
    sendHexChar(); 
   	ch = headerData[2]; 
	crcxmUpdate(&crc, ch); 
    sendHexChar(); 
   	ch = headerData[3]; 
    crcxmUpdate(&crc, ch); 
    sendHexChar(); 
   	ch = crcxmHighbyte(&crc); 
	sendHexChar(); 
   	ch = crcxmLowbyte(&crc); 
	sendHexChar(); 
	ch = 0x0d; 
	sendChar(); 
	ch = 0x0a; 
	sendChar(); 
	ch = 0x11; 
	sendChar(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendBinHeader() 
//----------------------------------------------------------------------------- 
{	//  
	CRCXM crc; 
   //  
	crcxmInit(&crc); 
	ch = ZPAD; 
	sendChar(); 
	ch = ZDLE; 
	sendChar(); 
	ch = frameType; 
	sendChar(); 
	ch = headerType; 
	crcxmUpdate(&crc, ch); 
	sendDLEChar(); 
   	ch = headerData[0]; 
    crcxmUpdate(&crc, ch); 
    sendDLEChar(); 
   	ch = headerData[1]; 
    crcxmUpdate(&crc, ch); 
	sendDLEChar(); 
   	ch = headerData[2]; 
    crcxmUpdate(&crc, ch); 
    sendDLEChar(); 
  	ch = headerData[3]; 
    crcxmUpdate(&crc, ch); 
    sendDLEChar(); 
	ch = crcxmHighbyte(&crc); 
    sendDLEChar(); 
   	ch = crcxmLowbyte(&crc); 
    sendDLEChar(); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendBin32Header() 
//----------------------------------------------------------------------------- 
{	//  
	CRC32 crc; 
	//  
	crc32Init(&crc); 
	ch = ZPAD; 
	sendChar(); 
   	ch = ZDLE; 
    sendChar(); 
	ch = frameType; 
    sendChar(); 
  	ch = headerType; 
    crc32Update(&crc, ch); 
    sendDLEChar(); 
	ch = headerData[0]; 
    crc32Update(&crc, ch); 
    sendDLEChar(); 
   	ch = headerData[1]; 
    crc32Update(&crc, ch); 
    sendDLEChar(); 
	ch = headerData[2]; 
    crc32Update(&crc, ch); 
    sendDLEChar(); 
	ch = headerData[3]; 
    crc32Update(&crc, ch); 
    sendDLEChar(); 
	crc = ~crc; 
	for(int i=0;i<4;i++) 
	{ 
   		ch=(unsigned char)crc; 
		sendDLEChar(); 
		crc >>= 8; 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getHexHeader() 
//----------------------------------------------------------------------------- 
{	//  
	CRCXM crc; 
	unsigned int theirCRC; 
	//  
	getNextHexCh(); 
	while(ALLOK && !gotHeader) 
	{ 
		crcxmInit(&crc); 
		headerType = (unsigned char)ch; 
		TRACE("got headertype %lu\n",headerType); 
		crcxmUpdate(&crc, ch); 
		getNextHexCh(); 
		if(ALLOK) 
		{ 
			headerData[0] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextHexCh(); 
			headerData[1] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextHexCh(); 
			headerData[2] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextHexCh(); 
			headerData[3] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextHexCh(); 
		} 
		if(ALLOK) 
		{ 
			theirCRC = ch; 
			getNextHexCh(); 
		} 
		if(ALLOK) 
		{ 
			theirCRC = (theirCRC << 8) | ch; 
			if (crcxmValue(&crc) != theirCRC) 
			{ 
				TRACE("set error %s\n","ZMODEM_CRCXM"); 
				SetLastError(ZMODEM_CRCXM); 
			} 
			else 
			{ 
				gotHeader = 1; 
			} 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getBinaryHeader() 
//----------------------------------------------------------------------------- 
{	//  
	CRCXM crc; 
	unsigned int theirCRC; 
	//  
	getNextDLECh(); 
	while(ALLOK && !gotHeader) 
	{ 
   		crcxmInit(&crc); 
		headerType = (unsigned char)ch; 
		TRACE("got headertype %lu\n",headerType); 
		crcxmUpdate(&crc, ch); 
		getNextDLECh(); 
		if(ALLOK) 
		{ 
      		headerData[0] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextDLECh(); 
			headerData[1] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextDLECh(); 
	      	headerData[2] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
			getNextDLECh(); 
	      	headerData[3] = (unsigned char)ch; 
			crcxmUpdate(&crc, ch); 
		    getNextDLECh(); 
		} 
		if(ALLOK) 
		{ 
      		theirCRC = ch; 
			getNextDLECh(); 
		} 
		if(ALLOK) 
		{ 
      		theirCRC = (theirCRC << 8) | ch; 
			if (crcxmValue(&crc) != theirCRC) 
			{ 
				TRACE("set error %s\n","ZMODEM_CRCXM"); 
				SetLastError(ZMODEM_CRCXM); 
			} 
			else 
				gotHeader = 1; 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getBin32Header() 
//----------------------------------------------------------------------------- 
{	//  
	CRC32 crc; 
	DWORD theirCRC; 
	//  
	getNextDLECh(); 
	while(ALLOK && !gotHeader) 
	{ 
   		crc32Init(&crc); 
		headerType = (unsigned char)ch; 
		TRACE("got headertype %lu\n",headerType); 
		crc32Update(&crc, ch); 
		getNextDLECh(); 
		if(ALLOK) 
		{ 
			headerData[0] = (unsigned char)ch; 
			crc32Update(&crc, ch); 
			getNextDLECh(); 
			headerData[1] = (unsigned char)ch; 
			crc32Update(&crc, ch); 
			getNextDLECh(); 
      		headerData[2] = (unsigned char)ch; 
			crc32Update(&crc, ch); 
			getNextDLECh(); 
      		headerData[3] = (unsigned char)ch; 
			crc32Update(&crc, ch); 
			getNextDLECh(); 
		} 
		if(ALLOK) 
		{ 
      		theirCRC = (unsigned long)ch; 
			getNextDLECh(); 
			theirCRC = theirCRC | ((unsigned long)ch << 8); 
			getNextDLECh(); 
      		theirCRC = theirCRC | ((unsigned long)ch << 16); 
			getNextDLECh(); 
      		theirCRC = theirCRC | ((unsigned long)ch << 24); 
			if (~crc32Value(&crc) != theirCRC) 
			{ 
				TRACE("set error %s\n","ZMODEM_CRC32"); 
         		SetLastError(ZMODEM_CRC32); 
			} 
			else 
				gotHeader = 1; 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
bool CZModemCore::posMatch() 
//----------------------------------------------------------------------------- 
{	//  
	DWORD templ; 
	bool ret; 
	//  
	templ = headerData[3]; 
	templ = (templ << 8) | headerData[2]; 
	templ = (templ << 8) | headerData[1]; 
	templ = (templ << 8) | headerData[0]; 
	if(templ == goodOffset) 
		ret = true; 
	else 
	{ 
		TRACE("error posMatch"); 
		ret = false; 
	} 
	return(ret); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getData() 
//----------------------------------------------------------------------------- 
{ 
	if(frameType == ZBIN32) 
		getData32(); 
	else 
		getData16(); 
	if(!ALLOK) 
		moreData = 0; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getData16() 
//----------------------------------------------------------------------------- 
{	//  
	int quit; 
	CRCXM crc; 
	unsigned int theirCRC; 
	//  
	bufPos = mainBuf; 
	quit = 0; 
	crcxmInit(&crc); 
	while(ALLOK && (bufPos < bufTop) && !quit) 
	{ 
		getNextDLECh(); 
		if(ALLOK) 
		{ 
			if(gotSpecial) 
			{ 
				if(ch != ZCRCG) 
				{ 
					moreData = 0; 
				} 
				crcxmUpdate(&crc, ch); 
				getNextDLECh(); 
				if(ALLOK) 
				{ 
					theirCRC = ch; 
					getNextDLECh(); 
				} 
				if(ALLOK) 
				{ 
					theirCRC = (theirCRC << 8) | ch; 
					if(crcxmValue(&crc) != theirCRC) 
					{ 
						TRACE("set error %s\n","ZMODEM_CRCXM"); 
						SetLastError(ZMODEM_CRCXM); 
					} 
					else 
					{ 
						goodOffset += (bufPos - mainBuf); 
						quit = 1; 
					} 
				} 
			} 
			else 
			{ 
				crcxmUpdate(&crc, ch); 
				*bufPos = (unsigned char)ch; 
				bufPos++; 
			} 
		} 
	} 
	if(bufPos == bufTop) 
	{ 
		TRACE("set error %s\n","ZMODEM_LONGSP"); 
		::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)ZMODEM_LONGSP,0L); 
		SetLastError(ZMODEM_LONGSP); 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getData32() 
//----------------------------------------------------------------------------- 
{	//variablen 
	int quit; 
	CRC32 crc; 
	DWORD theirCRC; 
	//  
	bufPos = mainBuf; 
	quit = 0; 
	crc32Init(&crc); 
	while(ALLOK && (bufPos < bufTop) && !quit) 
	{ 
		getNextDLECh(); 
		if(ALLOK) 
		{ 
			if(gotSpecial) 
			{ 
				if(ch != ZCRCG) 
				{ 
					moreData = 0; 
				} 
				crc32Update(&crc, ch); 
				getNextDLECh(); 
				if(ALLOK) 
				{ 
					theirCRC = ch; 
					getNextDLECh(); 
				} 
				if(ALLOK) 
				{ 
					theirCRC = theirCRC | ((DWORD)ch << 8); 
					getNextDLECh(); 
				} 
				if(ALLOK) 
				{ 
					theirCRC = theirCRC | ((DWORD)ch << 16); 
					getNextDLECh(); 
				} 
				if(ALLOK) 
				{ 
					theirCRC = theirCRC | ((DWORD)ch << 24); 
					if (~crc32Value(&crc) != theirCRC) 
					{ 
						TRACE("set error %s\n","ZMODEM_CRC32"); 
						SetLastError(ZMODEM_CRC32); 
					} 
					else 
					{ 
						goodOffset += (bufPos - mainBuf); 
						quit = 1; 
					} 
				} 
			} 
			else 
			{ 
				crc32Update(&crc, ch); 
				*bufPos = (unsigned char)ch; 
				bufPos++; 
			} 
		} 
	} 
	if(bufPos == bufTop) 
	{ 
		TRACE("set error %s\n","ZMODEM_LONGSP"); 
   		SetLastError(ZMODEM_LONGSP); 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendData() 
//----------------------------------------------------------------------------- 
{	//  
	char sptype; 
	//  
	// send ZCRCG if more data, ZCRCE otherwise 
	sptype = moreData ? ZCRCG : ZCRCE; 
	if(bcrc32) 
	   sendData32(bytes,sptype); 
	else 
   		sendData16(bytes,sptype); 
	goodOffset = goodOffset + bytes; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendData32(int len,char frameend) 
//----------------------------------------------------------------------------- 
{ 
	unsigned long crc; 
 
	crc32Init(&crc); 
	for(int i=0;i>= 8; 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendData16(int len,char frameend) 
//----------------------------------------------------------------------------- 
{ 
	CRCXM	crcxm; 
 
	crcxmInit(&crcxm); 
	for(int i=0;i>= 8; 
	} 
} 
 
// Layer 0 #################################################################### 
//----------------------------------------------------------------------------- 
void CZModemCore::getNextHexCh() 
//----------------------------------------------------------------------------- 
{	//  
	int tempCh; 
	//  
	getNextCh(); 
	if(ALLOK) 
	{ 
		if ((ch <= 0x39) && (ch >= 0x30)) 
		{ 
			tempCh = (ch - 0x30); 
		} 
		else if ((ch >= 0x61) && (ch <= 0x66)) 
		{ 
			tempCh = (ch - 0x61) + 0x0a; 
		} 
		else 
		{ 
			SetLastError(ZMODEM_BADHEX); 
			TRACE("set error %s\n","ZMODEM_BADHEX"); 
		} 
		if(ALLOK) 
			getNextCh(); 
		if(ALLOK) 
		{ 
			tempCh = tempCh << 4; 
			if ((ch <= 0x39) && (ch >= 0x30)) 
			{ 
         		ch = (ch - 0x30); 
			} 
			else if ((ch >= 0x61) && (ch <= 0x66)) 
			{ 
         		ch = (ch - 0x61) + 0x0a; 
			} 
			else 
			{ 
				TRACE("set error %s\n","ZMODEM_BADHEX"); 
         		SetLastError(ZMODEM_BADHEX); 
			} 
		} 
		if(ALLOK) 
		{ 
      		ch = ch | tempCh; 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getNextDLECh() 
//----------------------------------------------------------------------------- 
{ 
	gotSpecial = 0; 
	getNextCh(); 
	if(ALLOK) 
	{ 
		if(ch == ZDLE) 
		{ 
      		getNextCh(); 
			if(ALLOK) 
			{ 
         		if(((ch & 0x40) != 0) && ((ch & 0x20) == 0)) 
				{ 
					ch &= 0xbf; 
					gotSpecial = 0; 
				} 
				else 
				{ 
            		gotSpecial = 1; 
				} 
			} 
		} 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::getNextCh() 
//----------------------------------------------------------------------------- 
{	//  
	unsigned char buf[1]; 
	DWORD actual; 
	//  
	if(m_bWait) 
		m_ZModemComm->GetBlock(buf,1,&actual); 
	else 
		m_ZModemComm->GetBlockImm(buf,1,&actual); 
	if(ALLOK && (actual == 1)) 
		ch = buf[0]; 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendChar() 
//----------------------------------------------------------------------------- 
{	//  
	unsigned char buf[1]; 
	//  
	buf[0] = (unsigned char)ch; 
	m_ZModemComm->WriteBlock(buf, 1); 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendChar(int c) 
//----------------------------------------------------------------------------- 
{	//  
	unsigned char buf[1]; 
	//  
	buf[0] = (unsigned char)c; 
	m_ZModemComm->WriteBlock(buf, 1); 
} 
 
//----------------------------------------------------------------------------- 
// purpose: masking special characters withZDLE 
//			HEX: 0x18(ZDLE selbst) 0x10 0x90 0x11 0x91 0x13 0x93 0xFF 
//			OCT:  030               020 0220  021 0221  023 0223 0377 
void CZModemCore::sendDLEChar() 
//----------------------------------------------------------------------------- 
{ 
	//  
	ch &= 0xFF; 
	switch(ch) 
	{ 
   		case ZDLE: 
      		sendChar(ZDLE); 
			sendChar(ch ^= 0x40); 
			break; 
		case 021: 
		case 0221: 
		case 023: 
		case 0223: 
      		sendChar(ZDLE); 
			sendChar(ch ^= 0x40); 
			break; 
		default: 
			if((ch & 0140) == 0) 
			{ 
				sendChar(ZDLE); 
				ch ^= 0x40; 
			} 
			sendChar(ch); 
			break; 
	} 
} 
 
//----------------------------------------------------------------------------- 
void CZModemCore::sendHexChar() 
//----------------------------------------------------------------------------- 
{	//  
	int tempCh; 
	unsigned char hexdigit[]="\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x61\x62\x63\x64\x65\x66"; 
	//  
	tempCh = ch; 
	ch = hexdigit[(tempCh >> 4) & 0x0f]; 
	sendChar(); 
	if(ALLOK) 
	{ 
   		ch = hexdigit[tempCh & 0x0f]; 
		sendChar(); 
	} 
}