• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Compress/RangeCoder.h
2 // 2013-01-10 : Igor Pavlov : Public domain
3 
4 #ifndef __COMPRESS_RANGE_CODER_H
5 #define __COMPRESS_RANGE_CODER_H
6 
7 #include "../Common/InBuffer.h"
8 #include "../Common/OutBuffer.h"
9 
10 namespace NCompress {
11 namespace NRangeCoder {
12 
13 const unsigned kNumTopBits = 24;
14 const UInt32 kTopValue = (1 << kNumTopBits);
15 
16 class CEncoder
17 {
18   UInt32 _cacheSize;
19   Byte _cache;
20 public:
21   UInt64 Low;
22   UInt32 Range;
23   COutBuffer Stream;
Create(UInt32 bufSize)24   bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
25 
SetStream(ISequentialOutStream * stream)26   void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); }
Init()27   void Init()
28   {
29     Stream.Init();
30     Low = 0;
31     Range = 0xFFFFFFFF;
32     _cacheSize = 1;
33     _cache = 0;
34   }
35 
FlushData()36   void FlushData()
37   {
38     // Low += 1;
39     for (int i = 0; i < 5; i++)
40       ShiftLow();
41   }
42 
FlushStream()43   HRESULT FlushStream() { return Stream.Flush();  }
44 
Encode(UInt32 start,UInt32 size,UInt32 total)45   void Encode(UInt32 start, UInt32 size, UInt32 total)
46   {
47     Low += start * (Range /= total);
48     Range *= size;
49     while (Range < kTopValue)
50     {
51       Range <<= 8;
52       ShiftLow();
53     }
54   }
55 
ShiftLow()56   void ShiftLow()
57   {
58     if ((UInt32)Low < (UInt32)0xFF000000 || (unsigned)(Low >> 32) != 0)
59     {
60       Byte temp = _cache;
61       do
62       {
63         Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32)));
64         temp = 0xFF;
65       }
66       while (--_cacheSize != 0);
67       _cache = (Byte)((UInt32)Low >> 24);
68     }
69     _cacheSize++;
70     Low = (UInt32)Low << 8;
71   }
72 
EncodeDirectBits(UInt32 value,int numBits)73   void EncodeDirectBits(UInt32 value, int numBits)
74   {
75     for (numBits--; numBits >= 0; numBits--)
76     {
77       Range >>= 1;
78       Low += Range & (0 - ((value >> numBits) & 1));
79       if (Range < kTopValue)
80       {
81         Range <<= 8;
82         ShiftLow();
83       }
84     }
85   }
86 
EncodeBit(UInt32 size0,UInt32 numTotalBits,UInt32 symbol)87   void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol)
88   {
89     UInt32 newBound = (Range >> numTotalBits) * size0;
90     if (symbol == 0)
91       Range = newBound;
92     else
93     {
94       Low += newBound;
95       Range -= newBound;
96     }
97     while (Range < kTopValue)
98     {
99       Range <<= 8;
100       ShiftLow();
101     }
102   }
103 
GetProcessedSize()104   UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; }
105 };
106 
107 class CDecoder
108 {
109 public:
110   CInBuffer Stream;
111   UInt32 Range;
112   UInt32 Code;
Create(UInt32 bufSize)113   bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
114 
Normalize()115   void Normalize()
116   {
117     while (Range < kTopValue)
118     {
119       Code = (Code << 8) | Stream.ReadByte();
120       Range <<= 8;
121     }
122   }
123 
SetStream(ISequentialInStream * stream)124   void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
Init()125   void Init()
126   {
127     Stream.Init();
128     Code = 0;
129     Range = 0xFFFFFFFF;
130     for (int i = 0; i < 5; i++)
131       Code = (Code << 8) | Stream.ReadByte();
132   }
133 
GetThreshold(UInt32 total)134   UInt32 GetThreshold(UInt32 total)
135   {
136     return (Code) / (Range /= total);
137   }
138 
Decode(UInt32 start,UInt32 size)139   void Decode(UInt32 start, UInt32 size)
140   {
141     Code -= start * Range;
142     Range *= size;
143     Normalize();
144   }
145 
DecodeDirectBits(int numTotalBits)146   UInt32 DecodeDirectBits(int numTotalBits)
147   {
148     UInt32 range = Range;
149     UInt32 code = Code;
150     UInt32 result = 0;
151     for (int i = numTotalBits; i != 0; i--)
152     {
153       range >>= 1;
154       /*
155       result <<= 1;
156       if (code >= range)
157       {
158         code -= range;
159         result |= 1;
160       }
161       */
162       UInt32 t = (code - range) >> 31;
163       code -= range & (t - 1);
164       result = (result << 1) | (1 - t);
165 
166       if (range < kTopValue)
167       {
168         code = (code << 8) | Stream.ReadByte();
169         range <<= 8;
170       }
171     }
172     Range = range;
173     Code = code;
174     return result;
175   }
176 
DecodeBit(UInt32 size0,UInt32 numTotalBits)177   UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits)
178   {
179     UInt32 newBound = (Range >> numTotalBits) * size0;
180     UInt32 symbol;
181     if (Code < newBound)
182     {
183       symbol = 0;
184       Range = newBound;
185     }
186     else
187     {
188       symbol = 1;
189       Code -= newBound;
190       Range -= newBound;
191     }
192     Normalize();
193     return symbol;
194   }
195 
GetProcessedSize()196   UInt64 GetProcessedSize() { return Stream.GetProcessedSize(); }
197 };
198 
199 }}
200 
201 #endif
202