nuclear@0: /******************************************************************** nuclear@0: * * nuclear@0: * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * nuclear@0: * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * nuclear@0: * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * nuclear@0: * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * nuclear@0: * * nuclear@0: * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * nuclear@0: * by the Xiph.Org Foundation http://www.xiph.org/ * nuclear@0: * * nuclear@0: ******************************************************************** nuclear@0: nuclear@0: function: packing variable sized words into an octet stream nuclear@0: last mod: $Id: bitwise.c 18051 2011-08-04 17:56:39Z giles $ nuclear@0: nuclear@0: ********************************************************************/ nuclear@0: nuclear@0: /* We're 'LSb' endian; if we write a word but read individual bits, nuclear@0: then we'll read the lsb first */ nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #define BUFFER_INCREMENT 256 nuclear@0: nuclear@0: static const unsigned long mask[]= nuclear@0: {0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, nuclear@0: 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, nuclear@0: 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, nuclear@0: 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, nuclear@0: 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, nuclear@0: 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, nuclear@0: 0x3fffffff,0x7fffffff,0xffffffff }; nuclear@0: nuclear@0: static const unsigned int mask8B[]= nuclear@0: {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; nuclear@0: nuclear@0: void oggpack_writeinit(oggpack_buffer *b){ nuclear@0: memset(b,0,sizeof(*b)); nuclear@0: b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); nuclear@0: b->buffer[0]='\0'; nuclear@0: b->storage=BUFFER_INCREMENT; nuclear@0: } nuclear@0: nuclear@0: void oggpackB_writeinit(oggpack_buffer *b){ nuclear@0: oggpack_writeinit(b); nuclear@0: } nuclear@0: nuclear@0: int oggpack_writecheck(oggpack_buffer *b){ nuclear@0: if(!b->ptr || !b->storage)return -1; nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int oggpackB_writecheck(oggpack_buffer *b){ nuclear@0: return oggpack_writecheck(b); nuclear@0: } nuclear@0: nuclear@0: void oggpack_writetrunc(oggpack_buffer *b,long bits){ nuclear@0: long bytes=bits>>3; nuclear@0: if(b->ptr){ nuclear@0: bits-=bytes*8; nuclear@0: b->ptr=b->buffer+bytes; nuclear@0: b->endbit=bits; nuclear@0: b->endbyte=bytes; nuclear@0: *b->ptr&=mask[bits]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void oggpackB_writetrunc(oggpack_buffer *b,long bits){ nuclear@0: long bytes=bits>>3; nuclear@0: if(b->ptr){ nuclear@0: bits-=bytes*8; nuclear@0: b->ptr=b->buffer+bytes; nuclear@0: b->endbit=bits; nuclear@0: b->endbyte=bytes; nuclear@0: *b->ptr&=mask8B[bits]; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /* Takes only up to 32 bits. */ nuclear@0: void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ nuclear@0: if(bits<0 || bits>32) goto err; nuclear@0: if(b->endbyte>=b->storage-4){ nuclear@0: void *ret; nuclear@0: if(!b->ptr)return; nuclear@0: if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; nuclear@0: ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); nuclear@0: if(!ret) goto err; nuclear@0: b->buffer=ret; nuclear@0: b->storage+=BUFFER_INCREMENT; nuclear@0: b->ptr=b->buffer+b->endbyte; nuclear@0: } nuclear@0: nuclear@0: value&=mask[bits]; nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: b->ptr[0]|=value<endbit; nuclear@0: nuclear@0: if(bits>=8){ nuclear@0: b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); nuclear@0: if(bits>=16){ nuclear@0: b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); nuclear@0: if(bits>=24){ nuclear@0: b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); nuclear@0: if(bits>=32){ nuclear@0: if(b->endbit) nuclear@0: b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); nuclear@0: else nuclear@0: b->ptr[4]=0; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: b->endbyte+=bits/8; nuclear@0: b->ptr+=bits/8; nuclear@0: b->endbit=bits&7; nuclear@0: return; nuclear@0: err: nuclear@0: oggpack_writeclear(b); nuclear@0: } nuclear@0: nuclear@0: /* Takes only up to 32 bits. */ nuclear@0: void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ nuclear@0: if(bits<0 || bits>32) goto err; nuclear@0: if(b->endbyte>=b->storage-4){ nuclear@0: void *ret; nuclear@0: if(!b->ptr)return; nuclear@0: if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; nuclear@0: ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); nuclear@0: if(!ret) goto err; nuclear@0: b->buffer=ret; nuclear@0: b->storage+=BUFFER_INCREMENT; nuclear@0: b->ptr=b->buffer+b->endbyte; nuclear@0: } nuclear@0: nuclear@0: value=(value&mask[bits])<<(32-bits); nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: b->ptr[0]|=value>>(24+b->endbit); nuclear@0: nuclear@0: if(bits>=8){ nuclear@0: b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); nuclear@0: if(bits>=16){ nuclear@0: b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); nuclear@0: if(bits>=24){ nuclear@0: b->ptr[3]=(unsigned char)(value>>(b->endbit)); nuclear@0: if(bits>=32){ nuclear@0: if(b->endbit) nuclear@0: b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); nuclear@0: else nuclear@0: b->ptr[4]=0; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: b->endbyte+=bits/8; nuclear@0: b->ptr+=bits/8; nuclear@0: b->endbit=bits&7; nuclear@0: return; nuclear@0: err: nuclear@0: oggpack_writeclear(b); nuclear@0: } nuclear@0: nuclear@0: void oggpack_writealign(oggpack_buffer *b){ nuclear@0: int bits=8-b->endbit; nuclear@0: if(bits<8) nuclear@0: oggpack_write(b,0,bits); nuclear@0: } nuclear@0: nuclear@0: void oggpackB_writealign(oggpack_buffer *b){ nuclear@0: int bits=8-b->endbit; nuclear@0: if(bits<8) nuclear@0: oggpackB_write(b,0,bits); nuclear@0: } nuclear@0: nuclear@0: static void oggpack_writecopy_helper(oggpack_buffer *b, nuclear@0: void *source, nuclear@0: long bits, nuclear@0: void (*w)(oggpack_buffer *, nuclear@0: unsigned long, nuclear@0: int), nuclear@0: int msb){ nuclear@0: unsigned char *ptr=(unsigned char *)source; nuclear@0: nuclear@0: long bytes=bits/8; nuclear@0: bits-=bytes*8; nuclear@0: nuclear@0: if(b->endbit){ nuclear@0: int i; nuclear@0: /* unaligned copy. Do it the hard way. */ nuclear@0: for(i=0;iendbyte+bytes+1>=b->storage){ nuclear@0: void *ret; nuclear@0: if(!b->ptr) goto err; nuclear@0: if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err; nuclear@0: b->storage=b->endbyte+bytes+BUFFER_INCREMENT; nuclear@0: ret=_ogg_realloc(b->buffer,b->storage); nuclear@0: if(!ret) goto err; nuclear@0: b->buffer=ret; nuclear@0: b->ptr=b->buffer+b->endbyte; nuclear@0: } nuclear@0: nuclear@0: memmove(b->ptr,source,bytes); nuclear@0: b->ptr+=bytes; nuclear@0: b->endbyte+=bytes; nuclear@0: *b->ptr=0; nuclear@0: nuclear@0: } nuclear@0: if(bits){ nuclear@0: if(msb) nuclear@0: w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); nuclear@0: else nuclear@0: w(b,(unsigned long)(ptr[bytes]),bits); nuclear@0: } nuclear@0: return; nuclear@0: err: nuclear@0: oggpack_writeclear(b); nuclear@0: } nuclear@0: nuclear@0: void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ nuclear@0: oggpack_writecopy_helper(b,source,bits,oggpack_write,0); nuclear@0: } nuclear@0: nuclear@0: void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ nuclear@0: oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); nuclear@0: } nuclear@0: nuclear@0: void oggpack_reset(oggpack_buffer *b){ nuclear@0: if(!b->ptr)return; nuclear@0: b->ptr=b->buffer; nuclear@0: b->buffer[0]=0; nuclear@0: b->endbit=b->endbyte=0; nuclear@0: } nuclear@0: nuclear@0: void oggpackB_reset(oggpack_buffer *b){ nuclear@0: oggpack_reset(b); nuclear@0: } nuclear@0: nuclear@0: void oggpack_writeclear(oggpack_buffer *b){ nuclear@0: if(b->buffer)_ogg_free(b->buffer); nuclear@0: memset(b,0,sizeof(*b)); nuclear@0: } nuclear@0: nuclear@0: void oggpackB_writeclear(oggpack_buffer *b){ nuclear@0: oggpack_writeclear(b); nuclear@0: } nuclear@0: nuclear@0: void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ nuclear@0: memset(b,0,sizeof(*b)); nuclear@0: b->buffer=b->ptr=buf; nuclear@0: b->storage=bytes; nuclear@0: } nuclear@0: nuclear@0: void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ nuclear@0: oggpack_readinit(b,buf,bytes); nuclear@0: } nuclear@0: nuclear@0: /* Read in bits without advancing the bitptr; bits <= 32 */ nuclear@0: long oggpack_look(oggpack_buffer *b,int bits){ nuclear@0: unsigned long ret; nuclear@0: unsigned long m; nuclear@0: nuclear@0: if(bits<0 || bits>32) return -1; nuclear@0: m=mask[bits]; nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: if(b->endbyte >= b->storage-4){ nuclear@0: /* not the main path */ nuclear@0: if(b->endbyte > b->storage-((bits+7)>>3)) return -1; nuclear@0: /* special case to avoid reading b->ptr[0], which might be past the end of nuclear@0: the buffer; also skips some useless accounting */ nuclear@0: else if(!bits)return(0L); nuclear@0: } nuclear@0: nuclear@0: ret=b->ptr[0]>>b->endbit; nuclear@0: if(bits>8){ nuclear@0: ret|=b->ptr[1]<<(8-b->endbit); nuclear@0: if(bits>16){ nuclear@0: ret|=b->ptr[2]<<(16-b->endbit); nuclear@0: if(bits>24){ nuclear@0: ret|=b->ptr[3]<<(24-b->endbit); nuclear@0: if(bits>32 && b->endbit) nuclear@0: ret|=b->ptr[4]<<(32-b->endbit); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: return(m&ret); nuclear@0: } nuclear@0: nuclear@0: /* Read in bits without advancing the bitptr; bits <= 32 */ nuclear@0: long oggpackB_look(oggpack_buffer *b,int bits){ nuclear@0: unsigned long ret; nuclear@0: int m=32-bits; nuclear@0: nuclear@0: if(m<0 || m>32) return -1; nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: if(b->endbyte >= b->storage-4){ nuclear@0: /* not the main path */ nuclear@0: if(b->endbyte > b->storage-((bits+7)>>3)) return -1; nuclear@0: /* special case to avoid reading b->ptr[0], which might be past the end of nuclear@0: the buffer; also skips some useless accounting */ nuclear@0: else if(!bits)return(0L); nuclear@0: } nuclear@0: nuclear@0: ret=b->ptr[0]<<(24+b->endbit); nuclear@0: if(bits>8){ nuclear@0: ret|=b->ptr[1]<<(16+b->endbit); nuclear@0: if(bits>16){ nuclear@0: ret|=b->ptr[2]<<(8+b->endbit); nuclear@0: if(bits>24){ nuclear@0: ret|=b->ptr[3]<<(b->endbit); nuclear@0: if(bits>32 && b->endbit) nuclear@0: ret|=b->ptr[4]>>(8-b->endbit); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); nuclear@0: } nuclear@0: nuclear@0: long oggpack_look1(oggpack_buffer *b){ nuclear@0: if(b->endbyte>=b->storage)return(-1); nuclear@0: return((b->ptr[0]>>b->endbit)&1); nuclear@0: } nuclear@0: nuclear@0: long oggpackB_look1(oggpack_buffer *b){ nuclear@0: if(b->endbyte>=b->storage)return(-1); nuclear@0: return((b->ptr[0]>>(7-b->endbit))&1); nuclear@0: } nuclear@0: nuclear@0: void oggpack_adv(oggpack_buffer *b,int bits){ nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; nuclear@0: nuclear@0: b->ptr+=bits/8; nuclear@0: b->endbyte+=bits/8; nuclear@0: b->endbit=bits&7; nuclear@0: return; nuclear@0: nuclear@0: overflow: nuclear@0: b->ptr=NULL; nuclear@0: b->endbyte=b->storage; nuclear@0: b->endbit=1; nuclear@0: } nuclear@0: nuclear@0: void oggpackB_adv(oggpack_buffer *b,int bits){ nuclear@0: oggpack_adv(b,bits); nuclear@0: } nuclear@0: nuclear@0: void oggpack_adv1(oggpack_buffer *b){ nuclear@0: if(++(b->endbit)>7){ nuclear@0: b->endbit=0; nuclear@0: b->ptr++; nuclear@0: b->endbyte++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void oggpackB_adv1(oggpack_buffer *b){ nuclear@0: oggpack_adv1(b); nuclear@0: } nuclear@0: nuclear@0: /* bits <= 32 */ nuclear@0: long oggpack_read(oggpack_buffer *b,int bits){ nuclear@0: long ret; nuclear@0: unsigned long m; nuclear@0: nuclear@0: if(bits<0 || bits>32) goto err; nuclear@0: m=mask[bits]; nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: if(b->endbyte >= b->storage-4){ nuclear@0: /* not the main path */ nuclear@0: if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; nuclear@0: /* special case to avoid reading b->ptr[0], which might be past the end of nuclear@0: the buffer; also skips some useless accounting */ nuclear@0: else if(!bits)return(0L); nuclear@0: } nuclear@0: nuclear@0: ret=b->ptr[0]>>b->endbit; nuclear@0: if(bits>8){ nuclear@0: ret|=b->ptr[1]<<(8-b->endbit); nuclear@0: if(bits>16){ nuclear@0: ret|=b->ptr[2]<<(16-b->endbit); nuclear@0: if(bits>24){ nuclear@0: ret|=b->ptr[3]<<(24-b->endbit); nuclear@0: if(bits>32 && b->endbit){ nuclear@0: ret|=b->ptr[4]<<(32-b->endbit); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ret&=m; nuclear@0: b->ptr+=bits/8; nuclear@0: b->endbyte+=bits/8; nuclear@0: b->endbit=bits&7; nuclear@0: return ret; nuclear@0: nuclear@0: overflow: nuclear@0: err: nuclear@0: b->ptr=NULL; nuclear@0: b->endbyte=b->storage; nuclear@0: b->endbit=1; nuclear@0: return -1L; nuclear@0: } nuclear@0: nuclear@0: /* bits <= 32 */ nuclear@0: long oggpackB_read(oggpack_buffer *b,int bits){ nuclear@0: long ret; nuclear@0: long m=32-bits; nuclear@0: nuclear@0: if(m<0 || m>32) goto err; nuclear@0: bits+=b->endbit; nuclear@0: nuclear@0: if(b->endbyte+4>=b->storage){ nuclear@0: /* not the main path */ nuclear@0: if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; nuclear@0: /* special case to avoid reading b->ptr[0], which might be past the end of nuclear@0: the buffer; also skips some useless accounting */ nuclear@0: else if(!bits)return(0L); nuclear@0: } nuclear@0: nuclear@0: ret=b->ptr[0]<<(24+b->endbit); nuclear@0: if(bits>8){ nuclear@0: ret|=b->ptr[1]<<(16+b->endbit); nuclear@0: if(bits>16){ nuclear@0: ret|=b->ptr[2]<<(8+b->endbit); nuclear@0: if(bits>24){ nuclear@0: ret|=b->ptr[3]<<(b->endbit); nuclear@0: if(bits>32 && b->endbit) nuclear@0: ret|=b->ptr[4]>>(8-b->endbit); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); nuclear@0: nuclear@0: b->ptr+=bits/8; nuclear@0: b->endbyte+=bits/8; nuclear@0: b->endbit=bits&7; nuclear@0: return ret; nuclear@0: nuclear@0: overflow: nuclear@0: err: nuclear@0: b->ptr=NULL; nuclear@0: b->endbyte=b->storage; nuclear@0: b->endbit=1; nuclear@0: return -1L; nuclear@0: } nuclear@0: nuclear@0: long oggpack_read1(oggpack_buffer *b){ nuclear@0: long ret; nuclear@0: nuclear@0: if(b->endbyte >= b->storage) goto overflow; nuclear@0: ret=(b->ptr[0]>>b->endbit)&1; nuclear@0: nuclear@0: b->endbit++; nuclear@0: if(b->endbit>7){ nuclear@0: b->endbit=0; nuclear@0: b->ptr++; nuclear@0: b->endbyte++; nuclear@0: } nuclear@0: return ret; nuclear@0: nuclear@0: overflow: nuclear@0: b->ptr=NULL; nuclear@0: b->endbyte=b->storage; nuclear@0: b->endbit=1; nuclear@0: return -1L; nuclear@0: } nuclear@0: nuclear@0: long oggpackB_read1(oggpack_buffer *b){ nuclear@0: long ret; nuclear@0: nuclear@0: if(b->endbyte >= b->storage) goto overflow; nuclear@0: ret=(b->ptr[0]>>(7-b->endbit))&1; nuclear@0: nuclear@0: b->endbit++; nuclear@0: if(b->endbit>7){ nuclear@0: b->endbit=0; nuclear@0: b->ptr++; nuclear@0: b->endbyte++; nuclear@0: } nuclear@0: return ret; nuclear@0: nuclear@0: overflow: nuclear@0: b->ptr=NULL; nuclear@0: b->endbyte=b->storage; nuclear@0: b->endbit=1; nuclear@0: return -1L; nuclear@0: } nuclear@0: nuclear@0: long oggpack_bytes(oggpack_buffer *b){ nuclear@0: return(b->endbyte+(b->endbit+7)/8); nuclear@0: } nuclear@0: nuclear@0: long oggpack_bits(oggpack_buffer *b){ nuclear@0: return(b->endbyte*8+b->endbit); nuclear@0: } nuclear@0: nuclear@0: long oggpackB_bytes(oggpack_buffer *b){ nuclear@0: return oggpack_bytes(b); nuclear@0: } nuclear@0: nuclear@0: long oggpackB_bits(oggpack_buffer *b){ nuclear@0: return oggpack_bits(b); nuclear@0: } nuclear@0: nuclear@0: unsigned char *oggpack_get_buffer(oggpack_buffer *b){ nuclear@0: return(b->buffer); nuclear@0: } nuclear@0: nuclear@0: unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ nuclear@0: return oggpack_get_buffer(b); nuclear@0: } nuclear@0: nuclear@0: /* Self test of the bitwise routines; everything else is based on nuclear@0: them, so they damned well better be solid. */ nuclear@0: nuclear@0: #ifdef _V_SELFTEST nuclear@0: #include nuclear@0: nuclear@0: static int ilog(unsigned int v){ nuclear@0: int ret=0; nuclear@0: while(v){ nuclear@0: ret++; nuclear@0: v>>=1; nuclear@0: } nuclear@0: return(ret); nuclear@0: } nuclear@0: nuclear@0: oggpack_buffer o; nuclear@0: oggpack_buffer r; nuclear@0: nuclear@0: void report(char *in){ nuclear@0: fprintf(stderr,"%s",in); nuclear@0: exit(1); nuclear@0: } nuclear@0: nuclear@0: void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ nuclear@0: long bytes,i; nuclear@0: unsigned char *buffer; nuclear@0: nuclear@0: oggpack_reset(&o); nuclear@0: for(i=0;i