From 92516db383e24a4074978e83338a85f8787922b8 Mon Sep 17 00:00:00 2001 From: dm1sh Date: Mon, 27 Dec 2021 17:14:36 +0300 Subject: [PATCH] Added comments in russian --- Demo/main.cpp | 69 +++++++++++++++------------ QRCodeLibrary/BitArray.cpp | 38 +++++++-------- QRCodeLibrary/BitArray.hpp | 15 ++++-- QRCodeLibrary/DataBlocks.cpp | 58 +++++++++++------------ QRCodeLibrary/DataBlocks.hpp | 17 ++++--- QRCodeLibrary/Encoder.cpp | 21 ++++---- QRCodeLibrary/Encoder.hpp | 8 ++-- QRCodeLibrary/Method.cpp | 2 +- QRCodeLibrary/QRCode.cpp | 14 +++--- QRCodeLibrary/QRCode.hpp | 4 +- QRCodeLibrary/QRMatrix.cpp | 92 ++++++++++++++++++++---------------- QRCodeLibrary/QRMatrix.hpp | 26 ++++++++++ QRCodeLibrary/Tables.hpp | 14 ++++++ QRCodeLibrary/TritMatrix.cpp | 27 +---------- QRCodeLibrary/TritMatrix.hpp | 5 +- QRCodeLibrary/utils.hpp | 1 + tests/DataBlocks_test.cpp | 20 ++++---- tests/Encoder_test.cpp | 3 -- 18 files changed, 241 insertions(+), 193 deletions(-) diff --git a/Demo/main.cpp b/Demo/main.cpp index f26cdf6..abccc4f 100644 --- a/Demo/main.cpp +++ b/Demo/main.cpp @@ -1,31 +1,36 @@ #include #include -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) -#include +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) +#define IS_WINDOWS +#endif + +#ifdef IS_WINDOWS +#include #endif #include "../QRCodeLibrary/QRCode.hpp" using namespace std; -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) +#ifdef IS_WINDOWS +// Переводит строку из кодировки CP 1251 в UTF-8 std::string cp1251_to_utf8(const char* str) { std::string res; WCHAR* ures = NULL; char* cres = NULL; - int result_u = MultiByteToWideChar(1251, 0, str, -1, 0, 0); + int result_u = MultiByteToWideChar(1251, 0, str, -1, 0, 0); // определяем сколько символов будет иметь широкосимвольная строка (UTF-16) if (result_u != 0) { - ures = new WCHAR[result_u]; + ures = new WCHAR[result_u]; // инициализируем временную строку для символов в UTF-16 if (MultiByteToWideChar(1251, 0, str, -1, ures, result_u)) { - int result_c = WideCharToMultiByte(CP_UTF8, 0, ures, -1, 0, 0, 0, 0); + int result_c = WideCharToMultiByte(CP_UTF8, 0, ures, -1, 0, 0, 0, 0); // определяем сколько символов будет иметь строка в кодировке UTF-8 if (result_c != 0) { - cres = new char[result_c]; + cres = new char[result_c]; // инициализируем временную строку для символов в UTF-8 if (WideCharToMultiByte(CP_UTF8, 0, ures, -1, cres, result_c, 0, 0)) { res = cres; @@ -40,6 +45,7 @@ std::string cp1251_to_utf8(const char* str) return res; } #else +// создаёт строку, состоящую из k раз повторённых строк input string str_of(unsigned k, const string& input) { string res; for (;k > 0; k--) @@ -49,19 +55,20 @@ string str_of(unsigned k, const string& input) { #endif int main() { -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) - SetConsoleCP(1251); +#ifdef IS_WINDOWS + SetConsoleCP(1251); // устанавливаем кодировку в консоли CP 1251 #endif - string input, buff; + string input; // строка, содержащая пользовательский ввод + string buff; // буфер для ввода строк - while (getline(cin, buff)) { - input += buff + '\n'; + while (getline(cin, buff)) { // пока пользователь не ввёл символ EOF + input += buff + '\n'; // сохраняем ввод с символом переноса строки в конце } - input.pop_back(); + input.pop_back(); // удаляем последний добавленный символ переноса строки -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) - input = cp1251_to_utf8(input.c_str()); +#ifdef IS_WINDOWS + input = cp1251_to_utf8(input.c_str()); // переводим ввод в UTF-8 #endif QRCode qr(input, CorrectionLevel::H); @@ -70,26 +77,27 @@ int main() { #define SQUARE_WIDTH 2 -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) - const string long_sep = string((res.size() + 8) * SQUARE_WIDTH, 219), - short_sep = string(4 * SQUARE_WIDTH, 219), - black = string(SQUARE_WIDTH, ' '), - white = string(SQUARE_WIDTH, 219); +#ifdef IS_WINDOWS + const string long_sep = string((res.size() + 8) * SQUARE_WIDTH, 219), // строка из блоков на всю ширину QR кода для рамок над и под ним + short_sep = string(4 * SQUARE_WIDTH, 219), // строка из 4 блоков для боковых рамок справа и слева вокруг QR кода + black = string(SQUARE_WIDTH, ' '), // строка для чёрного квадрата в QR коде + white = string(SQUARE_WIDTH, 219); // строка для белого квадрата в QR коде SetConsoleCP(855); #else - const string long_sep = str_of((res.size() + 8) * SQUARE_WIDTH, "█"), - short_sep = str_of(4 * SQUARE_WIDTH, "█"), - black = string(SQUARE_WIDTH, ' '), - white = str_of(SQUARE_WIDTH, "█"); + const string long_sep = str_of((res.size() + 8) * SQUARE_WIDTH, "█"), // строка из блоков на всю ширину QR кода для рамок над и под ним + short_sep = str_of(4 * SQUARE_WIDTH, "█"), // строка из 4 блоков для боковых рамок справа и слева вокруг QR кода + black = string(SQUARE_WIDTH, ' '), // строка для чёрного квадрата в QR коде + white = str_of(SQUARE_WIDTH, "█"); // строка для белого квадрата в QR коде #endif + // Вывод четырёх строк белых квадратов в качестве фона for (int i = 0; i < 4; i++) cout << long_sep << endl; - for (unsigned i = 0; i < res.size(); i++) { - cout << short_sep; - for (auto cell : res[i]) + for (unsigned i = 0; i < res.size(); i++) { // для каждой строки QR кода + cout << short_sep; // вывод белого фона справа от строки + for (auto cell : res[i]) // для каждой клетки QR кода switch (cell) { case Trit::T: cout << black; @@ -100,13 +108,14 @@ int main() { default: throw std::runtime_error("Empty cell is not allowed. Your QR code is corrupted."); } - cout << short_sep << endl; + cout << short_sep << endl; // вывод белого фона слева от строки } + // Вывод четырёх строк белых квадратов в качестве фона for (int i = 0; i < 4; i++) cout << long_sep << endl; -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) +#ifdef IS_WINDOWS system("pause"); #endif -} \ No newline at end of file +} diff --git a/QRCodeLibrary/BitArray.cpp b/QRCodeLibrary/BitArray.cpp index 8a172c2..11388ab 100644 --- a/QRCodeLibrary/BitArray.cpp +++ b/QRCodeLibrary/BitArray.cpp @@ -8,50 +8,50 @@ bool BitArray::get(unsigned index) const { if (index >= size) throw std::out_of_range("No such element in array"); - return (v[index / 8] >> (8 - 1 - index % 8)) & 1; + return (v[index / 8] >> (8 - index % 8 - 1)) & 1; // получаем байт, в котором хранится искомый бит, смещаем его вправо на то, сколько бит стоят справа от индекса и применяем маску 00000001 } BitArray::operator std::string() const { std::stringstream res; - for (unsigned i = 0; i < size; i++) - res << static_cast((*this).get(i)); + for (unsigned i = 0; i < size; i++) // для каждого бита в массиве + res << static_cast(get(i)); // выводим его как число в строковый поток - return res.str(); + return res.str(); // возвращаем строку, полученную из строкового потока } void BitArray::set(unsigned index, bool val) { if (index >= size) throw std::out_of_range("No such element in array"); - if (val) - v[index / 8] |= 1 << (8 - 1 - index % 8); + if (val == 1) + v[index / 8] |= 1 << (8 - index % 8 - 1); // к байту, где нужно установить бит прибавляем при помощи битового или единицу, сменённую на то, сколько бит стоят справа от индекса else - v[index / 8] &= ~(1 << (8 - 1 - index % 8)); + v[index / 8] &= ~(1 << (8 - index % 8 - 1)); // к байту, где нужно установить бит применяем битовую маску, где включены все биты кроме того, который соответсвует данному индексу } unsigned BitArray::set(unsigned index, int32_t val, unsigned size) { if (index >= this->size) throw std::out_of_range("No such element in array"); - unsigned shift = index % 8, written = 0; + unsigned shift = index % 8; // смещение слева внутри байта + unsigned written = 0; // количество записанных байт if (size > this->size - index) throw std::out_of_range("Number of bits to write from this index is more than BitArray capability"); - index /= 8; + // Цикл для каждого изменяемого в процессе записи байта массива пока не записали все входные данные + for (int i = index / 8; written < size; i++) { + int input_shift = size - (8 - shift) - written; // смещение справа для входных данных данных + int right_rem = input_shift < 0 ? -input_shift : 0; // то, сколько бит нужно взять из исходного массива справа от записываемых данных - while (written < size) { - int input_shift = size - (8 - shift) - written; - int right_rem = input_shift < 0 ? -input_shift : 0; + v[i] = (v[i] & (-1 << (8 - shift))) | // данные исходного байта слева от записываемых. Битовая маска зануляет те биты, которые будут браться из записываемых данных + (((1 << (8 - shift)) - 1) & // битовая маска, оставляющая 8-shift бит слева + ((input_shift >= 0) ? (val >> input_shift) : (val << -input_shift))) | // если положительное, тогда смещаемся вправо, иначе - влево + (v[i] & ((1 << right_rem) - 1)); // берём последние right_rem бит исходного байта - v[index] = ((v[index] >> (8 - shift)) << (8 - shift)) | - (unsigned char)(((1 << (8 - shift)) - 1) & ((input_shift >= 0) ? (val >> input_shift) : (val << -input_shift))) | - (v[index] & ((1 << right_rem) - 1)); - - written += 8 - shift; - index++; - shift = 0; + written += 8 - shift; // наращиваем количество записанных бит на то, сколько бит было записано на этой итерации + shift = 0; // сбрасываем левое смещение после первой итерации } return written; diff --git a/QRCodeLibrary/BitArray.hpp b/QRCodeLibrary/BitArray.hpp index 010266b..d077635 100644 --- a/QRCodeLibrary/BitArray.hpp +++ b/QRCodeLibrary/BitArray.hpp @@ -8,7 +8,8 @@ using namespace std; -constexpr unsigned ceil_div(unsigned a, unsigned b) { +// Деление a на b с округлением в большую сторону +constexpr static unsigned ceil_div(unsigned a, unsigned b) { if (b == 0) throw runtime_error("Dividion by zero not possible"); return a / b + (a % b > 0); } @@ -16,18 +17,24 @@ constexpr unsigned ceil_div(unsigned a, unsigned b) { class BitArray { public: + // Создаёт массив заполненный нулями размера size BitArray(unsigned size_ = 0) : size{ size_ }, v(ceil_div(size_, 8), 0) {}; - BitArray(const vector& input) : size(to_U(input.size()) * 8), v{ input } {}; + // Создаёт массив из байт input + BitArray(const byte_list& input) : size(to_U(input.size()) * 8), v{ input } {}; operator std::string() const; - unsigned size; - vector v; + unsigned size; // размер массива в битах + byte_list v; + // Принимает index - индекс в массиве, возвращает соответствующий index-ый бит bool get(unsigned index) const; + // Принимает индекс и булевую переменную (0 или 1). Устанавливает соответствующий бит массива void set(unsigned index, bool val); + // Принимает индекс, 32-х битное число и количество бит из числа. Устанавливает начиная с индекса size бит соответствующими младшими двоичными разрядами числа val unsigned set(unsigned index, int32_t val, unsigned size); + // Принимает новый размер для массива в битах void resize(unsigned new_size); }; diff --git a/QRCodeLibrary/DataBlocks.cpp b/QRCodeLibrary/DataBlocks.cpp index 566c997..72629e7 100644 --- a/QRCodeLibrary/DataBlocks.cpp +++ b/QRCodeLibrary/DataBlocks.cpp @@ -4,20 +4,19 @@ #include "Tables.hpp" #include "utils.hpp" -vector& DataBlocks::compose_joined_data_and_EC_blocks() +DataBlocks::DataBlocks(const byte_list& e_data_, CorrectionLevel corr_lvl_, char version_) : e_data{ e_data_ }, corr_lvl{ corr_lvl_ }, version{ version_ } { - vector>data_block_sizes; + vector>data_block_sizes; // массив из пар, состоящих из размера соответствующего блока и его смещения от начала данных divide_to_blocks(data_block_sizes, to_U(e_data.size()), Tables::data_blocks_number.at(corr_lvl).at(version)); unsigned EC_bytes_number = Tables::correction_bytes_num.at(corr_lvl).at(version); - vector> EC_blocks(data_block_sizes.size(), vector()); - for (unsigned i = 0; i < data_block_sizes.size(); i++) + vector EC_blocks(data_block_sizes.size(), byte_list()); // массив для наборов соответствующих блокам данных байтов коррекции + + for (unsigned i = 0; i < data_block_sizes.size(); i++) // для каждого блока данных compose_EC_bytes(EC_blocks[i], e_data.cbegin() + data_block_sizes[i].second, EC_bytes_number, data_block_sizes[i].first); join_data_and_EC_blocks(data, e_data, data_block_sizes, EC_blocks, EC_bytes_number); - - return data; } void DataBlocks::divide_to_blocks(vector>& db_sizes, unsigned data_size, unsigned db_number) @@ -27,31 +26,34 @@ void DataBlocks::divide_to_blocks(vector>& db_sizes, un for (unsigned i = 0; i < db_number; i++) db_sizes.push_back(std::make_pair(data_size / db_number, data_size / db_number * i)); - for (unsigned i = 0; i < data_size % db_number; i++) { - db_sizes[db_number - 1 - i].first++; - db_sizes[db_number - 1 - i].second += (data_size % db_number - 1 - i); + for (unsigned i = 0; i < data_size % db_number; i++) { // если количество данных не делится на количество блоков + db_sizes[db_number - 1 - i].first++; // с конца дополняем блоки на 1 + db_sizes[db_number - 1 - i].second += (data_size % db_number - 1 - i); // и увеличиваем смещение } } -void DataBlocks::compose_EC_bytes(vector& res, const vector::const_iterator& src, unsigned corr_bytes_num, unsigned db_size) +void DataBlocks::compose_EC_bytes(byte_list& res, const byte_list::const_iterator& src, unsigned corr_bytes_num, unsigned db_size) { - res.reserve(max(db_size, corr_bytes_num)); - res.insert(res.end(), src, src + db_size); - res.resize(res.capacity(), 0); + res.reserve(max(db_size, corr_bytes_num)); // подготавливаем массив коэффициентов + res.insert(res.end(), src, src + db_size); // записываем туда блок данных + res.resize(res.capacity(), 0); // дополняем нулями если кодов коррекции нужно больше, чем есть данных - for (unsigned j = 0; j < db_size; j++) { - unsigned char A = res[0]; + auto gen_poly = Tables::reed_solomon_generative_polynomial.at(corr_bytes_num); + + for (unsigned j = 0; j < db_size; j++) { // повторяем столько, сколько есть байт данных + // Сохраняем первый коэффициент и удаляем его из массива + unsigned char A = res[0]; res.erase(res.begin()); res.push_back(0); if (A == 0) continue; - unsigned char B = Tables::reverse_galois_field.at(A); + unsigned char B = Tables::reverse_galois_field.at(A); // переводим его в логарифм - for (unsigned k = 0; k < corr_bytes_num; k++) { - unsigned char C = (Tables::reed_solomon_generative_polynomial.at(corr_bytes_num).at(k) + B) % 255; - res[k] ^= Tables::galois_field[C]; + for (unsigned k = 0; k < corr_bytes_num; k++) { // для каждого коэффициента порождающего многочлена + unsigned char C = (gen_poly.at(k) + B) % 255; // складываем степени + res[k] ^= Tables::galois_field[C]; // переводим обратно и вычиатем } } } @@ -60,20 +62,16 @@ unsigned get_db_byte_index(unsigned block_index, unsigned byte_index, const vect return db_sizes[block_index].second + byte_index; } -void DataBlocks::join_data_and_EC_blocks(vector& res, const vector& e_data, const vector>& db_sizes, const vector>& ec_codes, unsigned ec_bytes_number) +void DataBlocks::join_data_and_EC_blocks(byte_list& res, const byte_list& e_data, const vector>& db_sizes, const vector& ec_codes, unsigned ec_bytes_number) { - if (ec_codes.size()) - res.reserve(e_data.size() + ec_codes.at(0).size() * ec_codes.size()); - else - res.reserve(e_data.size()); + res.reserve(e_data.size() + ec_codes.at(0).size() * ec_codes.size()); // резервируем память для результирующего массива for (unsigned i = 0; i < db_sizes[db_sizes.size() - 1].first; i++) for (unsigned j = 0; j < db_sizes.size(); j++) - if (i < db_sizes[j].first) - res.push_back(e_data[get_db_byte_index(j, i, db_sizes)]); + if (i < db_sizes[j].first) // если этот блок данных ещё не закончился + res.push_back(e_data[get_db_byte_index(j, i, db_sizes)]); // записываем в результирующий масив i-тый байт j-того блока данных - if (ec_codes.size()) - for (unsigned i = 0; i < ec_bytes_number; i++) - for (unsigned j = 0; j < ec_codes.size(); j++) - res.push_back(ec_codes[j][i]); + for (unsigned i = 0; i < ec_bytes_number; i++) + for (unsigned j = 0; j < ec_codes.size(); j++) + res.push_back(ec_codes[j][i]); // записываем в результирующий массив i-тый байт j-того блока кодов коррекции } diff --git a/QRCodeLibrary/DataBlocks.hpp b/QRCodeLibrary/DataBlocks.hpp index 90c81f4..f8ec908 100644 --- a/QRCodeLibrary/DataBlocks.hpp +++ b/QRCodeLibrary/DataBlocks.hpp @@ -7,22 +7,27 @@ using namespace std; +// Разделяет данные на блоки, генерирует для них коды коррекции и объединяет их class DataBlocks { public: - DataBlocks(const vector& e_data_, CorrectionLevel corr_lvl_, char version_) : e_data{ e_data_ }, corr_lvl{ corr_lvl_ }, version{ version_ } {}; + DataBlocks(const byte_list& e_data_, CorrectionLevel corr_lvl_, char version_); - vector& compose_joined_data_and_EC_blocks(); + // Возвращает массив из соединённых блоков + byte_list& get_joined_data_and_EC_blocks() { return data; }; + // Считает размеры блоков данных static void divide_to_blocks(vector>& db_sizes, unsigned data_size, unsigned db_number); - static void compose_EC_bytes(vector& res, const vector::const_iterator& src, unsigned corr_bytes_num, unsigned db_size); - static void join_data_and_EC_blocks(vector&res, const vector& e_data, const vector>& db_sizes, const vector>& ec_codes, unsigned ec_bytes_number); + // Генерирует коды коррекции для данного блока данных + static void compose_EC_bytes(byte_list& res, const byte_list::const_iterator& src, unsigned corr_bytes_num, unsigned db_size); + // Объединяет данные и коды коррекции + static void join_data_and_EC_blocks(byte_list&res, const byte_list& e_data, const vector>& db_sizes, const vector& ec_codes, unsigned ec_bytes_number); private: - const vector& e_data; + const byte_list& e_data; CorrectionLevel corr_lvl; char version; - vector data; + byte_list data; }; diff --git a/QRCodeLibrary/Encoder.cpp b/QRCodeLibrary/Encoder.cpp index a3dc2a0..392819c 100644 --- a/QRCodeLibrary/Encoder.cpp +++ b/QRCodeLibrary/Encoder.cpp @@ -6,12 +6,12 @@ #include -BitArray& Encoder::encode() +Encoder::Encoder(const byte_list& input_, CorrectionLevel corr_lvl_, QRCodeMethod method_, char version_): input{ input_ }, corr_lvl{ corr_lvl_ }, method{ method_ }, version{ version_ } { unsigned encoded_bit_num = calculate_encoded_input_size(to_U(input.size()), method); unsigned metadata_bit_num = calculate_metadata_size(method, ((version < 0) ? 0 : version)); - if (version < 0) { + if (version < 0) { // если передана отрицательная версия, вычисляем минимальную, в которую поместится это количество данных version = 0; while (metadata_bit_num + encoded_bit_num >= Tables::max_capability.at(corr_lvl).at(version)) { version = determite_version(metadata_bit_num + encoded_bit_num, corr_lvl); @@ -27,8 +27,6 @@ BitArray& Encoder::encode() encode_input(metadata_bit_num); pad_data(e, metadata_bit_num + encoded_bit_num); - - return e; } char Encoder::determite_version(unsigned size, CorrectionLevel corr_lvl) @@ -52,7 +50,7 @@ unsigned Encoder::calculate_metadata_size(QRCodeMethod method, char version) for (int i = 0; i < 3 && lengths[i].first <= version; i++) size = lengths[i].second; - return size + 4; + return size + 4; // четыре бита для метода кодирования } void Encoder::write_metadata(unsigned input_size, unsigned input_bits_amount_size, QRCodeMethod method, BitArray& out) @@ -65,17 +63,20 @@ void Encoder::write_metadata(unsigned input_size, unsigned input_bits_amount_siz void Encoder::encode_numeric(const string& input, BitArray& out, unsigned offset) { + int bin; for (unsigned i = 0; i < input.size() / 3; i++) { - int bin = stoi(input.substr(i * 3, 3)); + bin = stoi(input.substr(i * 3, 3)); out.set(offset + i * 10, bin, 10); } if (input.size() % 3 == 2) { - int bin = stoi(input.substr(input.size() - 2, 2)); + bin = stoi(input.substr(input.size() - 2, 2)); out.set(offset + to_U(input.size()) / 3 * 10, bin, 7); } - else if (input.size() % 3 == 1) - out.set(offset + to_U(input.size()) / 3 * 10, input[input.size() - 1] - '0', 4); + else if (input.size() % 3 == 1) { + bin = input[input.size() - 1] - '0'; + out.set(offset + to_U(input.size()) / 3 * 10, bin, 4); + } } void Encoder::encode_alphabetic(const string& input, BitArray& out, unsigned offset) @@ -118,7 +119,7 @@ void Encoder::pad_data(BitArray& arr, unsigned bits_written) arr.v[i] = ((i - encoded_bytes) % 2 == 0) ? 0b11101100 : 0b00010001; } -BitArray Encoder::get_data() const +BitArray& Encoder::get_data() { if (e.size == 0) throw std::runtime_error("Data is not calculated yet"); diff --git a/QRCodeLibrary/Encoder.hpp b/QRCodeLibrary/Encoder.hpp index aa12a6e..35ede00 100644 --- a/QRCodeLibrary/Encoder.hpp +++ b/QRCodeLibrary/Encoder.hpp @@ -10,12 +10,11 @@ using namespace std; +// Кодирует данные и добавляет метаданные class Encoder { public: - Encoder(const byte_list& 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(); + Encoder(const byte_list& input_, CorrectionLevel corr_lvl_ = CorrectionLevel::M, QRCodeMethod method_ = QRCodeMethod::Dynamic, char version_ = -1); static char determite_version(unsigned size, CorrectionLevel corr_lvl); @@ -42,10 +41,11 @@ public: static void encode_alphabetic(const string& input, BitArray& out, unsigned offset); static void encode_byte(const byte_list& 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; + BitArray& get_data(); private: static constexpr unsigned char encode_char(char ch); diff --git a/QRCodeLibrary/Method.cpp b/QRCodeLibrary/Method.cpp index 0b0dc2d..5a34f88 100644 --- a/QRCodeLibrary/Method.cpp +++ b/QRCodeLibrary/Method.cpp @@ -7,7 +7,7 @@ QRCodeMethod Method::determite_method(const byte_list& input) { QRCodeMethod type = QRCodeMethod::Numeric; - for (auto ch : input) { + for (auto ch : input) { // перебирая байты данных if (type == QRCodeMethod::Numeric) if (!is_num(ch)) type = QRCodeMethod::Alphabetic; diff --git a/QRCodeLibrary/QRCode.cpp b/QRCodeLibrary/QRCode.cpp index 17b51f0..ff8dc58 100644 --- a/QRCodeLibrary/QRCode.cpp +++ b/QRCodeLibrary/QRCode.cpp @@ -9,24 +9,24 @@ QRCode::QRCode(const byte_list& input_, CorrectionLevel corr_lvl_, QRCodeMethod input{ input_ }, corr_lvl{ corr_lvl_ }, method{ method_ }, version{ version_ }, matrix(0) { if (method == QRCodeMethod::Dynamic) { - if (input.size() > Tables::max_capability.at(corr_lvl).at(0) / 8) + if (input.size() > Tables::max_capability.at(corr_lvl).at(0) / 8) // Если данных мало, можно не пытаться кодировать данные, а просто использовать байты method = Method::determite_method(input); else method = QRCodeMethod::Byte; } - + + /* Кодирование данных */ Encoder encoder(input, corr_lvl, method, version); - const BitArray& encoded_data = encoder.encode(); + const BitArray& encoded_data = encoder.get_data(); version = encoder.get_version(); + /* Создание байтов коррекции и объединение данных */ DataBlocks data_blocks(encoded_data.v, corr_lvl, version); - const BitArray final_message(data_blocks.compose_joined_data_and_EC_blocks()); + const BitArray final_message(data_blocks.get_joined_data_and_EC_blocks()); + /* Компоновка рисунка QR кода */ matrix.set_version(version); - matrix.draw_patterns(); - matrix.place_metadata(corr_lvl, mask_n); - matrix.place_data(final_message, mask_n); } diff --git a/QRCodeLibrary/QRCode.hpp b/QRCodeLibrary/QRCode.hpp index 5be5373..f97f97f 100644 --- a/QRCodeLibrary/QRCode.hpp +++ b/QRCodeLibrary/QRCode.hpp @@ -19,11 +19,11 @@ public: vector> to_vector() const { return matrix.to_vector(); }; protected: - byte_list input; + byte_list input; // данные для кодирования в QR код CorrectionLevel corr_lvl; QRCodeMethod method; char version; - QRMatrix matrix; + QRMatrix matrix; // матрица, содержащая QR код }; diff --git a/QRCodeLibrary/QRMatrix.cpp b/QRCodeLibrary/QRMatrix.cpp index f6b5ffd..6f7bd66 100644 --- a/QRCodeLibrary/QRMatrix.cpp +++ b/QRCodeLibrary/QRMatrix.cpp @@ -14,9 +14,9 @@ void QRMatrix::draw_patterns() void QRMatrix::draw_finder_patterns() { - draw_finder_square(0, 0); - draw_finder_square(to_U(c.size()) - 7, 0); - draw_finder_square(0, to_U(c.size()) - 7); + draw_finder_square(0, 0); // левый верхний + draw_finder_square(to_U(c.size()) - 7, 0); // левый нижний + draw_finder_square(0, to_U(c.size()) - 7); // правый верхний draw_finder_square_separators(); } @@ -34,29 +34,31 @@ void QRMatrix::draw_finder_square(unsigned y, unsigned x) void QRMatrix::draw_finder_square_separators() { - set(7, 0, 0b0000000, 7); - set(7, to_U(c.size()) - 7, 0b0000000, 7); - set(to_U(c.size()) - 8, 0, 0b0000000, 7); + set(7, 0, 0b0000000, 7); // низ левого верхнего + set(7, to_U(c.size()) - 7, 0b0000000, 7); // низ правого верхнего + set(to_U(c.size()) - 8, 0, 0b0000000, 7); // верх левого нижнего for (unsigned i = 0; i < 8; i++) { - set(i, 7, 0); - set(i, to_U(c.size()) - 8, 0); - set(to_U(c.size()) - 8 + i, 7, 0); + set(i, 7, 0); // право левого верхнего + set(i, to_U(c.size()) - 8, 0); // лево верхнего правого + set(to_U(c.size()) - 8 + i, 7, 0); // право нижнего левого } } void QRMatrix::draw_alignment_patters() { auto& coordinates = Tables::alignment_patterns_coordinates.at(version); + + // Нужно поставить выравнивающий узор в каждой парной комбинации координат за исключением тех, где происходит пересечение с поисковыми узорами for (unsigned i = 0; i < coordinates.size(); i++) { - unsigned s = i, e = to_U(coordinates.size()); - if (coordinates[i] == 6) - s++, e--; + unsigned s = i, e = to_U(coordinates.size()); // начинаем выбирать вторую координату с i-того индекса, така как комбинации до него уже поставлены отражением относительно главной диагонали + if (coordinates[i] == 6) // если одна из координат равна 6, значит крайние координаты (6 и ближняя к другому краю) будут давать пересечение с поисковыми паттернами + s++, e--; // а значит их неужно исключить for (unsigned j = s; j < e; j++) { draw_alignment_square(coordinates[i], coordinates[j]); - if (i != j) - draw_alignment_square(coordinates[j], coordinates[i]); + if (i != j) // если координаты различны + draw_alignment_square(coordinates[j], coordinates[i]); // рисуем симметрично относительно главной диагонали } } } @@ -73,8 +75,10 @@ void QRMatrix::draw_alignment_square(unsigned y, unsigned x) void QRMatrix::draw_timing_patterns() { for (unsigned i = 8; i < c.size() - 8; i += 2) { + // вертикальная полоса синхронизации set(6, i, 1); set(6, i + 1, 0); + // горизонтальная set(i, 6, 1); set(i + 1, 6, 0); } @@ -87,35 +91,43 @@ void QRMatrix::draw_dark_module() void QRMatrix::place_metadata(CorrectionLevel corr_lvl, unsigned char mask_n) { - if (version >= 6) { + if (version >= 6) { // для версий начиная с седьмой const auto& v_codes = Tables::version_codes.at(version-6); + for (unsigned i = 0; i < 3; i++) for (unsigned j = 0; j < 6; j++) { - set(to_U(c.size()) - 11 + i, j, (v_codes.at(i) >> (6 - 1 - j)) & 1); - set(j, to_U(c.size()) - 11 + i, (v_codes.at(i) >> (6 - 1 - j)) & 1); + // побитово наносим информацию + set(to_U(c.size()) - 11 + i, j, (v_codes.at(i) >> (6 - 1 - j)) & 1); // горизонтально и + set(j, to_U(c.size()) - 11 + i, (v_codes.at(i) >> (6 - 1 - j)) & 1); // вертикально + // соответствующие биты информации получаются путём смещения и применения единичной битовой маски } } unsigned code = Tables::corr_lvl_and_mask_codes.at(corr_lvl)[mask_n]; - + // Используются два "курсора" с координатами (y1, x2), (y2, x2). Первый огибает против часововй стрелки левый верхний поисковой квадрат, второй поднимается по правой стороне левого нижнего квадрата и слева направо под правым верхним квадратом unsigned y1 = 8, y2 = to_U(c.size()) - 1, x1 = 0, x2 = 8; for (unsigned i = 0; i < 15; i++) { set(y1, x1, (code >> (15 - 1 - i)) & 1); set(y2, x2, (code >> (15 - 1 - i)) & 1); - if (x1 < 8) { - x1++; - if (x1 == 6) x1++; + // Первый курсор + if (x1 < 8) { // пока не достигли правого нижнего угла квадрата + x1++; // наращиваем горизонтальную координату + if (x1 == 6) x1++; // пропускаем столбец с синхронизирующей линией } - else { - if (x1 == 8) y1--; - if (y1 == 6) y1--; + else { // если достигли правой стороны + y1--; // уменьшаем вертикальную координату + if (y1 == 6) y1--; // пропускаем строку с синхронизирующей линией } - if (y2 > c.size() - 8) y2--; - if (y2 == to_U(c.size()) - 8) { y2 = 8; x2 = to_U(c.size()) - 8; } - else if (y2 == 8) - x2++; + // Второй курсор + if (y2 > c.size() - 8) // пока не достигли верха левого нижнего квадрата + y2--; // уменьшаем вертикальую координату + if (y2 == to_U(c.size()) - 8) { // когда достигли, "перепрыгиваем" к правому верхнему квадрату + y2 = 8; + x2 = to_U(c.size()) - 8; + } else if (y2 == 8) // если находимся под правым верхним квадратом + x2++; // наращиваем горизонтальную координату } @@ -126,25 +138,25 @@ void QRMatrix::place_data(const BitArray& data, unsigned char mask_n) { unsigned y = to_U(c.size()) - 1; unsigned x = y; - unsigned step = 0; - bool horiz_dir = true; - bool up = true; + unsigned step = 0; // то, сколько бит данных было записано и индекс по совместительству + bool horiz_dir = true; // флаг обозначающий то, что на этом шаге нужно двигаться горизонтально + bool up = true; // флаг, обозначающий направление вертикального движения (true => вверх) const auto& mask = Tables::mask_functions.at(mask_n); while (true) { - if (x == 6) - x--; + if (x == 6) // если попадаем на вертикальную линию синхронизации + x--; // сразу пропускаем её и перемещаемся на столбец влево - if (get(y, x) == Trit::EMPTY) { - if (step < data.size) { - set(y, x, mask(y, x) ? data.get(step) : !data.get(step)); + if (get(y, x) == Trit::EMPTY) { // если клетка не заполнена + if (step < data.size) { // если ещё не закончились данные + set(y, x, mask(y, x) ? data.get(step) : !data.get(step)); // устанавливаем клетке значение и инвертируем его если маска равно нулю step++; } - else set(y, x, !mask(y, x)); + else set(y, x, !mask(y, x)); // иначе считаем, что значение равно 0 и применяем маску } - if (horiz_dir) + if (horiz_dir) x--; else { x++; @@ -158,8 +170,8 @@ void QRMatrix::place_data(const BitArray& data, unsigned char mask_n) } else { if (y == c.size() - 1) { - if (x == 1) // т.к. сделали шаг "вправо" на строчке 130 - break; + if (x == 1) // если достигли точки (c.size() - 1, 0) но x проверяется 1, так как уже на этой итерации сделали шаг "вправо" на строчке 162 (x++) + break; // можно прерывать цикл записи. запись всегда будет заканчиваться в левом нижнем углу, так как это так для первой версси, а потом размеры QR кода увеличиваются на 4 с каждой версией, а значит будет успевать пройти весь "цикл смены наравления" (визуализация представлена на изображениях в п. "Расположение данных") x -= 2; up = !up; diff --git a/QRCodeLibrary/QRMatrix.hpp b/QRCodeLibrary/QRMatrix.hpp index 6bdb4d6..cb246b7 100644 --- a/QRCodeLibrary/QRMatrix.hpp +++ b/QRCodeLibrary/QRMatrix.hpp @@ -6,6 +6,7 @@ #include "BitArray.hpp" #include "TritMatrix.hpp" +// Переводит версию в соответствующий ей размер QR кода constexpr unsigned v_to_size(char version) { return version * 4 + 21; }; class QRMatrix : public TritMatrix @@ -13,22 +14,47 @@ class QRMatrix : public TritMatrix public: QRMatrix(char version_) : TritMatrix(v_to_size(version_)), version{ version_ } {}; + // Рисует стандартные обязательные элементы QR кода void draw_patterns(); + // Рисует поисковые узоры void draw_finder_patterns(); + /* Рисует поисковой квадрат с координатами (y, x) + ####### + # # + # ### # + # ### # + # ### # + # # + ####### + */ void draw_finder_square(unsigned y, unsigned x); + // Рисует контуры вокруг поисковых квадратов void draw_finder_square_separators(); + // Рисует выравнивающие узоры void draw_alignment_patters(); + /* Рисует выравнивающий квадрат с координатами центра (y, x) + ##### + # # + # # # + # # + ##### + */ void draw_alignment_square(unsigned y, unsigned x); + // Рисует синхронизирующие полосы void draw_timing_patterns(); + // Рисует чёрный пиксель возле левого нижнего квадрата void draw_dark_module(); + // Размещает метаданные на QR коде (уровень коррекции, номер маски, начиная с 7-ой версии, версию) void place_metadata(CorrectionLevel corr_lvl, unsigned char mask_n); + // Размещает данные с применённой маской mask_n void place_data(const BitArray& data, unsigned char mask_n); + // Устанавливает версию и соответственно размер матрицы void set_version(char version); private: diff --git a/QRCodeLibrary/Tables.hpp b/QRCodeLibrary/Tables.hpp index a16df0d..ef435a3 100644 --- a/QRCodeLibrary/Tables.hpp +++ b/QRCodeLibrary/Tables.hpp @@ -8,6 +8,7 @@ #include "Method.hpp" namespace Tables { + // массив из символов, расположенных так, чтобы их индекс соответствовал коду при алфавитном кодировании static constexpr std::array alphabetic{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', @@ -25,6 +26,7 @@ namespace Tables { return false; } + // максимальное количество бит, которое можно закодировать при данном уровне коррекции и соответствующей индексу массива версии static const std::map>max_capability{ { CorrectionLevel::L, {{ 152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 2192, 2592, 2960, 3424, 3688, 4184, 4712, 5176, 5768, 6360, 6888, 7456, 8048, 8752, 9392, 10208, 10960, 11744, 12248, 13048, 13880, 14744, 15640, 16568, 17528, 18448, 19472, 20528, 21616, 22496, 23648 }} }, { CorrectionLevel::M, {{ 128, 224, 352, 512, 688, 864, 992, 1232, 1456, 1728, 2032, 2320, 2672, 2920, 3320, 3624, 4056, 4504, 5016, 5352, 5712, 6256, 6880, 7312, 8000, 8496, 9024, 9544, 10136, 10984, 11640, 12328, 13048, 13800, 14496, 15312, 15936, 16816, 17728, 18672 }} }, @@ -32,17 +34,21 @@ namespace Tables { { CorrectionLevel::H, {{ 72, 128, 208, 288, 368, 480, 528, 688, 800, 976, 1120, 1264, 1440, 1576, 1784, 2024, 2264, 2504, 2728, 3080, 3248, 3536, 3712, 4112, 4304, 4768, 5024, 5288, 5608, 5960, 6344, 6760, 7208, 7688, 7888, 8432, 8768, 9136, 9776, 10208 }} } }; + // четырёхбитный код режима кодирования, записываемый в метаданных static const std::mapmode_indicator{ { QRCodeMethod::Numeric, 0b0001 }, { QRCodeMethod::Alphabetic, 0b0010 }, { QRCodeMethod::Byte, 0b0100 } }; + + // то, сколько бит должно занимать количество символов в метаданных static const std::map, 3>>data_amount_lengths{ { QRCodeMethod::Numeric, {{ {0, 10}, {9, 12}, {26, 14} }} }, { QRCodeMethod::Alphabetic, {{ {0, 9}, {9, 11}, {26, 13} }} }, { QRCodeMethod::Byte, {{ {0, 8}, {9, 16}, {26, 16} }} } }; + // то, насколько блоков нужно разделить данные static const std::map>data_blocks_number{ { CorrectionLevel::L, {{ 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25 }} }, { CorrectionLevel::M, {{ 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49 }} }, @@ -50,6 +56,7 @@ namespace Tables { { CorrectionLevel::H, {{ 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81 }} } }; + // количество байт коррекции для одного блока данных static const std::map>correction_bytes_num{ { CorrectionLevel::L, {{ 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }} }, { CorrectionLevel::M, {{ 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 }} }, @@ -57,6 +64,7 @@ namespace Tables { { CorrectionLevel::H, {{ 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }} } }; + // предпосчитанные коэффициенты для порождающего многочлена Рида-Соломона для данной длины static const std::map>reed_solomon_generative_polynomial{ { 7, {{ 87, 229, 146, 149, 238, 102, 21 }}}, { 10, {{ 251, 67, 46, 61, 118, 70, 64, 94, 32, 45 }}}, @@ -73,6 +81,7 @@ namespace Tables { { 30, {{ 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193, 224, 130, 156, 37, 251, 216, 238, 40, 192, 180 }}} }; + // таблица перевода чисел в двоичные логарифмы static constexpr std::arraygalois_field{ 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, @@ -92,6 +101,7 @@ namespace Tables { 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, }; + // таблица перевода логарифмов в числа static constexpr std::arrayreverse_galois_field{ 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, @@ -111,6 +121,7 @@ namespace Tables { 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 }; + // static const array, 40>alignment_patterns_coordinates{ vector(), {18,}, {22,}, {26,}, {30,}, {34,}, {6, 22, 38}, {6, 24, 42}, {6, 26, 46}, {6, 28, 50}, @@ -123,6 +134,7 @@ namespace Tables { {6, 28, 54, 80, 106, 132, 158}, {6, 32, 58, 84, 110, 136, 162}, {6, 26, 54, 82, 110, 138, 166}, {6, 30, 58, 86, 114, 142, 170} }; + // коды версий (для версий начиная с 7), наносимые на матрицу static constexpr array, 34>version_codes{ { { 0b000010, 0b011110, 0b100110 }, { 0b010001, 0b011100, 0b111000 }, @@ -160,6 +172,7 @@ namespace Tables { { 0b111001, 0b000100, 0b010101 } } }; + // коды уровней коррекции и масок, наносимые на матрицу static const map>corr_lvl_and_mask_codes{ { CorrectionLevel::L, { 0b111011111000100, 0b111001011110011, 0b111110110101010, 0b111100010011101, 0b110011000101111, 0b110001100011000, 0b110110001000001, 0b110100101110110 } @@ -175,6 +188,7 @@ namespace Tables { } }; + // Массив лямбд, масок, принимающих координаты и возвращающие булевое значение static const array, 8>mask_functions{ { [](unsigned y, unsigned x) { return (x + y) % 2; }, [](unsigned y, unsigned x) { return y % 2; }, diff --git a/QRCodeLibrary/TritMatrix.cpp b/QRCodeLibrary/TritMatrix.cpp index 0141112..e435a4d 100644 --- a/QRCodeLibrary/TritMatrix.cpp +++ b/QRCodeLibrary/TritMatrix.cpp @@ -17,7 +17,7 @@ void TritMatrix::set(unsigned y, unsigned x, int32_t val, unsigned char size) { if (x + size > c.at(0).size()) throw std::out_of_range("Value to write is out of matrix range"); for (unsigned char i = 0; i < size; i++) - set(y, x + i, ((val >> (size - 1 - i)) & 1) ? Trit::T : Trit::F); + set(y, x + i, (val >> (size - 1 - i)) & 1); // побитово записываем последние size бит из val в матрицу в прямом порядке } void TritMatrix::set(unsigned y, unsigned x, bool val) @@ -50,31 +50,6 @@ string TritMatrix::to_ascii(char black, char white, char empty) const return res; } -string TritMatrix::to_string() const -{ - string res; - - for (unsigned i = 0; i < c.size(); i++) { - for (unsigned j = 0; j < c.at(0).size(); j++) - switch (c[i][j]) - { - case Trit::T: - res.push_back('1'); - break; - case Trit::F: - res.push_back('0'); - break; - case Trit::EMPTY: - res.push_back('E'); - break; - } - if (i != c.size() - 1) - res.push_back('\n'); - } - - return res; -} - void TritMatrix::resize(unsigned width, unsigned height) { c.resize(height); diff --git a/QRCodeLibrary/TritMatrix.hpp b/QRCodeLibrary/TritMatrix.hpp index 26c9c07..b037938 100644 --- a/QRCodeLibrary/TritMatrix.hpp +++ b/QRCodeLibrary/TritMatrix.hpp @@ -14,19 +14,22 @@ enum Trit { class TritMatrix { public: + // Создаёт матрицу heigt x width TritMatrix(unsigned width, unsigned height) : c{ height, vector(width, Trit::EMPTY) } {}; + // Создаёт матрицу size x size TritMatrix(unsigned size) : c{ size, vector(size, Trit::EMPTY) } {}; Trit get(unsigned y, unsigned x) const; void set(unsigned y, unsigned x, Trit val); void set(unsigned y, unsigned x, bool val); + // записывает size последних бит val в строку y матрицы. 1 передодится в Trit.T, 0 в Trit.F void set(unsigned y, unsigned x, int32_t val, unsigned char size); void resize(unsigned width, unsigned height); string to_ascii(char black = '#', char white = ' ', char empty = 'E') const; - string to_string() const; + string to_string() const { return to_ascii('1', '0', 'E'); }; vector> to_vector() const { return c; }; protected: diff --git a/QRCodeLibrary/utils.hpp b/QRCodeLibrary/utils.hpp index 77a5d60..9fbe77b 100644 --- a/QRCodeLibrary/utils.hpp +++ b/QRCodeLibrary/utils.hpp @@ -6,6 +6,7 @@ #include #include +// Функция для приведения типа size_t в unsigned constexpr static unsigned to_U(size_t val) { if (val > (std::numeric_limits::max)()) throw std::runtime_error("Too big number to convert it to unsigned int" + std::to_string(val)); diff --git a/tests/DataBlocks_test.cpp b/tests/DataBlocks_test.cpp index 5c5589d..5993f5c 100644 --- a/tests/DataBlocks_test.cpp +++ b/tests/DataBlocks_test.cpp @@ -15,25 +15,25 @@ TEST(DataBlocksTests, ComposesSizesOfDatablocks) { } TEST(DataBlocksTests, GeneratesECBytes) { - const vector input{ 64, 196, 132, 84, 196, 196, 242, 194, 4, 132, 20, 37, 34, 16, 236, 17 }; - vector tmp; + const byte_list input{ 64, 196, 132, 84, 196, 196, 242, 194, 4, 132, 20, 37, 34, 16, 236, 17 }; + byte_list tmp; DataBlocks::compose_EC_bytes(tmp, input.cbegin(), 28, 16); - const vector res{ 16, 85, 12, 231, 54, 54, 140, 70, 118, 84, 10, 174, 235, 197, 99, 218, 12, 254, 246, 4, 190, 56, 39, 217, 115, 189, 193, 24 }; + const byte_list res{ 16, 85, 12, 231, 54, 54, 140, 70, 118, 84, 10, 174, 235, 197, 99, 218, 12, 254, 246, 4, 190, 56, 39, 217, 115, 189, 193, 24 }; EXPECT_EQ(tmp, res); } TEST(DataBlocksTests, JoinsDataAndECBlocks) { - vectorjoined; - const vectore_data{ + byte_list joined; + const byte_list e_data{ 67, 85, 70, 134, 87, 38, 85, 194, 119, 50, 6, 18, 6, 103, 38, 246, 246, 66, 7, 118, 134, 242, 7, 38, 86, 22, 198, 199, 146, 6, 182, 230, 247, 119, 50, 7, 118, 134, 87, 38, 82, 6, 134, 151, 50, 7, 70, 247, 118, 86, 194, 6, 151, 50, 16, 236, 17, 236, 17, 236, 17, 236 }; const vector> d_b_sizes{ {15, 0}, {15, 15}, {16, 30}, {16, 46} }; - const vector> EC_blocks{ + const vector EC_blocks{ { 213, 199, 11, 45, 115, 247, 241, 223, 229, 248, 154, 117, 154, 111, 86, 161, 111, 39 }, { 87, 204, 96, 60, 202, 182, 124, 157, 200, 134, 27, 129, 209, 17, 163, 163, 120, 133 }, { 148, 116, 177, 212, 76, 133, 75, 242, 238, 76, 195, 230, 189, 10, 108, 240, 192, 141 }, @@ -42,7 +42,7 @@ TEST(DataBlocksTests, JoinsDataAndECBlocks) { DataBlocks::join_data_and_EC_blocks(joined, e_data, d_b_sizes, EC_blocks, 18); - const vectorres{ + const byte_list res{ 67, 246, 182, 70, 85, 246, 230, 247, 70, 66, 247, 118, 134, 7, 119, 86, 87, 118, 50, 194, 38, 134, 7, 6, 85, 242, 118, 151, 194, 7, 134, 50, 119, 38, 87, 16, 50, 86, 38, 236, 6, 22, 82, 17, 18, @@ -57,7 +57,7 @@ TEST(DataBlocksTests, JoinsDataAndECBlocks) { } TEST(DataBlocksTests, ComposesJoinedDataAndECBlocks) { - const vectore_data{ + const byte_list e_data{ 67, 85, 70, 134, 87, 38, 85, 194, 119, 50, 6, 18, 6, 103, 38, 246, 246, 66, 7, 118, 134, 242, 7, 38, 86, 22, 198, 199, 146, 6, 182, 230, 247, 119, 50, 7, 118, 134, 87, 38, 82, 6, 134, 151, 50, 7, @@ -66,7 +66,7 @@ TEST(DataBlocksTests, ComposesJoinedDataAndECBlocks) { DataBlocks db(e_data, CorrectionLevel::Q, 4); - const vector joined{ + const byte_list joined{ 67, 246, 182, 70, 85, 246, 230, 247, 70, 66, 247, 118, 134, 7, 119, 86, 87, 118, 50, 194, 38, 134, 7, 6, 85, 242, 118, 151, 194, 7, 134, 50, 119, 38, 87, 16, 50, 86, 38, 236, 6, 22, 82, 17, 18, @@ -78,5 +78,5 @@ TEST(DataBlocksTests, ComposesJoinedDataAndECBlocks) { 108, 131, 161, 163, 240, 32, 111, 120, 192, 178, 39, 133, 141, 236 }; - EXPECT_EQ(db.compose_joined_data_and_EC_blocks(), joined); + EXPECT_EQ(db.get_joined_data_and_EC_blocks(), joined); } \ No newline at end of file diff --git a/tests/Encoder_test.cpp b/tests/Encoder_test.cpp index b48ae3c..939d635 100644 --- a/tests/Encoder_test.cpp +++ b/tests/Encoder_test.cpp @@ -106,14 +106,11 @@ TEST(EncoderTests, PadsData) { TEST(EncoderTests, EncodesInput) { Encoder e1(str_to_bytes("8675309"), CorrectionLevel::Q, QRCodeMethod::Numeric); - e1.encode(); EXPECT_EQ(std::string(e1.get_data()), "00010000000111110110001110000100101001001110110000010001111011000001000111101100000100011110110000010001"); Encoder e2(str_to_bytes("HELLO WORLD"), CorrectionLevel::M, QRCodeMethod::Alphabetic); - e2.encode(); EXPECT_EQ(std::string(e2.get_data()), "00100000010110110000101101111000110100010111001011011100010011010100001101000000111011000001000111101100000100011110110000010001"); Encoder e3(str_to_bytes(u8"Дмитрий Шишков"), CorrectionLevel::Q, QRCodeMethod::Byte); - e3.encode(); EXPECT_EQ(std::string(e3.get_data()), "01000001101111010000100101001101000010111100110100001011100011010001100000101101000110000000110100001011100011010000101110010010000011010000101010001101000010111000110100011000100011010000101110101101000010111110110100001011001000001110110000010001111011000001000111101100"); } \ No newline at end of file