Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | minor: Cleaning up code, adding comments. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
f44eb823c80cc55db2a2f997e2cbc285 |
User & Date: | dkf 2012-05-24 09:54:19 |
Context
2012-05-24
| ||
10:54 | Revert most of [3caedf05df], since when we let cygwin share the win32 stub table this is no longer n... check-in: 3873dc6035 user: jan.nijtmans tags: trunk | |
10:05 | merge trunk check-in: baf67cf0df user: dkf tags: tip-400-impl | |
09:54 | minor: Cleaning up code, adding comments. check-in: f44eb823c8 user: dkf tags: trunk | |
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 | |
Changes
Changes to generic/tclZlib.c.
︙ | ︙ | |||
87 88 89 90 91 92 93 | 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. */ | | | 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 decompressed; /* 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. |
︙ | ︙ | |||
110 111 112 113 114 115 116 | /* * 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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | /* * Size of buffers allocated by default. Should be enough... */ #define DEFAULT_BUFFER_SIZE 4096 /* * Time to wait before delivering a timer event. */ #define TRANSFORM_TIMEOUT 0 /* * Prototypes for private procedures defined later in this file: */ static Tcl_CmdDeleteProc ZlibStreamCmdDelete; static Tcl_DriverBlockModeProc ZlibTransformBlockMode; static Tcl_DriverCloseProc ZlibTransformClose; static Tcl_DriverGetHandleProc ZlibTransformGetHandle; static Tcl_DriverGetOptionProc ZlibTransformGetOption; static Tcl_DriverHandlerProc ZlibTransformEventHandler; static Tcl_DriverInputProc ZlibTransformInput; static Tcl_DriverOutputProc ZlibTransformOutput; static Tcl_DriverSetOptionProc ZlibTransformSetOption; static Tcl_DriverWatchProc ZlibTransformWatch; static Tcl_ObjCmdProc ZlibCmd; static Tcl_ObjCmdProc ZlibStreamCmd; static void ConvertError(Tcl_Interp *interp, int code); static void ExtractHeader(gz_header *headerPtr, Tcl_Obj *dictObj); static int GenerateHeader(Tcl_Interp *interp, Tcl_Obj *dictObj, GzipHeader *headerPtr, int *extraSizePtr); static inline int ResultCopy(ZlibChannelData *cd, char *buf, int toRead); static int ResultGenerate(ZlibChannelData *cd, int n, int flush, int *errorCodePtr); static Tcl_Channel ZlibStackChannelTransform(Tcl_Interp *interp, int mode, int format, int level, Tcl_Channel channel, Tcl_Obj *gzipHeaderDictPtr); static void ZlibStreamCleanup(ZlibStreamHandle *zshPtr); static inline void ZlibTransformEventTimerKill(ZlibChannelData *cd); static void ZlibTransformTimerRun(ClientData clientData); /* * Type of zlib-based compressing and decompressing channels. */ static const Tcl_ChannelType zlibChannelType = { "zlib", TCL_CHANNEL_VERSION_3, ZlibTransformClose, ZlibTransformInput, ZlibTransformOutput, NULL, /* seekProc */ ZlibTransformSetOption, ZlibTransformGetOption, ZlibTransformWatch, ZlibTransformGetHandle, NULL, /* close2Proc */ ZlibTransformBlockMode, NULL, /* flushProc */ ZlibTransformEventHandler, NULL, /* wideSeekProc */ NULL, NULL }; /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 | return TCL_OK; } /* *---------------------------------------------------------------------- * Set of functions to support channel stacking. *---------------------------------------------------------------------- */ static int ZlibTransformClose( ClientData instanceData, Tcl_Interp *interp) { ZlibChannelData *cd = instanceData; int e, result = TCL_OK; /* * Delete the support timer. */ | > > > > > > | | 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 | return TCL_OK; } /* *---------------------------------------------------------------------- * Set of functions to support channel stacking. *---------------------------------------------------------------------- * * ZlibTransformClose -- * * How to shut down a stacked compressing/decompressing transform. * *---------------------------------------------------------------------- */ static int ZlibTransformClose( ClientData instanceData, Tcl_Interp *interp) { ZlibChannelData *cd = instanceData; int e, result = TCL_OK; /* * Delete the support timer. */ ZlibTransformEventTimerKill(cd); /* * Flush any data waiting to be compressed. */ if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) { cd->outStream.avail_in = 0; |
︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 | e = inflateEnd(&cd->inStream); } /* * Release all memory. */ | | > > > > > > > > > > | 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 | e = inflateEnd(&cd->inStream); } /* * Release all memory. */ Tcl_DStringFree(&cd->decompressed); if (cd->inBuffer) { ckfree(cd->inBuffer); cd->inBuffer = NULL; } if (cd->outBuffer) { ckfree(cd->outBuffer); cd->outBuffer = NULL; } ckfree(cd); return result; } /* *---------------------------------------------------------------------- * * ZlibTransformInput -- * * Reader filter that does decompression. * *---------------------------------------------------------------------- */ static int ZlibTransformInput( ClientData instanceData, char *buf, int toRead, int *errorCodePtr) |
︙ | ︙ | |||
2359 2360 2361 2362 2363 2364 2365 | gotBytes = 0; while (toRead > 0) { /* * Loop until the request is satisfied (or no data available from * below, possibly EOF). */ | | | | > > > > > > > > > > | < < | | | | | > | | | | | | | | | | | | | > | | | | | | | < < | < | | | | | | | > | < | < > | < < < | > > > > > > > > > | 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 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 | gotBytes = 0; while (toRead > 0) { /* * Loop until the request is satisfied (or no data available from * below, possibly EOF). */ copied = ResultCopy(cd, buf, toRead); toRead -= copied; buf += copied; gotBytes += copied; if (toRead == 0) { return gotBytes; } /* * 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->decompressed) == 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); /* * Three cases here: * 1. Got some data from the underlying channel (readBytes > 0) so * it should be fed through the decompression engine. * 2. Got an error (readBytes < 0) which we should report up except * for the case where we can convert it to a short read. * 3. Got an end-of-data from EOF or blocking (readBytes == 0). If * it is EOF, try flushing the data out of the decompressor. */ 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. */ return gotBytes; } *errorCodePtr = Tcl_GetErrno(); return -1; } else 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; return -1; } return gotBytes; } /* * (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) != TCL_OK) { return -1; } if (Tcl_DStringLength(&cd->decompressed) == 0) { /* * The drain delivered nothing. Time to deliver what we've * got. */ return gotBytes; } /* * Reset eof, force caller to drain result buffer. */ ((Channel *) cd->parent)->state->flags &= ~CHANNEL_EOF; } else /* 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) != TCL_OK) { return -1; } } } return gotBytes; } /* *---------------------------------------------------------------------- * * ZlibTransformOutput -- * * Writer filter that does compression. * *---------------------------------------------------------------------- */ static int ZlibTransformOutput( ClientData instanceData, const char *buf, int toWrite, int *errorCodePtr) |
︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 | Tcl_NewStringObj(cd->outStream.msg, -1)); *errorCodePtr = EINVAL; return -1; } return toWrite - cd->outStream.avail_in; } static int ZlibTransformSetOption( /* not used */ ClientData instanceData, Tcl_Interp *interp, const char *optionName, const char *value) | > > > > > > > > > > | 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 | Tcl_NewStringObj(cd->outStream.msg, -1)); *errorCodePtr = EINVAL; return -1; } return toWrite - cd->outStream.avail_in; } /* *---------------------------------------------------------------------- * * ZlibTransformSetOption -- * * Writing side of [fconfigure] on our channel. * *---------------------------------------------------------------------- */ static int ZlibTransformSetOption( /* not used */ ClientData instanceData, Tcl_Interp *interp, const char *optionName, const char *value) |
︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 | ConvertError(interp, e); return TCL_ERROR; } else if (cd->outStream.avail_out == 0) { break; } if (Tcl_WriteRaw(cd->parent, cd->outBuffer, | | > > > > > > > > > > | 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 | ConvertError(interp, e); 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; } 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); } /* *---------------------------------------------------------------------- * * ZlibTransformGetOption -- * * Reading side of [fconfigure] on our channel. * *---------------------------------------------------------------------- */ static int ZlibTransformGetOption( ClientData instanceData, Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr) |
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 | interp, optionName, dsPtr); } if (optionName == NULL) { return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, chanOptions); } static void ZlibTransformWatch( ClientData instanceData, int mask) { ZlibChannelData *cd = instanceData; Tcl_DriverWatchProc *watchProc; /* * This code is based on the code in tclIORTrans.c */ watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(cd->parent)); watchProc(Tcl_GetChannelInstanceData(cd->parent), mask); | > > > > > > > > > > > | < < < < < < < < | < < < < < | < < | < | < < < < | < < < < | < | < | | | < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | interp, optionName, dsPtr); } if (optionName == NULL) { return TCL_OK; } return Tcl_BadChannelOption(interp, optionName, chanOptions); } /* *---------------------------------------------------------------------- * * ZlibTransformWatch, ZlibTransformEventHandler -- * * If we have data pending, trigger a readable event after a short time * (in order to allow a real event to catch up). * *---------------------------------------------------------------------- */ static void ZlibTransformWatch( ClientData instanceData, int mask) { ZlibChannelData *cd = instanceData; Tcl_DriverWatchProc *watchProc; /* * 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->decompressed) == 0) { ZlibTransformEventTimerKill(cd); } else if (cd->timer == NULL) { cd->timer = Tcl_CreateTimerHandler(TRANSFORM_TIMEOUT, ZlibTransformTimerRun, cd); } } static int ZlibTransformEventHandler( ClientData instanceData, int interestMask) { ZlibChannelData *cd = instanceData; ZlibTransformEventTimerKill(cd); return interestMask; } static inline void ZlibTransformEventTimerKill( ZlibChannelData *cd) { if (cd->timer != NULL) { Tcl_DeleteTimerHandler(cd->timer); cd->timer = NULL; } } static void ZlibTransformTimerRun( ClientData clientData) { ZlibChannelData *cd = clientData; cd->timer = NULL; Tcl_NotifyChannel(cd->chan, TCL_READABLE); } /* *---------------------------------------------------------------------- * * ZlibTransformGetHandle -- * * Anything that needs the OS handle is told to get it from what we are * stacked on top of. * *---------------------------------------------------------------------- */ static int ZlibTransformGetHandle( ClientData instanceData, int direction, ClientData *handlePtr) { ZlibChannelData *cd = instanceData; return Tcl_GetChannelHandle(cd->parent, direction, handlePtr); } /* *---------------------------------------------------------------------- * * ZlibTransformBlockMode -- * * We need to keep track of the blocking mode; it changes our behavior. * *---------------------------------------------------------------------- */ static int ZlibTransformBlockMode( ClientData instanceData, int mode) { ZlibChannelData *cd = instanceData; if (mode == TCL_MODE_NONBLOCKING) { cd->flags |= ASYNC; } else { cd->flags &= ~ASYNC; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ZlibStackChannelTransform -- * * Stacks either compression or decompression onto a channel. |
︙ | ︙ | |||
2866 2867 2868 2869 2870 2871 2872 | e = deflateSetHeader(&cd->outStream, &cd->outHeader.header); if (e != Z_OK) { goto error; } } } | | | 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 | e = deflateSetHeader(&cd->outStream, &cd->outHeader.header); if (e != Z_OK) { goto error; } } } Tcl_DStringInit(&cd->decompressed); chan = Tcl_StackChannel(interp, &zlibChannelType, cd, Tcl_GetChannelMode(channel), channel); if (chan == NULL) { goto error; } cd->chan = chan; |
︙ | ︙ | |||
2909 2910 2911 2912 2913 2914 2915 | * * Result: * The number of actually copied bytes, possibly less than 'toRead'. * *---------------------------------------------------------------------- */ | | | | | < | | | | | | | 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 3035 3036 3037 3038 3039 3040 3041 3042 | * * Result: * The number of actually copied bytes, possibly less than 'toRead'. * *---------------------------------------------------------------------- */ static inline int ResultCopy( ZlibChannelData *cd, /* The location of the buffer to read from. */ char *buf, /* The buffer to copy into */ int toRead) /* Number of requested bytes */ { int have = Tcl_DStringLength(&cd->decompressed); if (have == 0) { /* * Nothing to copy in the case of an empty buffer. */ return 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(&cd->decompressed); memcpy(buf, src, toRead); memmove(src, src + toRead, have - toRead); Tcl_DStringSetLength(&cd->decompressed, have - toRead); return 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(&cd->decompressed), have); Tcl_DStringSetLength(&cd->decompressed, 0); return have; } } /* *---------------------------------------------------------------------- * * ResultGenerate -- * * Extract uncompressed bytes from the compression engine and store them * in our working buffer. * * Result: * TCL_OK/TCL_ERROR (with *errorCodePtr updated with reason). * * Side effects: * See above. * *---------------------------------------------------------------------- */ |
︙ | ︙ | |||
2994 2995 2996 2997 2998 2999 3000 | /* * 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) { | | | | | | 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 | /* * 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->decompressed, (char *) buf, written); } /* * The cases where we're definitely done. */ if (((flush == Z_SYNC_FLUSH) && (e == Z_BUF_ERROR)) || (e == Z_STREAM_END) || (e == Z_OK && cd->inStream.avail_out == 0)) { return TCL_OK; } /* * 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. * * Otherwise, we've got errors and need to report to higher-up. */ 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 TCL_ERROR; } /* * Check if the inflate stopped early. */ if (cd->inStream.avail_in <= 0 && flush != Z_SYNC_FLUSH) { return TCL_OK; } } } /* *---------------------------------------------------------------------- * Finally, the TclZlibInit function. Used to install the zlib API. |
︙ | ︙ |