/******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** function: packing variable sized words into an octet stream ********************************************************************/ /* We're 'LSb' endian; if we write a word but read individual bits, then we'll read the lsb first */ #include "config-tremor.h" #include #include "ogg.h" static const unsigned long mask[] ICONST_ATTR = {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 }; /* mark read process as having run off the end */ static void _adv_halt(oggpack_buffer *b){ b->headptr=b->head->buffer->data+b->head->begin+b->head->length; b->headend=-1; b->headbit=0; } /* spans forward, skipping as many bytes as headend is negative; if headend is zero, simply finds next byte. If we're up to the end of the buffer, leaves headend at zero. If we've read past the end, halt the decode process. */ static void _span(oggpack_buffer *b){ while(b->headend<1){ if(b->head->next){ b->count+=b->head->length; b->head=b->head->next; b->headptr=b->head->buffer->data+b->head->begin-b->headend; b->headend+=b->head->length; }else{ /* we've either met the end of decode, or gone past it. halt only if we're past */ if(b->headend<0 || b->headbit) /* read has fallen off the end */ _adv_halt(b); break; } } } void oggpack_readinit(oggpack_buffer *b,ogg_reference *r){ memset(b,0,sizeof(*b)); b->tail=b->head=r; b->count=0; b->headptr=b->head->buffer->data+b->head->begin; b->headend=b->head->length; _span(b); } #define _lookspan() while(!end){\ head=head->next;\ if(!head) return -1;\ ptr=head->buffer->data + head->begin;\ end=head->length;\ } /* Read in bits without advancing the bitptr; bits <= 32 */ long oggpack_look(oggpack_buffer *b,int bits) ICODE_ATTR; long oggpack_look(oggpack_buffer *b,int bits){ unsigned long m=mask[bits]; unsigned long ret=0; bits+=b->headbit; if(bits >= b->headend<<3){ int end=b->headend; unsigned char *ptr=b->headptr; ogg_reference *head=b->head; if(end<0)return -1; if(bits){ _lookspan(); ret=*ptr++>>b->headbit; if(bits>8){ --end; _lookspan(); ret|=*ptr++<<(8-b->headbit); if(bits>16){ --end; _lookspan(); ret|=*ptr++<<(16-b->headbit); if(bits>24){ --end; _lookspan(); ret|=*ptr++<<(24-b->headbit); if(bits>32 && b->headbit){ --end; _lookspan(); ret|=*ptr<<(32-b->headbit); } } } } } }else{ /* make this a switch jump-table */ ret=b->headptr[0]>>b->headbit; if(bits>8){ ret|=b->headptr[1]<<(8-b->headbit); if(bits>16){ ret|=b->headptr[2]<<(16-b->headbit); if(bits>24){ ret|=b->headptr[3]<<(24-b->headbit); if(bits>32 && b->headbit) ret|=b->headptr[4]<<(32-b->headbit); } } } } ret&=m; return ret; } /* limited to 32 at a time */ #if CONFIG_CPU!=PP5020 /* TODO: This function (and this function only) causes a "relocation truncated to fit: R_ARM_PC24" error when in IRAM on ARM targets */ void oggpack_adv(oggpack_buffer *b,int bits) ICODE_ATTR; #endif void oggpack_adv(oggpack_buffer *b,int bits){ bits+=b->headbit; b->headbit=bits&7; b->headptr+=bits/8; if((b->headend-=bits/8)<1)_span(b); } /* spans forward and finds next byte. Never halts */ static void _span_one(oggpack_buffer *b){ while(b->headend<1){ if(b->head->next){ b->count+=b->head->length; b->head=b->head->next; b->headptr=b->head->buffer->data+b->head->begin; b->headend=b->head->length; }else break; } } static int _halt_one(oggpack_buffer *b){ if(b->headend<1){ _adv_halt(b); return -1; } return 0; } int oggpack_eop(oggpack_buffer *b){ if(b->headend<0)return -1; return 0; } /* bits <= 32 */ long oggpack_read(oggpack_buffer *b,int bits){ unsigned long m=mask[bits]; ogg_uint32_t ret=0; bits+=b->headbit; if(bits >= b->headend<<3){ if(b->headend<0)return -1; if(bits){ if (_halt_one(b)) return -1; ret=*b->headptr>>b->headbit; if(bits>=8){ ++b->headptr; --b->headend; _span_one(b); if(bits>8){ if (_halt_one(b)) return -1; ret|=*b->headptr<<(8-b->headbit); if(bits>=16){ ++b->headptr; --b->headend; _span_one(b); if(bits>16){ if (_halt_one(b)) return -1; ret|=*b->headptr<<(16-b->headbit); if(bits>=24){ ++b->headptr; --b->headend; _span_one(b); if(bits>24){ if (_halt_one(b)) return -1; ret|=*b->headptr<<(24-b->headbit); if(bits>=32){ ++b->headptr; --b->headend; _span_one(b); if(bits>32){ if (_halt_one(b)) return -1; if(b->headbit)ret|=*b->headptr<<(32-b->headbit); } } } } } } } } } }else{ ret=b->headptr[0]>>b->headbit; if(bits>8){ ret|=b->headptr[1]<<(8-b->headbit); if(bits>16){ ret|=b->headptr[2]<<(16-b->headbit); if(bits>24){ ret|=b->headptr[3]<<(24-b->headbit); if(bits>32 && b->headbit){ ret|=b->headptr[4]<<(32-b->headbit); } } } } b->headptr+=bits/8; b->headend-=bits/8; } ret&=m; b->headbit=bits&7; return ret; } long oggpack_bytes(oggpack_buffer *b){ return(b->count+b->headptr-b->head->buffer->data-b->head->begin+ (b->headbit+7)/8); } long oggpack_bits(oggpack_buffer *b){ return((b->count+b->headptr-b->head->buffer->data-b->head->begin)*8+ b->headbit); }