|
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 |
}
|