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