Commit message: quic: Check we have some data to start decoding quic image

All paths already pass some data to quic_decode_begin but for the
test check it, it's not that expensive test.
Checking for not 0 is enough, all other words will potentially be
read calling more_io_words but we need one to avoid a potential
initial buffer overflow or deferencing an invalid pointer.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
CVE: None
Vulnerability description: None

Project: spice-common
File: quic.c

static void find_model_params(Encoder *encoder,
                              const int bpc,
                              unsigned int *ncounters,
                              unsigned int *levels,
                              unsigned int *n_buckets_ptrs,
                              unsigned int *repfirst,
                              unsigned int *firstsize,
                              unsigned int *repnext,
                              unsigned int *mulsize,
                              unsigned int *nbuckets)
{
    unsigned int bsize;              /* bucket size */
    unsigned int bstart, bend = 0;   /* bucket start and end, range : 0 to levels-1*/
    unsigned int repcntr;            /* helper */

    /* The only valid values are 1, 3 and 5.
       0, 2 and 4 are obsolete and the rest of the
       values are considered out of the range. */
    SPICE_VERIFY(DEFevol == 1 || DEFevol == 3 || DEFevol == 5);
    spice_assert(bpc <= 8 && bpc > 0);

    *ncounters = 8;

    *levels = 0x1 << bpc;

    *n_buckets_ptrs = 0;  /* ==0 means: not set yet */

    switch (DEFevol) {   /* set repfirst firstsize repnext mulsize */
    case 1: /* buckets contain following numbers of contexts: 1 1 1 2 2 4 4 8 8 ... */
        *repfirst = 3;
        *firstsize = 1;
        *repnext = 2;
        *mulsize = 2;
        break;
    case 3: /* 1 2 4 8 16 32 64 ... */
        *repfirst = 1;
        *firstsize = 1;
        *repnext = 1;
        *mulsize = 2;
        break;
    case 5:                     /* 1 4 16 64 256 1024 4096 16384 65536 */
        *repfirst = 1;
        *firstsize = 1;
        *repnext = 1;
        *mulsize = 4;
        break;
    default:
        encoder->usr->error(encoder->usr, "findmodelparams(): DEFevol out of range!!!\n");
        return;
    }

    *nbuckets = 0;
    repcntr = *repfirst + 1;    /* first bucket */
    bsize = *firstsize;

    do { /* other buckets */
        if (*nbuckets) {         /* bucket start */
            bstart = bend + 1;
        } else {
            bstart = 0;
        }

        if (!--repcntr) {         /* bucket size */
            repcntr = *repnext;
            bsize *= *mulsize;
        }

        bend = bstart + bsize - 1;  /* bucket end */
        if (bend + bsize >= *levels) {  /* if following bucked was bigger than current one */
            bend = *levels - 1;     /* concatenate them */
        }

        if (!*n_buckets_ptrs) {           /* array size not set yet? */
            *n_buckets_ptrs = *levels;
 #if 0
            if (bend == *levels - 1) {   /* this bucket is last - all in the first array */
                *n_buckets_ptrs = *levels;
            } else if (bsize >= 256) { /* this bucket is allowed to reside in the 2nd table */
                b_lo_ptrs = bstart;
                spice_assert(bstart);     /* previous bucket exists */
            }
 #endif
        }

        (*nbuckets)++;
    } while (bend < *levels - 1);
}

Project: spice-common
File: quic.c

static void quic_image_params(Encoder *encoder, QuicImageType type, int *channels, int *bpc)
{
    spice_assert(channels && bpc);
    switch (type) {
    case QUIC_IMAGE_TYPE_GRAY:
        *channels = 1;
        *bpc = 8;
        break;
    case QUIC_IMAGE_TYPE_RGB16:
        *channels = 3;
        *bpc = 5;
        break;
    case QUIC_IMAGE_TYPE_RGB24:
        *channels = 3;
        *bpc = 8;
        break;
    case QUIC_IMAGE_TYPE_RGB32:
        *channels = 3;
        *bpc = 8;
        break;
    case QUIC_IMAGE_TYPE_RGBA:
        *channels = 4;
        *bpc = 8;
        break;
    case QUIC_IMAGE_TYPE_INVALID:
    default:
        *channels = 0;
        *bpc = 0;
        encoder->usr->error(encoder->usr, "bad image type\n");
    }
}

