summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/compress_stream/compress_stream_kernel_1.h
blob: 1a75ec6ced988ec9108379d47d29617e3930b511 (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright (C) 2003  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_
#define DLIB_COMPRESS_STREAM_KERNEl_1_

#include "../algs.h"
#include <iostream>
#include <streambuf>
#include <cstdio>
#include "compress_stream_kernel_abstract.h"

namespace dlib
{

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    class compress_stream_kernel_1
    {
        /*!
            REQUIREMENTS ON fce
                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
                the alphabet_size of fce must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON fcd
                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
                the alphabet_size of fcd must be 257.
                fce and fcd share the same kernel number.

            REQUIREMENTS ON crc32
                is an implementation of crc32/crc32_kernel_abstract.h



            INITIAL VALUE
                this object has no state

            CONVENTION
                this object has no state
        !*/

        const static unsigned long eof_symbol = 256;

    public:

        class decompression_error : public dlib::error 
        { 
            public: 
                decompression_error(
                    const char* i
                ) :
                    dlib::error(std::string(i))
                {}

                decompression_error(
                    const std::string& i
                ) :
                    dlib::error(i)
                {}
        };


        compress_stream_kernel_1 (
        )
        {}

        ~compress_stream_kernel_1 (
        )
        {}

        void compress (
            std::istream& in,
            std::ostream& out
        ) const;

        void decompress (
            std::istream& in,
            std::ostream& out
        ) const;

    private:

        // restricted functions
        compress_stream_kernel_1(compress_stream_kernel_1&);        // copy constructor
        compress_stream_kernel_1& operator=(compress_stream_kernel_1&);    // assignment operator

    };

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
    // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    void compress_stream_kernel_1<fce,fcd,crc32>::
    compress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {
        std::streambuf::int_type temp;

        std::streambuf& in = *in_.rdbuf();

        typename fce::entropy_encoder_type coder;
        coder.set_stream(out_);

        fce model(coder);

        crc32 crc;

        unsigned long count = 0;

        while (true)
        {
            // write out a known value every 20000 symbols
            if (count == 20000)
            {
                count = 0;
                coder.encode(1500,1501,8000);
            }
            ++count;

            // get the next character
            temp = in.sbumpc();

            // if we have hit EOF then encode the marker symbol
            if (temp != EOF)  
            {
                // encode the symbol
                model.encode(static_cast<unsigned long>(temp));
                crc.add(static_cast<unsigned char>(temp));
                continue;
            }
            else
            {
                model.encode(eof_symbol);

                // now write the checksum
                unsigned long checksum = crc.get_checksum();
                unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);
                unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);
                unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);
                unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);

                model.encode(byte1);
                model.encode(byte2);
                model.encode(byte3);
                model.encode(byte4);

                break;
            }
        }      
    }

// ----------------------------------------------------------------------------------------

    template <
        typename fce,
        typename fcd,
        typename crc32
        >
    void compress_stream_kernel_1<fce,fcd,crc32>::
    decompress (
        std::istream& in_,
        std::ostream& out_
    ) const
    {

        std::streambuf& out = *out_.rdbuf();

        typename fcd::entropy_decoder_type coder;
        coder.set_stream(in_);

        fcd model(coder);

        unsigned long symbol;
        unsigned long count = 0;

        crc32 crc;

        // decode until we hit the marker symbol
        while (true)
        {
            // make sure this is the value we expect
            if (count == 20000)
            {
                if (coder.get_target(8000) != 1500)
                {
                    throw decompression_error("Error detected in compressed data stream.");
                }
                count = 0;
                coder.decode(1500,1501);
            }
            ++count;

            // decode the next symbol
            model.decode(symbol);
            if (symbol != eof_symbol)
            {
                crc.add(static_cast<unsigned char>(symbol));
                // write this symbol to out
                if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
                {
                    throw std::ios::failure("error occurred in compress_stream_kernel_1::decompress");
                }
                continue;
            }
            else
            {
                // we read eof from the encoded data.  now we just have to check the checksum and we are done.
                unsigned char byte1;
                unsigned char byte2;
                unsigned char byte3;
                unsigned char byte4;

                model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);
                model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);

                unsigned long checksum = byte1;
                checksum <<= 8;
                checksum |= byte2;
                checksum <<= 8;
                checksum |= byte3;
                checksum <<= 8;
                checksum |= byte4;

                if (checksum != crc.get_checksum())
                    throw decompression_error("Error detected in compressed data stream.");

                break;
            }
        } // while (true)

    }

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_COMPRESS_STREAM_KERNEl_1_