Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Compress / BitlDecoder.h
1 // BitlDecoder.h -- the Least Significant Bit of byte is First\r
2 \r
3 #ifndef __BITL_DECODER_H\r
4 #define __BITL_DECODER_H\r
5 \r
6 #include "../IStream.h"\r
7 \r
8 namespace NBitl {\r
9 \r
10 const unsigned kNumBigValueBits = 8 * 4;\r
11 const unsigned kNumValueBytes = 3;\r
12 const unsigned kNumValueBits = 8  * kNumValueBytes;\r
13 \r
14 const UInt32 kMask = (1 << kNumValueBits) - 1;\r
15 \r
16 extern Byte kInvertTable[256];\r
17 \r
18 template<class TInByte>\r
19 class CBaseDecoder\r
20 {\r
21 protected:\r
22   unsigned m_BitPos;\r
23   UInt32 m_Value;\r
24   TInByte m_Stream;\r
25 public:\r
26   UInt32 NumExtraBytes;\r
27   bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }\r
28   void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream); }\r
29   void ReleaseStream() { m_Stream.ReleaseStream(); }\r
30   void Init()\r
31   {\r
32     m_Stream.Init();\r
33     m_BitPos = kNumBigValueBits;\r
34     m_Value = 0;\r
35     NumExtraBytes = 0;\r
36   }\r
37   UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() + NumExtraBytes - (kNumBigValueBits - m_BitPos) / 8; }\r
38 \r
39   void Normalize()\r
40   {\r
41     for (; m_BitPos >= 8; m_BitPos -= 8)\r
42     {\r
43       Byte b = 0;\r
44       if (!m_Stream.ReadByte(b))\r
45       {\r
46         b = 0xFF; // check it\r
47         NumExtraBytes++;\r
48       }\r
49       m_Value = (b << (kNumBigValueBits - m_BitPos)) | m_Value;\r
50     }\r
51   }\r
52   \r
53   UInt32 ReadBits(unsigned numBits)\r
54   {\r
55     Normalize();\r
56     UInt32 res = m_Value & ((1 << numBits) - 1);\r
57     m_BitPos += numBits;\r
58     m_Value >>= numBits;\r
59     return res;\r
60   }\r
61 \r
62   bool ExtraBitsWereRead() const\r
63   {\r
64     if (NumExtraBytes == 0)\r
65       return false;\r
66     return ((UInt32)(kNumBigValueBits - m_BitPos) < (NumExtraBytes << 3));\r
67   }\r
68 };\r
69 \r
70 template<class TInByte>\r
71 class CDecoder: public CBaseDecoder<TInByte>\r
72 {\r
73   UInt32 m_NormalValue;\r
74 \r
75 public:\r
76   void Init()\r
77   {\r
78     CBaseDecoder<TInByte>::Init();\r
79     m_NormalValue = 0;\r
80   }\r
81 \r
82   void Normalize()\r
83   {\r
84     for (; this->m_BitPos >= 8; this->m_BitPos -= 8)\r
85     {\r
86       Byte b = 0;\r
87       if (!this->m_Stream.ReadByte(b))\r
88       {\r
89         b = 0xFF; // check it\r
90         this->NumExtraBytes++;\r
91       }\r
92       m_NormalValue = (b << (kNumBigValueBits - this->m_BitPos)) | m_NormalValue;\r
93       this->m_Value = (this->m_Value << 8) | kInvertTable[b];\r
94     }\r
95   }\r
96   \r
97   UInt32 GetValue(unsigned numBits)\r
98   {\r
99     Normalize();\r
100     return ((this->m_Value >> (8 - this->m_BitPos)) & kMask) >> (kNumValueBits - numBits);\r
101   }\r
102 \r
103   void MovePos(unsigned numBits)\r
104   {\r
105     this->m_BitPos += numBits;\r
106     m_NormalValue >>= numBits;\r
107   }\r
108   \r
109   UInt32 ReadBits(unsigned numBits)\r
110   {\r
111     Normalize();\r
112     UInt32 res = m_NormalValue & ((1 << numBits) - 1);\r
113     MovePos(numBits);\r
114     return res;\r
115   }\r
116 \r
117   void AlignToByte() { MovePos((32 - this->m_BitPos) & 7); }\r
118 \r
119   Byte ReadByte()\r
120   {\r
121     if (this->m_BitPos == kNumBigValueBits)\r
122     {\r
123       Byte b = 0;\r
124       if (!this->m_Stream.ReadByte(b))\r
125       {\r
126         b = 0xFF;\r
127         this->NumExtraBytes++;\r
128       }\r
129       return b;\r
130     }\r
131     {\r
132       Byte b = (Byte)(m_NormalValue & 0xFF);\r
133       MovePos(8);\r
134       return b;\r
135     }\r
136   }\r
137 };\r
138 \r
139 }\r
140 \r
141 #endif\r