Blame |
Last modification |
View Log
| RSS feed
/********************************************************************
* *
* 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 <string.h>
#include <stdlib.h>
#include "os.h"
#include "ogg.h"
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 };
/* 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
){
unsigned long m
=mask
[bits
];
unsigned long ret
;
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 */
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
;
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
);
}