📄 zmodem.cpp
字号:
error( "ReceiveSingleFile: ReadHeader "
"returned %d", c );
return ERROR;
}
SendAttentionString();
continue;
case ZSKIP:
fclose( file );
status("ReceiveSingleFile: Sender SKIPPED file");
return c;
case ZDATA:
if ( UnpackHeaderIntoLong( received_header ) != rxbytes ) {
if ( ++error_count >= 20 )
return ERROR;
SendAttentionString();
continue;
}
moredata:
switch ( c = ReadDataFrame( buffer, 1024 ) ) {
case ZCAN:
error( "ReceiveSingleFile: ReadData returned %d",
c );
return ERROR;
case ERROR:
if ( ++error_count >= 20 ) {
error( "ReceiveSingleFile: ReadData "
"returned %d", c );
return ERROR;
}
SendAttentionString();
continue;
case TIMEOUT:
if ( ++error_count >= 20 ) {
error( "ReceiveSingleFile: ReadData "
"returned %d", c );
return ERROR;
}
continue;
case GOTCRCW:
error_count = 0;
fwrite( buffer, 1, Rxcount, file );
rxbytes += Rxcount;
PackLongIntoHeader( rxbytes );
SendHexHeader( 4, ZACK, transmitted_header );
SendChar( XON );
goto nxthdr;
case GOTCRCQ:
error_count = 0;
fwrite( buffer, 1, Rxcount, file );
rxbytes += Rxcount;
PackLongIntoHeader( rxbytes );
SendHexHeader( 4, ZACK, transmitted_header );
goto moredata;
case GOTCRCG:
error_count = 0;
fwrite( buffer, 1, Rxcount, file );
rxbytes += Rxcount;
goto moredata;
case GOTCRCE:
error_count = 0;
fwrite( buffer, 1, Rxcount, file );
rxbytes += Rxcount;
goto nxthdr;
}
}
}
#ifdef _MSC_VER
return 0; // MSC 7.0 generates an error w/o this line,
// although it can never be reached
#endif
}
// This routine just has to decide whether to send the binary
// header using CRC-16 or CRC-32. After that it just spits out
// the data.
void Zmodem::SendBinaryHeader( int length,
int type,
char *header )
{
int i;
Crc32 crc32( 0xFFFFFFFFL );
unsigned long crc32val;
Crc16 crc16( 0 );
status( "SendBinaryHeader: %d %s %lx",
length,
frametypes[ type + 4 ],
UnpackHeaderIntoLong( header ) );
SendChar( ZPAD );
SendChar( ZDLE );
if ( receiver_wants_crc32 ) {
SendChar( ZBIN32 );
SendEncodedChar( type );
crc32.update( type );
for ( i = 0; i < length; i++ ) {
crc32.update( 0xff & header[ i ] );
SendEncodedChar( header[ i ] );
}
crc32val = ~crc32.value();
for ( i = 0 ; i < 4 ; i++ ) {
SendEncodedChar( (int) crc32val );
crc32val >>= 8;
}
} else {
SendChar( ZBIN );
SendEncodedChar( type );
crc16.update( type );
for ( i = 0 ; i < length ; i++ ) {
SendEncodedChar( header[ i ] );
crc16.update( header[ i ] & 0xff );
}
crc16.update( 0 );
crc16.update( 0 );
SendEncodedChar( crc16.value() >> 8 );
SendEncodedChar( crc16.value() );
}
}
// Sending the hex header involves no decisions whatsoever.
void Zmodem::SendHexHeader( int len, int type, char *header )
{
int n;
Crc16 crc( 0 );
status( "SendHexHeader: %d %s %lx", len,
frametypes[type+4], UnpackHeaderIntoLong( header ) );
SendChar( ZPAD );
SendChar( ZPAD );
SendChar( ZDLE );
SendChar( ZHEX );
SendHexEncodedChar( type );
crc.update( type );
for ( n = 0 ; n < len ; n++ ) {
SendHexEncodedChar( header[ n ] );
crc.update( 0xff & header[ n ] );
}
crc.update( 0 );
crc.update( 0 );
SendHexEncodedChar( crc.value() >> 8 );
SendHexEncodedChar( crc.value() );
SendChar( CR );
SendChar( LF | 0x80 );
if ( type != ZFIN && type != ZACK )
SendChar( XON );
}
// Reading in headers and data subpackets is a relatively
// difficult job. The next four routines combine to read in
// headers. The first routine dispatches one of the next three,
// depending on what the header type is.
int Zmodem::ReadHeader( char *header )
{
int c;
int n;
int cancount;
Settings settings;
port->ReadSettings( settings );
n = 1400;
n += ( settings.BaudRate > 19200L ) ?
19200 : (int) settings.BaudRate;
startover:
cancount = 0;
again:
switch ( c = ReadChar( 10000L ) ) {
case TIMEOUT:
goto finished;
case CAN:
gotcan:
if ( ++cancount >= 5 ) {
c = ZCAN;
goto finished;
}
switch ( c = ReadChar( 100 ) ) {
case TIMEOUT:
goto again;
case ZCRCW:
switch ( ReadChar( 100 ) ) {
case TIMEOUT:
c = ERROR;
goto finished;
default:
goto agn2;
}
default:
break;
case CAN:
if ( ++cancount >= 5 ) {
c = ZCAN;
goto finished;
}
goto again;
}
default:
agn2:
if ( --n == 0 ) {
c = GARBAGE_COUNT;
goto finished;
}
goto startover;
case ZPAD | 0x80: /* This is what we want. */
case ZPAD:
break;
}
cancount = 0;
splat:
switch ( c = ReadUnencodedByte() ) {
case ZPAD:
goto splat;
case TIMEOUT:
goto finished;
default:
goto agn2;
case ZDLE: /* This is what we want. */
break;
}
c = ReadUnencodedByte();
switch ( c ) {
case ZBIN32:
current_frame_uses_crc32 = 1;
c = ReadBinaryHeaderCRC32( header );
break;
case TIMEOUT:
goto finished;
case ZBIN:
current_frame_uses_crc32 = 0;
c = ReadBinaryHeaderCRC16( header );
break;
case ZHEX:
current_frame_uses_crc32 = 0;
c = ReadHexHeaderCRC16( header );
break;
case CAN:
goto gotcan;
default:
goto agn2;
}
received_file_position = header[ ZP3 ] & 0xff;
received_file_position <<= 8;
received_file_position += header[ ZP2 ] & 0xff;
received_file_position <<= 8;
received_file_position += header[ ZP1 ] & 0xff;
received_file_position <<= 8;
received_file_position += header[ ZP0 ] & 0xff;
finished:
switch ( c ) {
case GOTCAN:
c = ZCAN;
/* **** FALL THRU TO **** */
case ZNAK:
case ZCAN:
case ERROR:
case TIMEOUT:
case GARBAGE_COUNT:
error( "Got %s", frametypes[ c + 4 ] );
/* **** FALL THRU TO **** */
default:
if ( c >= -4 && c <= 22 )
error( "ReadHeader: %s %lx",
frametypes[ c + 4 ],
received_file_position );
else
error( "ReadHeader: %d %lx",
c,
received_file_position );
}
return c;
}
// At this point most of the hard work has been done. The next
//three routines just read in the type of header and the data
// associated with it, then check to see if the CRC is correct.
int Zmodem::ReadBinaryHeaderCRC16( char *header )
{
int c;
int i;
Crc16 crc( 0 );
int header_type;
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
header_type = c;
crc.update( c );
for ( i = 0 ; i < 4 ; i++ ) {
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
crc.update( c );
header[ i ] = (char) c;
}
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
crc.update( c );
if ( crc.value() & 0xFFFF ) {
error( "Bad CRC" );
return ERROR;
}
return header_type;
}
int Zmodem::ReadBinaryHeaderCRC32( char *header )
{
int c;
int i;
Crc32 crc( 0xFFFFFFFFL );
int header_type;
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
header_type = c;
crc.update( c );
for ( i = 0 ; i < 4 ; i++ ) {
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
crc.update( c );
header[ i ] = (char) c;
}
for ( i = 0; i < 4 ; i++ ) {
if ( ( c = ReadEncodedByte() ) & ~0xff )
return c;
crc.update( c );
}
if ( crc.value() != 0xDEBB20E3L ) {
error( "Bad CRC" );
return ERROR;
}
return header_type;
}
int Zmodem::ReadHexHeaderCRC16( char *header )
{
int c;
Crc16 crc( 0 );
int i;
int header_type;
if ( ( c = ReadHexByte() ) < 0 )
return c;
header_type = c;
crc.update( c );
for ( i = 0 ; i < 4 ; i++ ) {
if ( ( c = ReadHexByte() ) < 0 )
return c;
crc.update( c );
header[ i ] = (char) c;
}
if ( ( c = ReadHexByte() ) < 0 )
return c;
crc.update( c );
if ( ( c = ReadHexByte() ) < 0 )
return c;
crc.update( c );
if ( crc.value() & 0xFFFF ) {
error( "Bad CRC" );
return ERROR;
}
switch ( c = ReadChar( 100 ) ) {
case CR :
case CR | 0x80 :
ReadChar( 100 );
}
return header_type;
}
// The next three routines are used to read in binary data
// subpackets. This code is somewhat simpler than the code
// used to read in a header, mostly because there are fewer
// things to go wrong.
int Zmodem::ReadDataFrame( char *buffer, int length )
{
if ( current_frame_uses_crc32 )
return ReadDataFrameCRC32( buffer, length );
else
return ReadDataFrameCRC16( buffer, length );
}
int Zmodem::ReadDataFrameCRC32( char *buffer, int length )
{
int c;
Crc32 crc( 0xFFFFFFFFL );
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:
d = c;
c &= 0xff;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
goto crcfoo;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
goto crcfoo;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
goto crcfoo;
crc.update( c );
if ( ( c = ReadEncodedByte() ) & ~0xff )
goto crcfoo;
crc.update( c );
if ( crc.value() != 0xDEBB20E3L ) {
error( "Bad CRC" );
return ERROR;
}
Rxcount = (int) ( length - (end - buffer) );
error( "ReadDataFrameCRC32: %d %s",
Rxcount,
Zendnames[ d - GOTCRCE & 3 ] );
return d;
case GOTCAN:
error( "Sender Canceled" );
return ZCAN;
case TIMEOUT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -