kusano fc6ab3
/* infcover.c -- test zlib's inflate routines with full code coverage
kusano fc6ab3
 * Copyright (C) 2011 Mark Adler
kusano fc6ab3
 * For conditions of distribution and use, see copyright notice in zlib.h
kusano fc6ab3
 */
kusano fc6ab3
kusano fc6ab3
/* to use, do: ./configure --cover && make cover */
kusano fc6ab3
kusano fc6ab3
#include <stdio.h></stdio.h>
kusano fc6ab3
#include <stdlib.h></stdlib.h>
kusano fc6ab3
#include <string.h></string.h>
kusano fc6ab3
#include <assert.h></assert.h>
kusano fc6ab3
#include "zlib.h"
kusano fc6ab3
kusano fc6ab3
/* get definition of internal structure so we can mess with it (see pull()),
kusano fc6ab3
   and so we can call inflate_trees() (see cover5()) */
kusano fc6ab3
#define ZLIB_INTERNAL
kusano fc6ab3
#include "inftrees.h"
kusano fc6ab3
#include "inflate.h"
kusano fc6ab3
kusano fc6ab3
#define local static
kusano fc6ab3
kusano fc6ab3
/* -- memory tracking routines -- */
kusano fc6ab3
kusano fc6ab3
/*
kusano fc6ab3
   These memory tracking routines are provided to zlib and track all of zlib's
kusano fc6ab3
   allocations and deallocations, check for LIFO operations, keep a current
kusano fc6ab3
   and high water mark of total bytes requested, optionally set a limit on the
kusano fc6ab3
   total memory that can be allocated, and when done check for memory leaks.
kusano fc6ab3
kusano fc6ab3
   They are used as follows:
kusano fc6ab3
kusano fc6ab3
   z_stream strm;
kusano fc6ab3
   mem_setup(&strm)         initializes the memory tracking and sets the
kusano fc6ab3
                            zalloc, zfree, and opaque members of strm to use
kusano fc6ab3
                            memory tracking for all zlib operations on strm
kusano fc6ab3
   mem_limit(&strm, limit)  sets a limit on the total bytes requested -- a
kusano fc6ab3
                            request that exceeds this limit will result in an
kusano fc6ab3
                            allocation failure (returns NULL) -- setting the
kusano fc6ab3
                            limit to zero means no limit, which is the default
kusano fc6ab3
                            after mem_setup()
kusano fc6ab3
   mem_used(&strm, "msg")   prints to stderr "msg" and the total bytes used
kusano fc6ab3
   mem_high(&strm, "msg")   prints to stderr "msg" and the high water mark
kusano fc6ab3
   mem_done(&strm, "msg")   ends memory tracking, releases all allocations
kusano fc6ab3
                            for the tracking as well as leaked zlib blocks, if
kusano fc6ab3
                            any.  If there was anything unusual, such as leaked
kusano fc6ab3
                            blocks, non-FIFO frees, or frees of addresses not
kusano fc6ab3
                            allocated, then "msg" and information about the
kusano fc6ab3
                            problem is printed to stderr.  If everything is
kusano fc6ab3
                            normal, nothing is printed. mem_done resets the
kusano fc6ab3
                            strm members to Z_NULL to use the default memory
kusano fc6ab3
                            allocation routines on the next zlib initialization
kusano fc6ab3
                            using strm.
kusano fc6ab3
 */
