diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 0f314c88b0..bc84166874 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,61 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-01-06 07:27 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/src/rtl/gtwin/gtwin.c + + added support for HB_GTI_ISUNICODE + + * harbour/include/hbapifs.h + * added missing 'extern' in some declarations + + * harbour/include/hbzlib.ch + + added HB_ZLIB_STRATEGY_* constants + + added HB_ZLIB_COMPRESSION_DISABLE + + * harbour/include/Makefile + + harbour/include/hbznet.h + * harbour/include/hbextern.ch + * harbour/src/rtl/Makefile + * harbour/src/rtl/hbinet.c + + harbour/src/rtl/hbznet.c + + added support for ZLIB compression in stream sockets. + + added .prg function: + HB_INETCOMPRESS( , [], [] ) + which enables ZLIB compression for given HB_INET*() socket. + is a socket created by one of HB_INET*() functions + is compression factor between 1 (fastest) and + 9 (best) (see HB_ZLIB_COMPRESSION_*) + 0 (none) disable compression on output data + but decompression is still working. + is used to tune compression algorithm, + see HB_ZLIB_STRATEGY_* + The compression must be enabled on both connection sides, i.e. + on the server side: + conn := hb_inetAccept( sock ) + hb_inetCompress( conn ) + and on the client side: + sock := hb_inetConnect( cServer, nPort ) + hb_inetCompress( sock ) + in the same moment but it's not necessary to enable it at the + beginning of connection. It can be done later, i.e. when both + sides agree to enable connection using some custom protocol. + The compression has effect only on stream connections, i.e. + TCP and it's ignored in datagram connections like UDP. + This function can be executed more then once changing the compression + parameters but it causes that all data in readahead decompression + buffer is discarded. When called with HB_ZLIB_COMPRESSION_DISABLE + as then support for stream compression is removed + and sockets works again in raw mode. + The compression level and strategy do not have to be the same on both + connection sides. Each side can chose the best settings for data it's + going to send. + + This code was written in a way which allows to easy implement + alternative compression methods or other extensions like encryption + in existing HB_INET*() sockets also by non core code. The public C + functions declared in hbznet.h allows to use this extension with raw + harbour sockets two. + 2010-01-05 19:01 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) * contrib/hbxbp/tests/demoxbp.prg ! Changed to HBQT_SET_RELEASE_METHOD( HBQT_RELEASE_WITH_DELETE ) diff --git a/harbour/include/Makefile b/harbour/include/Makefile index 3a65d7e958..9dbd7fbbfb 100644 --- a/harbour/include/Makefile +++ b/harbour/include/Makefile @@ -69,6 +69,7 @@ C_HEADERS := \ hbwince.h \ hbwinuni.h \ hbzlib.h \ + hbznet.h \ hb_io.h \ PRG_HEADERS := \ diff --git a/harbour/include/hbapifs.h b/harbour/include/hbapifs.h index 8f63801720..e7dbadc6e4 100644 --- a/harbour/include/hbapifs.h +++ b/harbour/include/hbapifs.h @@ -341,32 +341,32 @@ extern HB_EXPORT const char * hb_fsNameConv( const char * szFileName, char ** ps } HB_FILE_FUNCS; - HB_EXPORT BOOL hb_fileRegister( const HB_FILE_FUNCS * pFuncs ); + extern HB_EXPORT BOOL hb_fileRegister( const HB_FILE_FUNCS * pFuncs ); #else typedef void * PHB_FILE; #endif -HB_EXPORT BOOL hb_fileExists( const char * pFilename, char * pRetPath ); -HB_EXPORT BOOL hb_fileDelete( const char * pFilename ); -HB_EXPORT BOOL hb_fileRename( const char * pFilename, const char * pszNewName ); -HB_EXPORT PHB_FILE hb_fileExtOpen( const char * pszFilename, const char * pDefExt, - USHORT uiExFlags, const char * pPaths, - PHB_ITEM pError ); -HB_EXPORT PHB_FILE hb_fileCreateTemp( const char * pszDir, const char * pszPrefix, - ULONG ulAttr, char * pszName ); -HB_EXPORT PHB_FILE hb_fileCreateTempEx( char * pszName, - const char * pszDir, - const char * pszPrefix, - const char * pszExt, - ULONG ulAttr ); -HB_EXPORT void hb_fileClose( PHB_FILE pFile ); -HB_EXPORT BOOL hb_fileLock( PHB_FILE pFile, HB_FOFFSET ulStart, HB_FOFFSET ulLen, int iType ); -HB_EXPORT ULONG hb_fileReadAt( PHB_FILE pFile, void * buffer, ULONG ulSize, HB_FOFFSET llOffset ); -HB_EXPORT ULONG hb_fileWriteAt( PHB_FILE pFile, const void * buffer, ULONG ulSize, HB_FOFFSET llOffset ); -HB_EXPORT BOOL hb_fileTruncAt( PHB_FILE pFile, HB_FOFFSET llOffset ); -HB_EXPORT HB_FOFFSET hb_fileSize( PHB_FILE pFile ); -HB_EXPORT void hb_fileCommit( PHB_FILE pFile ); -HB_EXPORT HB_FHANDLE hb_fileHandle( PHB_FILE pFile ); +extern HB_EXPORT BOOL hb_fileExists( const char * pFilename, char * pRetPath ); +extern HB_EXPORT BOOL hb_fileDelete( const char * pFilename ); +extern HB_EXPORT BOOL hb_fileRename( const char * pFilename, const char * pszNewName ); +extern HB_EXPORT PHB_FILE hb_fileExtOpen( const char * pszFilename, const char * pDefExt, + USHORT uiExFlags, const char * pPaths, + PHB_ITEM pError ); +extern HB_EXPORT PHB_FILE hb_fileCreateTemp( const char * pszDir, const char * pszPrefix, + ULONG ulAttr, char * pszName ); +extern HB_EXPORT PHB_FILE hb_fileCreateTempEx( char * pszName, + const char * pszDir, + const char * pszPrefix, + const char * pszExt, + ULONG ulAttr ); +extern HB_EXPORT void hb_fileClose( PHB_FILE pFile ); +extern HB_EXPORT BOOL hb_fileLock( PHB_FILE pFile, HB_FOFFSET ulStart, HB_FOFFSET ulLen, int iType ); +extern HB_EXPORT ULONG hb_fileReadAt( PHB_FILE pFile, void * buffer, ULONG ulSize, HB_FOFFSET llOffset ); +extern HB_EXPORT ULONG hb_fileWriteAt( PHB_FILE pFile, const void * buffer, ULONG ulSize, HB_FOFFSET llOffset ); +extern HB_EXPORT BOOL hb_fileTruncAt( PHB_FILE pFile, HB_FOFFSET llOffset ); +extern HB_EXPORT HB_FOFFSET hb_fileSize( PHB_FILE pFile ); +extern HB_EXPORT void hb_fileCommit( PHB_FILE pFile ); +extern HB_EXPORT HB_FHANDLE hb_fileHandle( PHB_FILE pFile ); /* wrapper to fopen() which calls hb_fsNameConv() */ extern FILE * hb_fopen( const char *path, const char *mode ); diff --git a/harbour/include/hbextern.ch b/harbour/include/hbextern.ch index 56019d5906..97f9a54d83 100644 --- a/harbour/include/hbextern.ch +++ b/harbour/include/hbextern.ch @@ -1230,6 +1230,7 @@ EXTERNAL HB_INETGETSNDBUFSIZE EXTERNAL HB_INETGETRCVBUFSIZE EXTERNAL HB_INETSETSNDBUFSIZE EXTERNAL HB_INETSETRCVBUFSIZE +EXTERNAL HB_INETCOMPRESS EXTERNAL HB_ZLIBVERSION EXTERNAL HB_ZCOMPRESS diff --git a/harbour/include/hbzlib.ch b/harbour/include/hbzlib.ch index 9495b30a54..6b245102d5 100644 --- a/harbour/include/hbzlib.ch +++ b/harbour/include/hbzlib.ch @@ -53,12 +53,19 @@ #ifndef HB_ZLIB_CH_ #define HB_ZLIB_CH_ -#define HB_ZLIB_METHOD_STORE 0 -#define HB_ZLIB_METHOD_DEFLATED 8 +#define HB_ZLIB_METHOD_STORE 0 +#define HB_ZLIB_METHOD_DEFLATED 8 -#define HB_ZLIB_COMPRESSION_NONE 0 -#define HB_ZLIB_COMPRESSION_SPEED 1 -#define HB_ZLIB_COMPRESSION_SIZE 9 -#define HB_ZLIB_COMPRESSION_DEFAULT (-1) +#define HB_ZLIB_COMPRESSION_NONE 0 +#define HB_ZLIB_COMPRESSION_SPEED 1 +#define HB_ZLIB_COMPRESSION_SIZE 9 +#define HB_ZLIB_COMPRESSION_DEFAULT (-1) +#define HB_ZLIB_COMPRESSION_DISABLE (-2) -#endif +#define HB_ZLIB_STRATEGY_DEFAULT 0 +#define HB_ZLIB_STRATEGY_FILTERED 1 +#define HB_ZLIB_STRATEGY_HUFFMAN_ONLY 2 +#define HB_ZLIB_STRATEGY_RLE 3 +#define HB_ZLIB_STRATEGY_FIXED 4 + +#endif /* HB_ZLIB_CH_ */ diff --git a/harbour/include/hbznet.h b/harbour/include/hbznet.h new file mode 100644 index 0000000000..4c039d26f9 --- /dev/null +++ b/harbour/include/hbznet.h @@ -0,0 +1,89 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * ZLIB compression for Harbour stream sockets + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HB_ZNET_H_ +#define HB_ZNET_H_ + +#include "hbapi.h" + +HB_EXTERN_BEGIN + +#if defined( _HB_ZNET_INTERNAL_ ) + struct _HB_ZNETSTREAM; + typedef struct _HB_ZNETSTREAM * PHB_ZNETSTREAM; +#else + typedef void * PHB_ZNETSTREAM; +#endif + +typedef long ( * HB_INET_SFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, const void *, long, HB_LONG ); +typedef long ( * HB_INET_RFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, void *, long, HB_LONG ); +typedef long ( * HB_INET_FFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, HB_LONG ); +typedef void ( * HB_INET_CFUNC ) ( PHB_ZNETSTREAM ); + +extern HB_EXPORT int hb_znetError( PHB_ZNETSTREAM pStream ); + +extern HB_EXPORT PHB_ZNETSTREAM hb_znetOpen( int level, int strategy ); +extern HB_EXPORT void hb_znetClose( PHB_ZNETSTREAM pStream ); +extern HB_EXPORT int hb_znetError( PHB_ZNETSTREAM pStream ); +extern HB_EXPORT long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_LONG timeout ); +extern HB_EXPORT long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG timeout ); +extern HB_EXPORT long hb_znetWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, const void * buffer, long len, HB_LONG timeout ); + +extern HB_EXPORT BOOL hb_znetInetInitialize( PHB_ITEM, PHB_ZNETSTREAM, + HB_INET_RFUNC, + HB_INET_SFUNC, + HB_INET_FFUNC, + HB_INET_CFUNC ); + +HB_EXTERN_END + +#endif /* HB_ZNET_H_ */ diff --git a/harbour/src/rtl/Makefile b/harbour/src/rtl/Makefile index c2936da5cd..765bebfc0d 100644 --- a/harbour/src/rtl/Makefile +++ b/harbour/src/rtl/Makefile @@ -97,6 +97,7 @@ C_SOURCES := \ hbtoken.c \ hbzlib.c \ hbzlibgz.c \ + hbznet.c \ idle.c \ idlex.c \ inkey.c \ diff --git a/harbour/src/rtl/gtwin/gtwin.c b/harbour/src/rtl/gtwin/gtwin.c index 78ac66b3a0..3ec9aab5ec 100644 --- a/harbour/src/rtl/gtwin/gtwin.c +++ b/harbour/src/rtl/gtwin/gtwin.c @@ -1628,6 +1628,14 @@ static BOOL hb_gt_win_Info( PHB_GT pGT, int iType, PHB_GT_INFO pInfo ) pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); break; + case HB_GTI_ISUNICODE: +#if defined( UNICODE ) + pInfo->pResult = hb_itemPutL( pInfo->pResult, TRUE ); +#else + pInfo->pResult = hb_itemPutL( pInfo->pResult, FALSE ); +#endif + break; + case HB_GTI_CODEPAGE: { UINT uiCodePage = GetConsoleCP(); diff --git a/harbour/src/rtl/hbinet.c b/harbour/src/rtl/hbinet.c index 143fe21fa6..6478f62f05 100644 --- a/harbour/src/rtl/hbinet.c +++ b/harbour/src/rtl/hbinet.c @@ -66,6 +66,7 @@ #include "hbapierr.h" #include "hbvm.h" #include "hbthread.h" +#include "hbznet.h" #define HB_INET_ERR_OK 0 #define HB_INET_ERR_TIMEOUT ( -1 ) @@ -87,6 +88,11 @@ typedef struct int iTimeout; int iTimeLimit; PHB_ITEM pPeriodicBlock; + PHB_ZNETSTREAM stream; + HB_INET_RFUNC recvFunc; + HB_INET_SFUNC sendFunc; + HB_INET_FFUNC flushFunc; + HB_INET_CFUNC cleanFunc; } HB_SOCKET_STRUCT, * PHB_SOCKET_STRUCT; #define HB_INET_BUFFER_LEN 256 @@ -148,6 +154,18 @@ static int hb_inetCloseSocket( PHB_SOCKET_STRUCT socket ) return ret; } +static void hb_inetCloseStream( PHB_SOCKET_STRUCT socket ) +{ + if( socket->cleanFunc ) + socket->cleanFunc( socket->stream ); + + socket->recvFunc = NULL; + socket->sendFunc = NULL; + socket->flushFunc = NULL; + socket->cleanFunc = NULL; + socket->stream = NULL; +} + static HB_GARBAGE_FUNC( hb_inetSocketFinalize ) { PHB_SOCKET_STRUCT socket = ( PHB_SOCKET_STRUCT ) Cargo; @@ -173,6 +191,7 @@ static HB_GARBAGE_FUNC( hb_inetSocketFinalize ) hb_xfree( socket->buffer ); socket->buffer = NULL; } + hb_inetCloseStream( socket ); } static HB_GARBAGE_FUNC( hb_inetSocketMark ) @@ -207,6 +226,30 @@ static void hb_inetAutoInit( void ) } } +BOOL hb_znetInetInitialize( PHB_ITEM pItem, PHB_ZNETSTREAM pStream, + HB_INET_RFUNC recvFunc, + HB_INET_SFUNC sendFunc, + HB_INET_FFUNC flushFunc, + HB_INET_CFUNC cleanFunc ) +{ + PHB_SOCKET_STRUCT socket = ( PHB_SOCKET_STRUCT ) hb_itemGetPtrGC( pItem, &s_gcInetFuncs ); + + if( socket ) + { + hb_inetCloseStream( socket ); + + socket->recvFunc = recvFunc; + socket->sendFunc = sendFunc; + socket->flushFunc = flushFunc; + socket->cleanFunc = cleanFunc; + socket->stream = pStream; + return TRUE; + } + + hb_inetErrRT(); + return FALSE; +} + HB_FUNC( HB_INETINIT ) { int ret; @@ -568,8 +611,13 @@ static long s_inetRecv( PHB_SOCKET_STRUCT socket, char * buffer, long size, BOOL if( socket->buffer == NULL ) socket->buffer = ( char * ) hb_xgrab( socket->readahead ); socket->posbuffer = 0; - rec = hb_socketRecv( socket->sd, socket->buffer, socket->readahead, - 0, socket->iTimeout ); + if( socket->recvFunc ) + rec = socket->recvFunc( socket->stream, socket->sd, + socket->buffer, socket->readahead, + socket->iTimeout ); + else + rec = hb_socketRecv( socket->sd, socket->buffer, socket->readahead, + 0, socket->iTimeout ); socket->inbuffer = HB_MAX( 0, rec ); } else @@ -583,13 +631,25 @@ static long s_inetRecv( PHB_SOCKET_STRUCT socket, char * buffer, long size, BOOL socket->inbuffer -= rec; if( size > rec && !readahead ) { - size = hb_socketRecv( socket->sd, buffer + rec, size - rec, 0, 0 ); + if( socket->recvFunc ) + rec = socket->recvFunc( socket->stream, socket->sd, + buffer + rec, size - rec, + socket->iTimeout ); + else + size = hb_socketRecv( socket->sd, buffer + rec, size - rec, 0, 0 ); + if( size > 0 ) rec += size; } } else if( !readahead ) - rec = hb_socketRecv( socket->sd, buffer, size, 0, socket->iTimeout ); + { + if( socket->recvFunc ) + rec = socket->recvFunc( socket->stream, socket->sd, + buffer, size, socket->iTimeout ); + else + rec = hb_socketRecv( socket->sd, buffer, size, 0, socket->iTimeout ); + } return rec; } @@ -926,8 +986,13 @@ static void s_inetSendInternal( BOOL lAll ) iSent = iLen = 0; while( iSent < iSend ) { - iLen = hb_socketSend( socket->sd, buffer + iSent, iSend - iSent, 0, - socket->iTimeout ); + if( socket->sendFunc ) + iLen = socket->sendFunc( socket->stream, socket->sd, + buffer + iSent, iSend - iSent, + socket->iTimeout ); + else + iLen = hb_socketSend( socket->sd, buffer + iSent, iSend - iSent, + 0, socket->iTimeout ); if( iLen > 0 ) { iSent += iLen; diff --git a/harbour/src/rtl/hbznet.c b/harbour/src/rtl/hbznet.c new file mode 100644 index 0000000000..0ee07c7f3f --- /dev/null +++ b/harbour/src/rtl/hbznet.c @@ -0,0 +1,261 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * ZLIB compression for Harbour stream sockets + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#define _HB_ZNET_INTERNAL_ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapierr.h" +#include "hbsocket.h" +#include "hbznet.h" +#include "hbzlib.ch" + +#include +#include + +typedef struct _HB_ZNETSTREAM +{ + z_stream rd; /* input stream */ + z_stream wr; /* output stream */ + int err; /* error code for last stream operation */ + Bytef * inbuf; /* input buffer */ + Bytef * outbuf; /* output buffer */ +} +HB_ZNETSTREAM; + +#define HB_ZNET_BUFSIZE 16384 + +/* return status of last compression/decompression operation */ +int hb_znetError( PHB_ZNETSTREAM pStream ) +{ + return pStream->err; +} + +/* release stream structure + */ +void hb_znetClose( PHB_ZNETSTREAM pStream ) +{ + if( pStream->inbuf ) + hb_xfree( pStream->inbuf ); + + if( pStream->outbuf ) + hb_xfree( pStream->outbuf ); + + deflateEnd( &pStream->wr ); + inflateEnd( &pStream->rd ); + + hb_xfree( pStream ); +} + +/* create new stream structure + */ +PHB_ZNETSTREAM hb_znetOpen( int level, int strategy ) +{ + PHB_ZNETSTREAM pStream = ( PHB_ZNETSTREAM ) hb_xgrab( sizeof( HB_ZNETSTREAM ) ); + + memset( pStream, 0, sizeof( HB_ZNETSTREAM ) ); + + if( deflateInit2( &pStream->wr, level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy ) == Z_OK ) + { + pStream->wr.next_out = pStream->outbuf = ( Bytef * ) hb_xgrab( HB_ZNET_BUFSIZE ); + pStream->wr.avail_out = HB_ZNET_BUFSIZE; + + pStream->rd.next_in = pStream->inbuf = ( Bytef * ) hb_xgrab( HB_ZNET_BUFSIZE ); + if( inflateInit2( &pStream->rd, -MAX_WBITS ) == Z_OK ) + return pStream; + } + + hb_znetClose( pStream ); + return NULL; +} + +/* read data using stream structure + */ +long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_LONG timeout ) +{ + long rec = 0; + + pStream->rd.next_out = ( Bytef * ) buffer; + pStream->rd.avail_out = ( uInt ) len; + pStream->err = Z_OK; + + while( pStream->rd.avail_out ) + { + if( pStream->rd.avail_in == 0 && pStream->err == Z_STREAM_END ) + { + if( pStream->rd.avail_out != ( uInt ) len ) + timeout = 0; + rec = hb_socketRecv( sd, pStream->inbuf, HB_ZNET_BUFSIZE, 0, timeout ); + if( rec <= 0 ) + break; + pStream->rd.avail_in = ( uInt ) rec; + pStream->rd.next_in = pStream->inbuf; + rec = 0; + } + pStream->err = inflate( &pStream->rd, Z_SYNC_FLUSH ); + if( pStream->err == Z_BUF_ERROR ) + pStream->err = Z_STREAM_END; + if( pStream->err != Z_OK && pStream->err != Z_STREAM_END ) + break; + } + + len -= pStream->rd.avail_out; + + return len == 0 ? rec : len; +} + +/* flush data in stream structure - return number of bytes left in the + * buffer which were not sent + */ +long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG timeout ) +{ + if( pStream->wr.avail_out > 0 ) + pStream->err = deflate( &pStream->wr, Z_SYNC_FLUSH ); + else + pStream->err = Z_OK; + + while( pStream->wr.avail_out < HB_ZNET_BUFSIZE ) + { + long tosnd = HB_ZNET_BUFSIZE - pStream->wr.avail_out; + long snd = hb_socketSend( sd, pStream->outbuf, tosnd, 0, timeout ); + if( snd <= 0 ) + break; + if( snd < tosnd ) + memmove( pStream->outbuf, pStream->outbuf + snd, tosnd - snd ); + pStream->wr.avail_out += ( uInt ) snd; + pStream->wr.next_out = pStream->outbuf + tosnd - snd; + + if( pStream->err == Z_OK ) + pStream->err = deflate( &pStream->wr, Z_SYNC_FLUSH ); + } + + return HB_ZNET_BUFSIZE - pStream->wr.avail_out; +} + +/* write data using stream structure + */ +long hb_znetWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, const void * buffer, long len, HB_LONG timeout ) +{ + long snd = 0; + + pStream->wr.next_in = ( Bytef * ) buffer; + pStream->wr.avail_in = ( uInt ) len; + pStream->err = Z_OK; + + while( pStream->wr.avail_in ) + { + if( pStream->wr.avail_out == 0 ) + { + snd = hb_socketSend( sd, pStream->outbuf, HB_ZNET_BUFSIZE, 0, timeout ); + if( snd <= 0 ) + break; + if( snd < HB_ZNET_BUFSIZE ) + memmove( pStream->outbuf, pStream->outbuf + snd, HB_ZNET_BUFSIZE - snd ); + pStream->wr.avail_out += ( uInt ) snd; + pStream->wr.next_out = pStream->outbuf + HB_ZNET_BUFSIZE - snd; + snd = 0; + } + pStream->err = deflate( &pStream->wr, Z_NO_FLUSH ); + if( pStream->err != Z_OK ) + break; + } + + if( pStream->wr.avail_in == 0 || ( timeout >= 0 && timeout < 10000 && + ( pStream->err == Z_OK || pStream->err == Z_STREAM_END ) ) ) + hb_znetFlush( pStream, sd, timeout < 0 ? timeout : HB_MAX( timeout, 10000 ) ); + + len -= pStream->wr.avail_in; + + return len == 0 ? snd : len; +} + +/* this function is intentionally not in hbinet.c to not create binding + * to ZLIB if user does not use it + */ +HB_FUNC( HB_INETCOMPRESS ) +{ + PHB_ITEM pItem = hb_param( 1, HB_IT_POINTER ); + int iLevel = Z_DEFAULT_COMPRESSION, iStrategy = Z_DEFAULT_STRATEGY, i; + + if( HB_ISNUM( 2 ) ) + { + i = hb_parni( 2 ); + if( i >= Z_NO_COMPRESSION && i <= Z_BEST_COMPRESSION ) + iLevel = i; + } + + if( HB_ISNUM( 3 ) ) + { + i = hb_parni( 3 ); + if( i == Z_FILTERED || + i == Z_HUFFMAN_ONLY || + i == Z_RLE || + i == Z_FIXED ) + iStrategy = i; + } + + if( iLevel == HB_ZLIB_COMPRESSION_DISABLE ) + hb_znetInetInitialize( pItem, NULL, NULL, NULL, NULL, NULL ); + else + { + PHB_ZNETSTREAM pStream = hb_znetOpen( iLevel, iStrategy ); + if( pStream == NULL ) + pItem = NULL; + if( ! hb_znetInetInitialize( pItem, pStream, hb_znetRead, hb_znetWrite, + hb_znetFlush, hb_znetClose ) ) + { + if( pStream ) + hb_znetClose( pStream ); + } + } +}