1 #pragma once
2 
3 #include <fuzzing/exception.hpp>
4 #include <fuzzing/types.hpp>
5 #include <cstddef>
6 #include <cstdint>
7 #include <cstdlib>
8 #include <cstring>
9 #include <string>
10 #include <vector>
11 
12 namespace fuzzing {
13 namespace datasource  {
14 
15 class Base
16 {
17     protected:
18         virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
19     public:
20         Base(void) = default;
21         virtual ~Base(void) = default;
22 
23         template<class T> T Get(const uint64_t id = 0);
24         uint16_t GetChoice(const uint64_t id = 0);
25         std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
26         template <class T> std::vector<T> GetVector(const uint64_t id = 0);
27 
28         class OutOfData : public fuzzing::exception::FlowException {
29             public:
30                 OutOfData() = default;
31         };
32 
33         class DeserializationFailure : public fuzzing::exception::FlowException {
34             public:
35                 DeserializationFailure() = default;
36         };
37 };
38 
39 #ifndef FUZZING_HEADERS_NO_IMPL
Get(const uint64_t id)40 template<class T> T Base::Get(const uint64_t id)
41 {
42     T ret;
43     const auto v = get(sizeof(ret), sizeof(ret), id);
44     memcpy(&ret, v.data(), sizeof(ret));
45     return ret;
46 }
47 
Get(const uint64_t id)48 template <> bool Base::Get<bool>(const uint64_t id)
49 {
50     uint8_t ret;
51     const auto v = get(sizeof(ret), sizeof(ret), id);
52     memcpy(&ret, v.data(), sizeof(ret));
53     return (ret % 2) ? true : false;
54 }
55 
Get(const uint64_t id)56 template <> std::string Base::Get<std::string>(const uint64_t id)
57 {
58     auto data = GetData(id);
59     return std::string(data.data(), data.data() + data.size());
60 }
61 
Get(const uint64_t id)62 template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
63 {
64     std::vector<std::string> ret;
65     while ( true ) {
66         auto data = GetData(id);
67         ret.push_back( std::string(data.data(), data.data() + data.size()) );
68         if ( Get<bool>(id) == false ) {
69             break;
70         }
71     }
72     return ret;
73 }
74 
GetChoice(const uint64_t id)75 uint16_t Base::GetChoice(const uint64_t id)
76 {
77     return Get<uint16_t>(id);
78 }
79 
GetData(const uint64_t id,const size_t min,const size_t max)80 std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
81 {
82     return get(min, max, id);
83 }
84 
85 
Get(const uint64_t id)86 template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
87     const auto data = GetData(id);
88     types::String<> ret(data.data(), data.size());
89     return ret;
90 }
91 
Get(const uint64_t id)92 template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
93     const auto data = GetData(id);
94     types::Data<> ret(data.data(), data.size());
95     return ret;
96 }
97 
98 template <class T>
GetVector(const uint64_t id)99 std::vector<T> Base::GetVector(const uint64_t id) {
100     std::vector<T> ret;
101 
102     while ( Get<bool>(id) == true ) {
103         ret.push_back( Get<T>(id) );
104     }
105 
106     return ret;
107 }
108 #endif
109 
110 class Datasource : public Base
111 {
112     private:
113         const uint8_t* data;
114         const size_t size;
115         size_t idx;
116         size_t left;
117         std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
118 
119 		// Make copy constructor and assignment operator private.
Datasource(const Datasource &)120         Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
operator =(const Datasource &)121         Datasource& operator=(const Datasource &) { return *this; }
122     public:
123         Datasource(const uint8_t* _data, const size_t _size);
124 };
125 
126 #ifndef FUZZING_HEADERS_NO_IMPL
Datasource(const uint8_t * _data,const size_t _size)127 Datasource::Datasource(const uint8_t* _data, const size_t _size) :
128     Base(), data(_data), size(_size), idx(0), left(size)
129 {
130 }
131 
get(const size_t min,const size_t max,const uint64_t id)132 std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
133     (void)id;
134 
135     uint32_t getSize;
136     if ( left < sizeof(getSize) ) {
137         throw OutOfData();
138     }
139     memcpy(&getSize, data + idx, sizeof(getSize));
140     idx += sizeof(getSize);
141     left -= sizeof(getSize);
142 
143     if ( getSize < min ) {
144         getSize = min;
145     }
146     if ( max && getSize > max ) {
147         getSize = max;
148     }
149 
150     if ( left < getSize ) {
151         throw OutOfData();
152     }
153 
154     std::vector<uint8_t> ret(getSize);
155 
156     if ( getSize > 0 ) {
157         memcpy(ret.data(), data + idx, getSize);
158     }
159     idx += getSize;
160     left -= getSize;
161 
162     return ret;
163 }
164 #endif
165 
166 } /* namespace datasource */
167 } /* namespace fuzzing */
168