kusano fc6ab3
kusano fc6ab3
/* these items are strung together in a linked list, one for each allocation */
kusano fc6ab3
struct mem_item {
kusano fc6ab3
    void *ptr;                  /* pointer to allocated memory */
kusano fc6ab3
    size_t size;                /* requested size of allocation */
kusano fc6ab3
    struct mem_item *next;      /* pointer to next item in list, or NULL */
kusano fc6ab3
};
kusano fc6ab3
kusano fc6ab3
/* this structure is at the root of the linked list, and tracks statistics */
kusano fc6ab3
struct mem_zone {
kusano fc6ab3
    struct mem_item *first;     /* pointer to first item in list, or NULL */
kusano fc6ab3
    size_t total, highwater;    /* total allocations, and largest total */
kusano fc6ab3
    size_t limit;               /* memory allocation limit, or 0 if no limit */
kusano fc6ab3
    int notlifo, rogue;         /* counts of non-LIFO frees and rogue frees */
kusano fc6ab3
};
kusano fc6ab3
kusano fc6ab3
/* memory allocation routine to pass to zlib */
kusano fc6ab3
local void *mem_alloc(void *mem, unsigned count, unsigned size)
kusano fc6ab3
{
kusano fc6ab3
    void *ptr;
kusano fc6ab3
    struct mem_item *item;
kusano fc6ab3
    struct mem_zone *zone = mem;
kusano fc6ab3
    size_t len = count * (size_t)size;
kusano fc6ab3
kusano fc6ab3
    /* induced allocation failure */
kusano fc6ab3
    if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
kusano fc6ab3
        return NULL;
kusano fc6ab3
kusano fc6ab3
    /* perform allocation using the standard library, fill memory with a
kusano fc6ab3
       non-zero value to make sure that the code isn't depending on zeros */
kusano fc6ab3
    ptr = malloc(len);
kusano fc6ab3
    if (ptr == NULL)
kusano fc6ab3
        return NULL;
kusano fc6ab3
    memset(ptr, 0xa5, len);
kusano fc6ab3
kusano fc6ab3
    /* create a new item for the list */
kusano fc6ab3
    item = malloc(sizeof(struct mem_item));
kusano fc6ab3
    if (item == NULL) {
kusano fc6ab3
        free(ptr);
kusano fc6ab3
        return NULL;
kusano fc6ab3
    }
kusano fc6ab3
    item->ptr = ptr;
kusano fc6ab3
    item->size = len;
kusano fc6ab3
kusano fc6ab3
    /* insert item at the beginning of the list */
kusano fc6ab3
    item->next = zone->first;
kusano fc6ab3
    zone->first = item;
kusano fc6ab3
kusano fc6ab3
    /* update the statistics */
kusano fc6ab3
    zone->total += item->size;
kusano fc6ab3
    if (zone->total > zone->highwater)
kusano fc6ab3
        zone->highwater = zone->total;
kusano fc6ab3
kusano fc6ab3
    /* return the allocated memory */
kusano fc6ab3
    return ptr;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* memory free routine to pass to zlib */
kusano fc6ab3
local void mem_free(void *mem, void *ptr)
kusano fc6ab3
{
kusano fc6ab3
    struct mem_item *item, *next;
kusano fc6ab3
    struct mem_zone *zone = mem;
kusano fc6ab3
kusano fc6ab3
    /* if no zone, just do a free */
kusano fc6ab3
    if (zone == NULL) {
kusano fc6ab3
        free(ptr);
kusano fc6ab3
        return;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* point next to the item that matches ptr, or NULL if not found -- remove
kusano fc6ab3
       the item from the linked list if found */
kusano fc6ab3
    next = zone->first;
kusano fc6ab3
    if (next) {
kusano fc6ab3
        if (next->ptr == ptr)
kusano fc6ab3
            zone->first = next->next;   /* first one is it, remove from list */
kusano fc6ab3
        else {
kusano fc6ab3
            do {                        /* search the linked list */
kusano fc6ab3
                item = next;
kusano fc6ab3
                next = item->next;
kusano fc6ab3
            } while (next != NULL && next->ptr != ptr);
kusano fc6ab3
            if (next) {                 /* if found, remove from linked list */
kusano fc6ab3
                item->next = next->next;
kusano fc6ab3
                zone->notlifo++;        /* not a LIFO free */
kusano fc6ab3
            }
kusano fc6ab3
kusano fc6ab3
        }
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* if found, update the statistics and free the item */
kusano fc6ab3
    if (next) {
kusano fc6ab3
        zone->total -= next->size;
kusano fc6ab3
        free(next);
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* if not found, update the rogue count */
kusano fc6ab3
    else
kusano fc6ab3
        zone->rogue++;
kusano fc6ab3
kusano fc6ab3
    /* in any case, do the requested free with the standard library function */
kusano fc6ab3
    free(ptr);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* set up a controlled memory allocation space for monitoring, set the stream
kusano fc6ab3
   parameters to the controlled routines, with opaque pointing to the space */
kusano fc6ab3
local void mem_setup(z_stream *strm)
kusano fc6ab3
{
kusano fc6ab3
    struct mem_zone *zone;
kusano fc6ab3
kusano fc6ab3
    zone = malloc(sizeof(struct mem_zone));
kusano fc6ab3
    assert(zone != NULL);
kusano fc6ab3
    zone->first = NULL;
kusano fc6ab3
    zone->total = 0;
kusano fc6ab3
    zone->highwater = 0;
kusano fc6ab3
    zone->limit = 0;
kusano fc6ab3
    zone->notlifo = 0;
kusano fc6ab3
    zone->rogue = 0;
kusano fc6ab3
    strm->opaque = zone;
kusano fc6ab3
    strm->zalloc = mem_alloc;
kusano fc6ab3
    strm->zfree = mem_free;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* set a limit on the total memory allocation, or 0 to remove the limit */
kusano fc6ab3
local void mem_limit(z_stream *strm, size_t limit)
kusano fc6ab3
{
kusano fc6ab3
    struct mem_zone *zone = strm->opaque;
kusano fc6ab3
kusano fc6ab3
    zone->limit = limit;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* show the current total requested allocations in bytes */
kusano fc6ab3
local void mem_used(z_stream *strm, char *prefix)
kusano fc6ab3
{
kusano fc6ab3
    struct mem_zone *zone = strm->opaque;
kusano fc6ab3
kusano fc6ab3
    fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* show the high water allocation in bytes */
kusano fc6ab3
local void mem_high(z_stream *strm, char *prefix)
kusano fc6ab3
{
kusano fc6ab3
    struct mem_zone *zone = strm->opaque;
kusano fc6ab3
kusano fc6ab3
    fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* release the memory allocation zone -- if there are any surprises, notify */
kusano fc6ab3
local void mem_done(z_stream *strm, char *prefix)
kusano fc6ab3
{
kusano fc6ab3
    int count = 0;
kusano fc6ab3
    struct mem_item *item, *next;
kusano fc6ab3
    struct mem_zone *zone = strm->opaque;
kusano fc6ab3
kusano fc6ab3
    /* show high water mark */
kusano fc6ab3
    mem_high(strm, prefix);
kusano fc6ab3
kusano fc6ab3
    /* free leftover allocations and item structures, if any */
kusano fc6ab3
    item = zone->first;
kusano fc6ab3
    while (item != NULL) {
kusano fc6ab3
        free(item->ptr);
kusano fc6ab3
        next = item->next;
kusano fc6ab3
        free(item);
kusano fc6ab3
        item = next;
kusano fc6ab3
        count++;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* issue alerts about anything unexpected */
kusano fc6ab3
    if (count || zone->total)
kusano fc6ab3
        fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
kusano fc6ab3
                prefix, zone->total, count);
kusano fc6ab3
    if (zone->notlifo)
kusano fc6ab3
        fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo);
kusano fc6ab3
    if (zone->rogue)
kusano fc6ab3
        fprintf(stderr, "** %s: %d frees not recognized\n",
kusano fc6ab3
                prefix, zone->rogue);
kusano fc6ab3
kusano fc6ab3
    /* free the zone and delete from the stream */
kusano fc6ab3
    free(zone);
kusano fc6ab3
    strm->opaque = Z_NULL;
kusano fc6ab3
    strm->zalloc = Z_NULL;
kusano fc6ab3
    strm->zfree = Z_NULL;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- inflate test routines -- */
kusano fc6ab3
kusano fc6ab3
/* Decode a hexadecimal string, set *len to length, in[] to the bytes.  This
kusano fc6ab3
   decodes liberally, in that hex digits can be adjacent, in which case two in
kusano fc6ab3
   a row writes a byte.  Or they can delimited by any non-hex character, where
kusano fc6ab3
   the delimiters are ignored except when a single hex digit is followed by a
kusano fc6ab3
   delimiter in which case that single digit writes a byte.  The returned
kusano fc6ab3
   data is allocated and must eventually be freed.  NULL is returned if out of
kusano fc6ab3
   memory.  If the length is not needed, then len can be NULL. */
kusano fc6ab3
local unsigned char *h2b(const char *hex, unsigned *len)
kusano fc6ab3
{
kusano fc6ab3
    unsigned char *in;
kusano fc6ab3
    unsigned next, val;
kusano fc6ab3
kusano fc6ab3
    in = malloc((strlen(hex) + 1) >> 1);
kusano fc6ab3
    if (in == NULL)
kusano fc6ab3
        return NULL;
kusano fc6ab3
    next = 0;
kusano fc6ab3
    val = 1;
kusano fc6ab3
    do {
kusano fc6ab3
        if (*hex >= '0' && *hex <= '9')
kusano fc6ab3
            val = (val << 4) + *hex - '0';
kusano fc6ab3
        else if (*hex >= 'A' && *hex <= 'F')
kusano fc6ab3
            val = (val << 4) + *hex - 'A' + 10;
kusano fc6ab3
        else if (*hex >= 'a' && *hex <= 'f')
kusano fc6ab3
            val = (val << 4) + *hex - 'a' + 10;
kusano fc6ab3
        else if (val != 1 && val < 32)  /* one digit followed by delimiter */
kusano fc6ab3
            val += 240;                 /* make it look like two digits */
kusano fc6ab3
        if (val > 255) {                /* have two digits */
kusano fc6ab3
            in[next++] = val & 0xff;    /* save the decoded byte */
kusano fc6ab3
            val = 1;                    /* start over */
kusano fc6ab3
        }
kusano fc6ab3
    } while (*hex++);       /* go through the loop with the terminating null */
kusano fc6ab3
    if (len != NULL)
kusano fc6ab3
        *len = next;
kusano fc6ab3
    in = reallocf(in, next);
kusano fc6ab3
    return in;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* generic inflate() run, where hex is the hexadecimal input data, what is the
kusano fc6ab3
   text to include in an error message, step is how much input data to feed
kusano fc6ab3
   inflate() on each call, or zero to feed it all, win is the window bits
kusano fc6ab3
   parameter to inflateInit2(), len is the size of the output buffer, and err
kusano fc6ab3
   is the error code expected from the first inflate() call (the second
kusano fc6ab3
   inflate() call is expected to return Z_STREAM_END).  If win is 47, then
kusano fc6ab3
   header information is collected with inflateGetHeader().  If a zlib stream
kusano fc6ab3
   is looking for a dictionary, then an empty dictionary is provided.
kusano fc6ab3
   inflate() is run until all of the input data is consumed. */
kusano fc6ab3
local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
kusano fc6ab3
               int err)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    unsigned have;
kusano fc6ab3
    unsigned char *in, *out;
kusano fc6ab3
    z_stream strm, copy;
kusano fc6ab3
    gz_header head;
kusano fc6ab3
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit2(&strm, win);
kusano fc6ab3
    if (ret != Z_OK) {
kusano fc6ab3
        mem_done(&strm, what);
kusano fc6ab3
        return;
kusano fc6ab3
    }
kusano fc6ab3
    out = malloc(len);                          assert(out != NULL);
kusano fc6ab3
    if (win == 47) {
kusano fc6ab3
        head.extra = out;
kusano fc6ab3
        head.extra_max = len;
kusano fc6ab3
        head.name = out;
kusano fc6ab3
        head.name_max = len;
kusano fc6ab3
        head.comment = out;
kusano fc6ab3
        head.comm_max = len;
kusano fc6ab3
        ret = inflateGetHeader(&strm, &head);   assert(ret == Z_OK);
kusano fc6ab3
    }
kusano fc6ab3
    in = h2b(hex, &have);                       assert(in != NULL);
kusano fc6ab3
    if (step == 0 || step > have)
kusano fc6ab3
        step = have;
kusano fc6ab3
    strm.avail_in = step;
kusano fc6ab3
    have -= step;
kusano fc6ab3
    strm.next_in = in;
kusano fc6ab3
    do {
kusano fc6ab3
        strm.avail_out = len;
kusano fc6ab3
        strm.next_out = out;
kusano fc6ab3
        ret = inflate(&strm, Z_NO_FLUSH);       assert(err == 9 || ret == err);
kusano fc6ab3
        if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
kusano fc6ab3
            break;
kusano fc6ab3
        if (ret == Z_NEED_DICT) {
kusano fc6ab3
            ret = inflateSetDictionary(&strm, in, 1);
kusano fc6ab3
                                                assert(ret == Z_DATA_ERROR);
kusano fc6ab3
            mem_limit(&strm, 1);
kusano fc6ab3
            ret = inflateSetDictionary(&strm, out, 0);
kusano fc6ab3
                                                assert(ret == Z_MEM_ERROR);
kusano fc6ab3
            mem_limit(&strm, 0);
kusano fc6ab3
            ((struct inflate_state *)strm.state)->mode = DICT;
kusano fc6ab3
            ret = inflateSetDictionary(&strm, out, 0);
kusano fc6ab3
                                                assert(ret == Z_OK);
kusano fc6ab3
            ret = inflate(&strm, Z_NO_FLUSH);   assert(ret == Z_BUF_ERROR);
kusano fc6ab3
        }
kusano fc6ab3
        ret = inflateCopy(©, &strm);        assert(ret == Z_OK);
kusano fc6ab3
        ret = inflateEnd(©);                assert(ret == Z_OK);
kusano fc6ab3
        err = 9;                        /* don't care next time around */
kusano fc6ab3
        have += strm.avail_in;
kusano fc6ab3
        strm.avail_in = step > have ? have : step;
kusano fc6ab3
        have -= strm.avail_in;
kusano fc6ab3
    } while (strm.avail_in);
kusano fc6ab3
    free(in);
kusano fc6ab3
    free(out);
kusano fc6ab3
    ret = inflateReset2(&strm, -8);             assert(ret == Z_OK);
kusano fc6ab3
    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
kusano fc6ab3
    mem_done(&strm, what);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover all of the lines in inflate.c up to inflate() */
kusano fc6ab3
local void cover_support(void)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    z_stream strm;
kusano fc6ab3
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit(&strm);                   assert(ret == Z_OK);
kusano fc6ab3
    mem_used(&strm, "inflate init");
kusano fc6ab3
    ret = inflatePrime(&strm, 5, 31);           assert(ret == Z_OK);
kusano fc6ab3
    ret = inflatePrime(&strm, -1, 0);           assert(ret == Z_OK);
kusano fc6ab3
    ret = inflateSetDictionary(&strm, Z_NULL, 0);
kusano fc6ab3
                                                assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
kusano fc6ab3
    mem_done(&strm, "prime");
kusano fc6ab3
kusano fc6ab3
    inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
kusano fc6ab3
    inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
kusano fc6ab3
    inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
kusano fc6ab3
    inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
kusano fc6ab3
    inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
kusano fc6ab3
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
kusano fc6ab3
                                                assert(ret == Z_VERSION_ERROR);
kusano fc6ab3
    mem_done(&strm, "wrong version");
kusano fc6ab3
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit(&strm);                   assert(ret == Z_OK);
kusano fc6ab3
    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
kusano fc6ab3
    fputs("inflate built-in memory routines\n", stderr);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover all inflate() header and trailer cases and code after inflate() */
kusano fc6ab3
local void cover_wrap(void)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    z_stream strm, copy;
kusano fc6ab3
    unsigned char dict[257];
kusano fc6ab3
kusano fc6ab3
    ret = inflate(Z_NULL, 0);                   assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateEnd(Z_NULL);                   assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateCopy(Z_NULL, Z_NULL);          assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    fputs("inflate bad parameters\n", stderr);
kusano fc6ab3
kusano fc6ab3
    inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
kusano fc6ab3
    inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
kusano fc6ab3
    inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
kusano fc6ab3
    inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
kusano fc6ab3
    inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
kusano fc6ab3
    inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
kusano fc6ab3
    inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
kusano fc6ab3
        Z_DATA_ERROR);
kusano fc6ab3
    inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length",
kusano fc6ab3
        0, 47, 0, Z_STREAM_END);
kusano fc6ab3
    inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
kusano fc6ab3
    inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
kusano fc6ab3
    inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
kusano fc6ab3
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit2(&strm, -8);
kusano fc6ab3
    strm.avail_in = 2;
kusano fc6ab3
    strm.next_in = (void *)"\x63";
kusano fc6ab3
    strm.avail_out = 1;
kusano fc6ab3
    strm.next_out = (void *)&ret;
kusano fc6ab3
    mem_limit(&strm, 1);
kusano fc6ab3
    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
kusano fc6ab3
    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
kusano fc6ab3
    mem_limit(&strm, 0);
kusano fc6ab3
    memset(dict, 0, 257);
kusano fc6ab3
    ret = inflateSetDictionary(&strm, dict, 257);
kusano fc6ab3
                                                assert(ret == Z_OK);
kusano fc6ab3
    mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
kusano fc6ab3
    ret = inflatePrime(&strm, 16, 0);           assert(ret == Z_OK);
kusano fc6ab3
    strm.avail_in = 2;
kusano fc6ab3
    strm.next_in = (void *)"\x80";
kusano fc6ab3
    ret = inflateSync(&strm);                   assert(ret == Z_DATA_ERROR);
kusano fc6ab3
    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    strm.avail_in = 4;
kusano fc6ab3
    strm.next_in = (void *)"\0\0\xff\xff";
kusano fc6ab3
    ret = inflateSync(&strm);                   assert(ret == Z_OK);
kusano fc6ab3
    (void)inflateSyncPoint(&strm);
kusano fc6ab3
    ret = inflateCopy(©, &strm);            assert(ret == Z_MEM_ERROR);
kusano fc6ab3
    mem_limit(&strm, 0);
kusano fc6ab3
    ret = inflateUndermine(&strm, 1);           assert(ret == Z_DATA_ERROR);
kusano fc6ab3
    (void)inflateMark(&strm);
kusano fc6ab3
    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
kusano fc6ab3
    mem_done(&strm, "miscellaneous, force memory errors");
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* input and output functions for inflateBack() */
kusano fc6ab3
local unsigned pull(void *desc, unsigned char **buf)
kusano fc6ab3
{
kusano fc6ab3
    static unsigned int next = 0;
kusano fc6ab3
    static unsigned char dat[] = {0x63, 0, 2, 0};
kusano fc6ab3
    struct inflate_state *state;
kusano fc6ab3
kusano fc6ab3
    if (desc == Z_NULL) {
kusano fc6ab3
        next = 0;
kusano fc6ab3
        return 0;   /* no input (already provided at next_in) */
kusano fc6ab3
    }
kusano fc6ab3
    state = (void *)((z_stream *)desc)->state;
kusano fc6ab3
    if (state != Z_NULL)
kusano fc6ab3
        state->mode = SYNC;     /* force an otherwise impossible situation */
kusano fc6ab3
    return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
local int push(void *desc, unsigned char *buf, unsigned len)
kusano fc6ab3
{
kusano fc6ab3
    buf += len;
kusano fc6ab3
    return desc != Z_NULL;      /* force error if desc not null */
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover inflateBack() up to common deflate data cases and after those */
kusano fc6ab3
local void cover_back(void)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    z_stream strm;
kusano fc6ab3
    unsigned char win[32768];
kusano fc6ab3
kusano fc6ab3
    ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
kusano fc6ab3
                                                assert(ret == Z_VERSION_ERROR);
kusano fc6ab3
    ret = inflateBackInit(Z_NULL, 0, win);      assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
kusano fc6ab3
                                                assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateBackEnd(Z_NULL);               assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    fputs("inflateBack bad parameters\n", stderr);
kusano fc6ab3
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
kusano fc6ab3
    strm.avail_in = 2;
kusano fc6ab3
    strm.next_in = (void *)"\x03";
kusano fc6ab3
    ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
kusano fc6ab3
                                                assert(ret == Z_STREAM_END);
kusano fc6ab3
        /* force output error */
kusano fc6ab3
    strm.avail_in = 3;
kusano fc6ab3
    strm.next_in = (void *)"\x63\x00";
kusano fc6ab3
    ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
kusano fc6ab3
                                                assert(ret == Z_BUF_ERROR);
kusano fc6ab3
        /* force mode error by mucking with state */
kusano fc6ab3
    ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
kusano fc6ab3
                                                assert(ret == Z_STREAM_ERROR);
kusano fc6ab3
    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
kusano fc6ab3
    mem_done(&strm, "inflateBack bad state");
kusano fc6ab3
kusano fc6ab3
    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
kusano fc6ab3
    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
kusano fc6ab3
    fputs("inflateBack built-in memory routines\n", stderr);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
kusano fc6ab3
local int try(char *hex, char *id, int err)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    unsigned len, size;
kusano fc6ab3
    unsigned char *in, *out, *win;
kusano fc6ab3
    char *prefix;
kusano fc6ab3
    z_stream strm;
kusano fc6ab3
kusano fc6ab3
    /* convert to hex */
kusano fc6ab3
    in = h2b(hex, &len);
kusano fc6ab3
    assert(in != NULL);
kusano fc6ab3
kusano fc6ab3
    /* allocate work areas */
kusano fc6ab3
    size = len << 3;
kusano fc6ab3
    out = malloc(size);
kusano fc6ab3
    assert(out != NULL);
kusano fc6ab3
    win = malloc(32768);
kusano fc6ab3
    assert(win != NULL);
kusano fc6ab3
    prefix = malloc(strlen(id) + 6);
kusano fc6ab3
    assert(prefix != NULL);
kusano fc6ab3
kusano fc6ab3
    /* first with inflate */
kusano fc6ab3
    strcpy(prefix, id);
kusano fc6ab3
    strcat(prefix, "-late");
kusano fc6ab3
    mem_setup(&strm);
kusano fc6ab3
    strm.avail_in = 0;
kusano fc6ab3
    strm.next_in = Z_NULL;
kusano fc6ab3
    ret = inflateInit2(&strm, err < 0 ? 47 : -15);
kusano fc6ab3
    assert(ret == Z_OK);
kusano fc6ab3
    strm.avail_in = len;
kusano fc6ab3
    strm.next_in = in;
kusano fc6ab3
    do {
kusano fc6ab3
        strm.avail_out = size;
kusano fc6ab3
        strm.next_out = out;
kusano fc6ab3
        ret = inflate(&strm, Z_TREES);
kusano fc6ab3
        assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
kusano fc6ab3
        if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
kusano fc6ab3
            break;
kusano fc6ab3
    } while (strm.avail_in || strm.avail_out == 0);
kusano fc6ab3
    if (err) {
kusano fc6ab3
        assert(ret == Z_DATA_ERROR);
kusano fc6ab3
        assert(strcmp(id, strm.msg) == 0);
kusano fc6ab3
    }
kusano fc6ab3
    inflateEnd(&strm);
kusano fc6ab3
    mem_done(&strm, prefix);
kusano fc6ab3
kusano fc6ab3
    /* then with inflateBack */
kusano fc6ab3
    if (err >= 0) {
kusano fc6ab3
        strcpy(prefix, id);
kusano fc6ab3
        strcat(prefix, "-back");
kusano fc6ab3
        mem_setup(&strm);
kusano fc6ab3
        ret = inflateBackInit(&strm, 15, win);
kusano fc6ab3
        assert(ret == Z_OK);
kusano fc6ab3
        strm.avail_in = len;
kusano fc6ab3
        strm.next_in = in;
kusano fc6ab3
        ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
kusano fc6ab3
        assert(ret != Z_STREAM_ERROR);
kusano fc6ab3
        if (err) {
kusano fc6ab3
            assert(ret == Z_DATA_ERROR);
kusano fc6ab3
            assert(strcmp(id, strm.msg) == 0);
kusano fc6ab3
        }
kusano fc6ab3
        inflateBackEnd(&strm);
kusano fc6ab3
        mem_done(&strm, prefix);
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* clean up */
kusano fc6ab3
    free(prefix);
kusano fc6ab3
    free(win);
kusano fc6ab3
    free(out);
kusano fc6ab3
    free(in);
kusano fc6ab3
    return ret;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover deflate data cases in both inflate() and inflateBack() */
kusano fc6ab3
local void cover_inflate(void)
kusano fc6ab3
{
kusano fc6ab3
    try("0 0 0 0 0", "invalid stored block lengths", 1);
kusano fc6ab3
    try("3 0", "fixed", 0);
kusano fc6ab3
    try("6", "invalid block type", 1);
kusano fc6ab3
    try("1 1 0 fe ff 0", "stored", 0);
kusano fc6ab3
    try("fc 0 0", "too many length or distance symbols", 1);
kusano fc6ab3
    try("4 0 fe ff", "invalid code lengths set", 1);
kusano fc6ab3
    try("4 0 24 49 0", "invalid bit length repeat", 1);
kusano fc6ab3
    try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
kusano fc6ab3
    try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
kusano fc6ab3
    try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
kusano fc6ab3
        "invalid literal/lengths set", 1);
kusano fc6ab3
    try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
kusano fc6ab3
    try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
kusano fc6ab3
    try("2 7e ff ff", "invalid distance code", 1);
kusano fc6ab3
    try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
kusano fc6ab3
kusano fc6ab3
    /* also trailer mismatch just in inflate() */
kusano fc6ab3
    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
kusano fc6ab3
    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
kusano fc6ab3
        "incorrect length check", -1);
kusano fc6ab3
    try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
kusano fc6ab3
    try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
kusano fc6ab3
        "long code", 0);
kusano fc6ab3
    try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
kusano fc6ab3
    try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c",
kusano fc6ab3
        "long distance and extra", 0);
kusano fc6ab3
    try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
kusano fc6ab3
        "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
kusano fc6ab3
    inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
kusano fc6ab3
        Z_STREAM_END);
kusano fc6ab3
    inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover remaining lines in inftrees.c */
kusano fc6ab3
local void cover_trees(void)
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    unsigned bits;
kusano fc6ab3
    unsigned short lens[16], work[16];
kusano fc6ab3
    code *next, table[ENOUGH_DISTS];
kusano fc6ab3
kusano fc6ab3
    /* we need to call inflate_table() directly in order to manifest not-
kusano fc6ab3
       enough errors, since zlib insures that enough is always enough */
kusano fc6ab3
    for (bits = 0; bits < 15; bits++)
kusano fc6ab3
        lens[bits] = (unsigned short)(bits + 1);
kusano fc6ab3
    lens[15] = 15;
kusano fc6ab3
    next = table;
kusano fc6ab3
    bits = 15;
kusano fc6ab3
    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
kusano fc6ab3
                                                assert(ret == 1);
kusano fc6ab3
    next = table;
kusano fc6ab3
    bits = 1;
kusano fc6ab3
    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
kusano fc6ab3
                                                assert(ret == 1);
kusano fc6ab3
    fputs("inflate_table not enough errors\n", stderr);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* cover remaining inffast.c decoding and window copying */
kusano fc6ab3
local void cover_fast(void)
kusano fc6ab3
{
kusano fc6ab3
    inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
kusano fc6ab3
        " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
kusano fc6ab3
    inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
kusano fc6ab3
        " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
kusano fc6ab3
        Z_DATA_ERROR);
kusano fc6ab3
    inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
kusano fc6ab3
        Z_DATA_ERROR);
kusano fc6ab3
    inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
kusano fc6ab3
        Z_DATA_ERROR);
kusano fc6ab3
    inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0",
kusano fc6ab3
        "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
kusano fc6ab3
    inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
kusano fc6ab3
    inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
kusano fc6ab3
        "contiguous and wrap around window", 6, -8, 259, Z_OK);
kusano fc6ab3
    inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
kusano fc6ab3
        Z_STREAM_END);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
int main(void)
kusano fc6ab3
{
kusano fc6ab3
    fprintf(stderr, "%s\n", zlibVersion());
kusano fc6ab3
    cover_support();
kusano fc6ab3
    cover_wrap();
kusano fc6ab3
    cover_back();
kusano fc6ab3
    cover_inflate();
kusano fc6ab3
    cover_trees();
kusano fc6ab3
    cover_fast();
kusano fc6ab3
    return 0;
kusano fc6ab3
}