/*
 * The Python Imaging Library.
 * $Id$
 *
 * decoder for packed bitfields (converts to floating point)
 *
 * history:
 * 97-05-31 fl created (much more than originally intended)
 *
 * Copyright (c) Fredrik Lundh 1997.
 * Copyright (c) Secret Labs AB 1997.
 *
 * See the README file for information on usage and redistribution.
 */

#include "Imaging.h"

#include "Bit.h"

int
ImagingBitDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
    BITSTATE *bitstate = state->context;
    UINT8 *ptr;

    if (state->state == 0) {
        /* Initialize context variables */

        /* this decoder only works for float32 image buffers */
        if (im->type != IMAGING_TYPE_FLOAT32) {
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        }

        /* sanity check */
        if (bitstate->bits < 1 || bitstate->bits >= 32) {
            state->errcode = IMAGING_CODEC_CONFIG;
            return -1;
        }

        bitstate->mask = (1 << bitstate->bits) - 1;

        if (bitstate->sign) {
            bitstate->signmask = (1 << (bitstate->bits - 1));
        }

        /* check image orientation */
        if (state->ystep < 0) {
            state->y = state->ysize - 1;
            state->ystep = -1;
        } else {
            state->ystep = 1;
        }

        state->state = 1;
    }

    ptr = buf;

    while (bytes > 0) {
        UINT8 byte = *ptr;

        ptr++;
        bytes--;

        /* get a byte from the input stream and insert in the bit buffer */
        if (bitstate->fill & 1) {
            /* fill MSB first */
            bitstate->bitbuffer |= (unsigned long)byte << bitstate->bitcount;
        } else {
            /* fill LSB first */
            bitstate->bitbuffer = (bitstate->bitbuffer << 8) | byte;
        }

        bitstate->bitcount += 8;

        while (bitstate->bitcount >= bitstate->bits) {
            /* get a pixel from the bit buffer */
            unsigned long data;
            FLOAT32 pixel;

            if (bitstate->fill & 2) {
                /* store LSB first */
                data = bitstate->bitbuffer & bitstate->mask;
                if (bitstate->bitcount > 32) {
                    /* bitbuffer overflow; restore it from last input byte */
                    bitstate->bitbuffer =
                        byte >> (8 - (bitstate->bitcount - bitstate->bits));
                } else {
                    bitstate->bitbuffer >>= bitstate->bits;
                }
            } else {
                /* store MSB first */
                data = (bitstate->bitbuffer >> (bitstate->bitcount - bitstate->bits)) &
                       bitstate->mask;
            }

            bitstate->bitcount -= bitstate->bits;

            if (bitstate->lutsize > 0) {
                /* map through lookup table */
                if (data <= 0) {
                    pixel = bitstate->lut[0];
                } else if (data >= bitstate->lutsize) {
                    pixel = bitstate->lut[bitstate->lutsize - 1];
                } else {
                    pixel = bitstate->lut[data];
                }
            } else {
                /* convert */
                if (data & bitstate->signmask) {
                    /* image memory contains signed data */
                    pixel = (FLOAT32)(INT32)(data | ~bitstate->mask);
                } else {
                    pixel = (FLOAT32)data;
                }
            }

            *(FLOAT32 *)(&im->image32[state->y][state->x]) = pixel;

            /* step forward */
            if (++state->x >= state->xsize) {
                /* new line */
                state->y += state->ystep;
                if (state->y < 0 || state->y >= state->ysize) {
                    /* end of file (errcode = 0) */
                    return -1;
                }
                state->x = 0;
                /* reset bit buffer */
                if (bitstate->pad > 0) {
                    bitstate->bitcount = 0;
                }
            }
        }
    }

    return ptr - buf;
}
