summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/zlib.n41
-rw-r--r--generic/tclZlib.c113
2 files changed, 99 insertions, 55 deletions
diff --git a/doc/zlib.n b/doc/zlib.n
index a78e8e3..0233ba8 100644
--- a/doc/zlib.n
+++ b/doc/zlib.n
@@ -179,15 +179,24 @@ Passes a description of the gzip header to create, in the same format that
.
How hard to compress the data. Must be an integer from 0 (uncompressed) to 9
(maximally compressed).
-'\".TP
-'\"\fB\-limit\fI readaheadLimit\fR
-'\".
-'\"The maximum number of bytes ahead to read.
-'\"\fITODO: not yet implemented!\fR
+.TP
+\fB\-limit\fI readaheadLimit\fR
+.
+The maximum number of bytes ahead to read when decompressing. This defaults to
+1, which ensures that data is always decompressed correctly, but may be
+increased to improve performance. This is more useful when the channel is
+non-blocking.
.PP
Both compressing and decompressing channel transformations add extra
-configuration options that may be accessed through \fBchan configure\fR. Each
-option is either a read-only or a write-only option. The options are:
+configuration options that may be accessed through \fBchan configure\fR. The
+options are:
+.TP
+\fB\-checksum\fI checksum\fR
+.
+This read-only option gets the current checksum for the uncompressed data that
+the compression engine has seen so far. It is valid for both compressing and
+decompressing transforms, but not for the raw inflate and deflate formats. The
+compression algorithm depends on what format is being produced or consumed.
.TP
\fB\-flush\fI type\fR
.
@@ -198,19 +207,19 @@ expensive flush respectively. Flushing degrades the compression ratio, but
makes it easier for a decompressor to recover more of the file in the case of
data corruption.
.TP
-\fB\-checksum\fR
-.
-This read-only option gets the current checksum for the uncompressed data
-that the compression engine has seen so far. It is valid for both
-compressing and decompressing transforms, but not for the raw inflate
-and deflate formats. The compression algorithm depends on what
-format is being produced or consumed.
-.TP
-\fB\-header\fR
+\fB\-header\fI dictionary\fR
.
This read-only option, only valid for decompressing transforms that are
processing gzip-format data, returns the dictionary describing the header read
off the data stream.
+.TP
+\fB\-limit\fI readaheadLimit\fR
+.
+This read-write option is used by decompressing channels to control the
+maximum number of bytes ahead to read from the underlying data source. This
+defaults to 1, which ensures that data is always decompressed correctly, but
+may be increased to improve performance. This is more useful when the channel
+is non-blocking.
.RE
.SS "STREAMING SUBCOMMAND"
.TP
diff --git a/generic/tclZlib.c b/generic/tclZlib.c
index a7c4453..c96594d 100644
--- a/generic/tclZlib.c
+++ b/generic/tclZlib.c
@@ -110,6 +110,8 @@ typedef struct {
int format; /* What format of data is going on the wire.
* Needed so that the correct [fconfigure]
* options can be enabled. */
+ int readAheadLimit; /* The maximum number of bytes to read from
+ * the underlying stream in one go. */
z_stream inStream; /* Structure used by zlib for decompression of
* input. */
z_stream outStream; /* Structure used by zlib for compression of
@@ -2958,7 +2960,7 @@ ZlibTransformInput(
* reading over the border.
*/
- readBytes = Tcl_ReadRaw(cd->parent, cd->inBuffer, 1);
+ readBytes = Tcl_ReadRaw(cd->parent, cd->inBuffer, cd->readAheadLimit);
/*
* Three cases here:
@@ -3131,8 +3133,10 @@ ZlibTransformSetOption( /* not used */
ZlibChannelData *cd = instanceData;
Tcl_DriverSetOptionProc *setOptionProc =
Tcl_ChannelSetOptionProc(Tcl_GetChannelType(cd->parent));
- static const char *chanOptions = "dictionary flush";
+ static const char *compressChanOptions = "dictionary flush";
static const char *gzipChanOptions = "flush";
+ static const char *decompressChanOptions = "dictionary limit";
+ static const char *gunzipChanOptions = "flush limit";
int haveFlushOpt = (cd->mode == TCL_ZLIB_STREAM_DEFLATE);
if (optionName && (strcmp(optionName, "-dictionary") == 0)
@@ -3164,56 +3168,75 @@ ZlibTransformSetOption( /* not used */
return TCL_OK;
}
- if (haveFlushOpt && optionName && strcmp(optionName, "-flush") == 0) {
- int flushType;
+ if (haveFlushOpt) {
+ if (optionName && strcmp(optionName, "-flush") == 0) {
+ int flushType;
- if (value[0] == 'f' && strcmp(value, "full") == 0) {
- flushType = Z_FULL_FLUSH;
- } else if (value[0] == 's' && strcmp(value, "sync") == 0) {
- flushType = Z_SYNC_FLUSH;
- } else {
- Tcl_AppendResult(interp, "unknown -flush type \"", value,
- "\": must be full or sync", NULL);
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "FLUSH", NULL);
- return TCL_ERROR;
- }
+ if (value[0] == 'f' && strcmp(value, "full") == 0) {
+ flushType = Z_FULL_FLUSH;
+ } else if (value[0] == 's' && strcmp(value, "sync") == 0) {
+ flushType = Z_SYNC_FLUSH;
+ } else {
+ Tcl_AppendResult(interp, "unknown -flush type \"", value,
+ "\": must be full or sync", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "FLUSH", NULL);
+ return TCL_ERROR;
+ }
- /*
- * Try to actually do the flush now.
- */
+ /*
+ * Try to actually do the flush now.
+ */
- cd->outStream.avail_in = 0;
- while (1) {
- int e;
+ cd->outStream.avail_in = 0;
+ while (1) {
+ int e;
- cd->outStream.next_out = (Bytef *) cd->outBuffer;
- cd->outStream.avail_out = cd->outAllocated;
+ cd->outStream.next_out = (Bytef *) cd->outBuffer;
+ cd->outStream.avail_out = cd->outAllocated;
- e = deflate(&cd->outStream, flushType);
- if (e == Z_BUF_ERROR) {
- break;
- } else if (e != Z_OK) {
- ConvertError(interp, e, cd->outStream.adler);
- return TCL_ERROR;
- } else if (cd->outStream.avail_out == 0) {
- break;
+ e = deflate(&cd->outStream, flushType);
+ if (e == Z_BUF_ERROR) {
+ break;
+ } else if (e != Z_OK) {
+ ConvertError(interp, e, cd->outStream.adler);
+ return TCL_ERROR;
+ } else if (cd->outStream.avail_out == 0) {
+ break;
+ }
+
+ if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
+ cd->outStream.next_out - (Bytef *) cd->outBuffer)<0) {
+ Tcl_AppendResult(interp, "problem flushing channel: ",
+ Tcl_PosixError(interp), NULL);
+ return TCL_ERROR;
+ }
}
+ return TCL_OK;
+ }
+ } else {
+ if (optionName && strcmp(optionName, "-limit") == 0) {
+ int newLimit;
- if (Tcl_WriteRaw(cd->parent, cd->outBuffer,
- cd->outStream.next_out - (Bytef *) cd->outBuffer) < 0) {
- Tcl_AppendResult(interp, "problem flushing channel: ",
- Tcl_PosixError(interp), NULL);
+ if (Tcl_GetInt(interp, value, &newLimit) != TCL_OK) {
+ return TCL_ERROR;
+ } else if (newLimit < 1 || newLimit > 65535) {
+ Tcl_AppendResult(interp, "-limit must be between 1 and 65535",
+ NULL);
+ Tcl_SetErrorCode(interp, "TCL", "VALUE", "READLIMIT", NULL);
return TCL_ERROR;
}
}
- return TCL_OK;
}
if (setOptionProc == NULL) {
if (cd->format == TCL_ZLIB_FORMAT_GZIP) {
- return Tcl_BadChannelOption(interp, optionName, gzipChanOptions);
+ return Tcl_BadChannelOption(interp, optionName,
+ (cd->mode == TCL_ZLIB_STREAM_DEFLATE)
+ ? gzipChanOptions : gunzipChanOptions);
} else {
- return Tcl_BadChannelOption(interp, optionName, chanOptions);
+ return Tcl_BadChannelOption(interp, optionName,
+ (cd->mode == TCL_ZLIB_STREAM_DEFLATE)
+ ? compressChanOptions : decompressChanOptions);
}
}
@@ -3246,7 +3269,10 @@ ZlibTransformGetOption(
ZlibChannelData *cd = instanceData;
Tcl_DriverGetOptionProc *getOptionProc =
Tcl_ChannelGetOptionProc(Tcl_GetChannelType(cd->parent));
- static const char *chanOptions = "checksum dictionary header";
+ static const char *compressChanOptions = "checksum dictionary";
+ static const char *gzipChanOptions = "checksum";
+ static const char *decompressChanOptions = "checksum dictionary limit";
+ static const char *gunzipChanOptions = "checksum header limit";
/*
* The "crc" option reports the current CRC (calculated with the Adler32
@@ -3331,7 +3357,15 @@ ZlibTransformGetOption(
if (optionName == NULL) {
return TCL_OK;
}
- return Tcl_BadChannelOption(interp, optionName, chanOptions);
+ if (cd->format == TCL_ZLIB_FORMAT_GZIP) {
+ return Tcl_BadChannelOption(interp, optionName,
+ (cd->mode == TCL_ZLIB_STREAM_DEFLATE)
+ ? gzipChanOptions : gunzipChanOptions);
+ } else {
+ return Tcl_BadChannelOption(interp, optionName,
+ (cd->mode == TCL_ZLIB_STREAM_DEFLATE)
+ ? compressChanOptions : decompressChanOptions);
+ }
}
/*
@@ -3496,6 +3530,7 @@ ZlibStackChannelTransform(
memset(cd, 0, sizeof(ZlibChannelData));
cd->mode = mode;
cd->format = format;
+ cd->readAheadLimit = 1;
if (format == TCL_ZLIB_FORMAT_GZIP || format == TCL_ZLIB_FORMAT_AUTO) {
if (mode == TCL_ZLIB_STREAM_DEFLATE) {