104 lines
2.5 KiB
C++

#pragma once
#include <string>
#include <array>
#include <stdexcept>
#include "Method.hpp"
#include "BitArray.hpp"
using namespace std;
class Encoder
{
public:
Encoder(const string& input_, CorrectionLevel corr_lvl_ = CorrectionLevel::M, QRCodeMethod method_ = QRCodeMethod::Dynamic, char version_ = -1) : input{ input_ }, corr_lvl{ corr_lvl_ }, method{ method_ }, version{ version_ } {};
BitArray& encode();
static char determite_version(unsigned size, CorrectionLevel corr_lvl);
static constexpr unsigned calculate_encoded_input_size(unsigned input_size, QRCodeMethod method);
static unsigned calculate_metadata_size(QRCodeMethod method, char version);
static void write_metadata(unsigned input_size, unsigned input_bits_amount_size, QRCodeMethod method, BitArray& out);
constexpr void encode_input(unsigned offset) {
switch (method) {
case QRCodeMethod::Numeric:
encode_numeric(input, e, offset);
break;
case QRCodeMethod::Alphabetic:
encode_alphabetic(input, e, offset);
break;
case QRCodeMethod::Byte:
encode_byte(input, e, offset);
break;
}
};
static void encode_numeric(const string& input, BitArray& out, unsigned offset);
static void encode_alphabetic(const string& input, BitArray& out, unsigned offset);
static void encode_byte(const string& input, BitArray& out, unsigned offset);
static void pad_data(BitArray& arr, unsigned bits_written);
constexpr char get_version() const { return version; };
BitArray get_data() const;
private:
static constexpr unsigned char encode_char(char ch);
const string input;
CorrectionLevel corr_lvl;
const QRCodeMethod method;
char version;
BitArray e;
};
constexpr unsigned Encoder::calculate_encoded_input_size(unsigned input_size, QRCodeMethod method)
{
if (method == QRCodeMethod::Dynamic) throw std::runtime_error("Specify correct method");
unsigned bit_num = 0;
switch (method) {
case QRCodeMethod::Numeric:
bit_num = 10 * (input_size / 3);
if (input_size % 3 == 2)
bit_num += 7;
else if (input_size % 3 == 1)
bit_num += 4;
break;
case QRCodeMethod::Alphabetic:
bit_num = 11 * (input_size / 2);
if (input_size % 2 == 1)
bit_num += 6;
break;
case QRCodeMethod::Byte:
bit_num = input_size * 8;
break;
}
return bit_num;
}
template <typename T, size_t N>
constexpr unsigned upper_index(const array<T, N> arr, T val) {
unsigned count = arr.size(), s = 0, e = 0, step = 0;
while (count > 0) {
step = count / 2;
e = s + step;
if (arr[e] < val) {
s = e + 1;
count -= step + 1;
}
else
count = step;
}
return s;
}