summaryrefslogtreecommitdiff
path: root/lib/bitpack.c
blob: 8195003bad1bd3bb6683c721bd61539ff1ec8d57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE OggTheora SOFTWARE 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 OggTheora SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
 *                                                                  *
 ********************************************************************

  function: packing variable sized words into an octet stream
  last mod: $Id: bitpack.c 16503 2009-08-22 18:14:02Z giles $

 ********************************************************************/
#include <string.h>
#include <stdlib.h>
#include "bitpack.h"

/*We're 'MSb' endian; if we write a word but read individual bits,
   then we'll read the MSb first.*/

void oc_pack_readinit(oc_pack_buf *_b,unsigned char *_buf,long _bytes){
  memset(_b,0,sizeof(*_b));
  _b->ptr=_buf;
  _b->stop=_buf+_bytes;
}

static oc_pb_window oc_pack_refill(oc_pack_buf *_b,int _bits){
  const unsigned char *ptr;
  const unsigned char *stop;
  oc_pb_window         window;
  int                  available;
  window=_b->window;
  available=_b->bits;
  ptr=_b->ptr;
  stop=_b->stop;
  while(available<=OC_PB_WINDOW_SIZE-8&&ptr<stop){
    available+=8;
    window|=(oc_pb_window)*ptr++<<OC_PB_WINDOW_SIZE-available;
  }
  _b->ptr=ptr;
  if(_bits>available){
    if(ptr>=stop){
      _b->eof=1;
      available=OC_LOTS_OF_BITS;
    }
    else window|=*ptr>>(available&7);
  }
  _b->bits=available;
  return window;
}

int oc_pack_look1(oc_pack_buf *_b){
  oc_pb_window window;
  int          available;
  window=_b->window;
  available=_b->bits;
  if(available<1)_b->window=window=oc_pack_refill(_b,1);
  return window>>OC_PB_WINDOW_SIZE-1;
}

void oc_pack_adv1(oc_pack_buf *_b){
  _b->window<<=1;
  _b->bits--;
}

/*Here we assume that 0<=_bits&&_bits<=32.*/
long oc_pack_read(oc_pack_buf *_b,int _bits){
  oc_pb_window window;
  int          available;
  long         result;
  window=_b->window;
  available=_b->bits;
  if(_bits==0)return 0;
  if(available<_bits){
    window=oc_pack_refill(_b,_bits);
    available=_b->bits;
  }
  result=window>>OC_PB_WINDOW_SIZE-_bits;
  available-=_bits;
  window<<=1;
  window<<=_bits-1;
  _b->bits=available;
  _b->window=window;
  return result;
}

int oc_pack_read1(oc_pack_buf *_b){
  oc_pb_window window;
  int          available;
  int          result;
  window=_b->window;
  available=_b->bits;
  if(available<1){
    window=oc_pack_refill(_b,1);
    available=_b->bits;
  }
  result=window>>OC_PB_WINDOW_SIZE-1;
  available--;
  window<<=1;
  _b->bits=available;
  _b->window=window;
  return result;
}

long oc_pack_bytes_left(oc_pack_buf *_b){
  if(_b->eof)return -1;
  return _b->stop-_b->ptr+(_b->bits>>3);
}