Project: spice-common
File: quic.c

static int decode_state_run(Encoder *encoder, CommonState *state)
{
    int runlen = 0;

    do {
        register int temp, hits;
        temp = lzeroes[(BYTE)(~(encoder->io_word >> 24))];/* number of leading ones in the
                                                                      input stream, up to 8 */
        for (hits = 1; hits <= temp; hits++) {
            runlen += state->melcorder;

            if (state->melcstate < MELCSTATES - 1) {
                state->melclen = J[++state->melcstate];
                state->melcorder = (1U << state->melclen);
            }
        }
        if (temp != 8) {
            decode_eatbits(encoder, temp + 1);  /* consume the leading
                                                            0 of the remainder encoding */
            break;
        }
        decode_eatbits(encoder, 8);
    } while (1);

    /* read the length of the remainder */
    if (state->melclen) {
        runlen += encoder->io_word >> (32 - state->melclen);
        decode_eatbits(encoder, state->melclen);
    }

    /* adjust melcorder parameters */
    if (state->melcstate) {
        state->melclen = J[--state->melcstate];
        state->melcorder = (1U << state->melclen);
    }

    return runlen;
}

Project: spice-common
File: quic.c

static void decorrelate_init(QuicFamily *family, int bpc)
{
    const unsigned int pixelbitmask = bppmask[bpc];
    const unsigned int pixelbitmaskshr = pixelbitmask >> 1;
    unsigned int s;

    //spice_assert(bpc <= 8);

    for (s = 0; s <= pixelbitmask; s++) {
        if (s <= pixelbitmaskshr) {
            family->xlatU2L[s] = s << 1;
        } else {
            family->xlatU2L[s] = ((pixelbitmask - s) << 1) + 1;
        }
    }
}

Project: spice-common
File: quic.c

QuicContext *quic_create(QuicUsrContext *usr)
{
    Encoder *encoder;

    if (!usr || !usr->error || !usr->warn || !usr->info || !usr->malloc ||
        !usr->free || !usr->more_space || !usr->more_lines) {
        return NULL;
    }

    if (!(encoder = (Encoder *)usr->malloc(usr, sizeof(Encoder)))) {
        return NULL;
    }

    if (!init_encoder(encoder, usr)) {
        usr->free(usr, encoder);
        return NULL;
    }
    return (QuicContext *)encoder;
}

Project: spice-common
File: quic.c

static unsigned int stabrand(void)
{
    SPICE_VERIFY( !(TABRAND_SEEDMASK & TABRAND_TABSIZE));
    SPICE_VERIFY( TABRAND_SEEDMASK + 1 == TABRAND_TABSIZE );

    return TABRAND_SEEDMASK;
}

Project: spice-common
File: quic.c

static void golomb_coding_slow(const QuicFamily *family, const BYTE n, const unsigned int l,
                               unsigned int * const codeword,
                               unsigned int * const codewordlen)
{
    if (n < family->nGRcodewords[l]) {
        (*codeword) = bitat(l) | (n & bppmask[l]);
        (*codewordlen) = (n >> l) + l + 1;
    } else {
        (*codeword) = n - family->nGRcodewords[l];
        (*codewordlen) = family->notGRcwlen[l];
    }
}

Project: spice-common
File: quic.c

static inline void decode_eatbits(Encoder *encoder, int len)
{
    int delta;

    spice_extra_assert(len > 0 && len < 32);
    encoder->io_word <<= len;

    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
        encoder->io_available_bits = delta;
        encoder->io_word |= encoder->io_next_word >> encoder->io_available_bits;
        return;
    }

    delta = -delta;
    encoder->io_word |= encoder->io_next_word << delta;
    read_io_word(encoder);
    encoder->io_available_bits = 32 - delta;
    encoder->io_word |= (encoder->io_next_word >> encoder->io_available_bits);
}

Project: spice-common
File: quic.c

SPICE_CONSTRUCTOR_FUNC(quic_global_init)
{
    family_init(&family_8bpc, 8, DEFmaxclen);
    family_init(&family_5bpc, 5, DEFmaxclen);
}

