📄 stream.c
字号:
int sread( STREAM *stream, void *buffer, int length )
{
#if defined( __WIN32__ )
DWORD bytesRead;
#elif defined( __MAC__ )
long bytesRead = length;
#endif /* __WIN32__ */
BYTE *bufPtr = buffer;
assert( stream != NULL && stream->type != STREAM_TYPE_NULL );
assert( buffer != NULL );
assert( length > 0 );
/* If there's a problem with the stream, don't try to do anything */
if( stream->status != CRYPT_OK )
return( stream->status );
/* If we ungot a char, return this first */
if( stream->ungetChar )
{
*bufPtr++ = stream->lastChar;
stream->ungetChar = FALSE;
if( !--length )
return( CRYPT_OK );
}
/* If it's a memory stream, read the data from the buffer */
if( stream->type == STREAM_TYPE_MEMORY )
{
if( stream->bufSize != STREAMSIZE_UNKNOWN && \
stream->bufPos + length > stream->bufEnd )
{
memset( bufPtr, 0, length ); /* Clear the output buffer */
stream->status = CRYPT_ERROR_UNDERFLOW;
return( CRYPT_ERROR_UNDERFLOW );
}
memcpy( bufPtr, stream->buffer + stream->bufPos, length );
stream->bufPos += length;
return( CRYPT_OK );
}
#ifdef NET_TCP
/* If it's a network stream, read the data from the network */
if( stream->type == STREAM_TYPE_NETWORK )
{
void *bufPtr = buffer;
int localLength, status;
assert( stream->isServer || stream->host != NULL );
/* Some protocols require special handling for header data and
handshaking, which we have to handle before reading the actual
data */
status = readProtocolHeader( stream, &bufPtr, &localLength, length,
stream->isServer );
if( cryptStatusError( status ) )
{
stream->status = status;
return( status );
}
return( readSocket( stream, bufPtr, localLength ) );
}
#endif /* NET_TCP */
#ifndef NO_STDIO
/* It's a file stream, read the data from the file */
#ifdef __WIN32__
if( !ReadFile( stream->hFile, bufPtr, length, &bytesRead, NULL ) || \
( int ) bytesRead != length )
#elif defined( __MAC__ )
if( FSRead( stream->refNum, &bytesRead, bufPtr ) != noErr || \
( int ) bytesRead != length )
#else
if( fread( bufPtr, 1, length, stream->filePtr ) != ( size_t ) length )
#endif /* __WIN32__ */
{
stream->status = CRYPT_ERROR_READ;
return( CRYPT_ERROR_READ );
}
#else
assert( NOTREACHED );
#endif /* NO_STDIO */
return( CRYPT_OK );
}
/* Write a block of data to a stream */
int swrite( STREAM *stream, const void *buffer, const int length )
{
#ifdef __WIN32__
DWORD bytesWritten;
#elif defined( __MAC__ )
long bytesWritten = length;
#endif /* __WIN32__ */
assert( stream != NULL );
assert( buffer != NULL );
assert( length > 0 );
assert( !( stream->flags & STREAM_FLAG_READONLY ) );
/* If there's a problem with the stream, don't try to do anything until
the error is cleared */
if( stream->status != CRYPT_OK )
return( stream->status );
/* If it's a null stream, just record the write and return */
if( stream->type == STREAM_TYPE_NULL )
{
stream->bufPos += length;
return( CRYPT_OK );
}
/* If it's a memory stream, deposit the data in the buffer */
if( stream->type == STREAM_TYPE_MEMORY )
{
if( stream->bufSize != STREAMSIZE_UNKNOWN && \
stream->bufPos + length > stream->bufSize )
{
#ifdef NO_STDIO
/* If it's a non-sensitive pseudo-I/O stream, expand the buffer */
if( stream->isIOStream && !stream->isSensitive )
{
const int status = expandBuffer( stream, length );
if( cryptStatusError( status ) )
return( status );
}
else
#endif /* NO_STDIO */
{
stream->status = CRYPT_ERROR_OVERFLOW;
return( CRYPT_ERROR_OVERFLOW );
}
}
memcpy( stream->buffer + stream->bufPos, buffer, length );
stream->bufPos += length;
if( stream->bufEnd < stream->bufPos )
/* Move up the end-of-data pointer if necessary */
stream->bufEnd = stream->bufPos;
stream->flags |= STREAM_FLAG_DIRTY;
return( CRYPT_OK );
}
#ifdef NET_TCP
/* If it's a network stream, write the data to the network */
if( stream->type == STREAM_TYPE_NETWORK )
{
int status;
assert( stream->isServer || stream->host != NULL );
/* If it's a stateless protocol, connect to the remote server */
if( stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION )
{
char headerBuffer[ MAX_URL_SIZE + CRYPT_MAX_TEXTSIZE + 128 ];
int headerPos;
assert( stream->netSocket == CRYPT_ERROR );
assert( stream->protocolState == STREAM_PROTOCOLSTATE_NONE );
assert( strlen( stream->contentType ) );
/* Open the connection to the remote host */
status = connectStream( stream );
if( cryptStatusError( status ) )
return( status );
/* Send the HTTP POST header */
strcpy( headerBuffer, "POST " );
strcat( headerBuffer, stream->path );
strcat( headerBuffer, " HTTP/1.0\r\nContent-Type: " );
strcat( headerBuffer, stream->contentType );
strcat( headerBuffer, "\r\nContent-Transfer-Encoding: Binary\r\n"
"Content-Length: " );
headerPos = strlen( headerBuffer );
sprintf( headerBuffer + headerPos, "%d\r\n"
"Cache-Control: no-cache\r\n\r\n", length );
status = writeSocket( stream, headerBuffer,
strlen( headerBuffer ) );
if( cryptStatusError( status ) )
{
stream->status = status;
return( status );
}
stream->protocolState = STREAM_PROTOCOLSTATE_FETCHSENT;
}
/* If it's an HTTP write, send the out-of-band header data to the
client */
if( stream->protocol == STREAM_PROTOCOL_HTTP )
{
char headerBuffer[ CRYPT_MAX_TEXTSIZE + 128 ];
int headerPos;
strcpy( headerBuffer, "HTTP/1.0 200 OK\r\nContent-Type: " );
strcat( headerBuffer, stream->contentType );
strcat( headerBuffer, "\r\nContent-Transfer-Encoding: Binary\r\n"
"Content-Length: " );
headerPos = strlen( headerBuffer );
sprintf( headerBuffer + headerPos, "%d\r\n"
"Cache-Control: no-cache\r\n\r\n", length );
status = writeSocket( stream, headerBuffer,
strlen( headerBuffer ) );
if( cryptStatusError( status ) )
{
stream->status = status;
return( status );
}
}
/* If it's a packet-based protocol, write the packet header */
if( stream->protocol == STREAM_PROTOCOL_CMP )
{
BYTE headerBuffer[ 64 ];
int headerLength, status;
headerLength = writeCmpHeader( headerBuffer, length,
stream->lastMessage );
status = writeSocket( stream, headerBuffer, headerLength );
if( cryptStatusError( status ) )
{
stream->status = status;
return( status );
}
}
/* Send the data to the server */
status = writeSocket( stream, buffer, length );
if( cryptStatusError( status ) )
{
stream->status = status;
return( status );
}
return( CRYPT_OK );
}
#endif /* NET_TCP */
#ifndef NO_STDIO
/* It's a file stream, write the data to the file */
#if defined( __WIN32__ )
if( !WriteFile( stream->hFile, buffer, length, &bytesWritten, NULL ) || \
( int ) bytesWritten != length )
#elif defined( __MAC__ )
if( FSWrite( stream->refNum, &bytesWritten, buffer ) != noErr || \
( int ) bytesWritten != length )
#else
if( fwrite( buffer, 1, length, stream->filePtr ) != ( size_t ) length )
#endif /* __WIN32__ */
{
stream->status = CRYPT_ERROR_WRITE;
return( CRYPT_ERROR_WRITE );
}
stream->flags |= STREAM_FLAG_DIRTY;
#else
assert( NOTREACHED );
#endif /* NO_STDIO */
return( CRYPT_OK );
}
/* Commit data in a stream to backing storage */
int sflush( STREAM *stream )
{
#if defined( __MAC__ )
FileParam paramBlock;
#endif /* __MAC__ */
assert( stream != NULL && \
( stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE ) );
/* If there's a problem with the stream, don't try to do anything until
the error is cleared */
if( stream->status != CRYPT_OK )
return( stream->status );
/* If there's no backing storage or the data is unchanged, there's
nothing to do */
#ifdef NO_STDIO
if( !( stream->flags & STREAM_FLAG_DIRTY ) || \
( stream->type == STREAM_TYPE_MEMORY && !stream->isIOStream ) )
#else
if( !( stream->flags & STREAM_FLAG_DIRTY ) || \
stream->type == STREAM_TYPE_MEMORY )
#endif /* NO_STDIO */
return( CRYPT_OK );
/* Commit the data as required by the system */
#if defined( __WIN32__ )
FlushFileBuffers( stream->hFile );
#elif defined( __MAC__ )
paramBlock.ioCompletion = NULL;
paramBlock.ioFRefNum = stream->refNum;
PBFlushFileSync(( union ParamBlockRec* ) ¶mBlock );
#elif defined( NO_STDIO )
#if defined( __IBM4758__ )
/* Write the data to flash or BB memory as appropriate */
if( sccSavePPD( stream->name, stream->buffer, stream->bufEnd,
( ( stream->isSensitive ) ? PPD_BBRAM : PPD_FLASH ) | PPD_TRIPLE ) != PPDGood )
return( CRYPT_ERROR_WRITE );
#elif defined( __VMCMS__ )
/* Under CMS, MVS, TSO, etc the only consistent way to handle writes is
to write a fixed-length single-record file containing all the data in
one record, so we can't really do anything until the data is flushed */
{
FILE *filePtr;
char formatBuffer[ 32 ];
int count;
sprintf( formatBuffer, "wb, recfm=F, lrecl=%d, noseek", stream->bufPos );
filePtr = fopen( stream->name, formatBuffer );
if( filePtr == NULL )
return( CRYPT_ERROR_WRITE );
count = fwrite( stream->buffer, stream->bufEnd, 1, filePtr );
fclose( filePtr );
if( count != 1 )
return( CRYPT_ERROR_WRITE );
}
#else
#error Need to add mechanism to save data to backing store
#endif /* Nonstandard I/O enviroments */
#else
fflush( stream->filePtr );
#endif /* OS-specific data commit */
stream->flags &= ~STREAM_FLAG_DIRTY;
return( CRYPT_OK );
}
/* Move to an absolute position in a stream */
int sseek( STREAM *stream, const long position )
{
assert( stream != NULL && \
( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE ) );
assert( position >= 0 );
/* If it's a memory or null stream, move to the position in the buffer */
if( stream->type == STREAM_TYPE_NULL )
{
stream->bufPos = ( int ) position;
return( CRYPT_OK );
}
if( stream->type == STREAM_TYPE_MEMORY )
{
stream->ungetChar = FALSE;
if( stream->bufSize != STREAMSIZE_UNKNOWN && \
( int ) position > stream->bufSize )
{
stream->bufPos = stream->bufSize;
stream->status = CRYPT_ERROR_UNDERFLOW;
return( CRYPT_ERROR_UNDERFLOW );
}
/* Set the new R/W position */
stream->bufPos = ( int ) position;
if( stream->bufPos > stream->bufEnd )
/* If we've moved past the end of the valid data in the buffer,
move the end of data pointer to match the current position.
This mimics the behaviour of fseek(), which allows a seek past
the end of the file */
stream->bufEnd = stream->bufPos;
return( CRYPT_OK );
}
#ifndef NO_STDIO
/* It's a file stream, seek to the position in the file */
#if defined( __WIN32__ )
if( SetFilePointer( stream->hFile, position, NULL,
FILE_BEGIN ) == 0xFFFFFFFF )
#elif defined( __MAC__ )
if( SetFPos( stream->refNum, fsFromStart, position) != noErr )
#else
if( fseek( stream->filePtr, position, SEEK_SET ) )
#endif /* __WIN32__ */
return( CRYPT_ERROR_WRITE );
#else
assert( NOTREACHED );
#endif /* NO_STDIO */
return( CRYPT_OK );
}
/* Determine the position in a stream */
long stell( const STREAM *stream )
{
long position;
assert( stream != NULL && \
( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE ) );
/* If it's a memory or null stream, return the position in the buffer */
if( stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_NULL )
return( ( stream )->bufPos - ( stream )->ungetChar );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -