blob: 09fa8db6308cf54fae314e75865e490606990903 [file] [log] [blame]
#pragma once
#include <fuzzing/exception.hpp>
#include <fuzzing/types.hpp>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
namespace fuzzing {
namespace datasource {
class Base
{
protected:
virtual std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) = 0;
public:
Base(void) = default;
virtual ~Base(void) = default;
template<class T> T Get(const uint64_t id = 0);
uint16_t GetChoice(const uint64_t id = 0);
std::vector<uint8_t> GetData(const uint64_t id, const size_t min = 0, const size_t max = 0);
template <class T> std::vector<T> GetVector(const uint64_t id = 0);
class OutOfData : public fuzzing::exception::FlowException {
public:
OutOfData() = default;
};
class DeserializationFailure : public fuzzing::exception::FlowException {
public:
DeserializationFailure() = default;
};
};
#ifndef FUZZING_HEADERS_NO_IMPL
template<class T> T Base::Get(const uint64_t id)
{
T ret;
const auto v = get(sizeof(ret), sizeof(ret), id);
memcpy(&ret, v.data(), sizeof(ret));
return ret;
}
template <> bool Base::Get<bool>(const uint64_t id)
{
uint8_t ret;
const auto v = get(sizeof(ret), sizeof(ret), id);
memcpy(&ret, v.data(), sizeof(ret));
return (ret % 2) ? true : false;
}
template <> std::string Base::Get<std::string>(const uint64_t id)
{
auto data = GetData(id);
return std::string(data.data(), data.data() + data.size());
}
template <> std::vector<std::string> Base::Get<std::vector<std::string>>(const uint64_t id)
{
std::vector<std::string> ret;
while ( true ) {
auto data = GetData(id);
ret.push_back( std::string(data.data(), data.data() + data.size()) );
if ( Get<bool>(id) == false ) {
break;
}
}
return ret;
}
uint16_t Base::GetChoice(const uint64_t id)
{
return Get<uint16_t>(id);
}
std::vector<uint8_t> Base::GetData(const uint64_t id, const size_t min, const size_t max)
{
return get(min, max, id);
}
template <> types::String<> Base::Get<types::String<>>(const uint64_t id) {
const auto data = GetData(id);
types::String<> ret(data.data(), data.size());
return ret;
}
template <> types::Data<> Base::Get<types::Data<>>(const uint64_t id) {
const auto data = GetData(id);
types::Data<> ret(data.data(), data.size());
return ret;
}
template <class T>
std::vector<T> Base::GetVector(const uint64_t id) {
std::vector<T> ret;
while ( Get<bool>(id) == true ) {
ret.push_back( Get<T>(id) );
}
return ret;
}
#endif
class Datasource : public Base
{
private:
const uint8_t* data;
const size_t size;
size_t idx;
size_t left;
std::vector<uint8_t> get(const size_t min, const size_t max, const uint64_t id = 0) override;
// Make copy constructor and assignment operator private.
Datasource(const Datasource &) : data(0), size(0), idx(0), left(0) {}
Datasource& operator=(const Datasource &) { return *this; }
public:
Datasource(const uint8_t* _data, const size_t _size);
};
#ifndef FUZZING_HEADERS_NO_IMPL
Datasource::Datasource(const uint8_t* _data, const size_t _size) :
Base(), data(_data), size(_size), idx(0), left(size)
{
}
std::vector<uint8_t> Datasource::get(const size_t min, const size_t max, const uint64_t id) {
(void)id;
uint32_t getSize;
if ( left < sizeof(getSize) ) {
throw OutOfData();
}
memcpy(&getSize, data + idx, sizeof(getSize));
idx += sizeof(getSize);
left -= sizeof(getSize);
if ( getSize < min ) {
getSize = min;
}
if ( max && getSize > max ) {
getSize = max;
}
if ( left < getSize ) {
throw OutOfData();
}
std::vector<uint8_t> ret(getSize);
if ( getSize > 0 ) {
memcpy(ret.data(), data + idx, getSize);
}
idx += getSize;
left -= getSize;
return ret;
}
#endif
} /* namespace datasource */
} /* namespace fuzzing */