Project: spice-common
File: quic.c

static void encode_state_run(Encoder *encoder, CommonState *state, unsigned int runlen)
{
    int hits = 0;

    while (runlen >= state->melcorder) {
        hits++;
        runlen -= state->melcorder;
        if (state->melcstate < MELCSTATES - 1) {
            state->melclen = J[++state->melcstate];
            state->melcorder = (1L << state->melclen);
        }
    }

    /* send the required number of "hit" bits (one per occurrence
       of a run of length melcorder). This number is never too big:
       after 31 such "hit" bits, each "hit" would represent a run of 32K
       pixels.
    */
    encode_ones(encoder, hits);

    encode(encoder, runlen, state->melclen + 1);

    /* adjust melcoder parameters */
    if (state->melcstate) {
        state->melclen = J[--state->melcstate];
        state->melcorder = (1L << state->melclen);
    }
}

Project: spice-common
File: quic.c

static void family_init(QuicFamily *family, int bpc, int limit)
{
    int l, b;

    for (l = 0; l < bpc; l++) { /* fill arrays indexed by code number */
        int altprefixlen, altcodewords;

        altprefixlen = limit - bpc;
        if (altprefixlen > (int)(bppmask[bpc - l])) {
            altprefixlen = bppmask[bpc - l];
        }

        altcodewords = bppmask[bpc] + 1 - (altprefixlen << l);

        family->nGRcodewords[l] = (altprefixlen << l);
        family->notGRsuffixlen[l] = ceil_log_2(altcodewords); /* needed for decoding only */
        family->notGRcwlen[l] = altprefixlen + family->notGRsuffixlen[l];
        family->notGRprefixmask[l] = bppmask[32 - altprefixlen]; /* needed for decoding only */

        for (b = 0; b < 256; b++) {
            unsigned int code, len;
            golomb_coding_slow(family, b, l, &code, &len);
            family->golomb_code[b][l] = code;
            family->golomb_code_len[b][l] = len;
        }
    }

    decorrelate_init(family, bpc);
    correlate_init(family, bpc);
}

Project: spice-common
File: quic.c

static int init_encoder(Encoder *encoder, QuicUsrContext *usr)
{
    int i;

    encoder->usr = usr;

    for (i = 0; i < MAX_CHANNELS; i++) {
        if (!init_channel(encoder, &encoder->channels[i])) {
            for (--i; i >= 0; i--) {
                destroy_channel(encoder, &encoder->channels[i]);
            }
            return FALSE;
        }
    }
    return TRUE;
}

Project: spice-common
File: quic.c

static int encoder_reset_channels(Encoder *encoder, int channels, int width, int bpc)
{
    int i;

    for (i = 0; i < channels; i++) {
        s_bucket *bucket;
        s_bucket *end_bucket;

        if (encoder->channels[i].correlate_row_width < width) {
            encoder->channels[i].correlate_row_width = 0;
            if (encoder->channels[i].correlate_row) {
                encoder->usr->free(encoder->usr, encoder->channels[i].correlate_row - 1);
            }
            if (!(encoder->channels[i].correlate_row = (BYTE *)encoder->usr->malloc(encoder->usr,
                                                                                    width + 1))) {
                return FALSE;
            }
            encoder->channels[i].correlate_row++;
            encoder->channels[i].correlate_row_width = width;
        }

        if (bpc == 8) {
            MEMCLEAR(encoder->channels[i].family_stat_8bpc.counters,
                     encoder->n_buckets_8bpc * sizeof(COUNTER) * MAXNUMCODES);
            bucket = encoder->channels[i].family_stat_8bpc.buckets_buf;
            end_bucket = bucket + encoder->n_buckets_8bpc;
            for (; bucket < end_bucket; bucket++) {
                bucket->bestcode = /*BPC*/ 8 - 1;
            }
            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_8bpc.buckets_ptrs;
        } else if (bpc == 5) {
            MEMCLEAR(encoder->channels[i].family_stat_5bpc.counters,
                     encoder->n_buckets_5bpc * sizeof(COUNTER) * MAXNUMCODES);
            bucket = encoder->channels[i].family_stat_5bpc.buckets_buf;
            end_bucket = bucket + encoder->n_buckets_5bpc;
            for (; bucket < end_bucket; bucket++) {
                bucket->bestcode = /*BPC*/ 5 - 1;
            }
            encoder->channels[i]._buckets_ptrs = encoder->channels[i].family_stat_5bpc.buckets_ptrs;
        } else {
            encoder->usr->warn(encoder->usr, "%s: bad bpc %d\n", __FUNCTION__, bpc);
            return FALSE;
        }

        encoder->channels[i].state.waitcnt = 0;
        encoder->channels[i].state.tabrand_seed = stabrand();
        encoder->channels[i].state.wmidx = DEFwmistart;
        encoder->channels[i].state.wmileft = DEFwminext;
        set_wm_trigger(&encoder->channels[i].state);

        encoder_init_rle(&encoder->channels[i].state);
    }
    return TRUE;
}

