📄 zmodem.cpp
字号:
error( "TIMEOUT" );
return c;
default:
error( "Garbled data subpacket" );
return c;
}
}
*buffer++ = (char) c;
crc.update( c );
}
error( "Data subpacket too long" );
return ERROR;
}
int Zmodem::ReadDataFrameCRC16( char *buffer, int length )
{
int c;
Crc16 crc( 0 );
char *end;
int d;
Rxcount = 0;
end = buffer + length;
while ( buffer <= end ) {
if ( ( c = ReadEncodedByte() ) & ~0xff ) {
crcfoo:
switch ( c ) {
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
crc.update( (d = c) & 0xff );
if ( ( c = ReadEncodedByte()) & ~0xff )
goto crcfoo;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
goto crcfoo;
crc.update( c );
if ( crc.value() & 0xFFFF ) {
error( "Bad CRC");
return ERROR;
}
Rxcount = (int) ( length - ( end - buffer ) );
error( "ReadDataFrame: %d %s",
Rxcount,
Zendnames[ d - GOTCRCE & 3 ] );
return d;
case GOTCAN:
error( "Sender Canceled" );
return ZCAN;
case TIMEOUT:
error( "TIMEOUT" );
return c;
default:
error( "Garbled data subpacket" );
return c;
}
}
*buffer++ = (char) c;
crc.update( c );
}
error( "Data subpacket too long" );
return ERROR;
}
// The attention string processor has to process a couple of
// special characters used to sleep and send breaks.
void Zmodem::SendAttentionString()
{
int i = 0;
int c;
long timer;
while ( port->TXSpaceUsed() > 0 )
port->IdleFunction();
while ( ( c = attention_string[ i++ ] ) != 0 ) {
switch ( c ) {
case 0xde :
timer = ReadTime() + 1000L;
while ( ReadTime() < timer )
port->IdleFunction();
break;
case 0xdd :
port->Break();
break;
default:
SendChar( c );
}
}
}
// This function is called by the receiver before exiting.
void Zmodem::AckZFIN( void )
{
int n;
status( "AckZFIN" );
PackLongIntoHeader( 0L );
for ( n = 0 ; n < 4 ; n++ ) {
port->FlushRXBuffer();
SendHexHeader( 4, ZFIN, transmitted_header );
switch ( ReadChar( 10000L ) ) {
case 'O':
ReadChar( 120 ); /* Discard 2nd 'O' */
status( "AckZFIN complete" );
return;
case TIMEOUT:
default:
break;
}
}
}
// This utility routine has to scan the incoming data subpacket
// for the file name and length.
int Zmodem::OpenInputFile( char *data )
{
strcpy( file_name, data );
if (sscanf(data+strlen(data)+1, "%ld", &file_length ) < 1 )
file_length = -1L;
file = fopen( file_name, "wb" );
if ( !file)
return ERROR;
return OK;
}
// File position values are longs packed into a four byt header.
// The following two routines are resposible for packing and
// unpacking the data.
void Zmodem::PackLongIntoHeader( long header_data )
{
transmitted_header[ ZP0 ] = (char) header_data;
transmitted_header[ ZP1 ] = (char) ( header_data >> 8 );
transmitted_header[ ZP2 ] = (char) ( header_data >> 16 );
transmitted_header[ ZP3 ] = (char) ( header_data >> 24 );
}
long Zmodem::UnpackHeaderIntoLong( char *header )
{
long l;
l = header[ ZP3 ] & 0xff;
l = ( l << 8 ) | ( header[ ZP2 ] & 0xff );
l = ( l << 8 ) | ( header[ ZP1 ] & 0xff );
l = ( l << 8 ) | ( header[ ZP0 ] & 0xff );
return l;
}
// Hex headers need to send data in hex format.
void Zmodem::SendHexEncodedChar( int c )
{
static char *digits = "0123456789abcdef";
SendChar( digits[ ( c & 0xF0 ) >> 4 ] );
SendChar( digits[ c & 0xF ] );
}
// This routine handles all the escape sequences necessary to send
// control characters.
void Zmodem::SendEncodedChar( int c )
{
if ( c & 0x60 )
SendChar( last_char_sent = c );
else {
switch ( c &= 0xff ) {
case CR :
case CR | 0x80 :
if ( ( last_char_sent & 0x7f ) != '@' ) {
SendChar( last_char_sent = c );
break;
} // else fall through
case ZDLE :
case DLE :
case XON :
case XOFF :
case DLE | 0x80 :
case XON | 0x80 :
case XOFF | 0x80 :
SendChar( ZDLE );
c ^= 0x40;
SendChar( last_char_sent = c );
break;
default:
SendChar( last_char_sent = c );
}
}
}
// Read a byte, taking into account escape sequences, and checking
// for the 5*CAN abort sequence.
int Zmodem::ReadEncodedByte( void )
{
int c;
for ( ; ; ) {
c = ReadChar( 10000L );
if ( c == ZDLE )
break;
switch ( c ) {
case XON :
case XON | 0x80 :
case XOFF :
case XOFF | 0x80 :
break;
default:
return c;
}
}
for ( ; ; ) {
if ( ( c = ReadChar( 10000L ) ) < 0 )
return c;
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
return c;
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
return c;
if ( c == CAN && ( c = ReadChar( 10000L ) ) < 0 )
return c;
switch ( c ) {
case CAN:
return GOTCAN;
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
return c | GOTFLAG;
case ZRUB0:
return 0x7f;
case ZRUB1:
return 0xff;
case XOFF :
case XOFF | 0x80 :
case XON :
case XON | 0x80 :
break;
default:
if ( ( c & 0x60 ) == 0x40 )
return ( c ^ 0x40 );
else
return ERROR;
}
}
}
// This routine reads a raw data byte, throws out the parity bit and
// ignores handshaking characters.
int Zmodem::ReadUnencodedByte( void )
{
int c;
for ( ; ; ) {
if ( ( c = ReadChar( 10000L ) ) < 0 )
return c;
switch ( c &= 0x7f ) {
case XON:
case XOFF:
continue;
default:
return c;
}
}
}
// When reading Hex headers, we need to convert hex values to a
// usable format.
int Zmodem::ReadHexByte( void )
{
int c;
int n;
if ( ( c = ReadUnencodedByte() ) < 0 )
return c;
n = c - '0';
if ( n > 9 )
n -= ( 'a' - ':' );
if ( n & ~0xF )
return ERROR;
if ( ( c = ReadUnencodedByte( )) < 0 )
return c;
c -= '0';
if ( c > 9 )
c -= ( 'a' - ':' );
if ( c & ~0xF )
return ERROR;
c += ( n << 4 );
return c;
}
// The sender needs to get the RINIT frame before it can start
// sending the file. This routine takes care of that.
int Zmodem::GetRinitHeader( void )
{
int i;
for ( i = 0 ; i < 10 ; i++ ) {
switch ( ReadHeader( received_header ) ) {
case ZCHALLENGE: // Echo receiver's challenge number
PackLongIntoHeader( received_file_position );
SendHexHeader( 4, ZACK, transmitted_header );
continue;
case ZCOMMAND: // They didn't see our ZRQINIT
PackLongIntoHeader( 0L );
SendHexHeader( 4, ZRQINIT, transmitted_header );
continue;
case ZRINIT:
receiver_wants_crc32 = received_header[ ZF0 ] & CANFC32;
receiver_buffer_length =
( received_header[ ZP0 ] & 0xff ) +
( ( received_header[ ZP1 ] & 0xff ) << 8 );
return OK;
case ZCAN:
case TIMEOUT:
return ERROR;
case ZRQINIT:
if ( received_header[ ZF0 ] == ZCOMMAND )
continue;
default:
SendHexHeader( 4, ZNAK, transmitted_header );
continue;
}
}
return ERROR;
}
// This routine sends a data subpacket, which is used here to send
// file names and file data.
void Zmodem::SendDataFrame( char *buffer, int length, int frameend )
{
Crc32 crc32( 0xFFFFFFFFL );
unsigned long crc32val;
Crc16 crc16( 0 );
int i;
status( "SendDataFrame: %d %s",
length, Zendnames[ frameend - ZCRCE & 3 ] );
if ( receiver_wants_crc32 ) {
for ( i = 0 ; i < length ; i++ ) {
SendEncodedChar( buffer[ i ] );
crc32.update( buffer[ i ] & 0xff );
}
SendChar( ZDLE );
SendChar( frameend );
crc32.update( frameend );
crc32val = ~crc32.value();
for ( i = 0 ; i < 4 ; i++ ) {
SendEncodedChar( (int) crc32val );
crc32val >>= 8;
}
} else {
for ( i = 0 ; i < length ; i++ ) {
SendEncodedChar( buffer[ i ] );
crc16.update( buffer[ i ] & 0xff );
}
SendChar( ZDLE);
SendChar( frameend);
crc16.update( frameend );
crc16.update( 0 );
crc16.update( 0 );
SendEncodedChar( crc16.value() >> 8 );
SendEncodedChar( crc16.value() );
}
if ( frameend == ZCRCW )
SendChar( XON );
}
// The sender sends a ZFIN frame just before exiting.
void Zmodem::SendZFIN( void )
{
for ( ; ; ) {
PackLongIntoHeader( 0L );
SendHexHeader( 4, ZFIN, transmitted_header );
switch ( ReadHeader( received_header ) ) {
case ZFIN:
SendChar( 'O');
SendChar( 'O');
case ZCAN:
case TIMEOUT:
return;
}
}
}
int Zmodem::SyncWithReceiver( int flag )
{
int c;
for ( ; ; ) {
c = ReadHeader( received_header );
switch ( c ) {
case ZCAN:
case ZABORT:
case ZFIN:
case TIMEOUT:
return ERROR;
case ZRPOS:
if ( fseek( file, received_file_position, SEEK_SET ) )
return ERROR;
file_at_eof = 0;
byte_count = last_reported_position
= transmitted_file_position = received_file_position;
last_sync_position = received_file_position;
return c;
case ZACK:
last_reported_position = received_file_position;
if ( flag || transmitted_file_position ==
received_file_position )
return ZACK;
continue;
case ZRINIT:
case ZSKIP:
fclose( file );
return c;
case ERROR:
default:
SendBinaryHeader( 4, ZNAK, transmitted_header );
continue;
}
}
}
// ********************* END OF ZMODEM.CPP **********************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -