Blame src/util/bits.c

Packit 5e46da
/*****************************************************************************
Packit 5e46da
 * bits.c : Bit handling helpers
Packit 5e46da
 *****************************************************************************
Packit 5e46da
 * Copyright (C) 2003 the VideoLAN team
Packit 5e46da
 *
Packit 5e46da
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
Packit 5e46da
 *
Packit 5e46da
 * This library is free software; you can redistribute it and/or
Packit 5e46da
 * modify it under the terms of the GNU Lesser General Public
Packit 5e46da
 * License as published by the Free Software Foundation; either
Packit 5e46da
 * version 2.1 of the License, or (at your option) any later version.
Packit 5e46da
 *
Packit 5e46da
 * This library is distributed in the hope that it will be useful,
Packit 5e46da
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e46da
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 5e46da
 * Lesser General Public License for more details.
Packit 5e46da
 *
Packit 5e46da
 * You should have received a copy of the GNU Lesser General Public
Packit 5e46da
 * License along with this library. If not, see
Packit 5e46da
 * <http://www.gnu.org/licenses/>.
Packit 5e46da
 *****************************************************************************/
Packit 5e46da
Packit 5e46da
#if HAVE_CONFIG_H
Packit 5e46da
#include "config.h"
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#include "bits.h"
Packit 5e46da
Packit 5e46da
#include "file/file.h"
Packit 5e46da
#include "util/logging.h"
Packit 5e46da
Packit 5e46da
#include <stdio.h>  // SEEK_*
Packit 5e46da
Packit 5e46da
/**
Packit 5e46da
 * \file
Packit 5e46da
 * This file defines functions, structures for handling streams of bits
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
void bb_init( BITBUFFER *bb, const uint8_t *p_data, size_t i_data )
Packit 5e46da
{
Packit 5e46da
    bb->p_start = p_data;
Packit 5e46da
    bb->p       = bb->p_start;
Packit 5e46da
    bb->p_end   = bb->p_start + i_data;
Packit 5e46da
    bb->i_left  = 8;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _bs_read( BITSTREAM *bs)
Packit 5e46da
{
Packit 5e46da
    int result = 0;
Packit 5e46da
    int64_t got;
Packit 5e46da
Packit 5e46da
    got = file_read(bs->fp, bs->buf, BF_BUF_SIZE);
Packit 5e46da
    if (got <= 0 || got > BF_BUF_SIZE) {
Packit 5e46da
        BD_DEBUG(DBG_FILE, "_bs_read(): read error\n");
Packit 5e46da
        got = 0;
Packit 5e46da
        result = -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    bs->size = (size_t)got;
Packit 5e46da
    bb_init(&bs->bb, bs->buf, bs->size);
Packit 5e46da
Packit 5e46da
    return result;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _bs_read_at( BITSTREAM *bs, int64_t off )
Packit 5e46da
{
Packit 5e46da
    if (file_seek(bs->fp, off, SEEK_SET) < 0) {
Packit 5e46da
        BD_DEBUG(DBG_FILE | DBG_CRIT, "bs_read(): seek failed\n");
Packit 5e46da
        /* no change in state. Caller _must_ check return value. */
Packit 5e46da
        return -1;
Packit 5e46da
    }
Packit 5e46da
    bs->pos = off;
Packit 5e46da
    return _bs_read(bs);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
int bs_init( BITSTREAM *bs, BD_FILE_H *fp )
Packit 5e46da
{
Packit 5e46da
    int64_t size = file_size(fp);;
Packit 5e46da
    bs->fp = fp;
Packit 5e46da
    bs->pos = 0;
Packit 5e46da
    bs->end = (size < 0) ? 0 : size;
Packit 5e46da
Packit 5e46da
    return _bs_read(bs);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void bb_seek( BITBUFFER *bb, int64_t off, int whence)
Packit 5e46da
{
Packit 5e46da
    int64_t b;
Packit 5e46da
Packit 5e46da
    switch (whence) {
Packit 5e46da
        case SEEK_CUR:
Packit 5e46da
            off = (bb->p - bb->p_start) * 8 + off;
Packit 5e46da
            break;
Packit 5e46da
        case SEEK_END:
Packit 5e46da
            off = (bb->p_end - bb->p_start) * 8 - off;
Packit 5e46da
            break;
Packit 5e46da
        case SEEK_SET:
Packit 5e46da
        default:
Packit 5e46da
            break;
Packit 5e46da
    }
Packit 5e46da
    b = off >> 3;
Packit 5e46da
    bb->p = &bb->p_start[b];
Packit 5e46da
Packit 5e46da
    int i_tmp = bb->i_left - (off & 0x07);
Packit 5e46da
    if (i_tmp <= 0) {
Packit 5e46da
        bb->i_left = 8 + i_tmp;
Packit 5e46da
        bb->p++;
Packit 5e46da
    } else {
Packit 5e46da
        bb->i_left = i_tmp;
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _bs_seek( BITSTREAM *bs, int64_t off, int whence)
Packit 5e46da
{
Packit 5e46da
    int result = 0;
Packit 5e46da
    int64_t b;
Packit 5e46da
Packit 5e46da
    switch (whence) {
Packit 5e46da
        case SEEK_CUR:
Packit 5e46da
            off = bs->pos * 8 + (bs->bb.p - bs->bb.p_start) * 8 + off;
Packit 5e46da
            break;
Packit 5e46da
        case SEEK_END:
Packit 5e46da
            off = bs->end * 8 - off;
Packit 5e46da
            break;
Packit 5e46da
        case SEEK_SET:
Packit 5e46da
        default:
Packit 5e46da
            break;
Packit 5e46da
    }
Packit 5e46da
    if (off < 0) {
Packit 5e46da
        BD_DEBUG(DBG_FILE | DBG_CRIT, "bs_seek(): seek failed (negative offset)\n");
Packit 5e46da
        return -1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    b = off >> 3;
Packit 5e46da
    if (b >= bs->end)
Packit 5e46da
    {
Packit 5e46da
        int64_t pos;
Packit 5e46da
        if (BF_BUF_SIZE < bs->end) {
Packit 5e46da
            pos = bs->end - BF_BUF_SIZE;
Packit 5e46da
        } else {
Packit 5e46da
            pos = 0;
Packit 5e46da
        }
Packit 5e46da
        result = _bs_read_at(bs, pos);
Packit 5e46da
        bs->bb.p = bs->bb.p_end;
Packit 5e46da
    } else if (b < bs->pos || b >= (bs->pos + BF_BUF_SIZE)) {
Packit 5e46da
        result  = _bs_read_at(bs, b);
Packit 5e46da
    } else {
Packit 5e46da
        b -= bs->pos;
Packit 5e46da
        bs->bb.p = &bs->bb.p_start[b];
Packit 5e46da
        bs->bb.i_left = 8 - (off & 0x07);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return result;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
#if 0
Packit 5e46da
void bb_seek_byte( BITBUFFER *bb, int64_t off)
Packit 5e46da
{
Packit 5e46da
    bb_seek(bb, off << 3, SEEK_SET);
Packit 5e46da
}
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
int bs_seek_byte( BITSTREAM *s, int64_t off)
Packit 5e46da
{
Packit 5e46da
    return _bs_seek(s, off << 3, SEEK_SET);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
Packit 5e46da
uint32_t bb_read( BITBUFFER *bb, int i_count )
Packit 5e46da
{
Packit 5e46da
    static const uint32_t i_mask[33] = {
Packit 5e46da
        0x00,
Packit 5e46da
        0x01,      0x03,      0x07,      0x0f,
Packit 5e46da
        0x1f,      0x3f,      0x7f,      0xff,
Packit 5e46da
        0x1ff,     0x3ff,     0x7ff,     0xfff,
Packit 5e46da
        0x1fff,    0x3fff,    0x7fff,    0xffff,
Packit 5e46da
        0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,
Packit 5e46da
        0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,
Packit 5e46da
        0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
Packit 5e46da
        0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff
Packit 5e46da
    };
Packit 5e46da
    int      i_shr;
Packit 5e46da
    uint32_t i_result = 0;
Packit 5e46da
Packit 5e46da
    while( i_count > 0 ) {
Packit 5e46da
Packit 5e46da
        if( bb->p >= bb->p_end ) {
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        i_shr = bb->i_left - i_count;
Packit 5e46da
        if( i_shr >= 0 ) {
Packit 5e46da
            /* more in the buffer than requested */
Packit 5e46da
            i_result |= ( *bb->p >> i_shr )&i_mask[i_count];
Packit 5e46da
            bb->i_left -= i_count;
Packit 5e46da
            if( bb->i_left == 0 ) {
Packit 5e46da
                bb->p++;
Packit 5e46da
                bb->i_left = 8;
Packit 5e46da
            }
Packit 5e46da
            return( i_result );
Packit 5e46da
        } else {
Packit 5e46da
            /* less in the buffer than requested */
Packit 5e46da
           i_result |= (unsigned)(*bb->p&i_mask[bb->i_left]) << -i_shr;
Packit 5e46da
           i_count  -= bb->i_left;
Packit 5e46da
           bb->p++;
Packit 5e46da
           bb->i_left = 8;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return( i_result );
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
uint32_t bs_read( BITSTREAM *bs, int i_count )
Packit 5e46da
{
Packit 5e46da
    int left;
Packit 5e46da
    int bytes = (i_count + 7) >> 3;
Packit 5e46da
Packit 5e46da
    if (bs->bb.p + bytes >= bs->bb.p_end) {
Packit 5e46da
        bs->pos = bs->pos + (bs->bb.p - bs->bb.p_start);
Packit 5e46da
        left = bs->bb.i_left;
Packit 5e46da
        file_seek(bs->fp, bs->pos, SEEK_SET);
Packit 5e46da
        bs->size = file_read(bs->fp, bs->buf, BF_BUF_SIZE);
Packit 5e46da
        bb_init(&bs->bb, bs->buf, bs->size);
Packit 5e46da
        bs->bb.i_left = left;
Packit 5e46da
    }
Packit 5e46da
    return bb_read(&bs->bb, i_count);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void bb_skip( BITBUFFER *bb, size_t i_count )
Packit 5e46da
{
Packit 5e46da
    bb->p += i_count >> 3;
Packit 5e46da
    bb->i_left -= i_count & 0x07;
Packit 5e46da
Packit 5e46da
    if( bb->i_left <= 0 ) {
Packit 5e46da
        bb->p++;
Packit 5e46da
        bb->i_left += 8;
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void bs_skip( BITSTREAM *bs, size_t i_count )
Packit 5e46da
{
Packit 5e46da
    int left;
Packit 5e46da
    size_t bytes = (i_count + 7) >> 3;
Packit 5e46da
Packit 5e46da
    if (bs->bb.p + bytes >= bs->bb.p_end) {
Packit 5e46da
        bs->pos = bs->pos + (bs->bb.p - bs->bb.p_start);
Packit 5e46da
        left = bs->bb.i_left;
Packit 5e46da
        file_seek(bs->fp, bs->pos, SEEK_SET);
Packit 5e46da
        bs->size = file_read(bs->fp, bs->buf, BF_BUF_SIZE);
Packit 5e46da
        bb_init(&bs->bb, bs->buf, bs->size);
Packit 5e46da
        bs->bb.i_left = left;
Packit 5e46da
    }
Packit 5e46da
    bb_skip(&bs->bb, i_count);
Packit 5e46da
}