Project: spice-common
File: quic.c

static void encoder_init_rle(CommonState *state)
{
    state->melcstate = 0;
    state->melclen = J[0];
    state->melcorder = 1 << state->melclen;
}

Project: spice-common
File: quic.c

static void destroy_channel(Encoder *encoder, Channel *channel)
{
    QuicUsrContext *usr = encoder->usr;
    if (channel->correlate_row) {
        usr->free(usr, channel->correlate_row - 1);
    }
    free_family_stat(usr, &channel->family_stat_8bpc);
    free_family_stat(usr, &channel->family_stat_5bpc);
}

Project: spice-common
File: quic.c

int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
{
    Encoder *encoder = (Encoder *)quic;
    unsigned int row;
    uint8_t *prev;

    spice_assert(buf);

    switch (encoder->type) {
    case QUIC_IMAGE_TYPE_RGB32:
    case QUIC_IMAGE_TYPE_RGB24:
        if (type == QUIC_IMAGE_TYPE_RGB32) {
            spice_assert(ABS(stride) >= (int)encoder->width * 4);
            QUIC_UNCOMPRESS_RGB(32, rgb32_pixel_t);
            break;
        } else if (type == QUIC_IMAGE_TYPE_RGB24) {
            spice_assert(ABS(stride) >= (int)encoder->width * 3);
            QUIC_UNCOMPRESS_RGB(24, rgb24_pixel_t);
            break;
        }
        encoder->usr->warn(encoder->usr, "unsupported output format\n");
        return QUIC_ERROR;
    case QUIC_IMAGE_TYPE_RGB16:
        if (type == QUIC_IMAGE_TYPE_RGB16) {
            spice_assert(ABS(stride) >= (int)encoder->width * 2);
            QUIC_UNCOMPRESS_RGB(16, rgb16_pixel_t);
        } else if (type == QUIC_IMAGE_TYPE_RGB32) {
            spice_assert(ABS(stride) >= (int)encoder->width * 4);
            QUIC_UNCOMPRESS_RGB(16_to_32, rgb32_pixel_t);
        } else {
            encoder->usr->warn(encoder->usr, "unsupported output format\n");
            return QUIC_ERROR;
        }

        break;
    case QUIC_IMAGE_TYPE_RGBA:

        if (type != QUIC_IMAGE_TYPE_RGBA) {
            encoder->usr->warn(encoder->usr, "unsupported output format\n");
            return QUIC_ERROR;
        }
        spice_assert(ABS(stride) >= (int)encoder->width * 4);
        uncompress_rgba(encoder, buf, stride);
        break;
    case QUIC_IMAGE_TYPE_GRAY:

        if (type != QUIC_IMAGE_TYPE_GRAY) {
            encoder->usr->warn(encoder->usr, "unsupported output format\n");
            return QUIC_ERROR;
        }
        spice_assert(ABS(stride) >= (int)encoder->width);
        uncompress_gray(encoder, buf, stride);
        break;
    case QUIC_IMAGE_TYPE_INVALID:
    default:
        encoder->usr->error(encoder->usr, "bad image type\n");
    }
    return QUIC_OK;
}

Project: spice-common
File: quic.c

