1 // Copyright (C) 2003  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
4 #define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
5 #include "entropy_encoder_kernel_1.h"
6 #include <iostream>
7 #include <streambuf>
8 
9 namespace dlib
10 {
11 
12 
13 // ----------------------------------------------------------------------------------------
14 
15     entropy_encoder_kernel_1::
entropy_encoder_kernel_1()16     entropy_encoder_kernel_1(
17     ) :
18         initial_low(0x00000001),
19         initial_high(0xffffffff),
20         out(0),
21         low(initial_low),
22         high(initial_high),
23         buf(0),
24         buf_used(0)
25     {
26     }
27 
28 // ----------------------------------------------------------------------------------------
29 
30     entropy_encoder_kernel_1::
~entropy_encoder_kernel_1()31     ~entropy_encoder_kernel_1 (
32     )
33     {
34         try {
35             if (out != 0)
36             {
37                 flush();
38             }
39         } catch (...) {}
40     }
41 
42 // ----------------------------------------------------------------------------------------
43 
44     void entropy_encoder_kernel_1::
clear()45     clear(
46     )
47     {
48         if (out != 0)
49         {
50             flush();
51         }
52         out = 0;
53     }
54 
55 // ----------------------------------------------------------------------------------------
56 
57     void entropy_encoder_kernel_1::
set_stream(std::ostream & out_)58     set_stream (
59         std::ostream& out_
60     )
61     {
62         if (out != 0)
63         {
64             // if a stream is currently set then flush the buffers to it before
65             // we switch to the new stream
66             flush();
67         }
68 
69         out = &out_;
70         streambuf = out_.rdbuf();
71 
72         // reset the encoder state
73         buf_used = 0;
74         buf = 0;
75         low = initial_low;
76         high = initial_high;
77     }
78 
79 // ----------------------------------------------------------------------------------------
80 
81     bool entropy_encoder_kernel_1::
stream_is_set() const82     stream_is_set (
83     ) const
84     {
85         if (out != 0)
86             return true;
87         else
88             return false;
89     }
90 
91 // ----------------------------------------------------------------------------------------
92 
93     std::ostream& entropy_encoder_kernel_1::
get_stream() const94     get_stream (
95     ) const
96     {
97         return *out;
98     }
99 
100 // ----------------------------------------------------------------------------------------
101 
102     void entropy_encoder_kernel_1::
encode(uint32 low_count,uint32 high_count,uint32 total)103     encode (
104         uint32 low_count,
105         uint32 high_count,
106         uint32 total
107     )
108     {
109         // note that we must add one because of the convention that
110         // high == the real upper range minus 1
111         uint32 r = (high-low+1)/total;
112 
113         // note that we must subtract 1 to preserve the convention that
114         // high == the real upper range - 1
115         high = low + r*high_count-1;
116         low = low + r*low_count;
117 
118 
119         while (true)
120         {
121 
122             // if the highest order bit in high and low is the same
123             if ( low >= 0x80000000 || high < 0x80000000)
124             {
125                 // if buf is full then write it out
126                 if (buf_used == 8)
127                 {
128                     if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
129                     {
130                         throw std::ios_base::failure("error occurred in the entropy_encoder object");
131                     }
132                     buf = 0;
133                     buf_used = 0;
134                 }
135 
136 
137                 // write the high order bit from low into buf
138                 buf <<= 1;
139                 ++buf_used;
140                 if (low&0x80000000)
141                     buf |= 0x1;
142 
143                 // roll off the bit we just wrote to buf
144                 low <<= 1;
145                 high <<= 1;
146                 high |= 1;     // note that it is ok to add one to high here because
147                             // of the convention that high == real upper range - 1.
148                             // so that means that if we want to shift the upper range
149                             // left by one then we must shift a one into high also
150                             // since real upper range == high + 0.999999999...
151 
152                 // make sure low is never zero
153                 if (low == 0)
154                     low = 1;
155             }
156             // if the distance between high and low is small and there aren't
157             // any bits we can roll off then round low up or high down.
158             else if (high-low < 0x10000)
159             {
160                 if (high == 0x80000000)
161                     high = 0x7fffffff;
162                 else
163                     low = 0x80000000;
164             }
165             else
166             {
167                 break;
168             }
169         } // while (true)
170 
171     }
172 
173 // ----------------------------------------------------------------------------------------
174 
175     void entropy_encoder_kernel_1::
flush()176     flush (
177     )
178     {
179         // flush the next 4 or 5 bytes that are buffered
180         // thats whatever is contained in buf and then all of low plus any extra
181         // bits needed to pad that to be an even 4 or 5 bytes
182 
183 
184         if (buf_used != 8)
185         {
186             buf <<= (8-buf_used);
187             buf |= static_cast<unsigned char>(low>>(24+buf_used));
188             low <<= (8-buf_used);
189         }
190 
191         if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
192             throw std::ios_base::failure("error occurred in the entropy_encoder object");
193 
194 
195 
196         buf = static_cast<unsigned char>((low >> 24)&0xFF);
197         if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)
198             throw std::ios_base::failure("error occurred in the entropy_encoder object");
199 
200 
201 
202 
203         buf = static_cast<unsigned char>((low >> 16)&0xFF);
204         if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
205             throw std::ios_base::failure("error occurred in the entropy_encoder object");
206 
207 
208 
209         buf = static_cast<unsigned char>((low >> 8)&0xFF);
210         if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
211             throw std::ios_base::failure("error occurred in the entropy_encoder object");
212 
213 
214 
215         if (buf_used != 0)
216         {
217             buf = static_cast<unsigned char>((low)&0xFF);
218             if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)
219                 throw std::ios_base::failure("error occurred in the entropy_encoder object");
220         }
221 
222 
223 
224         // make sure the stream buffer flushes to its I/O channel
225         streambuf->pubsync();
226 
227 
228         // reset the encoder state
229         buf_used = 0;
230         buf = 0;
231         low = initial_low;
232         high = initial_high;
233     }
234 
235 // ----------------------------------------------------------------------------------------
236 
237 }
238 #endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_
239 
240