//------------------------------------------------------------------------------ // Desc: Streaming interface // Tabs: 3 // // Copyright (c) 2004-2007 Novell, Inc. All Rights Reserved. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; version 2.1 // of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com. // // $Id$ //------------------------------------------------------------------------------ #include "ftksys.h" #define LZW_MAGIC_NUMBER 0x3482 #define LZW_END_OF_DATA 256 #define LZW_NEW_DICT 257 #define LZW_STOP_COMPRESSION 258 #define LZW_START_CODE 259 #define LZW_MAX_CODE 0xFFFF #define MULTI_FILE_OUT_STREAM_MIN_FILE_SIZE 1048510 #define MULTI_FILE_OUT_STREAM_MAX_FILE_SIZE 2147483647 /**************************************************************************** Desc: ****************************************************************************/ FLMBYTE gv_ucBase64DecodeTable[ 256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0 .. 7 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8 .. 15 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 16 .. 23 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 24 .. 31 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 32 .. 39 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, // 40 .. 47 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 48 .. 55 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, // 56 .. 63 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 64 .. 71 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 72 .. 79 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 80 .. 87 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 88 .. 95 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 96 .. 103 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 104 .. 111 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 112 .. 119 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 120 .. 127 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 128 .. 135 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 136 .. 143 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 144 .. 151 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 152 .. 159 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 160 .. 167 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 168 .. 175 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 176 .. 183 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 184 .. 191 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 192 .. 199 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 200 .. 207 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 208 .. 215 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 216 .. 223 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 224 .. 231 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 232 .. 239 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 240 .. 247 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 248 .. 255 }; /**************************************************************************** Desc: ****************************************************************************/ FLMBYTE gv_ucBase64EncodeTable[ 64] = { ASCII_UPPER_A, ASCII_UPPER_B, ASCII_UPPER_C, ASCII_UPPER_D, ASCII_UPPER_E, ASCII_UPPER_F, ASCII_UPPER_G, ASCII_UPPER_H, ASCII_UPPER_I, ASCII_UPPER_J, ASCII_UPPER_K, ASCII_UPPER_L, ASCII_UPPER_M, ASCII_UPPER_N, ASCII_UPPER_O, ASCII_UPPER_P, ASCII_UPPER_Q, ASCII_UPPER_R, ASCII_UPPER_S, ASCII_UPPER_T, ASCII_UPPER_U, ASCII_UPPER_V, ASCII_UPPER_W, ASCII_UPPER_X, ASCII_UPPER_Y, ASCII_UPPER_Z, ASCII_LOWER_A, ASCII_LOWER_B, ASCII_LOWER_C, ASCII_LOWER_D, ASCII_LOWER_E, ASCII_LOWER_F, ASCII_LOWER_G, ASCII_LOWER_H, ASCII_LOWER_I, ASCII_LOWER_J, ASCII_LOWER_K, ASCII_LOWER_L, ASCII_LOWER_M, ASCII_LOWER_N, ASCII_LOWER_O, ASCII_LOWER_P, ASCII_LOWER_Q, ASCII_LOWER_R, ASCII_LOWER_S, ASCII_LOWER_T, ASCII_LOWER_U, ASCII_LOWER_V, ASCII_LOWER_W, ASCII_LOWER_X, ASCII_LOWER_Y, ASCII_LOWER_Z, ASCII_ZERO, ASCII_ONE, ASCII_TWO, ASCII_THREE, ASCII_FOUR, ASCII_FIVE, ASCII_SIX, ASCII_SEVEN, ASCII_EIGHT, ASCII_NINE, ASCII_PLUS, ASCII_SLASH }; /*************************************************************************** Desc: ***************************************************************************/ class FLMEXP F_StreamPrintfClient : public IF_PrintfClient { public: F_StreamPrintfClient( IF_OStream * pOStream) { m_pOStream = pOStream; m_pOStream->AddRef(); m_rc = NE_FLM_OK; m_uiBufOffset = 0; } virtual ~F_StreamPrintfClient() { if( m_pOStream) { m_pOStream->Release(); m_pOStream = NULL; } } FINLINE FLMINT FLMAPI outputChar( char cChar, FLMUINT uiCount) { FLMUINT uiTmpCount; FLMINT iBytesOutput = (FLMINT)uiCount; while( uiCount) { uiTmpCount = uiCount; if( m_uiBufOffset + uiTmpCount > sizeof( m_szOutBuf)) { uiTmpCount = sizeof( m_szOutBuf) - m_uiBufOffset; } f_memset( &m_szOutBuf[ m_uiBufOffset], cChar, uiTmpCount); m_uiBufOffset += uiTmpCount; uiCount -= uiTmpCount; if( m_uiBufOffset == sizeof( m_szOutBuf)) { flushBuffer(); } } return( iBytesOutput); } FINLINE FLMINT FLMAPI outputChar( char cChar) { m_szOutBuf[ m_uiBufOffset++] = cChar; if( m_uiBufOffset == sizeof( m_szOutBuf)) { flushBuffer(); } return( 1); } FINLINE FLMINT FLMAPI outputStr( const char * pszStr, FLMUINT uiLen) { FLMUINT uiTmpLen; FLMINT iBytesOutput = (FLMINT)uiLen; while( uiLen) { uiTmpLen = uiLen; if( m_uiBufOffset + uiTmpLen > sizeof( m_szOutBuf)) { uiTmpLen = sizeof( m_szOutBuf) - m_uiBufOffset; } f_memcpy( &m_szOutBuf[ m_uiBufOffset], pszStr, uiTmpLen); m_uiBufOffset += uiTmpLen; uiLen -= uiTmpLen; pszStr += uiTmpLen; if( m_uiBufOffset == sizeof( m_szOutBuf)) { flushBuffer(); } } return( iBytesOutput); } FINLINE FLMINT FLMAPI colorFormatter( char, // cFormatChar, eColorType, // eColor, FLMUINT) // uiFlags) { return( 0); } FINLINE RCODE flushBuffer( void) { if( RC_OK( m_rc) && m_uiBufOffset) { m_rc = m_pOStream->write( m_szOutBuf, m_uiBufOffset, NULL); } m_uiBufOffset = 0; return( m_rc); } private: RCODE m_rc; char m_szOutBuf[ 256]; FLMUINT m_uiBufOffset; IF_OStream * m_pOStream; }; /**************************************************************************** Desc: ****************************************************************************/ class F_TCPIOStream : public IF_IOStream { public: #if defined( FLM_WIN) && _MSC_VER < 1300 using IF_IStream::operator delete; #endif F_TCPIOStream( void); virtual ~F_TCPIOStream( void); RCODE openStream( const char * pucHostAddress, FLMUINT uiPort, FLMUINT uiFlags, FLMUINT uiConnectTimeout = 3, FLMUINT uiDataTimeout = 15); RCODE FLMAPI read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead); RCODE FLMAPI write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten); FINLINE RCODE socketPeekWrite( FLMINT iTimeOut) { return( socketPeek( iTimeOut, FALSE)); } FINLINE RCODE socketPeekRead( FLMINT iTimeOut) { return( socketPeek( iTimeOut, TRUE)); }; FINLINE const char * getName( void) { getLocalInfo(); return( (const char *)m_pszName); }; FINLINE const char * getAddr( void) { getLocalInfo(); return( (const char *)m_pszIp); }; FINLINE const char * getPeerName( void) { getRemoteInfo(); return( (const char *)m_pszPeerName); }; FINLINE const char * getPeerAddr( void) { getRemoteInfo(); return( (const char *)m_pszPeerIp); }; RCODE readNoWait( void * pvBuffer, FLMUINT uiCount, FLMUINT * puiReadRead); RCODE readAll( void * pvBuffer, FLMUINT uiCount, FLMUINT * puiBytesRead); RCODE setTcpDelay( FLMBOOL bOn); RCODE FLMAPI closeStream( void); private: RCODE getLocalInfo( void); RCODE getRemoteInfo( void); RCODE socketPeek( FLMINT iTimoutVal, FLMBOOL bPeekRead); #ifndef FLM_UNIX WSADATA m_wsaData; #endif FLMBOOL m_bInitialized; SOCKET m_iSocket; FLMUINT m_uiIOTimeout; FLMBOOL m_bConnected; char m_pszIp[ 256]; char m_pszName[ 256]; char m_pszPeerIp[ 256]; char m_pszPeerName[ 256]; unsigned long m_ulRemoteAddr; }; /**************************************************************************** Desc: ****************************************************************************/ #ifdef FLM_OPENSSL class F_SSLIOStream : public IF_SSLIOStream { public: F_SSLIOStream() { m_pBio = NULL; m_pContext = NULL; m_pSSL = NULL; m_pPeerCertificate = NULL; m_pszPeerCertText = NULL; m_szPeerName[ 0] = 0; } virtual ~F_SSLIOStream() { closeStream(); } RCODE FLMAPI openStream( const char * pszHost, FLMUINT uiPort = 443, FLMUINT uiFlags = 0); RCODE FLMAPI read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead = NULL); RCODE FLMAPI write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten = NULL); const char * FLMAPI getPeerCertificateText( void); RCODE FLMAPI closeStream( void); private: BIO * m_pBio; SSL_CTX * m_pContext; SSL * m_pSSL; X509 * m_pPeerCertificate; char * m_pszPeerCertText; char m_szPeerName[ 256]; }; #endif /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmAllocBufferIStream( IF_BufferIStream ** ppIStream) { if( (*ppIStream = f_new F_BufferIStream) == NULL) { return( RC_SET( NE_FLM_MEM)); } return( NE_FLM_OK); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenBufferIStream( const char * pucBuffer, FLMUINT uiLength, IF_PosIStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_BufferIStream * pIStream = NULL; if( (pIStream = f_new F_BufferIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pucBuffer, uiLength))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenBase64EncoderIStream( IF_IStream * pSourceIStream, FLMBOOL bLineBreaks, IF_IStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_Base64EncoderIStream * pIStream = NULL; if( (pIStream = f_new F_Base64EncoderIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pSourceIStream, bLineBreaks))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenBase64DecoderIStream( IF_IStream * pSourceIStream, IF_IStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_Base64DecoderIStream * pIStream = NULL; if( (pIStream = f_new F_Base64DecoderIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pSourceIStream))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenFileIStream( const char * pszPath, IF_PosIStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_FileIStream * pIStream = NULL; if( (pIStream = f_new F_FileIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pszPath))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenMultiFileIStream( const char * pszDirectory, const char * pszBaseName, IF_IStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_MultiFileIStream * pIStream = NULL; if( (pIStream = f_new F_MultiFileIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pszDirectory, pszBaseName))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenBufferedIStream( IF_IStream * pSourceIStream, FLMUINT uiBufferSize, IF_IStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_BufferedIStream * pIStream = NULL; if( (pIStream = f_new F_BufferedIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pSourceIStream, uiBufferSize))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenUncompressingIStream( IF_IStream * pSourceIStream, IF_IStream ** ppIStream) { RCODE rc = NE_FLM_OK; F_UncompressingIStream * pIStream = NULL; if( (pIStream = f_new F_UncompressingIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIStream->openStream( pSourceIStream))) { goto Exit; } *ppIStream = pIStream; pIStream = NULL; Exit: if( pIStream) { pIStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenFileOStream( const char * pszPath, FLMBOOL bTruncateIfExists, IF_OStream ** ppOStream) { RCODE rc = NE_FLM_OK; F_FileOStream * pOStream = NULL; if( (pOStream = f_new F_FileOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pOStream->openStream( pszPath, bTruncateIfExists))) { goto Exit; } *ppOStream = pOStream; pOStream = NULL; Exit: if( pOStream) { pOStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenMultiFileOStream( const char * pszDirectory, const char * pszBaseName, FLMUINT uiMaxFileSize, FLMBOOL bOkToOverwrite, IF_OStream ** ppOStream) { RCODE rc = NE_FLM_OK; F_MultiFileOStream * pOStream = NULL; if( (pOStream = f_new F_MultiFileOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pOStream->createStream( pszDirectory, pszBaseName, uiMaxFileSize, bOkToOverwrite))) { goto Exit; } *ppOStream = pOStream; pOStream = NULL; Exit: if( pOStream) { pOStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenBufferedOStream( IF_OStream * pDestOStream, FLMUINT uiBufferSize, IF_OStream ** ppOStream) { RCODE rc = NE_FLM_OK; F_BufferedOStream * pOStream = NULL; if( (pOStream = f_new F_BufferedOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pOStream->openStream( pDestOStream, uiBufferSize))) { goto Exit; } *ppOStream = pOStream; pOStream = NULL; Exit: if( pOStream) { pOStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmOpenCompressingOStream( IF_OStream * pDestOStream, IF_OStream ** ppOStream) { RCODE rc = NE_FLM_OK; F_CompressingOStream * pOStream = NULL; if( (pOStream = f_new F_CompressingOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pOStream->openStream( pDestOStream))) { goto Exit; } *ppOStream = pOStream; pOStream = NULL; Exit: if( pOStream) { pOStream->Release(); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmRemoveMultiFileStream( const char * pszDirectory, const char * pszBaseName) { RCODE rc = NE_FLM_OK; F_MultiFileOStream * pMultiStream = NULL; if( (pMultiStream = f_new F_MultiFileOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pMultiStream->processDirectory( pszDirectory, pszBaseName, TRUE))) { goto Exit; } Exit: if( pMultiStream) { pMultiStream->Release(); } return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenTCPIOStream( const char * pszHost, FLMUINT uiPort, FLMUINT uiFlags, IF_IOStream ** ppIOStream) { RCODE rc = NE_FLM_OK; F_TCPIOStream * pIOStream = NULL; if( (pIOStream = f_new F_TCPIOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, uiFlags))) { goto Exit; } *ppIOStream = pIOStream; pIOStream = NULL; Exit: if( pIOStream) { pIOStream->Release(); } return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmAllocSSLIOStream( IF_IOStream ** ppIOStream) { #ifdef FLM_OPENSSL if( (*ppIOStream = f_new F_SSLIOStream) == NULL) { return( RC_SET( NE_FLM_MEM)); } return( NE_FLM_OK); #else F_UNREFERENCED_PARM( ppIOStream); return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); #endif } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmOpenSSLIOStream( const char * pszHost, FLMUINT uiPort, FLMUINT uiFlags, IF_IOStream ** ppIOStream) { #ifdef FLM_OPENSSL RCODE rc = NE_FLM_OK; F_SSLIOStream * pIOStream = NULL; if( (pIOStream = f_new F_SSLIOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, uiFlags))) { goto Exit; } *ppIOStream = pIOStream; pIOStream = NULL; Exit: if( pIOStream) { pIOStream->Release(); } return( rc); #else F_UNREFERENCED_PARM( pszHost); F_UNREFERENCED_PARM( uiPort); F_UNREFERENCED_PARM( uiFlags); F_UNREFERENCED_PARM( ppIOStream); return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); #endif } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_FileIStream::openStream( const char * pszFilePath) { RCODE rc = NE_FLM_OK; closeStream(); if( RC_BAD( rc = f_getFileSysPtr()->openFile( (char *)pszFilePath, FLM_IO_RDONLY | FLM_IO_SH_DENYNONE, &m_pFileHdl))) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Closes the input stream and frees any resources *****************************************************************************/ RCODE F_FileIStream::closeStream( void) { RCODE rc = NE_FLM_OK; if( m_pFileHdl) { rc = m_pFileHdl->closeFile(); m_pFileHdl->Release(); m_pFileHdl = NULL; } m_ui64FileOffset = 0; return( rc); } /**************************************************************************** Desc: *****************************************************************************/ FLMUINT64 FLMAPI F_FileIStream::totalSize( void) { FLMUINT64 ui64FileSize = 0; (void)m_pFileHdl->size( &ui64FileSize); return( ui64FileSize); } /**************************************************************************** Desc: *****************************************************************************/ FLMUINT64 FLMAPI F_FileIStream::remainingSize( void) { FLMUINT64 ui64TotalSize = totalSize(); FLMUINT64 ui64Offset = getCurrPosition(); if( ui64TotalSize >= ui64Offset) { return( ui64TotalSize - ui64Offset); } return( 0); } /**************************************************************************** Desc: *****************************************************************************/ FLMUINT64 FLMAPI F_FileIStream::getCurrPosition( void) { return( m_ui64FileOffset); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_FileIStream::positionTo( FLMUINT64 ui64Offset) { m_ui64FileOffset = ui64Offset; return( NE_FLM_OK); } /**************************************************************************** Desc: Reads the requested amount of data from the stream. *****************************************************************************/ RCODE F_FileIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMUINT uiBytesRead = 0; if( !m_pFileHdl) { rc = RC_SET( NE_FLM_READING_FILE); goto Exit; } rc = m_pFileHdl->read( m_ui64FileOffset, uiBytesToRead, pvBuffer, &uiBytesRead); m_ui64FileOffset += uiBytesRead; if( RC_BAD( rc)) { if( rc == NE_FLM_IO_END_OF_FILE) { rc = RC_SET( NE_FLM_EOF_HIT); } goto Exit; } Exit: if( puiBytesRead) { *puiBytesRead = uiBytesRead; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedIStream::openStream( IF_IStream * pIStream, FLMUINT uiBufferSize) { RCODE rc = NE_FLM_OK; if( m_pIStream || !pIStream) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } m_pIStream = pIStream; m_pIStream->AddRef(); m_uiBufferSize = uiBufferSize; m_uiBufferOffset = 0; m_uiBytesAvail = 0; if( RC_BAD( rc = f_alloc( m_uiBufferSize, &m_pucBuffer))) { goto Exit; } Exit: if (RC_BAD( rc)) { closeStream(); } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; FLMUINT uiBytesRead = 0; FLMUINT uiMaxSize; if (!m_pIStream) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } while( uiBytesToRead) { if( (uiMaxSize = m_uiBytesAvail - m_uiBufferOffset) == 0) { if (RC_BAD( rc = m_pIStream->read( m_pucBuffer, m_uiBufferSize, &m_uiBytesAvail))) { if (rc != NE_FLM_EOF_HIT || !m_uiBytesAvail) { m_uiBufferOffset = 0; goto Exit; } } f_assert( m_uiBytesAvail <= m_uiBufferSize); m_uiBufferOffset = 0; } else if( uiBytesToRead < uiMaxSize) { f_memcpy( pucBuffer, &m_pucBuffer[ m_uiBufferOffset], uiBytesToRead); m_uiBufferOffset += uiBytesToRead; uiBytesRead += uiBytesToRead; uiBytesToRead = 0; break; } else { f_memcpy( pucBuffer, &m_pucBuffer[ m_uiBufferOffset], uiMaxSize); m_uiBufferOffset += uiMaxSize; pucBuffer += uiMaxSize; uiBytesToRead -= uiMaxSize; uiBytesRead += uiMaxSize; } } Exit: if (puiBytesRead) { *puiBytesRead = uiBytesRead; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedIStream::closeStream( void) { RCODE rc = NE_FLM_OK; if( m_pIStream) { if( m_pIStream->getRefCount() == 1) { rc = m_pIStream->closeStream(); } m_pIStream->Release(); m_pIStream = NULL; } if( m_pucBuffer) { f_free( &m_pucBuffer); } m_uiBufferSize = 0; m_uiBufferOffset = 0; m_uiBytesAvail = 0; return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_FileOStream::openStream( const char * pszFilePath, FLMBOOL bTruncateIfExists) { RCODE rc = NE_FLM_OK; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( m_pFileHdl) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if( bTruncateIfExists) { if( RC_BAD( rc = pFileSystem->deleteFile( (char *)pszFilePath))) { if( rc != NE_FLM_IO_PATH_NOT_FOUND) { goto Exit; } } if( RC_BAD( rc = pFileSystem->createFile( (char *)pszFilePath, FLM_IO_RDWR, &m_pFileHdl))) { goto Exit; } } else { if( RC_BAD( rc = pFileSystem->openFile( (char *)pszFilePath, FLM_IO_RDWR, &m_pFileHdl))) { if( rc != NE_FLM_IO_PATH_NOT_FOUND) { goto Exit; } if( RC_BAD( rc = pFileSystem->createFile( (char *)pszFilePath, FLM_IO_RDWR, &m_pFileHdl))) { goto Exit; } } } if( RC_BAD( rc = m_pFileHdl->size( &m_ui64FileOffset))) { goto Exit; } Exit: if( RC_BAD( rc)) { closeStream(); } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_FileOStream::write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; FLMUINT uiBytesWritten = 0; if (!m_pFileHdl) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if( RC_BAD( rc = m_pFileHdl->write( (FLMUINT)m_ui64FileOffset, uiBytesToWrite, (void *)pvBuffer, &uiBytesWritten))) { goto Exit; } Exit: m_ui64FileOffset += uiBytesWritten; if( puiBytesWritten) { *puiBytesWritten = uiBytesWritten; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_FileOStream::closeStream( void) { RCODE rc = NE_FLM_OK; if( m_pFileHdl) { m_pFileHdl->Release(); m_pFileHdl = NULL; } m_ui64FileOffset = 0; return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_MultiFileIStream::openStream( const char * pszDirectory, const char * pszBaseName) { RCODE rc = NE_FLM_OK; if( m_bOpen) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } f_strcpy( m_szDirectory, pszDirectory); f_strcpy( m_szBaseName, pszBaseName); m_uiFileNum = 0xFFFFFFFF; m_ui64FileOffset = 0; m_bEndOfStream = FALSE; m_bOpen = TRUE; Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE F_MultiFileIStream::rollToNextFile( void) { RCODE rc = NE_FLM_OK; F_FileIStream * pFileIStream = NULL; F_BufferedIStream * pBufferedIStream = NULL; FLMUINT uiNewFileNum = 0; char szFilePath[ F_PATH_MAX_SIZE + 1]; char szFileName[ F_PATH_MAX_SIZE + 1]; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( m_pIStream) { m_pIStream->Release(); m_pIStream = NULL; m_ui64FileOffset = 0; } if( m_uiFileNum == 0xFFFFFFFE) { rc = RC_SET( NE_FLM_STREAM_TOO_MANY_FILES); goto Exit; } else if( m_uiFileNum == 0xFFFFFFFF) { f_strcpy( szFileName, m_szBaseName); uiNewFileNum = 0; } else { uiNewFileNum = m_uiFileNum + 1; f_sprintf( (char *)szFileName, "%s.%08X", m_szBaseName, uiNewFileNum); } f_strcpy( szFilePath, m_szDirectory); if( RC_BAD( rc = pFileSystem->pathAppend( (char *)szFilePath, (char *)szFileName))) { goto Exit; } if( (pFileIStream = f_new F_FileIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pFileIStream->openStream( (const char *)szFilePath))) { if (rc == NE_FLM_IO_PATH_NOT_FOUND) { m_bEndOfStream = TRUE; rc = RC_SET( NE_FLM_EOF_HIT); } goto Exit; } if( (pBufferedIStream = f_new F_BufferedIStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pBufferedIStream->openStream( pFileIStream, 16384))) { goto Exit; } m_uiFileNum = uiNewFileNum; m_pIStream = pBufferedIStream; pBufferedIStream = NULL; Exit: if( pFileIStream) { pFileIStream->Release(); } if( pBufferedIStream) { pBufferedIStream->Release(); } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_MultiFileIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMUINT uiTmpRead; FLMUINT uiTotalRead = 0; FLMBOOL bRollToNextFile = FALSE; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; if( !m_bOpen) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if (m_bEndOfStream) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } if (!m_pIStream) { bRollToNextFile = TRUE; } while (uiBytesToRead) { if (bRollToNextFile) { if (RC_BAD( rc = rollToNextFile())) { goto Exit; } } if (RC_BAD( rc = m_pIStream->read( pucBuffer, uiBytesToRead, &uiTmpRead))) { if (rc != NE_FLM_EOF_HIT) { goto Exit; } rc = NE_FLM_OK; bRollToNextFile = TRUE; if (!uiTmpRead) { continue; } } pucBuffer += uiTmpRead; uiBytesToRead -= uiTmpRead; uiTotalRead += uiTmpRead; m_ui64FileOffset += uiTmpRead; } Exit: if (puiBytesRead) { *puiBytesRead = uiTotalRead; } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_MultiFileIStream::closeStream( void) { if( m_pIStream) { m_pIStream->Release(); m_pIStream = NULL; } m_uiFileNum = 0; m_ui64FileOffset = 0; m_szDirectory[ 0] = 0; m_szBaseName[ 0] = 0; m_bEndOfStream = FALSE; m_bOpen = FALSE; return( NE_FLM_OK); } /**************************************************************************** Desc: *****************************************************************************/ RCODE F_MultiFileOStream::createStream( const char * pszDirectory, const char * pszBaseName, FLMUINT uiMaxFileSize, FLMBOOL bOkToOverwrite) { RCODE rc = NE_FLM_OK; if( m_bOpen) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if( RC_BAD( rc = processDirectory( pszDirectory, pszBaseName, bOkToOverwrite))) { goto Exit; } f_strcpy( m_szDirectory, pszDirectory); f_strcpy( m_szBaseName, pszBaseName); if( !uiMaxFileSize) { uiMaxFileSize = MULTI_FILE_OUT_STREAM_MAX_FILE_SIZE; } else if( uiMaxFileSize < MULTI_FILE_OUT_STREAM_MIN_FILE_SIZE) { uiMaxFileSize = MULTI_FILE_OUT_STREAM_MIN_FILE_SIZE; } else if( uiMaxFileSize > MULTI_FILE_OUT_STREAM_MAX_FILE_SIZE) { uiMaxFileSize = MULTI_FILE_OUT_STREAM_MAX_FILE_SIZE; } m_uiFileNum = 0xFFFFFFFF; m_ui64FileOffset = 0; m_ui64MaxFileSize = uiMaxFileSize; m_bOpen = TRUE; Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE F_MultiFileOStream::processDirectory( const char * pszDirectory, const char * pszBaseName, FLMBOOL bOkToDelete) { RCODE rc = NE_FLM_OK; IF_DirHdl * pDirHandle = NULL; FLMUINT uiBaseNameLen = f_strlen( pszBaseName); const char * pszName = NULL; char szSearchPattern[ F_PATH_MAX_SIZE + 1]; char szFilePath[ F_PATH_MAX_SIZE + 1]; IF_FileSystem * pFileSystem = f_getFileSysPtr(); f_sprintf( szSearchPattern, "%s*", pszBaseName); if (!pszDirectory || *pszDirectory == 0) { pszDirectory = "."; } if( RC_BAD( rc = pFileSystem->openDir( (char *)pszDirectory, szSearchPattern, &pDirHandle))) { goto Exit; } for( ;;) { if( RC_BAD( rc = pDirHandle->next())) { if( rc != NE_FLM_IO_NO_MORE_FILES) { goto Exit; } rc = NE_FLM_OK; break; } // Verify that the file belongs to the stream pszName = pDirHandle->currentItemName(); if( f_strcmp( pszName, pszBaseName) == 0 || (f_strncmp( pszName, pszBaseName, uiBaseNameLen) == 0 && pszName[ uiBaseNameLen] == '.' && f_isValidHexNum( (FLMBYTE *)&pszName[ uiBaseNameLen + 1]))) { if (!bOkToDelete) { rc = RC_SET( NE_FLM_STREAM_EXISTS); goto Exit; } // Delete the file f_strcpy( szFilePath, pszDirectory); if( RC_BAD( rc = pFileSystem->pathAppend( szFilePath, pszName))) { goto Exit; } if( RC_BAD( pFileSystem->deleteFile( szFilePath))) { if (rc != NE_FLM_IO_PATH_NOT_FOUND) { goto Exit; } rc = NE_FLM_OK; } } } Exit: if( pDirHandle) { pDirHandle->Release(); pDirHandle = NULL; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE F_MultiFileOStream::rollToNextFile( void) { RCODE rc = NE_FLM_OK; F_FileOStream * pFileOStream = NULL; F_BufferedOStream * pBufferedOStream = NULL; FLMUINT uiNewFileNum = 0; char szFilePath[ F_PATH_MAX_SIZE + 1]; char szFileName[ F_PATH_MAX_SIZE + 1]; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( m_pOStream) { if( RC_BAD( rc = m_pOStream->closeStream())) { goto Exit; } m_pOStream->Release(); m_pOStream = NULL; m_ui64FileOffset = 0; } if( m_uiFileNum == 0xFFFFFFFE) { rc = RC_SET( NE_FLM_STREAM_TOO_MANY_FILES); goto Exit; } else if( m_uiFileNum == 0xFFFFFFFF) { f_strcpy( szFileName, m_szBaseName); uiNewFileNum = 0; } else { uiNewFileNum = m_uiFileNum + 1; f_sprintf( (char *)szFileName, "%s.%08X", m_szBaseName, uiNewFileNum); } f_strcpy( szFilePath, m_szDirectory); if( RC_BAD( rc = pFileSystem->pathAppend( (char *)szFilePath, (char *)szFileName))) { goto Exit; } if( (pFileOStream = f_new F_FileOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pFileOStream->openStream( (const char *)szFilePath, TRUE))) { goto Exit; } if( (pBufferedOStream = f_new F_BufferedOStream) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = pBufferedOStream->openStream( pFileOStream, 16384))) { goto Exit; } m_uiFileNum = uiNewFileNum; m_pOStream = pBufferedOStream; pBufferedOStream = NULL; Exit: if( pFileOStream) { pFileOStream->Release(); } if( pBufferedOStream) { pBufferedOStream->Release(); } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_MultiFileOStream::write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; FLMUINT uiMaxToWrite; FLMUINT uiBytesWritten = 0; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; if (!m_bOpen) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if (!m_pOStream) { if (RC_BAD( rc = rollToNextFile())) { goto Exit; } } while (uiBytesToWrite) { if ((uiMaxToWrite = (FLMUINT)(m_ui64MaxFileSize - m_ui64FileOffset)) < uiBytesToWrite) { if (RC_BAD( rc = m_pOStream->write( pucBuffer, uiMaxToWrite))) { goto Exit; } pucBuffer += uiMaxToWrite; uiBytesWritten += uiMaxToWrite; if (RC_BAD( rc = rollToNextFile())) { goto Exit; } } else { uiMaxToWrite = uiBytesToWrite; if (RC_BAD( rc = m_pOStream->write( pucBuffer, uiBytesToWrite))) { goto Exit; } } uiBytesWritten += uiBytesToWrite; uiBytesToWrite -= uiMaxToWrite; m_ui64FileOffset += uiMaxToWrite; } Exit: if( puiBytesWritten) { *puiBytesWritten = uiBytesWritten; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_MultiFileOStream::closeStream( void) { RCODE rc = NE_FLM_OK; if( m_pOStream) { rc = m_pOStream->closeStream(); m_pOStream->Release(); m_pOStream = NULL; } m_uiFileNum = 0; m_ui64MaxFileSize = 0; m_ui64FileOffset = 0; m_szDirectory[ 0] = 0; m_szBaseName[ 0] = 0; m_bOpen = FALSE; return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedOStream::openStream( IF_OStream * pOStream, FLMUINT uiBufferSize) { RCODE rc = NE_FLM_OK; if( !pOStream || m_pOStream || !uiBufferSize) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if( RC_BAD( rc = f_alloc( uiBufferSize, &m_pucBuffer))) { goto Exit; } m_pOStream = pOStream; m_pOStream->AddRef(); m_uiBufferSize = uiBufferSize; m_uiBufferOffset = 0; Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedOStream::flush( void) { RCODE rc = NE_FLM_OK; if( m_uiBufferOffset) { if( RC_BAD( rc = m_pOStream->write( m_pucBuffer, m_uiBufferOffset))) { goto Exit; } m_uiBufferOffset = 0; } Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedOStream::write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; FLMUINT uiMaxToWrite; FLMUINT uiBytesWritten = 0; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; while( uiBytesToWrite) { uiMaxToWrite = (FLMUINT)(m_uiBufferSize - m_uiBufferOffset); uiMaxToWrite = uiMaxToWrite > uiBytesToWrite ? uiBytesToWrite : uiMaxToWrite; f_memcpy( &m_pucBuffer[ m_uiBufferOffset], pucBuffer, uiMaxToWrite); pucBuffer += uiMaxToWrite; m_uiBufferOffset += uiMaxToWrite; uiBytesToWrite -= uiMaxToWrite; uiBytesWritten += uiMaxToWrite; if (m_uiBufferOffset == m_uiBufferSize) { if (RC_BAD( rc = flush())) { goto Exit; } } } Exit: if( puiBytesWritten) { *puiBytesWritten = uiBytesWritten; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_BufferedOStream::closeStream( void) { RCODE rc = NE_FLM_OK; if( m_pOStream) { if( RC_OK( rc = flush())) { if( m_pOStream->getRefCount() == 1) { rc = m_pOStream->closeStream(); } } m_pOStream->Release(); m_pOStream = NULL; } if( m_pucBuffer) { f_free( &m_pucBuffer); } m_uiBufferSize = 0; m_uiBufferOffset = 0; return( rc); } /***************************************************************************** Desc: ******************************************************************************/ F_BufferIStream::~F_BufferIStream() { closeStream(); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_BufferIStream::openStream( const char * pucBuffer, FLMUINT uiLength, char ** ppucAllocatedBuffer) { RCODE rc = NE_FLM_OK; f_assert( !m_pucBuffer); if( !pucBuffer && uiLength) { if( RC_BAD( rc = f_alloc( uiLength, &m_pucBuffer))) { goto Exit; } if( ppucAllocatedBuffer) { *ppucAllocatedBuffer = (char *)m_pucBuffer; } m_bAllocatedBuffer = TRUE; } else { m_pucBuffer = (FLMBYTE *)pucBuffer; } m_uiBufferLen = uiLength; m_uiOffset = 0; m_bIsOpen = TRUE; Exit: return( rc); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_BufferIStream::closeStream( void) { if( m_bIsOpen) { if( m_bAllocatedBuffer) { if( m_pucBuffer) { f_free( &m_pucBuffer); } m_bAllocatedBuffer = FALSE; } else { m_pucBuffer = NULL; } m_bIsOpen = FALSE; } return( NE_FLM_OK); } /***************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_BufferIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; FLMUINT uiBytesRead; f_assert( m_bIsOpen); uiBytesRead = uiBytesToRead < m_uiBufferLen - m_uiOffset ? uiBytesToRead : m_uiBufferLen - m_uiOffset; if (uiBytesRead) { if (pucBuffer) { f_memcpy( pucBuffer, &m_pucBuffer[ m_uiOffset], uiBytesRead); } m_uiOffset += uiBytesRead; } if (puiBytesRead) { *puiBytesRead = uiBytesRead; } if (uiBytesRead < uiBytesToRead) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } Exit: return( rc); } /***************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_Base64DecoderIStream::openStream( IF_IStream * pIStream) { RCODE rc = NE_FLM_OK; if( m_pIStream || !pIStream) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } m_uiBufOffset = 0; m_uiAvailBytes = 0; m_pIStream = pIStream; pIStream->AddRef(); Exit: return( rc); } /***************************************************************************** Desc: Reads decoded binary from the base64 ASCII source stream. *****************************************************************************/ RCODE FLMAPI F_Base64DecoderIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMBYTE * pucOutBuf = (FLMBYTE *)pvBuffer; FLMBYTE ucQuadBuffer[ 4]; FLMUINT uiOffset; FLMUINT uiBytesToCopy; if( puiBytesRead) { *puiBytesRead = 0; } if( !m_pIStream) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } while( uiBytesToRead) { if( !m_uiAvailBytes) { m_uiBufOffset = 0; for( uiOffset = 0; uiOffset < 4;) { if( RC_BAD( rc = m_pIStream->read( &ucQuadBuffer[ uiOffset], 1, NULL))) { if( rc != NE_FLM_EOF_HIT || !uiOffset) { goto Exit; } // Handle input that has not been padded correctly ucQuadBuffer[ uiOffset] = ASCII_EQUAL; } if( gv_ucBase64DecodeTable[ ucQuadBuffer[ uiOffset]] == 0xFF) { FLMBYTE ucTmp = ucQuadBuffer[ uiOffset]; if( ucTmp == 0 || ucTmp == ASCII_TAB || ucTmp == ASCII_SPACE || ucTmp == ASCII_NEWLINE || ucTmp == ASCII_CR) { continue; } rc = RC_SET( NE_FLM_BAD_BASE64_ENCODING); goto Exit; } uiOffset++; } // If we didn't get anything except padding, assume we are at the end // of an incorrectly encoded buffer. if( ucQuadBuffer[ 0] == ASCII_EQUAL) { goto Exit; } m_ucBuffer[ 0] = (gv_ucBase64DecodeTable[ ucQuadBuffer[ 0]] << 2) | (gv_ucBase64DecodeTable[ ucQuadBuffer[ 1]] >> 4); m_uiAvailBytes++; if( ucQuadBuffer[ 2] != '=') { m_ucBuffer[ 1] = (gv_ucBase64DecodeTable[ ucQuadBuffer[ 1]] << 4) | (gv_ucBase64DecodeTable[ ucQuadBuffer[ 2]] >> 2); m_uiAvailBytes++; } if( ucQuadBuffer[ 3] != '=') { m_ucBuffer[ 2] = (gv_ucBase64DecodeTable[ ucQuadBuffer[ 2]] << 6) | gv_ucBase64DecodeTable[ ucQuadBuffer[ 3]]; m_uiAvailBytes++; } } uiBytesToCopy = f_min( m_uiAvailBytes, uiBytesToRead); if( pucOutBuf) { f_memcpy( pucOutBuf, &m_ucBuffer[ m_uiBufOffset], uiBytesToCopy); } uiBytesToRead -= uiBytesToCopy; m_uiAvailBytes -= uiBytesToCopy; m_uiBufOffset += uiBytesToCopy; pucOutBuf += uiBytesToCopy; if( puiBytesRead) { *puiBytesRead += uiBytesToCopy; } } Exit: return( rc); } /***************************************************************************** Desc: *****************************************************************************/ RCODE FLMAPI F_Base64EncoderIStream::openStream( IF_IStream * pIStream, FLMBOOL bLineBreaks) { RCODE rc = NE_FLM_OK; if( m_pIStream || !pIStream) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } m_uiBase64Count = 0; m_uiBufOffset = 0; m_uiAvailBytes = 0; m_bLineBreaks = bLineBreaks; m_bInputExhausted = FALSE; m_bPriorLineEnd = FALSE; m_pIStream = pIStream; pIStream->AddRef(); Exit: return( rc); } /***************************************************************************** Desc: Reads ASCII base64 encoded binary from the source stream. *****************************************************************************/ RCODE FLMAPI F_Base64EncoderIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMBYTE * pucOutBuf = (FLMBYTE *)pvBuffer; FLMUINT uiBytesToCopy; FLMUINT uiBytesToEncode; FLMBYTE ucTriBuffer[ 3]; if( puiBytesRead) { *puiBytesRead = 0; } if( !m_pIStream) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } while( uiBytesToRead) { if( !m_uiAvailBytes) { m_uiBufOffset = 0; if( m_bInputExhausted) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } if( RC_BAD( rc = m_pIStream->read( ucTriBuffer, 3, &uiBytesToEncode))) { if( rc != NE_FLM_EOF_HIT) { goto Exit; } rc = NE_FLM_OK; m_bInputExhausted = TRUE; } if( uiBytesToEncode) { m_ucBuffer[ m_uiAvailBytes++] = gv_ucBase64EncodeTable[ ucTriBuffer[ 0] >> 2]; m_ucBuffer[ m_uiAvailBytes++] = gv_ucBase64EncodeTable[ ((ucTriBuffer[ 0] & 0x03) << 4) | (ucTriBuffer[ 1] >> 4)]; if( uiBytesToEncode >= 2) { m_ucBuffer[ m_uiAvailBytes++] = gv_ucBase64EncodeTable[ ((ucTriBuffer[ 1] & 0x0F) << 2) | (ucTriBuffer[ 2] >> 6)]; } else { m_ucBuffer[ m_uiAvailBytes++] = ASCII_EQUAL; } if( uiBytesToEncode == 3) { m_ucBuffer[ m_uiAvailBytes++] = gv_ucBase64EncodeTable[ ucTriBuffer[ 2] & 0x3F]; } else { m_ucBuffer[ m_uiAvailBytes++] = ASCII_EQUAL; } m_uiBase64Count += 4; } if( m_bLineBreaks) { if( (m_uiBase64Count % 72) == 0 || (m_bInputExhausted && !m_bPriorLineEnd)) { #ifdef FLM_UNIX m_ucBuffer[ m_uiAvailBytes++] = ASCII_NEWLINE; #elif FLM_OSX m_ucBuffer[ m_uiAvailBytes++] = ASCII_CR; #else m_ucBuffer[ m_uiAvailBytes++] = ASCII_CR; m_ucBuffer[ m_uiAvailBytes++] = ASCII_NEWLINE; #endif m_bPriorLineEnd = TRUE; } else { m_bPriorLineEnd = FALSE; } } if( !m_uiAvailBytes) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } } uiBytesToCopy = f_min( m_uiAvailBytes, uiBytesToRead); if( pucOutBuf) { f_memcpy( pucOutBuf, &m_ucBuffer[ m_uiBufOffset], uiBytesToCopy); } pucOutBuf += uiBytesToCopy; uiBytesToRead -= uiBytesToCopy; m_uiAvailBytes -= uiBytesToCopy; m_uiBufOffset += uiBytesToCopy; if( puiBytesRead) { *puiBytesRead += uiBytesToCopy; } } Exit: return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_CompressingOStream::openStream( IF_OStream * pOStream) { RCODE rc = NE_FLM_OK; FLMBYTE ucOutBuf[ 2]; // Setup the hash table m_uiHashTblSize = ((2 * 1024 * 1024) / sizeof( LZWODictItem *)); if( RC_BAD( rc = f_alloc( sizeof( LZWODictItem *) * m_uiHashTblSize, &m_ppHashTbl))) { goto Exit; } f_memset( m_ppHashTbl, 0, sizeof( LZWODictItem *) * m_uiHashTblSize); // Output a magic number so the stream can be identified UW2FBA( LZW_MAGIC_NUMBER, ucOutBuf); if( RC_BAD( rc = pOStream->write( ucOutBuf, 2))) { goto Exit; } // Setup misc. member variables m_pOStream = pOStream; m_pOStream->AddRef(); m_ui16CurrentCode = LZW_END_OF_DATA; m_ui16FreeCode = LZW_START_CODE; m_uiLastRatio = 100; m_uiBestRatio = 100; m_uiCurrentBytesIn = 0; m_uiTotalBytesIn = 0; m_uiCurrentBytesOut = 0; m_uiTotalBytesOut = 0; m_bStopCompression = FALSE; Exit: if( RC_BAD( rc)) { closeStream(); } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ LZWODictItem * F_CompressingOStream::findDictEntry( FLMUINT16 ui16CurrentCode, FLMBYTE ucChar) { FLMUINT uiHashBucket; LZWODictItem * pDictItem; FLMUINT uiLooks = 0; uiHashBucket = getHashBucket( ui16CurrentCode, ucChar); pDictItem = m_ppHashTbl[ uiHashBucket]; while( pDictItem) { if( pDictItem->ui16ParentCode == ui16CurrentCode && pDictItem->ucChar == ucChar) { break; } pDictItem = pDictItem->pNext; uiLooks++; } return( pDictItem); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_CompressingOStream::write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; FLMUINT uiBucket; FLMUINT uiBytesWritten = 0; FLMUINT uiTmp; LZWODictItem * pDictItem; const FLMBYTE * pucBuffer = (const FLMBYTE *)pvBuffer; FLMBYTE ucOut[ 2]; if( !uiBytesToWrite) { goto Exit; } if( m_bStopCompression) { rc = m_pOStream->write( pucBuffer, uiBytesToWrite, &uiTmp); uiBytesWritten += uiTmp; goto Exit; } if( !m_uiTotalBytesIn) { m_ui16CurrentCode = *pucBuffer++; m_uiCurrentBytesIn++; m_uiTotalBytesIn++; uiBytesToWrite--; } while( uiBytesToWrite) { if( (pDictItem = findDictEntry( m_ui16CurrentCode, *pucBuffer)) == NULL) { // No match. Output the code. UW2FBA( m_ui16CurrentCode, ucOut); if( RC_BAD( rc = m_pOStream->write( ucOut, 2))) { goto Exit; } m_uiCurrentBytesOut += 2; m_uiTotalBytesOut += 2; uiBytesWritten += 2; // Add the new code to the dictionary if( m_ui16FreeCode < LZW_MAX_CODE) { uiBucket = getHashBucket( m_ui16CurrentCode, *pucBuffer); if( RC_BAD( rc = m_pool.poolAlloc( sizeof( LZWODictItem), (void **)&pDictItem))) { goto Exit; } pDictItem->pNext = m_ppHashTbl[ uiBucket]; m_ppHashTbl[ uiBucket] = pDictItem; pDictItem->ucChar = *pucBuffer; pDictItem->ui16Code = m_ui16FreeCode++; pDictItem->ui16ParentCode = m_ui16CurrentCode; } m_ui16CurrentCode = *pucBuffer; // May need to reset the dictionary to improve compression. // If compression is causing the stream to grow, we // need to disable it. if( m_uiTotalBytesIn > (10 * 1024 * 1024) && m_uiTotalBytesOut > m_uiTotalBytesIn) { // Compression isn't buying us anything. From this // point forward in the stream, just store the bytes // without compression. UW2FBA( LZW_STOP_COMPRESSION, ucOut); if (RC_BAD( rc = m_pOStream->write( ucOut, 2))) { goto Exit; } uiBytesWritten += 2; m_bStopCompression = TRUE; m_ui16CurrentCode = LZW_END_OF_DATA; // Finish writing out the rest of the current buffer if( RC_BAD( rc = m_pOStream->write( pucBuffer, uiBytesToWrite))) { goto Exit; } m_uiCurrentBytesIn = 0; m_uiTotalBytesIn += uiBytesToWrite; uiBytesWritten += uiBytesToWrite; uiBytesToWrite = 0; break; } else if( m_uiCurrentBytesIn >= 8192) { FLMUINT uiRatio; uiRatio = (m_uiCurrentBytesOut * 100) / m_uiCurrentBytesIn; m_uiCurrentBytesIn = 0; m_uiCurrentBytesOut = 0; if( uiRatio > m_uiBestRatio) { if( uiRatio > 50 && (uiRatio > 90 || uiRatio > m_uiLastRatio + 10)) { // Output the dictionary reset token UW2FBA( LZW_NEW_DICT, ucOut); if (RC_BAD( rc = m_pOStream->write( ucOut, 2))) { goto Exit; } uiBytesWritten += 2; // Reset the dictionary m_pool.poolReset( NULL); f_memset( m_ppHashTbl, 0, sizeof( LZWODictItem *) * m_uiHashTblSize); m_ui16FreeCode = LZW_START_CODE; } else { m_uiBestRatio = uiRatio; } m_uiLastRatio = uiRatio; } // Good time to release the CPU f_yieldCPU(); } } else { m_ui16CurrentCode = pDictItem->ui16Code; } pucBuffer++; m_uiCurrentBytesIn++; m_uiTotalBytesIn++; uiBytesToWrite--; } Exit: if( puiBytesWritten) { *puiBytesWritten = uiBytesWritten; } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_CompressingOStream::closeStream( void) { RCODE rc = NE_FLM_OK; FLMBYTE ucOut[ 2]; if (m_pOStream) { if (RC_OK( rc) && m_ui16CurrentCode != LZW_END_OF_DATA) { UW2FBA( m_ui16CurrentCode, ucOut); rc = m_pOStream->write( ucOut, 2); m_uiCurrentBytesOut += 2; m_uiTotalBytesOut += 2; } // Write the end-of-data marker if (RC_OK( rc)) { UW2FBA( LZW_END_OF_DATA, ucOut); rc = m_pOStream->write( ucOut, 2); m_uiCurrentBytesOut += 2; m_uiTotalBytesOut += 2; } if (m_pOStream->getRefCount() == 1) { if (RC_OK( rc)) { rc = m_pOStream->closeStream(); } else { m_pOStream->closeStream(); } } m_pOStream->Release(); m_pOStream = NULL; } if( m_ppHashTbl) { f_free( &m_ppHashTbl); m_uiHashTblSize = 0; } m_pool.poolFree(); return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_UncompressingIStream::openStream( IF_IStream * pIStream) { RCODE rc = NE_FLM_OK; FLMBYTE ucInBuf[ 2]; FLMUINT16 ui16Magic; // Allocate the dictonary table if( RC_BAD( rc = f_alloc( sizeof( LZWIDictItem) * LZW_MAX_CODE, &m_pDict))) { goto Exit; } f_memset( m_pDict, 0, sizeof( LZWIDictItem) * LZW_MAX_CODE); // Allocate the decode buffer m_uiDecodeBufferSize = 4096; if( RC_BAD( rc = f_alloc( m_uiDecodeBufferSize, &m_pucDecodeBuffer))) { goto Exit; } // Read the magic number from the stream to ensure that this // is really an LZW compressed stream if( RC_BAD( rc = pIStream->read( ucInBuf, 2, NULL))) { goto Exit; } ui16Magic = FB2UW( ucInBuf); if( ui16Magic != LZW_MAGIC_NUMBER) { rc = RC_SET( NE_FLM_STREAM_NOT_COMPRESSED); goto Exit; } // Add a reference to the passed-in stream object m_pIStream = pIStream; m_pIStream->AddRef(); // Setup misc. member variables m_ui16FreeCode = LZW_START_CODE; m_ui16LastCode = LZW_END_OF_DATA; m_uiDecodeBufferOffset = 0; m_bStopCompression = FALSE; m_bEndOfStream = FALSE; Exit: if( RC_BAD( rc)) { closeStream(); } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE F_UncompressingIStream::readCode( FLMUINT16 * pui16Code) { RCODE rc = NE_FLM_OK; FLMBYTE ucInBuf[ 2]; if( m_bEndOfStream) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } if( RC_BAD( rc = m_pIStream->read( ucInBuf, 2, NULL))) { goto Exit; } *pui16Code = FB2UW( ucInBuf); if( *pui16Code == LZW_END_OF_DATA) { m_bEndOfStream = TRUE; rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } Exit: return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE F_UncompressingIStream::decodeToBuffer( FLMUINT16 ui16Code) { RCODE rc = NE_FLM_OK; if( ui16Code >= m_ui16FreeCode || m_ui16LastCode == LZW_END_OF_DATA) { rc = RC_SET_AND_ASSERT( NE_FLM_STREAM_DECOMPRESS_ERROR); goto Exit; } while( ui16Code > 0x00FF) { f_assert( m_uiDecodeBufferOffset < m_uiDecodeBufferSize); f_assert( ui16Code < m_ui16FreeCode); m_pucDecodeBuffer[ m_uiDecodeBufferOffset++] = m_pDict[ ui16Code].ucChar; ui16Code = m_pDict[ ui16Code].ui16ParentCode; } m_pucDecodeBuffer[ m_uiDecodeBufferOffset++] = (FLMBYTE)ui16Code; Exit: return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_UncompressingIStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; FLMUINT uiTmp; FLMUINT uiBytesRead = 0; FLMUINT uiSavePos; FLMUINT16 ui16Code; while( uiBytesToRead) { if( m_uiDecodeBufferOffset) { // Consume a byte from the decode buffer *pucBuffer++ = m_pucDecodeBuffer[ --m_uiDecodeBufferOffset]; uiBytesToRead--; continue; } if( m_bStopCompression) { if (RC_BAD( rc = m_pIStream->read( pvBuffer, uiBytesToRead, &uiTmp))) { if (rc != NE_FLM_EOF_HIT) { goto Exit; } uiBytesRead += uiTmp; } break; } if( RC_BAD( rc = readCode( &ui16Code))) { goto Exit; } if( ui16Code == LZW_NEW_DICT) { m_ui16FreeCode = LZW_START_CODE; m_ui16LastCode = LZW_END_OF_DATA; continue; } else if( ui16Code == LZW_STOP_COMPRESSION) { f_assert( !m_bStopCompression); m_bStopCompression = TRUE; continue; } else { if( ui16Code >= m_ui16FreeCode) { // The code isn't in our dictionary. There is only // one type of sequence that can result in this // condition. The code below builds the correct // sequence of bytes. f_assert( m_ui16LastCode != LZW_END_OF_DATA); uiSavePos = m_uiDecodeBufferOffset++; if( RC_BAD( rc = decodeToBuffer( m_ui16LastCode))) { goto Exit; } m_pucDecodeBuffer[ uiSavePos] = m_pucDecodeBuffer[ m_uiDecodeBufferOffset - 1]; } else if( m_ui16LastCode == LZW_END_OF_DATA) { f_assert( ui16Code <= 0x00FF); *pucBuffer++ = (FLMBYTE)ui16Code; uiBytesToRead--; m_ui16LastCode = ui16Code; continue; } else { if( RC_BAD( rc = decodeToBuffer( ui16Code))) { goto Exit; } } if( m_ui16FreeCode < LZW_MAX_CODE) { f_assert( m_uiDecodeBufferOffset); m_pDict[ m_ui16FreeCode].ui16ParentCode = m_ui16LastCode; m_pDict[ m_ui16FreeCode].ucChar = m_pucDecodeBuffer[ m_uiDecodeBufferOffset - 1]; m_ui16FreeCode++; } m_ui16LastCode = ui16Code; } } Exit: if( puiBytesRead) { *puiBytesRead = uiBytesRead; } return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI F_UncompressingIStream::closeStream( void) { if( m_pIStream) { m_pIStream->Release(); m_pIStream = NULL; } if( m_pDict) { f_free( &m_pDict); } if( m_pucDecodeBuffer) { f_free( &m_pucDecodeBuffer); } return( NE_FLM_OK); } /******************************************************************** Desc: *********************************************************************/ F_TCPIOStream::F_TCPIOStream( void) { m_pszIp[ 0] = 0; m_pszName[ 0] = 0; m_pszPeerIp[ 0] = 0; m_pszPeerName[ 0] = 0; m_uiIOTimeout = 10; m_iSocket = INVALID_SOCKET; m_ulRemoteAddr = 0; m_bInitialized = FALSE; m_bConnected = FALSE; #ifndef FLM_UNIX if( !WSAStartup( MAKEWORD( 2, 0), &m_wsaData)) { m_bInitialized = TRUE; } #endif } /******************************************************************** Desc: *********************************************************************/ F_TCPIOStream::~F_TCPIOStream( void) { if( m_bConnected) { closeStream(); } #ifndef FLM_UNIX if( m_bInitialized) { WSACleanup(); } #endif } /******************************************************************** Desc: Opens a new connection *********************************************************************/ RCODE F_TCPIOStream::openStream( const char * pucHostName, FLMUINT uiPort, FLMUINT, // uiFlags, FLMUINT uiConnectTimeout, FLMUINT uiDataTimeout) { RCODE rc = NE_FLM_OK; FLMINT iSockErr; FLMINT iTries; FLMINT iMaxTries = 5; struct sockaddr_in address; struct hostent * pHostEntry; unsigned long ulIPAddr; int iTmp; f_assert( !m_bConnected); m_iSocket = INVALID_SOCKET; if( pucHostName && pucHostName[ 0] != '\0') { ulIPAddr = inet_addr( (char *)pucHostName); if( ulIPAddr == (unsigned long)(-1)) { pHostEntry = gethostbyname( (char *)pucHostName); if( !pHostEntry) { rc = RC_SET( NE_FLM_NOIP_ADDR); goto Exit; } else { ulIPAddr = *((unsigned long *)pHostEntry->h_addr); } } } else { ulIPAddr = inet_addr( (char *)"127.0.0.1"); } // Fill in the Socket structure with family type f_memset( (char *)&address, 0, sizeof( struct sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = (unsigned)ulIPAddr; address.sin_port = htons( (unsigned short)uiPort); // Allocate a socket, then attempt to connect to it! if( (m_iSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { rc = RC_SET( NE_FLM_SOCKET_FAIL); goto Exit; } // Now attempt to connect with the specified partner host, // time-out if connection doesn't complete within alloted time #ifdef FLM_WIN if( uiConnectTimeout) { if ( uiConnectTimeout < 5 ) { iMaxTries = (iMaxTries * uiConnectTimeout) / 5; uiConnectTimeout = 5; } } else { iMaxTries = 1; } #endif for( iTries = 0; iTries < iMaxTries; iTries++ ) { iSockErr = 0; if( connect( m_iSocket, (struct sockaddr *)((void *)&address), (unsigned)sizeof(struct sockaddr)) >= 0) { break; } #ifndef FLM_UNIX iSockErr = WSAGetLastError(); #else iSockErr = errno; #endif #ifdef FLM_WIN // In WIN, we sometimes get WSAEINVAL when, if we keep // trying, we will eventually connect. Therefore, // here we'll treat WSAEINVAL as EINPROGRESS. if( iSockErr == WSAEINVAL) { #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif if( (m_iSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { rc = RC_SET( NE_FLM_SOCKET_FAIL); goto Exit; } #if defined( FLM_WIN) || defined( FLM_NLM) iSockErr = WSAEINPROGRESS; #else iSockErr = EINPROGRESS; #endif continue; } #endif #if defined( FLM_WIN) || defined( FLM_NLM) if( iSockErr == WSAEISCONN ) #else if( iSockErr == EISCONN ) #endif { break; } #if defined( FLM_WIN) || defined( FLM_NLM) else if( iSockErr == WSAEWOULDBLOCK) #else else if( iSockErr == EWOULDBLOCK) #endif { // Let's wait a split second to give the connection // request a chance. f_sleep( 100 ); continue; } #if defined( FLM_WIN) || defined( FLM_NLM) else if( iSockErr == WSAEINPROGRESS) #else else if( iSockErr == EINPROGRESS) #endif { if( RC_OK( rc = socketPeek( uiConnectTimeout, FALSE))) { // Let's wait a split second to give the connection // request a chance. f_sleep( 100 ); continue; } } rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } // Disable Nagel's algorithm iTmp = 1; if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iTmp, (unsigned)sizeof( iTmp) )) < 0) { rc = RC_SET( NE_FLM_SOCKET_SET_OPT_FAIL); goto Exit; } m_uiIOTimeout = uiDataTimeout; m_bConnected = TRUE; Exit: if( RC_BAD( rc)) { if( m_iSocket != INVALID_SOCKET) { #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif m_iSocket = INVALID_SOCKET; } } return( rc); } /******************************************************************** Desc: Gets information about the local host machine. *********************************************************************/ RCODE F_TCPIOStream::getLocalInfo( void) { RCODE rc = NE_FLM_OK; struct hostent * pHostEnt; FLMUINT32 ui32IPAddr; m_pszIp[ 0] = 0; m_pszName[ 0] = 0; if( !m_pszName[ 0]) { if( gethostname( m_pszName, (unsigned)sizeof( m_pszName))) { rc = RC_SET( NE_FLM_SOCKET_FAIL); goto Exit; } } if( !m_pszIp[ 0] && (pHostEnt = gethostbyname( m_pszName)) != NULL) { ui32IPAddr = (FLMUINT32)(*((unsigned long *)pHostEnt->h_addr)); if( ui32IPAddr != (FLMUINT32)-1) { struct in_addr InAddr; InAddr.s_addr = ui32IPAddr; f_strcpy( m_pszIp, inet_ntoa( InAddr)); } } Exit: return( rc); } /******************************************************************** Desc: Gets information about the remote machine. *********************************************************************/ RCODE F_TCPIOStream::getRemoteInfo( void) { RCODE rc = NE_FLM_OK; struct sockaddr_in SockAddrIn; char * InetAddr = NULL; struct hostent * HostsName; m_pszPeerIp[ 0] = 0; m_pszPeerName[ 0] = 0; SockAddrIn.sin_addr.s_addr = (unsigned)m_ulRemoteAddr; InetAddr = inet_ntoa( SockAddrIn.sin_addr); f_strcpy( m_pszPeerIp, InetAddr); // Try to get the peer's host name by looking up his IP // address. HostsName = gethostbyaddr( (char *)&SockAddrIn.sin_addr.s_addr, (unsigned)sizeof( unsigned long), AF_INET ); if( HostsName != NULL) { f_strcpy( m_pszPeerName, (char*) HostsName->h_name ); } else { if (!InetAddr) { InetAddr = inet_ntoa( SockAddrIn.sin_addr); } f_strcpy( m_pszPeerName, InetAddr); } return( rc); } /******************************************************************** Desc: Tests for socket data readiness *********************************************************************/ RCODE F_TCPIOStream::socketPeek( FLMINT iTimeoutVal, FLMBOOL bPeekRead) { RCODE rc = NE_FLM_OK; struct timeval TimeOut; int iMaxDescs; fd_set GenDescriptors; fd_set * DescrRead; fd_set * DescrWrt; if( m_iSocket != INVALID_SOCKET) { FD_ZERO( &GenDescriptors); #ifdef FLM_WIN #pragma warning( push) #pragma warning( disable : 4127) #endif FD_SET( m_iSocket, &GenDescriptors); #ifdef FLM_WIN #pragma warning( pop) #endif iMaxDescs = (int)(m_iSocket + 1); DescrRead = bPeekRead ? &GenDescriptors : NULL; DescrWrt = bPeekRead ? NULL : &GenDescriptors; TimeOut.tv_sec = (long)iTimeoutVal; TimeOut.tv_usec = (long)0; if( select( iMaxDescs, DescrRead, DescrWrt, NULL, &TimeOut) < 0 ) { rc = RC_SET( NE_FLM_SELECT_ERR); goto Exit; } else { if( !FD_ISSET( m_iSocket, &GenDescriptors)) { rc = bPeekRead ? RC_SET( NE_FLM_SOCKET_READ_TIMEOUT) : RC_SET( NE_FLM_SOCKET_WRITE_TIMEOUT); } } } else { rc = RC_SET( NE_FLM_CONNECT_FAIL); } Exit: return( rc); } /******************************************************************** Desc: *********************************************************************/ RCODE FLMAPI F_TCPIOStream::write( const void * pucBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; FLMINT iRetryCount = 0; FLMINT iBytesWritten = 0; if( m_iSocket == INVALID_SOCKET) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } f_assert( pucBuffer && uiBytesToWrite); Retry: if( puiBytesWritten) { *puiBytesWritten = 0; } if( RC_OK( rc = socketPeek( m_uiIOTimeout, FALSE))) { iBytesWritten = send( m_iSocket, (char *)pucBuffer, (int)uiBytesToWrite, 0); switch( iBytesWritten) { case -1: { if( puiBytesWritten) { *puiBytesWritten = 0; } rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); break; } case 0: { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); break; } default: { if( puiBytesWritten) { *puiBytesWritten = (FLMUINT)iBytesWritten; } break; } } } if( RC_BAD( rc) && rc != NE_FLM_SOCKET_WRITE_TIMEOUT) { #ifndef FLM_UNIX FLMINT iSockErr = WSAGetLastError(); #else FLMINT iSockErr = errno; #endif #if defined( FLM_WIN) || defined( FLM_NLM) if( iSockErr == WSAECONNABORTED) #else if( iSockErr == ECONNABORTED) #endif { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); } #if defined( FLM_WIN) || defined( FLM_NLM) else if( iSockErr == WSAEWOULDBLOCK && iRetryCount < 5) #else else if( iSockErr == EWOULDBLOCK && iRetryCount < 5) #endif { iRetryCount++; f_sleep( (FLMUINT)(100 * iRetryCount)); goto Retry; } } Exit: return( rc); } /******************************************************************** Desc: *********************************************************************/ RCODE FLMAPI F_TCPIOStream::read( void * pucBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMINT iReadCnt = 0; f_assert( m_bConnected && pucBuffer && uiBytesToWrite); if( RC_OK( rc = socketPeek( m_uiIOTimeout, TRUE))) { iReadCnt = (FLMINT)recv( m_iSocket, (char *)pucBuffer, (int)uiBytesToWrite, 0); switch ( iReadCnt) { case -1: { iReadCnt = 0; #if defined( FLM_WIN) || defined( FLM_NLM) if ( WSAGetLastError() == WSAECONNRESET) #else if( errno == ECONNRESET) #endif { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); } else { rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); } break; } case 0: { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); break; } default: { break; } } } if( puiBytesRead) { *puiBytesRead = (FLMUINT)iReadCnt; } return( rc); } /******************************************************************** Desc: Reads data from the connection - Timeout valkue is zero, no error is generated if timeout occurs. *********************************************************************/ RCODE F_TCPIOStream::readNoWait( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMINT iReadCnt = 0; f_assert( m_bConnected && pvBuffer && uiBytesToRead); if( puiBytesRead) { *puiBytesRead = 0; } if( RC_OK( rc = socketPeek( (FLMUINT)0, TRUE))) { iReadCnt = recv( m_iSocket, (char *)pvBuffer, (int)uiBytesToRead, 0); switch ( iReadCnt) { case -1: { *puiBytesRead = 0; #if defined( FLM_WIN) || defined( FLM_NLM) if ( WSAGetLastError() == WSAECONNRESET) #else if( errno == ECONNRESET) #endif { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); } else { rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); } goto Exit; } case 0: { rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); goto Exit; } default: { break; } } } else if (rc == NE_FLM_SOCKET_READ_TIMEOUT) { rc = NE_FLM_OK; } if( puiBytesRead) { *puiBytesRead = (FLMUINT)iReadCnt; } Exit: return( rc); } /******************************************************************** Desc: Reads data and does not return until all requested data has been read or a timeout error has been encountered. *********************************************************************/ RCODE F_TCPIOStream::readAll( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; FLMUINT uiToRead = 0; FLMUINT uiHaveRead = 0; FLMUINT uiPartialCnt; FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; f_assert( m_bConnected && pvBuffer && uiBytesToRead); uiToRead = uiBytesToRead; while( uiToRead) { if( RC_BAD( rc = read( pucBuffer, uiToRead, &uiPartialCnt))) { goto Exit; } pucBuffer += uiPartialCnt; uiHaveRead += uiPartialCnt; uiToRead = (FLMUINT)(uiBytesToRead - uiHaveRead); if( puiBytesRead) { *puiBytesRead = uiHaveRead; } } Exit: return( rc); } /******************************************************************** Desc: Closes any open connections *********************************************************************/ RCODE FLMAPI F_TCPIOStream::closeStream( void) { if( m_iSocket == INVALID_SOCKET) { goto Exit; } #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif Exit: m_iSocket = INVALID_SOCKET; m_bConnected = FALSE; return( NE_FLM_OK); } /**************************************************************************** Desc: ****************************************************************************/ #ifdef FLM_OPENSSL RCODE FLMAPI F_SSLIOStream::openStream( const char * pszHost, FLMUINT uiPort, FLMUINT uiFlags) { RCODE rc = NE_FLM_OK; char szPort[ 32]; X509_NAME * pPeerName; EVP_PKEY * pPublicKey = NULL; BIO * pMemBIO = NULL; FLMUINT uiCertTextLen; const char * pszCertText; if( !uiPort) { uiPort = 443; } // Setup the connection to use SSLv2, SSLv3, or TLSv1 depending on // the capabilities of the peer if( (m_pContext = SSL_CTX_new( SSLv23_client_method())) == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } // Set the default path for verifying certificates if( !SSL_CTX_set_default_verify_paths( m_pContext)) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } // Configure the BIO if( (m_pBio = BIO_new_ssl_connect( m_pContext)) == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } BIO_get_ssl( m_pBio, &m_pSSL); if( m_pSSL == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } SSL_set_mode( m_pSSL, SSL_MODE_AUTO_RETRY); BIO_set_conn_hostname( m_pBio, pszHost); f_sprintf( szPort, "%u", (unsigned)uiPort); BIO_set_conn_port( m_pBio, szPort); // Open the connection if( BIO_do_connect( m_pBio) <= 0) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( SSL_get_verify_result( m_pSSL) != X509_V_OK) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( (m_pPeerCertificate = SSL_get_peer_certificate( m_pSSL)) == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( (pPeerName = X509_get_subject_name( m_pPeerCertificate)) == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( (X509_NAME_get_text_by_NID( pPeerName, NID_commonName, m_szPeerName, sizeof( m_szPeerName))) == -1) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( f_stricmp( pszHost, m_szPeerName) != 0) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } // Get the peer's certificate text if( (pMemBIO = BIO_new( BIO_s_mem())) == NULL) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( (pPublicKey = X509_get_pubkey( m_pPeerCertificate)) == NULL) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( pPublicKey->type != EVP_PKEY_RSA) { rc = RC_SET( NE_FLM_CONNECT_FAIL); goto Exit; } if( (PEM_write_bio_X509( pMemBIO, m_pPeerCertificate)) == 0) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( (uiCertTextLen = BIO_get_mem_data( pMemBIO, &pszCertText)) == 0) { rc = RC_SET( NE_FLM_MEM); goto Exit; } if( RC_BAD( rc = f_alloc( uiCertTextLen + 1, &m_pszPeerCertText))) { goto Exit; } f_memcpy( m_pszPeerCertText, pszCertText, uiCertTextLen + 1); Exit: if( pMemBIO) { BIO_free( pMemBIO); } if( pPublicKey) { EVP_PKEY_free( pPublicKey); } if( RC_BAD( rc)) { closeStream(); } return( rc); } #endif /**************************************************************************** Desc: ****************************************************************************/ #ifdef FLM_OPENSSL RCODE FLMAPI F_SSLIOStream::read( void * pvBuffer, FLMUINT uiBytesToRead, FLMUINT * puiBytesRead) { RCODE rc = NE_FLM_OK; int iBytesRead; FLMUINT uiTotalBytesRead = 0; char * pucBuffer = (char *)pvBuffer; while( uiBytesToRead) { if( (iBytesRead = BIO_read( m_pBio, &pucBuffer[ uiTotalBytesRead], uiBytesToRead)) <= 0) { if( !BIO_should_retry( m_pBio)) { rc = RC_SET( NE_FLM_EOF_HIT); goto Exit; } continue; } uiTotalBytesRead += iBytesRead; uiBytesToRead -= iBytesRead; } Exit: if( puiBytesRead) { *puiBytesRead = uiTotalBytesRead; } return( rc); } #endif /**************************************************************************** Desc: ****************************************************************************/ #ifdef FLM_OPENSSL RCODE FLMAPI F_SSLIOStream::write( const void * pvBuffer, FLMUINT uiBytesToWrite, FLMUINT * puiBytesWritten) { RCODE rc = NE_FLM_OK; int iBytesWritten = 0; if( !uiBytesToWrite) { goto Exit; } if( (iBytesWritten = BIO_write( m_pBio, pvBuffer, uiBytesToWrite)) <= 0) { iBytesWritten = 0; rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); goto Exit; } Exit: if( puiBytesWritten) { *puiBytesWritten = (FLMUINT)iBytesWritten; } return( rc); } #endif /**************************************************************************** Desc: ****************************************************************************/ #ifdef FLM_OPENSSL RCODE FLMAPI F_SSLIOStream::closeStream( void) { if( m_pBio) { BIO_free_all( m_pBio); m_pBio = NULL; m_pSSL = NULL; } if( m_pPeerCertificate) { X509_free( m_pPeerCertificate); m_pPeerCertificate = NULL; } if( m_pszPeerCertText) { f_free( &m_pszPeerCertText); } if( m_pContext) { SSL_CTX_free( m_pContext); m_pContext = NULL; } m_szPeerName[ 0] = 0; return( NE_FLM_OK); } #endif /****************************************************************************** Desc: ******************************************************************************/ #ifdef FLM_OPENSSL const char * FLMAPI F_SSLIOStream::getPeerCertificateText( void) { return( m_pszPeerCertText); } #endif /****************************************************************************** Desc: Read all data from input stream and write to the output stream. ******************************************************************************/ RCODE FLMAPI FlmWriteToOStream( IF_IStream * pIStream, IF_OStream * pOStream) { RCODE rc = NE_FLM_OK; FLMBYTE ucBuffer[ 512]; FLMUINT uiBufferSize = sizeof( ucBuffer); FLMUINT uiBytesRead; for (;;) { if( RC_BAD( rc = pIStream->read( ucBuffer, uiBufferSize, &uiBytesRead))) { if( rc != NE_FLM_EOF_HIT) { if( uiBytesRead) { (void)pOStream->write( ucBuffer, uiBytesRead); } goto Exit; } rc = NE_FLM_OK; if( !uiBytesRead) { goto Exit; } } if( RC_BAD( rc = pOStream->write( ucBuffer, uiBytesRead))) { goto Exit; } } Exit: return( rc); } /****************************************************************************** Desc: ******************************************************************************/ RCODE FLMAPI FlmReadFully( IF_IStream * pIStream, F_DynaBuf * pDynaBuf) { RCODE rc = NE_FLM_OK; FLMBYTE ucBuffer[ 512]; FLMUINT uiBufferSize = sizeof( ucBuffer); FLMUINT uiBytesRead; for (;;) { if( RC_BAD( rc = pIStream->read( ucBuffer, uiBufferSize, &uiBytesRead))) { if( rc != NE_FLM_EOF_HIT) { if( uiBytesRead) { (void)pDynaBuf->appendData( ucBuffer, uiBytesRead); } goto Exit; } rc = NE_FLM_OK; if( !uiBytesRead) { goto Exit; } } if( RC_BAD( rc = pDynaBuf->appendData( ucBuffer, uiBytesRead))) { goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI FlmReadLine( IF_IStream * pIStream, F_DynaBuf * pBuffer) { RCODE rc = NE_FLM_OK; char ucTmpBuf[ 32]; pBuffer->truncateData( 0); for( ;;) { if( RC_BAD( rc = pIStream->read( ucTmpBuf, 1, NULL))) { goto Exit; } if( ucTmpBuf[ 0] != ASCII_CR) { if( RC_BAD( rc = pBuffer->appendByte( ucTmpBuf[ 0]))) { goto Exit; } } else { if( RC_BAD( rc = pIStream->read( ucTmpBuf, 1, NULL))) { goto Exit; } if( ucTmpBuf[ 0] != ASCII_LF) { rc = RC_SET( NE_FLM_SYNTAX); goto Exit; } break; } } if( RC_BAD( rc = pBuffer->appendByte( 0))) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_printf( IF_OStream * pOStream, const char * pszFormatStr, ...) { f_va_list args; F_StreamPrintfClient printfClient( pOStream); f_va_start( args, pszFormatStr); f_vprintf( &printfClient, pszFormatStr, &args); f_va_end( args); return( printfClient.flushBuffer()); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_vprintf( IF_OStream * pOStream, const char * pszFormatStr, f_va_list * args) { F_StreamPrintfClient printfClient( pOStream); f_vprintf( &printfClient, pszFormatStr, args); return( printfClient.flushBuffer()); }