static int init_channel(Encoder *encoder, Channel *channel)
{
    unsigned int ncounters;
    unsigned int levels;
    unsigned int rep_first;
    unsigned int first_size;
    unsigned int rep_next;
    unsigned int mul_size;
    unsigned int n_buckets;
    unsigned int n_buckets_ptrs;

    channel->correlate_row_width = 0;
    channel->correlate_row = NULL;

    find_model_params(encoder, 8, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
                      &first_size, &rep_next, &mul_size, &n_buckets);
    encoder->n_buckets_8bpc = n_buckets;
    if (!init_model_structures(encoder, &channel->family_stat_8bpc, rep_first, first_size,
                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
                               n_buckets)) {
        return FALSE;
    }

    find_model_params(encoder, 5, &ncounters, &levels, &n_buckets_ptrs, &rep_first,
                      &first_size, &rep_next, &mul_size, &n_buckets);
    encoder->n_buckets_5bpc = n_buckets;
    if (!init_model_structures(encoder, &channel->family_stat_5bpc, rep_first, first_size,
                               rep_next, mul_size, levels, ncounters, n_buckets_ptrs,
                               n_buckets)) {
        free_family_stat(encoder->usr, &channel->family_stat_8bpc);
        return FALSE;
    }

    return TRUE;
}

Project: spice-common
File: quic.c

static void set_wm_trigger(CommonState *state)
{
    unsigned int wm = state->wmidx;
    if (wm > 10) {
        wm = 10;
    }

    SPICE_VERIFY(DEFevol < 6);

    state->wm_trigger = besttrigtab[DEFevol / 2][wm];

    spice_assert(state->wm_trigger <= 2000);
    spice_assert(state->wm_trigger >= 1);
}

Project: spice-common
File: quic.c

static inline void encode(Encoder *encoder, unsigned int word, unsigned int len)
{
    int delta;

    spice_extra_assert(len > 0 && len < 32);
    spice_extra_assert(!(word & ~bppmask[len]));

    if ((delta = ((int)encoder->io_available_bits - len)) >= 0) {
        encoder->io_available_bits = delta;
        encoder->io_word |= word << encoder->io_available_bits;
        return;
    }
    delta = -delta;
    encoder->io_word |= word >> delta;
    write_io_word(encoder);
    encoder->io_available_bits = 32 - delta;
    encoder->io_word = word << encoder->io_available_bits;

    spice_extra_assert(encoder->io_available_bits < 32);
    spice_extra_assert((encoder->io_word & bppmask[encoder->io_available_bits]) == 0);
}

Project: spice-common
File: quic.c

static void uncompress_gray(Encoder *encoder, uint8_t *buf, int stride)
{
    unsigned int row;
    uint8_t *prev;

    encoder->channels[0].correlate_row[-1] = 0;
    quic_one_uncompress_row0(encoder, &encoder->channels[0], (one_byte_t *)buf, encoder->width);
    encoder->rows_completed++;
    for (row = 1; row < encoder->height; row++) {
        prev = buf;
        buf += stride;
        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
        quic_one_uncompress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
                                (one_byte_t *)buf, encoder->width);
        encoder->rows_completed++;
    }
}

Project: spice-common
File: quic.c

static inline void encode_32(Encoder *encoder, unsigned int word)
{
    encode(encoder, word >> 16, 16);
    encode(encoder, word & 0x0000ffff, 16);
}

Project: spice-common
File: quic.c

static void fill_model_structures(SPICE_GNUC_UNUSED Encoder *encoder, FamilyStat *family_stat,
                                  unsigned int rep_first, unsigned int first_size,
                                  unsigned int rep_next, unsigned int mul_size,
                                  unsigned int levels, unsigned int ncounters,
                                  unsigned int nbuckets, unsigned int n_buckets_ptrs)
{
    unsigned int
    bsize,
    bstart,
    bend = 0,
    repcntr,
    bnumber;

    COUNTER * free_counter = family_stat->counters;/* first free location in the array of
                                                      counters */

    bnumber = 0;

    repcntr = rep_first + 1;    /* first bucket */
    bsize = first_size;

    do { /* others */
        if (bnumber) {
            bstart = bend + 1;
        } else {
            bstart = 0;
        }

        if (!--repcntr) {
            repcntr = rep_next;
            bsize *= mul_size;
        }

        bend = bstart + bsize - 1;
        if (bend + bsize >= levels) {
            bend = levels - 1;
        }

        family_stat->buckets_buf[bnumber].pcounters = free_counter;
        free_counter += ncounters;

        spice_assert(bstart < n_buckets_ptrs);
        {
            unsigned int i;
            spice_assert(bend < n_buckets_ptrs);
            for (i = bstart; i <= bend; i++) {
                family_stat->buckets_ptrs[i] = family_stat->buckets_buf + bnumber;
            }
        }

        bnumber++;
    } while (bend < levels - 1);

    spice_assert(free_counter - family_stat->counters == (ptrdiff_t)(nbuckets * ncounters));
}

