Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch bug-3525907 Excluding Merge-Ins
This is equivalent to a diff from ba6087ec84 to 8971a30409
2012-05-23
| ||
13:13 | * generic/tclZlib.c (ZlibTransformInput): [Bug 3525907]: Ensure that decompressed input is flushed t... check-in: 0252132d3a user: dkf tags: trunk | |
2012-05-22
| ||
20:28 | Use zero-delays instead of finite ones when posting fileevents, because (1) they should be zero in t... Closed-Leaf check-in: 8971a30409 user: ferrieux tags: bug-3525907 | |
2012-05-20
| ||
20:46 | Add test showing both loss of bytes and empty-fileevent frenzy. check-in: 1897b2023d user: ferrieux tags: bug-3525907 | |
07:58 |
* generic/tclOOBasic.c (TclOO_Class_Constructor): [Bug 2023112]: Cut the amount of hackiness in cl...check-in: 5855f07bc4 user: dkf tags: trunk | |
2012-05-17
| ||
21:47 | Brought bugfix branch uptodate with head development. check-in: c003b262df user: andreask tags: bug-3525907 | |
17:26 | merge trunk check-in: 22b8f68842 user: dkf tags: tip-400-impl | |
17:20 | Cancel the timeout timers! If this isn't done, lingering timers from early tests can trigger false... check-in: ba6087ec84 user: dgp tags: trunk | |
16:43 |
* generic/tclCmdMZ.c (Tcl_SwitchObjCmd): [Bug 3106532]: Corrected resulting indexes from -indexvar...check-in: 0fb04d2cdf user: dkf tags: trunk, potential incompatibility | |
Changes to generic/tclIORTrans.c.
︙ | ︙ | |||
434 435 436 437 438 439 440 | static const char *msg_dstlost = "-code 1 -level 0 -errorcode NONE -errorinfo {} -errorline 1 {Owner lost}"; /* * Timer management (flushing out buffered data via artificial events). */ | < < < < < < < | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | static const char *msg_dstlost = "-code 1 -level 0 -errorcode NONE -errorinfo {} -errorline 1 {Owner lost}"; /* * Timer management (flushing out buffered data via artificial events). */ /* * Helper functions encapsulating some of the thread forwarding to make the * control flow in callers easier. */ static void TimerKill(ReflectedTransform *rtPtr); static void TimerSetup(ReflectedTransform *rtPtr); |
︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 | } /* *---------------------------------------------------------------------- * * ReflectOutput -- * | | | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | } /* *---------------------------------------------------------------------- * * ReflectOutput -- * * This function is invoked when data is written to the channel. * * Results: * The number of bytes actually written. * * Side effects: * Allocates memory. Arbitrary, as it calls upon a script. * |
︙ | ︙ | |||
2857 2858 2859 2860 2861 2862 2863 | TimerSetup( ReflectedTransform *rtPtr) { if (rtPtr->timer != NULL) { return; } | | | 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 | TimerSetup( ReflectedTransform *rtPtr) { if (rtPtr->timer != NULL) { return; } rtPtr->timer = Tcl_CreateTimerHandler(0, TimerRun, rtPtr); } /* *---------------------------------------------------------------------- * * TimerRun -- * |
︙ | ︙ |
Changes to generic/tclZlib.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #ifdef HAVE_ZLIB #include <zlib.h> /* * Magic flags used with wbits fields to indicate that we're handling the gzip * format or automatic detection of format. Putting it here is slightly less * gross! */ | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #ifdef HAVE_ZLIB #include <zlib.h> #include "tclIO.h" /* * Magic flags used with wbits fields to indicate that we're handling the gzip * format or automatic detection of format. Putting it here is slightly less * gross! */ |
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | int inAllocated, outAllocated; /* Sizes of working buffers. */ GzipHeader inHeader; /* Header read from input stream, when * decompressing a gzip stream. */ GzipHeader outHeader; /* Header to write to an output stream, when * compressing a gzip stream. */ Tcl_TimerToken timer; /* Timer used for keeping events fresh. */ } ZlibChannelData; /* * Value bits for the flags field. Definitions are: * ASYNC - Whether this is an asynchronous channel. * IN_HEADER - Whether the inHeader field has been registered with * the input compressor. | > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | int inAllocated, outAllocated; /* Sizes of working buffers. */ GzipHeader inHeader; /* Header read from input stream, when * decompressing a gzip stream. */ GzipHeader outHeader; /* Header to write to an output stream, when * compressing a gzip stream. */ Tcl_TimerToken timer; /* Timer used for keeping events fresh. */ Tcl_DString result; /* Buffer for decompression results */ } ZlibChannelData; /* * Value bits for the flags field. Definitions are: * ASYNC - Whether this is an asynchronous channel. * IN_HEADER - Whether the inHeader field has been registered with * the input compressor. |
︙ | ︙ | |||
108 109 110 111 112 113 114 | /* * Size of buffers allocated by default. Should be enough... */ #define DEFAULT_BUFFER_SIZE 4096 /* | | < | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | /* * Size of buffers allocated by default. Should be enough... */ #define DEFAULT_BUFFER_SIZE 4096 /* * Convenience macro to make some casts easier to use. */ #define UCHARP(x) ((unsigned char *) (x)) /* * Prototypes for private procedures defined later in this file: */ static Tcl_CmdDeleteProc ZlibStreamCmdDelete; static Tcl_DriverBlockModeProc ZlibTransformBlockMode; |
︙ | ︙ | |||
143 144 145 146 147 148 149 150 151 152 153 154 155 156 | int mode, int format, int level, Tcl_Channel channel, Tcl_Obj *gzipHeaderDictPtr); static void ZlibStreamCleanup(ZlibStreamHandle *zshPtr); static void ZlibTransformTimerKill(ZlibChannelData *cd); static void ZlibTransformTimerRun(ClientData clientData); static void ZlibTransformTimerSetup(ZlibChannelData *cd); /* * Type of zlib-based compressing and decompressing channels. */ static const Tcl_ChannelType zlibChannelType = { "zlib", TCL_CHANNEL_VERSION_3, | > > > | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | int mode, int format, int level, Tcl_Channel channel, Tcl_Obj *gzipHeaderDictPtr); static void ZlibStreamCleanup(ZlibStreamHandle *zshPtr); static void ZlibTransformTimerKill(ZlibChannelData *cd); static void ZlibTransformTimerRun(ClientData clientData); static void ZlibTransformTimerSetup(ZlibChannelData *cd); static int ResultCopy(Tcl_DString* r, unsigned char *buf, int toRead); static int ResultGenerate(ZlibChannelData *cd, int n, int flush, int* errorCodePtr); /* * Type of zlib-based compressing and decompressing channels. */ static const Tcl_ChannelType zlibChannelType = { "zlib", TCL_CHANNEL_VERSION_3, |
︙ | ︙ | |||
2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 | e = inflateEnd(&cd->inStream); } /* * Release all memory. */ if (cd->inBuffer) { ckfree(cd->inBuffer); cd->inBuffer = NULL; } if (cd->outBuffer) { ckfree(cd->outBuffer); cd->outBuffer = NULL; | > > | 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 | e = inflateEnd(&cd->inStream); } /* * Release all memory. */ Tcl_DStringFree (&cd->result); if (cd->inBuffer) { ckfree(cd->inBuffer); cd->inBuffer = NULL; } if (cd->outBuffer) { ckfree(cd->outBuffer); cd->outBuffer = NULL; |
︙ | ︙ | |||
2338 2339 2340 2341 2342 2343 2344 | char *buf, int toRead, int *errorCodePtr) { ZlibChannelData *cd = instanceData; Tcl_DriverInputProc *inProc = Tcl_ChannelInputProc(Tcl_GetChannelType(cd->parent)); | | < < < | < | < < < < < < < < < > > < < | < < < > | > < | | < < < | < < > | > | < | | < < < < < < | > | > > > > > > > > > > > > > > > > > | | > > > > > > > > > | > > > > | > > > | > > > > > > > > | > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 | char *buf, int toRead, int *errorCodePtr) { ZlibChannelData *cd = instanceData; Tcl_DriverInputProc *inProc = Tcl_ChannelInputProc(Tcl_GetChannelType(cd->parent)); int readBytes, gotBytes, copied; if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) { return inProc(Tcl_GetChannelInstanceData(cd->parent), buf, toRead, errorCodePtr); } gotBytes = 0; while (toRead > 0) { /* * Loop until the request is satisfied (or no data available from * below, possibly EOF). */ copied = ResultCopy(&cd->result, UCHARP(buf), toRead); toRead -= copied; buf += copied; gotBytes += copied; if (toRead == 0) { goto stop; } /* * The buffer is exhausted, but the caller wants even more. We now * have to go to the underlying channel, get more bytes and then * transform them for delivery. We may not get what we want (full EOF * or temporarily out of data). * * Length (cd->result) == 0, toRead > 0 here. * * The zlib transform allows us to read at most one character from the * underlying channel to properly identify Z_STREAM_END without * reading over the border. */ readBytes = Tcl_ReadRaw(cd->parent, cd->inBuffer, 1); if (readBytes < 0) { /* * Report errors to caller. The state of the seek system is * unchanged! */ if ((Tcl_GetErrno() == EAGAIN) && (gotBytes > 0)) { /* * EAGAIN is a special situation. If we had some data before * we report that instead of the request to re-try. */ goto stop; } *errorCodePtr = Tcl_GetErrno(); goto error; } if (readBytes == 0) { /* * Check wether we hit on EOF in 'parent' or not. If not * differentiate between blocking and non-blocking modes. In * non-blocking mode we ran temporarily out of data. Signal this * to the caller via EWOULDBLOCK and error return (-1). In the * other cases we simply return what we got and let the caller * wait for more. On the other hand, if we got an EOF we have to * convert and flush all waiting partial data. */ if (!Tcl_Eof(cd->parent)) { /* * The state of the seek system is unchanged! */ if ((gotBytes == 0) && (cd->flags & ASYNC)) { *errorCodePtr = EWOULDBLOCK; goto error; } goto stop; } else { /* * (Semi-)Eof in parent. * * Now this is a bit different. The partial data waiting is * converted and returned. */ if (ResultGenerate (cd, 0, Z_SYNC_FLUSH, errorCodePtr) < 0) { goto error; } if (Tcl_DStringLength(&cd->result) == 0) { /* * The drain delivered nothing. */ goto stop; } /* * Reset eof, force caller to drain result buffer. */ ((Channel *) cd->parent)->state->flags &= ~CHANNEL_EOF; continue; /* at: while (toRead > 0) */ } } /* readBytes == 0 */ /* * Transform the read chunk, which was not empty. Anything we get back * is a transformation result to be put into our buffers, and the next * iteration will put it into the result. */ if (ResultGenerate (cd, readBytes, Z_NO_FLUSH, errorCodePtr) < 0) { goto error; } } /* while toRead > 0 */ stop: return gotBytes; error: gotBytes = -1; goto stop; } static int ZlibTransformOutput( ClientData instanceData, const char *buf, int toWrite, |
︙ | ︙ | |||
2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 | return TCL_OK; } if (setOptionProc == NULL) { return Tcl_BadChannelOption(interp, optionName, chanOptions); } return setOptionProc(Tcl_GetChannelInstanceData(cd->parent), interp, optionName, value); } static int ZlibTransformGetOption( ClientData instanceData, | > > > > > | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 | return TCL_OK; } if (setOptionProc == NULL) { return Tcl_BadChannelOption(interp, optionName, chanOptions); } /* * Pass all unknown options down, to deeper transforms and/or the base * channel. */ return setOptionProc(Tcl_GetChannelInstanceData(cd->parent), interp, optionName, value); } static int ZlibTransformGetOption( ClientData instanceData, |
︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 | /* * This code is based on the code in tclIORTrans.c */ watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(cd->parent)); watchProc(Tcl_GetChannelInstanceData(cd->parent), mask); | > | < > | 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 | /* * This code is based on the code in tclIORTrans.c */ watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(cd->parent)); watchProc(Tcl_GetChannelInstanceData(cd->parent), mask); if (!(mask & TCL_READABLE) || (Tcl_DStringLength(&cd->result) == 0)) { ZlibTransformTimerKill(cd); } else { ZlibTransformTimerSetup(cd); } } static int |
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 | } static void ZlibTransformTimerSetup( ZlibChannelData *cd) { if (cd->timer == NULL) { | | | 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 | } static void ZlibTransformTimerSetup( ZlibChannelData *cd) { if (cd->timer == NULL) { cd->timer = Tcl_CreateTimerHandler(0, ZlibTransformTimerRun, cd); } } static void ZlibTransformTimerKill( ZlibChannelData *cd) |
︙ | ︙ | |||
2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | if (cd->flags & OUT_HEADER) { e = deflateSetHeader(&cd->outStream, &cd->outHeader.header); if (e != Z_OK) { goto error; } } } chan = Tcl_StackChannel(interp, &zlibChannelType, cd, Tcl_GetChannelMode(channel), channel); if (chan == NULL) { goto error; } cd->chan = chan; | > > | 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 | if (cd->flags & OUT_HEADER) { e = deflateSetHeader(&cd->outStream, &cd->outHeader.header); if (e != Z_OK) { goto error; } } } Tcl_DStringInit(&cd->result); chan = Tcl_StackChannel(interp, &zlibChannelType, cd, Tcl_GetChannelMode(channel), channel); if (chan == NULL) { goto error; } cd->chan = chan; |
︙ | ︙ | |||
2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 | if (cd->outBuffer) { ckfree(cd->outBuffer); deflateEnd(&cd->outStream); } ckfree(cd); return NULL; } /* *---------------------------------------------------------------------- * Finally, the TclZlibInit function. Used to install the zlib API. *---------------------------------------------------------------------- */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 | if (cd->outBuffer) { ckfree(cd->outBuffer); deflateEnd(&cd->outStream); } ckfree(cd); return NULL; } /* *---------------------------------------------------------------------- * * ResultCopy -- * * Copies the requested number of bytes from the buffer into the * specified array and removes them from the buffer afterward. Copies * less if there is not enough data in the buffer. * * Side effects: * See above. * * Result: * The number of actually copied bytes, possibly less than 'toRead'. * *---------------------------------------------------------------------- */ static int ResultCopy( Tcl_DString* ds, /* The buffer to read from */ unsigned char *buf, /* The buffer to copy into */ int toRead) /* Number of requested bytes */ { int copied; int have = Tcl_DStringLength (ds); if (have == 0) { /* * Nothing to copy in the case of an empty buffer. */ copied = 0; } else if (have > toRead) { /* * The internal buffer contains more than requested. Copy the * requested subset to the caller, shift the remaining bytes down, and * truncate. */ char* src = Tcl_DStringValue (ds); memcpy(buf, src, toRead); memmove(src, src + toRead, have - toRead); Tcl_DStringSetLength (ds, have - toRead); copied = toRead; } else /* have <= toRead */ { /* * There is just or not enough in the buffer to fully satisfy the * caller, so take everything as best effort. */ memcpy(buf, Tcl_DStringValue (ds), have); Tcl_DStringSetLength (ds, 0); copied = have; } /* -- common postwork code ------- */ return copied; } static int ResultGenerate(ZlibChannelData *cd, int n, int flush, int* errorCodePtr) { #define MAXBUF 1024 unsigned char buf [MAXBUF]; int e, written; cd->inStream.next_in = (Bytef *) cd->inBuffer; cd->inStream.avail_in = n; while (1) { cd->inStream.next_out = (Bytef *) buf; cd->inStream.avail_out = MAXBUF; e = inflate(&cd->inStream, flush); /* * avail_out is now the left over space in the output. * Therefore "MAXBUF - avail_out" is the amount of bytes * generated. */ written = MAXBUF - cd->inStream.avail_out; if (written) { Tcl_DStringAppend (&cd->result, (char*) buf, written); } if (((flush == Z_SYNC_FLUSH) && (e == Z_BUF_ERROR)) || (e == Z_STREAM_END) || (e==Z_OK && cd->inStream.avail_out==0)) { break; } /* * Z_BUF_ERROR can be ignored as per http://www.zlib.net/zlib_how.html * * Just indicates that the zlib couldn't consume input/produce output, * and is fixed by supplying more input. */ if ((e != Z_OK) && (e != Z_BUF_ERROR)) { Tcl_Obj *errObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(NULL, errObj, Tcl_NewStringObj(cd->inStream.msg, -1)); Tcl_SetChannelError(cd->parent, errObj); *errorCodePtr = EINVAL; return -1; } /* * Check if the inflate stopped early. */ if (cd->inStream.avail_in > 0) { continue; } if (flush == Z_SYNC_FLUSH) { continue; } break; } return 0; } /* *---------------------------------------------------------------------- * Finally, the TclZlibInit function. Used to install the zlib API. *---------------------------------------------------------------------- */ |
︙ | ︙ |
Changes to tests/zlib.test.
︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 | puts $fd "qwertyuiop" fconfigure $fd -flush sync puts $fd "qwertyuiop" } -cleanup { catch {close $fd} removeFile $file } -result {} test zlib-9.1 "check fcopy with push" -constraints zlib -setup { set sfile [makeFile {} testsrc.gz] set file [makeFile {} test.gz] set f [open $sfile wb] puts -nonewline $f [zlib gzip [string repeat a 81920]] close $f | > > > > > > > > > > > > > > > > > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | puts $fd "qwertyuiop" fconfigure $fd -flush sync puts $fd "qwertyuiop" } -cleanup { catch {close $fd} removeFile $file } -result {} test zlib-8.5 {transformation and flushing and fileevents: Bug 3525907} -setup { foreach {r w} [chan pipe] break } -constraints zlib -body { set ::res {} fconfigure $w -buffering none zlib push compress $w puts -nonewline $w qwertyuiop chan configure $w -flush sync after 500 {puts -nonewline $w asdfghjkl;close $w} fconfigure $r -blocking 0 -buffering none zlib push decompress $r fileevent $r readable {set msg [read $r];lappend ::res $msg;if {[eof $r]} {set ::done 1}} after 250 {lappend ::res MIDDLE} vwait ::done set ::res } -cleanup { catch {close $r} } -result {qwertyuiop MIDDLE asdfghjkl} test zlib-9.1 "check fcopy with push" -constraints zlib -setup { set sfile [makeFile {} testsrc.gz] set file [makeFile {} test.gz] set f [open $sfile wb] puts -nonewline $f [zlib gzip [string repeat a 81920]] close $f |
︙ | ︙ |