Added upper_index and input encoding with numeric, alphabetic and byte methods
This commit is contained in:
parent
e8a9846bf4
commit
304185d1a2
@ -1,29 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "Encode.hpp"
|
||||
|
||||
unsigned Encode::calculate_encoded_input_size(unsigned input_size, QRCodeMethod 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;
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Method.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Encode
|
||||
{
|
||||
public:
|
||||
static unsigned calculate_encoded_input_size(unsigned input_size, QRCodeMethod method);
|
||||
};
|
||||
|
84
QRCodeLibrary/Encoder.cpp
Normal file
84
QRCodeLibrary/Encoder.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "Encoder.hpp"
|
||||
#include "Tables.hpp"
|
||||
|
||||
unsigned char Encoder::determite_version()
|
||||
{
|
||||
const auto& sizes = Tables::max_capability.at(corr_lvl);
|
||||
|
||||
return upper_index(sizes, input.size());
|
||||
}
|
||||
|
||||
void Encoder::encode()
|
||||
{
|
||||
unsigned bit_num = calculate_encoded_input_size(input.size(), method);
|
||||
}
|
||||
|
||||
unsigned Encoder::calculate_encoded_input_size(unsigned input_size, QRCodeMethod 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;
|
||||
}
|
||||
|
||||
void Encoder::encode_numeric(const string& input, BitArray& out, unsigned offset)
|
||||
{
|
||||
for (unsigned i = 0; i < input.size() / 3; i++) {
|
||||
int 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));
|
||||
out.set(offset + input.size() / 3 * 10, bin, 7);
|
||||
}
|
||||
else if (input.size() % 3 == 1)
|
||||
out.set(offset + input.size() / 3 * 10, input[input.size() - 1] - '0', 4);
|
||||
}
|
||||
|
||||
void Encoder::encode_alphabetic(const string& input, BitArray& out, unsigned offset)
|
||||
{
|
||||
for (unsigned i = 0; i < input.size() / 2; i++) {
|
||||
int bin = encode_char(input[i * 2]) * 45 + encode_char(input[i * 2 + 1]);
|
||||
out.set(offset + i * 11, bin, 11);
|
||||
}
|
||||
|
||||
if (input.size() % 2 == 1) {
|
||||
int bin = encode_char(input[input.size() - 1]);
|
||||
out.set(offset + input.size() / 2 * 11, bin, 6);
|
||||
}
|
||||
}
|
||||
|
||||
void Encoder::encode_byte(const string& input, BitArray& out, unsigned offset)
|
||||
{
|
||||
for (unsigned i = 0; i < input.size(); i++)
|
||||
out.set(offset + i * 8, input[i], 8);
|
||||
}
|
||||
|
||||
unsigned char Encoder::encode_char(char ch)
|
||||
{
|
||||
for (unsigned i = 0; i < Tables::alphabetic.size(); i++)
|
||||
if (ch == Tables::alphabetic.at(i))
|
||||
return i;
|
||||
|
||||
throw std::runtime_error("No such character in alphabet. Use bytes QR code method.");
|
||||
}
|
69
QRCodeLibrary/Encoder.hpp
Normal file
69
QRCodeLibrary/Encoder.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include "Method.hpp"
|
||||
#include "BitArray.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Encoder
|
||||
{
|
||||
public:
|
||||
Encoder(const string& input_, CorrectionLevel corr_lvl_, QRCodeMethod method_, unsigned char version_) : input{ input_ }, corr_lvl{ corr_lvl_ }, method{ method_ }, version{ version_ } {};
|
||||
|
||||
unsigned char determite_version();
|
||||
|
||||
void encode();
|
||||
|
||||
static unsigned calculate_encoded_input_size(unsigned input_size, QRCodeMethod method);
|
||||
|
||||
constexpr void encode_input() {
|
||||
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 unsigned char encode_char(char ch);
|
||||
|
||||
private:
|
||||
const string& input;
|
||||
CorrectionLevel corr_lvl;
|
||||
const QRCodeMethod method;
|
||||
unsigned char version;
|
||||
|
||||
BitArray e;
|
||||
unsigned offset = 0;
|
||||
};
|
||||
|
||||
template <typename T, unsigned N>
|
||||
constexpr unsigned char upper_index(const array<T, N> arr, T val) {
|
||||
unsigned count = arr.size(), s = 0, e, step;
|
||||
|
||||
while (count > 0) {
|
||||
step = count / 2;
|
||||
e = s + step;
|
||||
|
||||
if (arr[e] < val) {
|
||||
s = e + 1;
|
||||
count -= step + 1;
|
||||
}
|
||||
else
|
||||
count = step;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
@ -152,7 +152,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BitArray.hpp" />
|
||||
<ClInclude Include="Encode.hpp" />
|
||||
<ClInclude Include="Encoder.hpp" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="Method.hpp" />
|
||||
<ClInclude Include="pch.h" />
|
||||
@ -161,7 +161,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BitArray.cpp" />
|
||||
<ClCompile Include="Encode.cpp" />
|
||||
<ClCompile Include="Encoder.cpp" />
|
||||
<ClCompile Include="Method.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
@ -30,7 +30,7 @@
|
||||
<ClInclude Include="Tables.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Encode.hpp">
|
||||
<ClInclude Include="Encoder.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BitArray.hpp">
|
||||
@ -50,7 +50,7 @@
|
||||
<ClCompile Include="Tables.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Encode.cpp">
|
||||
<ClCompile Include="Encoder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BitArray.cpp">
|
||||
|
@ -8,4 +8,11 @@ const std::array<char, 45> Tables::alphabetic{
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*',
|
||||
'+', '-', '.', '/', ':'
|
||||
};
|
||||
|
||||
const std::map<CorrectionLevel, const std::array<unsigned, 20>> Tables::max_capability{
|
||||
{ CorrectionLevel::L, {{152, 272, 440, 640, 864, 1088, 1248, 1552, 1856, 2192, 2592, 2960, 3424, 3688, 4184, 4712, 5176, 5768, 6360, 6888}} },
|
||||
{ CorrectionLevel::M, {{128, 224, 352, 512, 688, 864, 992, 1232, 1456, 1728, 2032, 2320, 2672, 2920, 3320, 3624, 4056, 4504, 5016, 5352}} },
|
||||
{ CorrectionLevel::Q, {{104, 176, 272, 384, 496, 608, 704, 880, 1056, 1232, 1440, 1648, 1952, 2088, 2360, 2600, 2936, 3176, 3560, 3880}} },
|
||||
{ CorrectionLevel::H, {{72, 128, 208, 288, 368, 480, 528, 688, 800, 976, 1120, 1264, 1440, 1576, 1784, 2024, 2264, 2504, 2728, 3080}} }
|
||||
};
|
@ -1,8 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "Method.hpp"
|
||||
|
||||
class Tables {
|
||||
public:
|
||||
static const std::array<char, 45>alphabetic;
|
||||
|
||||
static const std::map<CorrectionLevel, const std::array<unsigned, 20>> max_capability;
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#define protected public
|
||||
#define private public
|
||||
|
||||
#include "../QRCodeLibrary/Encode.hpp"
|
||||
|
||||
TEST(EncodeTests, CalculatesEncodedInputSize) {
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(3, QRCodeMethod::Numeric), 10);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(3 + 1, QRCodeMethod::Numeric), 10 + 4);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(3*3 + 1, QRCodeMethod::Numeric), 10*3 + 4);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(3 + 2, QRCodeMethod::Numeric), 10 + 7);
|
||||
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(2, QRCodeMethod::Alphabetic), 11);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(2*3, QRCodeMethod::Alphabetic), 11*3);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(2 + 1, QRCodeMethod::Alphabetic), 11 + 6);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(2*3 + 1, QRCodeMethod::Alphabetic), 11*3 + 6);
|
||||
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(5, QRCodeMethod::Byte), 5 * 8);
|
||||
EXPECT_EQ(Encode::calculate_encoded_input_size(10, QRCodeMethod::Byte), 10*8);
|
||||
}
|
67
tests/Encoder_test.cpp
Normal file
67
tests/Encoder_test.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "pch.h"
|
||||
|
||||
#define private public
|
||||
|
||||
#include "../QRCodeLibrary/Encoder.hpp"
|
||||
|
||||
TEST(UpperIndexTests, FindsExactMatch) {
|
||||
array<int, 5> arr1{ 1, 2, 3, 4, 5 };
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
EXPECT_EQ(upper_index(arr1, i+1), i);
|
||||
|
||||
array<int, 4> arr2{ 1, 2, 3, 4 };
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
EXPECT_EQ(upper_index(arr2, i + 1), i);
|
||||
}
|
||||
|
||||
TEST(UpperIndexTests, FindsClosestUpper) {
|
||||
array<int, 5> arr{ 1, 3, 5, 7, 9 };
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
EXPECT_EQ(upper_index(arr, i * 2), i);
|
||||
}
|
||||
|
||||
TEST(UpperIndexTests, IfNothingFoundReturnsArrSize) {
|
||||
array<int, 5> arr{ 0, 1, 2, 3, 4 };
|
||||
|
||||
EXPECT_EQ(upper_index(arr, 5), 5);
|
||||
EXPECT_EQ(upper_index(arr, 10), 5);
|
||||
}
|
||||
|
||||
TEST(EncoderTests, CalculatesEncodedInputSize) {
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(3, QRCodeMethod::Numeric), 10);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(3 + 1, QRCodeMethod::Numeric), 10 + 4);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(3*3 + 1, QRCodeMethod::Numeric), 10*3 + 4);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(3 + 2, QRCodeMethod::Numeric), 10 + 7);
|
||||
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(2, QRCodeMethod::Alphabetic), 11);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(2*3, QRCodeMethod::Alphabetic), 11*3);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(2 + 1, QRCodeMethod::Alphabetic), 11 + 6);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(2*3 + 1, QRCodeMethod::Alphabetic), 11*3 + 6);
|
||||
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(5, QRCodeMethod::Byte), 5 * 8);
|
||||
EXPECT_EQ(Encoder::calculate_encoded_input_size(10, QRCodeMethod::Byte), 10*8);
|
||||
}
|
||||
|
||||
TEST(EncoderTests, EncodesNumeric) {
|
||||
BitArray tmp(string("00110110001110000100101001").size());
|
||||
Encoder::encode_numeric("8675309", tmp, 2);
|
||||
|
||||
EXPECT_EQ(std::string(tmp), "00110110001110000100101001");
|
||||
}
|
||||
|
||||
TEST(EncoderTests, EncodesAlphabetic) {
|
||||
BitArray tmp(string("0000110000101101111000110100010111001011011100010011010100001101").size());
|
||||
Encoder::encode_alphabetic("HELLO WORLD", tmp, 3);
|
||||
|
||||
EXPECT_EQ(std::string(tmp), "0000110000101101111000110100010111001011011100010011010100001101");
|
||||
}
|
||||
|
||||
TEST(EncoderTests, EncodesBytes) {
|
||||
BitArray tmp(string("0000110100001001010011010000101111001101000010111000110100011000001011010001100000001101000010111000110100001011100100100000110100001010100011010000101110001101000110001000110100001011101011010000101111101101000010110010").size());
|
||||
Encoder::encode_byte(u8"Дмитрий Шишков", tmp, 4);
|
||||
|
||||
EXPECT_EQ(std::string(tmp), "0000110100001001010011010000101111001101000010111000110100011000001011010001100000001101000010111000110100001011100100100000110100001010100011010000101110001101000110001000110100001011101011010000101111101101000010110010");
|
||||
}
|
@ -37,7 +37,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BitArray_test.cpp" />
|
||||
<ClCompile Include="Encode_test.cpp" />
|
||||
<ClCompile Include="Encoder_test.cpp" />
|
||||
<ClCompile Include="Method_test.cpp" />
|
||||
<ClCompile Include="QRCode_test.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
Loading…
x
Reference in New Issue
Block a user