summaryrefslogtreecommitdiff
path: root/src/decoder.hpp
blob: 897f41047d6f13395e3c264acb70ca473fdba3f5 (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
/*
    Copyright (c) 2007-2009 FastMQ Inc.

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the Lesser GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    Lesser GNU General Public License for more details.

    You should have received a copy of the Lesser GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __ZMQ_DECODER_HPP_INCLUDED__
#define __ZMQ_DECODER_HPP_INCLUDED__

#include <stddef.h>
#include <string.h>
#include <algorithm>

namespace zmq
{

    //  Helper base class for decoders that know the amount of data to read
    //  in advance at any moment. Knowing the amount in advance is a property
    //  of the protocol used. Both AMQP and backend protocol are based on
    //  size-prefixed paradigm, therefore they are using decoder_t to parse
    //  the messages. On the other hand, XML-based transports (like XMPP or
    //  SOAP) don't allow for knowing the size of data to read in advance and
    //  should use different decoding algorithms.
    //
    //  Decoder implements the state machine that parses the incoming buffer.
    //  Derived class should implement individual state machine actions.

    template <typename T> class decoder_t
    {
    public:

        inline decoder_t () :
            read_ptr (NULL),
            to_read (0),
            next (NULL)
        {
        }

        //  Push the binary data to the decoder. Returns number of bytes
        // actually parsed.
        inline size_t write (unsigned char *data_, size_t size_)
        {
            size_t pos = 0;
            while (true) {
                size_t to_copy = std::min (to_read, size_ - pos);
                if (read_ptr) {
                    memcpy (read_ptr, data_ + pos, to_copy);
                    read_ptr += to_copy;
                }
                pos += to_copy;
                to_read -= to_copy;
                while (!to_read)
                    if (!(static_cast <T*> (this)->*next) ())
                        return pos;
                if (pos == size_)
                    return pos;
            }
        }

    protected:

        //  Prototype of state machine action. Action should return false if
        //  it is unable to push the data to the system.
        typedef bool (T::*step_t) ();

        //  This function should be called from derived class to read data
        //  from the buffer and schedule next state machine action.
        inline void next_step (void *read_ptr_, size_t to_read_,
            step_t next_)
        {
            read_ptr = (unsigned char*) read_ptr_;
            to_read = to_read_;
            next = next_;
        }

    private:

        unsigned char *read_ptr;
        size_t to_read;
        step_t next;

        decoder_t (const decoder_t&);
        void operator = (const decoder_t&);
    };

}

#endif