Project: spice-common
File: quic.c

static unsigned int tabrand(unsigned int *tabrand_seed)
{
    return tabrand_chaos[++*tabrand_seed & TABRAND_SEEDMASK];
}

Project: spice-common
File: quic.c

static inline void flush(Encoder *encoder)
{
    if (encoder->io_available_bits > 0 && encoder->io_available_bits != 32) {
        encode(encoder, 0, encoder->io_available_bits);
    }
    encode_32(encoder, 0);
    encode(encoder, 0, 1);
}

Project: spice-common
File: quic.c

static int ceil_log_2(int val) /* ceil(log_2(val)) */
{
    int result;

    //spice_assert(val>0);

    if (val == 1) {
        return 0;
    }

    result = 1;
    val -= 1;
    while (val >>= 1) {
        result++;
    }

    return result;
}

Project: spice-common
File: quic.c

static void correlate_init(QuicFamily *family, int bpc)
{
    const unsigned int pixelbitmask = bppmask[bpc];
    unsigned long int s;

    //spice_assert(bpc <= 8);

    for (s = 0; s <= pixelbitmask; s++) {
        if (s & 0x01) {
            family->xlatL2U[s] = pixelbitmask - (s >> 1);
        } else {
            family->xlatL2U[s] = (s >> 1);
        }
    }
}

Project: spice-common
File: quic.c

int quic_encode(QuicContext *quic, QuicImageType type, int width, int height,
                uint8_t *line, unsigned int num_lines, int stride,
                uint32_t *io_ptr, unsigned int num_io_words)
{
    Encoder *encoder = (Encoder *)quic;
    uint32_t *io_ptr_end = io_ptr + num_io_words;
    uint8_t *lines_end;
    int row;
    uint8_t *prev;
    int channels;
    int bpc;

    lines_end = line + num_lines * stride;
    if (line == NULL && lines_end != line) {
        spice_warn_if_reached();
        return QUIC_ERROR;
    }

    quic_image_params(encoder, type, &channels, &bpc);

    if (!encoder_reset(encoder, io_ptr, io_ptr_end) ||
        !encoder_reset_channels(encoder, channels, width, bpc)) {
        return QUIC_ERROR;
    }

    encoder->io_word = 0;
    encoder->io_available_bits = 32;

    encode_32(encoder, QUIC_MAGIC);
    encode_32(encoder, QUIC_VERSION);
    encode_32(encoder, type);
    encode_32(encoder, width);
    encode_32(encoder, height);

    FILL_LINES();

    switch (type) {
    case QUIC_IMAGE_TYPE_RGB32:
        spice_assert(ABS(stride) >= width * 4);
        QUIC_COMPRESS_RGB(32);
        break;
    case QUIC_IMAGE_TYPE_RGB24:
        spice_assert(ABS(stride) >= width * 3);
        QUIC_COMPRESS_RGB(24);
        break;
    case QUIC_IMAGE_TYPE_RGB16:
        spice_assert(ABS(stride) >= width * 2);
        QUIC_COMPRESS_RGB(16);
        break;
    case QUIC_IMAGE_TYPE_RGBA:
        spice_assert(ABS(stride) >= width * 4);

        encoder->channels[0].correlate_row[-1] = 0;
        encoder->channels[1].correlate_row[-1] = 0;
        encoder->channels[2].correlate_row[-1] = 0;
        quic_rgb32_compress_row0(encoder, (rgb32_pixel_t *)(line), width);

        encoder->channels[3].correlate_row[-1] = 0;
        quic_four_compress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(line + 3), width);

        encoder->rows_completed++;

        for (row = 1; row < height; row++) {
            prev = line;
            NEXT_LINE();
            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
            encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
            encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
            quic_rgb32_compress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)line, width);

            encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
            quic_four_compress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
                                   (four_bytes_t *)(line + 3), width);
            encoder->rows_completed++;
        }
        break;
    case QUIC_IMAGE_TYPE_GRAY:
        spice_assert(ABS(stride) >= width);
        encoder->channels[0].correlate_row[-1] = 0;
        quic_one_compress_row0(encoder, &encoder->channels[0], (one_byte_t *)line, width);
        encoder->rows_completed++;
        for (row = 1; row < height; row++) {
            prev = line;
            NEXT_LINE();
            encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
            quic_one_compress_row(encoder, &encoder->channels[0], (one_byte_t *)prev,
                                  (one_byte_t *)line, width);
            encoder->rows_completed++;
        }
        break;
    case QUIC_IMAGE_TYPE_INVALID:
    default:
        encoder->usr->error(encoder->usr, "bad image type\n");
    }

    flush(encoder);
    encoder->io_words_count -= (encoder->io_end - encoder->io_now);

    return encoder->io_words_count;
}

