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