summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclZlib.c190
1 files changed, 99 insertions, 91 deletions
diff --git a/generic/tclZlib.c b/generic/tclZlib.c
index 6115f41..64c4665 100644
--- a/generic/tclZlib.c
+++ b/generic/tclZlib.c
@@ -13,7 +13,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclZlib.c,v 1.14 2008/12/17 16:47:38 nijtmans Exp $
+ * RCS: @(#) $Id: tclZlib.c,v 1.15 2008/12/18 00:22:50 dkf Exp $
*/
#include "tclInt.h"
@@ -95,7 +95,6 @@ static void ChanWatch(ClientData instanceData, int mask);
static int ChanGetHandle(ClientData instanceData, int direction,
ClientData *handlePtr);
static int ChanBlockMode(ClientData instanceData, int mode);
-static int ChanFlush(ClientData instanceData);
static int ChanHandler(ClientData instanceData,
int interestMask);
static Tcl_Channel ZlibStackChannel(Tcl_Interp *interp, int mode,
@@ -113,9 +112,9 @@ static const Tcl_ChannelType zlibChannelType = {
ChanGetOption,
ChanWatch,
ChanGetHandle,
- NULL, /* close2Proc, */
+ NULL, /* close2Proc */
ChanBlockMode,
- ChanFlush,
+ NULL, /* flushProc */
NULL /*ChanHandler*/,
NULL /* wideSeekProc */
};
@@ -136,10 +135,9 @@ typedef struct {
z_stream outStream; /* Structure used by zlib for compression of
* output. */
char *inBuffer;
- int inAllocated, inUsed, inPos;
+ int inAllocated;
char *outBuffer;
- int outAllocated, outUsed, outPos;
- int flushType;
+ int outAllocated;
GzipHeader inHeader;
GzipHeader outHeader;
@@ -1030,7 +1028,6 @@ Tcl_ZlibStreamGet(
return TCL_ERROR;
}
- /*printf("listLen %d, e==%d, avail_out %d\n", listLen, e, zsh->stream.avail_out);*/
while ((zsh->stream.avail_out > 0) && (e==Z_OK || e==Z_BUF_ERROR)
&& (listLen > 0)) {
/*
@@ -2106,11 +2103,31 @@ ChanClose(
Tcl_Interp *interp)
{
ZlibChannelData *cd = instanceData;
- int e;
+ int e, result = TCL_OK;
if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) {
e = deflateEnd(&cd->inStream);
} else {
+ cd->outStream.avail_in = 0;
+ do {
+ cd->outStream.next_out = (Bytef *) cd->outBuffer;
+ cd->outStream.avail_out = cd->outAllocated;
+ e = deflate(&cd->outStream, Z_FINISH);
+ if (e != Z_OK && e != Z_STREAM_END) {
+ ConvertError(interp, e);
+ result = TCL_ERROR;
+ break;
+ }
+ if (cd->outStream.avail_out != cd->outAllocated) {
+ if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
+ cd->outAllocated - cd->outStream.avail_out) < 0) {
+ Tcl_AppendResult(interp, "error while finalizing file: ",
+ Tcl_PosixError(interp), NULL);
+ result = TCL_ERROR;
+ break;
+ }
+ }
+ } while (e != Z_STREAM_END);
e = inflateEnd(&cd->outStream);
}
@@ -2136,27 +2153,40 @@ ChanInput(
ZlibChannelData *cd = instanceData;
Tcl_DriverInputProc *inProc =
Tcl_ChannelInputProc(Tcl_GetChannelType(cd->parent));
+ int e, read, flush = Z_NO_FLUSH;
if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) {
return inProc(Tcl_GetChannelInstanceData(cd->parent), buf, toRead,
errorCodePtr);
}
-#if 0
- cd->inStream.avail_in = 0;
- do {
- cd->inStream.next_out = (Bytef *) cd->inBuffer;
- cd->inStream.avail_out = cd->inAllocated;
-
- if (inflate(&cd->inStream, Z_SYNC_FLUSH) != Z_OK) {
+ cd->inStream.next_out = (Bytef *) buf;
+ cd->inStream.avail_out = toRead;
+ while (1) {
+ e = inflate(&cd->inStream, flush);
+ if ((e == Z_STREAM_END) || (e==Z_OK && cd->inStream.avail_out==0)) {
+ return toRead - cd->inStream.avail_out;
+ }
+ if (e != Z_OK) {
*errorCodePtr = EINVAL;
- return 0;
+ return -1;
}
- } while (cd->inStream.avail_out > 0);
-#endif
- // TODO
- *errorCodePtr = EINVAL;
- return 0;
+
+ /*
+ * Emptied the buffer of data from the underlying channel. Get some
+ * more.
+ */
+
+ read = Tcl_ReadRaw(cd->parent, cd->inBuffer, cd->inAllocated);
+ if (read < 0) {
+ *errorCodePtr = Tcl_GetErrno();
+ return -1;
+ } else if (read == 0) {
+ flush = Z_SYNC_FLUSH;
+ }
+
+ cd->inStream.next_in = (Bytef *) cd->inBuffer;
+ }
}
static int
@@ -2186,19 +2216,19 @@ ChanOutput(
if (e == Z_OK && cd->outStream.avail_out > 0) {
if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
- (int) cd->outStream.avail_out) < 0) {
+ (int) cd->outAllocated - cd->outStream.avail_out) < 0) {
*errorCodePtr = Tcl_GetErrno();
- return 0;
+ return -1;
}
}
} while (e == Z_OK && cd->outStream.avail_in > 0);
if (e != Z_OK) {
*errorCodePtr = EINVAL;
- return 0;
+ return -1;
}
- return 1;
+ return toWrite - cd->outStream.avail_out;
}
static int
@@ -2211,20 +2241,48 @@ ChanSetOption( /* not used */
ZlibChannelData *cd = instanceData;
Tcl_DriverSetOptionProc *setOptionProc =
Tcl_ChannelSetOptionProc(Tcl_GetChannelType(cd->parent));
- static const char *chanOptions = "flushmode";
+ static const char *chanOptions = "flush";
+ int haveFlushOpt = (cd->mode == TCL_ZLIB_STREAM_DEFLATE);
+
+ if (haveFlushOpt && optionName && strcmp(optionName, "-flush") == 0) {
+ int flushType;
- if (optionName && strcmp(optionName, "-flushmode") == 0) {
if (value[0] == 'f' && strcmp(value, "full") == 0) {
- cd->flushType = Z_FULL_FLUSH;
- return TCL_OK;
+ flushType = Z_FULL_FLUSH;
+ goto doFlush;
}
if (value[0] == 's' && strcmp(value, "sync") == 0) {
- cd->flushType = Z_SYNC_FLUSH;
- return TCL_OK;
+ flushType = Z_SYNC_FLUSH;
+ goto doFlush;
}
- Tcl_AppendResult(interp, "unknown -flushmode \"", value,
+ Tcl_AppendResult(interp, "unknown -flush type \"", value,
"\": must be full or sync", NULL);
return TCL_ERROR;
+
+ doFlush:
+ cd->outStream.avail_in = 0;
+ do {
+ int e;
+
+ cd->outStream.next_out = (Bytef *) cd->outBuffer;
+ cd->outStream.avail_out = cd->outAllocated;
+
+ e = deflate(&cd->outStream, flushType);
+ if (e != Z_OK) {
+ ConvertError(interp, e);
+ return TCL_ERROR;
+ }
+
+ if (cd->outStream.avail_out > 0) {
+ if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
+ (int) cd->outStream.next_out) < 0) {
+ Tcl_AppendResult(interp, "problem flushing channel: ",
+ Tcl_PosixError(interp), NULL);
+ return TCL_ERROR;
+ }
+ }
+ } while (cd->outStream.avail_out > 0);
+ return TCL_OK;
}
if (setOptionProc == NULL) {
@@ -2245,7 +2303,7 @@ ChanGetOption(
ZlibChannelData *cd = instanceData;
Tcl_DriverGetOptionProc *getOptionProc =
Tcl_ChannelGetOptionProc(Tcl_GetChannelType(cd->parent));
- static const char *chanOptions = "crc flushmode header";
+ static const char *chanOptions = "crc header";
/*
* The "crc" option reports the current CRC (calculated with the Adler32
@@ -2276,29 +2334,6 @@ ChanGetOption(
}
/*
- * The "flushmode" option reports how the [flush] command will actually
- * effect the channel.
- */
-
- if (optionName == NULL || strcmp(optionName, "-flushmode") == 0) {
- char *value;
-
- if (cd->flushType == Z_FULL_FLUSH) {
- value = "full";
- } else {
- value = "sync";
- }
-
- if (optionName == NULL) {
- Tcl_DStringAppendElement(dsPtr, "-flushmode");
- Tcl_DStringAppendElement(dsPtr, value);
- } else {
- Tcl_DStringAppend(dsPtr, value, -1);
- return TCL_OK;
- }
- }
-
- /*
* The "header" option, which is only valid on inflating gzip channels,
* reports the header that has been read from the start of the stream.
*/
@@ -2371,34 +2406,6 @@ ChanBlockMode(
}
static int
-ChanFlush(
- ClientData instanceData)
-{
- ZlibChannelData *cd = instanceData;
-
- if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) {
- cd->outStream.avail_in = 0;
- do {
- cd->outStream.next_out = (Bytef *) cd->outBuffer;
- cd->outStream.avail_out = cd->outAllocated;
-
- if (deflate(&cd->outStream, cd->flushType) != Z_OK) {
- Tcl_SetErrno(EINVAL);
- return 0;
- }
-
- if (cd->outStream.avail_out > 0) {
- if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
- (int) cd->outStream.next_out) < 0) {
- return 0;
- }
- }
- } while (cd->outStream.avail_out > 0);
- }
- return 1;
-}
-
-static int
ChanHandler(
ClientData instanceData,
int interestMask)
@@ -2431,16 +2438,17 @@ ZlibStackChannel(
memset(cd, 0, sizeof(ZlibChannelData));
cd->mode = mode;
- cd->flushType = Z_SYNC_FLUSH;
if (format == TCL_ZLIB_FORMAT_GZIP || format == TCL_ZLIB_FORMAT_AUTO) {
if (mode == TCL_ZLIB_STREAM_DEFLATE) {
- int dummy = 0;
+ if (gzipHeaderDictPtr) {
+ int dummy = 0;
- cd->flags |= OUT_HEADER;
- if (GenerateHeader(interp, gzipHeaderDictPtr, &cd->outHeader,
- &dummy) != TCL_OK) {
- goto error;
+ cd->flags |= OUT_HEADER;
+ if (GenerateHeader(interp, gzipHeaderDictPtr, &cd->outHeader,
+ &dummy) != TCL_OK) {
+ goto error;
+ }
}
} else {
cd->flags |= IN_HEADER;