Project: spice-common
File: quic.c

static inline void write_io_word(Encoder *encoder)
{
    if (G_UNLIKELY(encoder->io_now == encoder->io_end)) {
        more_io_words(encoder);
    }
    *(encoder->io_now++) = GUINT32_TO_LE(encoder->io_word);
}

Project: spice-common
File: quic.c

static inline void init_decode_io(Encoder *encoder)
{
    encoder->io_next_word = encoder->io_word = GUINT32_FROM_LE(*(encoder->io_now));
    encoder->io_now++;
    encoder->io_available_bits = 0;
}

Project: spice-common
File: quic.c

void quic_destroy(QuicContext *quic)
{
    Encoder *encoder = (Encoder *)quic;
    int i;

    if (!quic) {
        return;
    }

    for (i = 0; i < MAX_CHANNELS; i++) {
        destroy_channel(encoder, &encoder->channels[i]);
    }
    encoder->usr->free(encoder->usr, encoder);
}

Project: spice-common
File: quic.c

static inline void decode_eat32bits(Encoder *encoder)
{
    decode_eatbits(encoder, 16);
    decode_eatbits(encoder, 16);
}

Project: spice-common
File: quic.c

static void uncompress_rgba(Encoder *encoder, uint8_t *buf, int stride)
{
    unsigned int row;
    uint8_t *prev;

    encoder->channels[0].correlate_row[-1] = 0;
    encoder->channels[1].correlate_row[-1] = 0;
    encoder->channels[2].correlate_row[-1] = 0;
    quic_rgb32_uncompress_row0(encoder, (rgb32_pixel_t *)buf, encoder->width);

    encoder->channels[3].correlate_row[-1] = 0;
    quic_four_uncompress_row0(encoder, &encoder->channels[3], (four_bytes_t *)(buf + 3),
                              encoder->width);

    encoder->rows_completed++;
    for (row = 1; row < encoder->height; row++) {
        prev = buf;
        buf += stride;

        encoder->channels[0].correlate_row[-1] = encoder->channels[0].correlate_row[0];
        encoder->channels[1].correlate_row[-1] = encoder->channels[1].correlate_row[0];
        encoder->channels[2].correlate_row[-1] = encoder->channels[2].correlate_row[0];
        quic_rgb32_uncompress_row(encoder, (rgb32_pixel_t *)prev, (rgb32_pixel_t *)buf,
                                  encoder->width);

        encoder->channels[3].correlate_row[-1] = encoder->channels[3].correlate_row[0];
        quic_four_uncompress_row(encoder, &encoder->channels[3], (four_bytes_t *)(prev + 3),
                                 (four_bytes_t *)(buf + 3), encoder->width);

        encoder->rows_completed++;
    }
}

Project: spice-common
File: quic.c

static inline void read_io_word(Encoder *encoder)
{
    if (G_UNLIKELY(encoder->io_now == encoder->io_end)) {
        more_io_words(encoder);
    }
    spice_extra_assert(encoder->io_now < encoder->io_end);

    encoder->io_next_word = GUINT32_FROM_LE(*(encoder->io_now));
    encoder->io_now++;
}

Project: spice-common
File: quic.c

