/******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * * THE GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH * * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2000 * * by Monty and the XIPHOPHORUS Company * * http://www.xiph.org/ * * * ******************************************************************** function: packing variable sized words into an octet stream last mod: $Id: bitwise.c,v 1.2.2.1 2000/11/04 06:17:23 xiphmont Exp $ ********************************************************************/ /* We're 'LSb' endian; if we write a word but read individual bits, then we'll read the lsb first */ #include #include #include #define BUFFER_INCREMENT 256 static unsigned long mask[]= {0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, 0x3fffffff,0x7fffffff,0xffffffff }; void oggpack_writeinit(oggpack_buffer *b){ memset(b,0,sizeof(oggpack_buffer)); b->ptr=b->buffer=malloc(BUFFER_INCREMENT); b->buffer[0]='\0'; b->storage=BUFFER_INCREMENT; } void oggpack_reset(oggpack_buffer *b){ b->ptr=b->buffer; b->buffer[0]=0; b->endbit=b->endbyte=0; } void oggpack_writeclear(oggpack_buffer *b){ free(b->buffer); memset(b,0,sizeof(oggpack_buffer)); } void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ memset(b,0,sizeof(oggpack_buffer)); b->buffer=b->ptr=buf; b->storage=bytes; } /* Takes only up to 32 bits. */ void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ if(b->endbyte+4>=b->storage){ b->buffer=realloc(b->buffer,b->storage+BUFFER_INCREMENT); b->storage+=BUFFER_INCREMENT; b->ptr=b->buffer+b->endbyte; } value&=mask[bits]; bits+=b->endbit; b->ptr[0]|=value<endbit; if(bits>=8){ b->ptr[1]=value>>(8-b->endbit); if(bits>=16){ b->ptr[2]=value>>(16-b->endbit); if(bits>=24){ b->ptr[3]=value>>(24-b->endbit); if(bits>=32){ if(b->endbit) b->ptr[4]=value>>(32-b->endbit); else b->ptr[4]=0; } } } } b->endbyte+=bits/8; b->ptr+=bits/8; b->endbit=bits&7; } /* Read in bits without advancing the bitptr; bits <= 32 */ long oggpack_look(oggpack_buffer *b,int bits){ unsigned long ret; unsigned long m=mask[bits]; bits+=b->endbit; if(b->endbyte+4>=b->storage){ /* not the main path */ if(b->endbyte+(bits-1)/8>=b->storage)return(-1); } ret=b->ptr[0]>>b->endbit; if(bits>8){ ret|=b->ptr[1]<<(8-b->endbit); if(bits>16){ ret|=b->ptr[2]<<(16-b->endbit); if(bits>24){ ret|=b->ptr[3]<<(24-b->endbit); if(bits>32 && b->endbit) ret|=b->ptr[4]<<(32-b->endbit); } } } return(m&ret); } long oggpack_look1(oggpack_buffer *b){ if(b->endbyte>=b->storage)return(-1); return((b->ptr[0]>>b->endbit)&1); } /* Read in bits without advancing the bitptr; bits <= 8 */ /* we never return 'out of bits'; we'll handle it on _adv */ long oggpack_look_huff(oggpack_buffer *b,int bits){ unsigned long ret; unsigned long m=mask[bits]; bits+=b->endbit; ret=b->ptr[0]>>b->endbit; if(bits>8){ ret|=b->ptr[1]<<(8-b->endbit); } return(m&ret); } void oggpack_adv(oggpack_buffer *b,int bits){ bits+=b->endbit; b->ptr+=bits/8; b->endbyte+=bits/8; b->endbit=bits&7; } void oggpack_adv1(oggpack_buffer *b){ if(++(b->endbit)>7){ b->endbit=0; b->ptr++; b->endbyte++; } } /* have to check for overflow now. return -1 on overflow */ int oggpack_adv_huff(oggpack_buffer *b,int bits){ if(b->endbyte+(b->endbit+bits-1)/8>=b->storage)return(-1); bits+=b->endbit; b->ptr+=bits/8; b->endbyte+=bits/8; b->endbit=bits&7; return 0; } /* bits <= 32 */ long oggpack_read(oggpack_buffer *b,int bits){ unsigned long ret; unsigned long m=mask[bits]; bits+=b->endbit; if(b->endbyte+4>=b->storage){ /* not the main path */ ret=-1; if(b->endbyte+(bits-1)/8>=b->storage)goto overflow; } ret=b->ptr[0]>>b->endbit; if(bits>8){ ret|=b->ptr[1]<<(8-b->endbit); if(bits>16){ ret|=b->ptr[2]<<(16-b->endbit); if(bits>24){ ret|=b->ptr[3]<<(24-b->endbit); if(bits>32 && b->endbit){ ret|=b->ptr[4]<<(32-b->endbit); } } } } ret&=m; overflow: b->ptr+=bits/8; b->endbyte+=bits/8; b->endbit=bits&7; return(ret); } long oggpack_read1(oggpack_buffer *b){ unsigned long ret; if(b->endbyte>=b->storage){ /* not the main path */ ret=-1; goto overflow; } ret=(b->ptr[0]>>b->endbit)&1; overflow: b->endbit++; if(b->endbit>7){ b->endbit=0; b->ptr++; b->endbyte++; } return(ret); } long oggpack_bytes(oggpack_buffer *b){ return(b->endbyte+(b->endbit+7)/8); } long oggpack_bits(oggpack_buffer *b){ return(b->endbyte*8+b->endbit); } unsigned char *oggpack_get_buffer(oggpack_buffer *b){ return(b->buffer); } /* Self test of the bitwise routines; everything else is based on them, so they damned well better be solid. */ #ifdef _V_SELFTEST #include static int ilog(unsigned int v){ int ret=0; while(v){ ret++; v>>=1; } return(ret); } oggpack_buffer o; oggpack_buffer r; void report(char *in){ fprintf(stderr,"%s",in); exit(1); } void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ long bytes,i; unsigned char *buffer; oggpack_reset(&o); for(i=0;i