static int init_model_structures(Encoder *encoder, FamilyStat *family_stat,
                                 unsigned int rep_first, unsigned int first_size,
                                 unsigned int rep_next, unsigned int mul_size,
                                 unsigned int levels, unsigned int ncounters,
                                 unsigned int n_buckets_ptrs, unsigned int n_buckets)
{
    family_stat->buckets_ptrs = (s_bucket **)encoder->usr->malloc(encoder->usr,
                                                                  n_buckets_ptrs *
                                                                  sizeof(s_bucket *));
    if (!family_stat->buckets_ptrs) {
        return FALSE;
    }

    family_stat->counters = (COUNTER *)encoder->usr->malloc(encoder->usr,
                                                            n_buckets * sizeof(COUNTER) *
                                                            MAXNUMCODES);
    if (!family_stat->counters) {
        goto error_1;
    }

    family_stat->buckets_buf = (s_bucket *)encoder->usr->malloc(encoder->usr,
                                                                n_buckets * sizeof(s_bucket));
    if (!family_stat->buckets_buf) {
        goto error_2;
    }

    fill_model_structures(encoder, family_stat, rep_first, first_size, rep_next, mul_size, levels,
                          ncounters, n_buckets, n_buckets_ptrs);

    return TRUE;

error_2:
    encoder->usr->free(encoder->usr, family_stat->counters);

error_1:
    encoder->usr->free(encoder->usr, family_stat->buckets_ptrs);

    return FALSE;
}

Project: spice-common
File: quic.c

static int encoder_reset(Encoder *encoder, uint32_t *io_ptr, uint32_t *io_ptr_end)
{
    spice_assert(((uintptr_t)io_ptr % 4) == ((uintptr_t)io_ptr_end % 4));
    spice_assert(io_ptr <= io_ptr_end);

    encoder->rgb_state.waitcnt = 0;
    encoder->rgb_state.tabrand_seed = stabrand();
    encoder->rgb_state.wmidx = DEFwmistart;
    encoder->rgb_state.wmileft = DEFwminext;
    set_wm_trigger(&encoder->rgb_state);

    encoder_init_rle(&encoder->rgb_state);

    encoder->io_words_count = io_ptr_end - io_ptr;
    encoder->io_now = io_ptr;
    encoder->io_end = io_ptr_end;
    encoder->rows_completed = 0;

    return TRUE;
}

Project: spice-common
File: quic.c

static void free_family_stat(QuicUsrContext *usr, FamilyStat *family_stat)
{
    usr->free(usr, family_stat->buckets_ptrs);
    usr->free(usr, family_stat->counters);
    usr->free(usr, family_stat->buckets_buf);
}

Project: spice-common
File: quic.c

static void more_io_words(Encoder *encoder)
{
    uint32_t *io_ptr;
    int num_io_words = encoder->usr->more_space(encoder->usr, &io_ptr, encoder->rows_completed);
    if (num_io_words <= 0) {
        encoder->usr->error(encoder->usr, "%s: no more words\n", __FUNCTION__);
    }
    spice_assert(io_ptr);
    encoder->io_words_count += num_io_words;
    encoder->io_now = io_ptr;
    encoder->io_end = encoder->io_now + num_io_words;
}

Project: spice-common
File: quic.c

static inline void encode_ones(Encoder *encoder, unsigned int n)
{
    unsigned int count;

    for (count = n >> 5; count; count--) {
        encode_32(encoder, ~0U);
    }

    if ((n &= 0x1f)) {
        encode(encoder, (1U << n) - 1, n);
    }
}

Project: spice-common
File: quic.c

static unsigned int cnt_l_zeroes(const unsigned int bits)
{
    spice_extra_assert(bits != 0);
#if defined(__GNUC__) && __GNUC__ >= 4
    return __builtin_clz(bits);
#else
    if (bits & 0xff800000) {
        return lzeroes[bits >> 24];
    } else if (bits & 0xffff8000) {
        return 8 + lzeroes[(bits >> 16) & 0x000000ff];
    } else if (bits & 0xffffff80) {
        return 16 + lzeroes[(bits >> 8) & 0x000000ff];
    } else {
        return 24 + lzeroes[bits & 0x000000ff];
    }
#endif
}