選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

385 行
11 KiB

#include "UserScript.h"
#include <algorithm>
#include <span>
#include <utility>
#include "UserScriptWizardry.h"
#include "UserScriptRequire.h"
using interpreter = decltype(scripting::prepare_interpreter({}));
using namespace scripting;
namespace bad_cryptography {
struct encode_n_parameters {
uint8_t spin;
uint8_t clash;
uint8_t maim;
};
static constexpr uint8_t encode_n_1(uint8_t value, const encode_n_parameters &params) {
value += 42;
value ^= 0b01010101;
value += params.clash;
value = std::rotl(value, params.spin);
value ^= 0b10101010;
value ^= params.maim;
return value;
}
static constexpr uint8_t decode_n_1(uint8_t value, const encode_n_parameters &params) {
value ^= params.maim;
value ^= 0b10101010;
value = std::rotl(value, -params.spin);
value -= params.clash;
value ^= 0b01010101;
value -= 42;
return value;
}
namespace eliminated_001 {
constexpr encode_n_parameters params{.spin = 3, .clash = 17, .maim = 54};
static_assert(0 == decode_n_1(encode_n_1(0, params), params));
static_assert(10 == decode_n_1(encode_n_1(10, params), params));
static_assert(100 == decode_n_1(encode_n_1(100, params), params));
static_assert(20 == decode_n_1(encode_n_1(20, params), params));
static_assert(200 == decode_n_1(encode_n_1(200, params), params));
static_assert(117 == decode_n_1(encode_n_1(117, params), params));
static_assert(42 == decode_n_1(encode_n_1(42, params), params));
};
namespace eliminated_002 {
constexpr encode_n_parameters params{.spin = 7, .clash = 97, .maim = 154};
static_assert(0 == decode_n_1(encode_n_1(0, params), params));
static_assert(10 == decode_n_1(encode_n_1(10, params), params));
static_assert(100 == decode_n_1(encode_n_1(100, params), params));
static_assert(20 == decode_n_1(encode_n_1(20, params), params));
static_assert(200 == decode_n_1(encode_n_1(200, params), params));
static_assert(117 == decode_n_1(encode_n_1(117, params), params));
static_assert(42 == decode_n_1(encode_n_1(42, params), params));
};
}
namespace scripting {
struct fn_string_to_binary final : public scripting::function_impl {
int32_t array_size_limit;
explicit fn_string_to_binary(int32_t _array_size_limit)
: array_size_limit(_array_size_limit)
{}
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
if(n.size() != 1) {
error = script_error{
.message = "/string_to_binary takes exactly 1 argument of type string"
};
return std::nullopt;
}
auto& arg = n.front();
script_value target;
if(std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
if(not std::holds_alternative<std::string>(target)) {
error = script_error{
.message = "/string_to_binary takes exactly 1 argument of type string"
};
return std::nullopt;
}
auto& str = std::get<std::string>(target);
array result;
std::transform(str.begin(), str.end(), std::back_inserter(result.value), [&](char value) -> script_value {
return (int32_t)value;
});
return result;
}
~fn_string_to_binary() final = default;
};
struct fn_binary_to_string final : public scripting::function_impl {
int32_t string_size_limit;
explicit fn_binary_to_string(int32_t _string_size_limit)
: string_size_limit(_string_size_limit) {}
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
if(n.size() != 1) {
error = script_error{
.message = "/binary_to_string takes exactly 1 argument of type array"
};
return std::nullopt;
}
auto& arg = n.front();
script_value target;
if(std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
if(not std::holds_alternative<array>(target)) {
error = script_error{
.message = "/binary_to_string takes exactly 1 argument of type array"
};
return std::nullopt;
}
auto& ary = std::get<array>(target);
if(ary.value.size() > string_size_limit) {
error = script_error{
.message = "/binary_to_string: array is too bit to fit string type"
};
return std::nullopt;
}
std::string result;
const bool valid = std::any_of(ary.value.begin(), ary.value.end(), [](auto val) {
return std::visit(
wizardry::overloaded{
[](int32_t v) { return 0 <= v && v <= 255; },
[](auto v) { return false; }
},
val
);
});
if(not valid) {
error = script_error{
.message = "/binary_to_string takes exactly 1 argument of type array of which contents must be numbers between 0 and 255 included"
};
return std::nullopt;
}
constexpr auto byte_convert = [](int32_t v) -> char {
const uint32_t v2 = v;
const uint8_t v3 = v2 & 0b1111'1111;
return char(v3);
};
std::transform(ary.value.begin(), ary.value.end(), std::back_inserter(result), [&](const script_value& value) -> char {
return std::visit(
wizardry::overloaded{
byte_convert,
[](auto v) { return '\0'; }
},
value
);
});
return result;
}
~fn_binary_to_string() final = default;
};
struct fn_encode_n final : public scripting::function_impl {
int32_t string_size_limit;
explicit fn_encode_n(int32_t _string_size_limit)
: string_size_limit(_string_size_limit) {}
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
using verifier = Verify<
details::SizeEquals<4>,
details::TypeVerifier<0, int32_t>,
details::TypeVerifier<1, int32_t>,
details::TypeVerifier<2, int32_t>,
details::OctetArrayVerifier<3>
>;
if(not verifier{}.verify(self, n)) {
error = script_error{
.message = "/encode_n takes exactly 3 arguments of type integer and an argument of type array"
};
return std::nullopt;
}
auto& arg = n.front();
script_value target;
if(std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
bad_cryptography::encode_n_parameters params;
{
auto& arg = n[3];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.spin = std::get<int32_t>(target);
}
{
auto& arg = n[2];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.clash = std::get<int32_t>(target);
}
{
auto& arg = n[1];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.maim = std::get<int32_t>(target);
}
auto ary = std::get<array>(target);
if(ary.value.size() > string_size_limit) {
error = script_error{
.message = "/encode_n: array is too bit to fit string type"
};
return std::nullopt;
}
std::transform(ary.value.begin(), ary.value.end(), ary.value.begin(), [&](const script_value& value) {
return std::visit(
wizardry::overloaded{
[&](int32_t v) -> script_value { return script_value{bad_cryptography::encode_n_1(v, params)};},
[](auto v) -> script_value { return null{}; }
},
value
);
});
return ary;
}
~fn_encode_n() final = default;
};
struct fn_decode_n final : public scripting::function_impl {
int32_t string_size_limit;
explicit fn_decode_n(int32_t _string_size_limit)
: string_size_limit(_string_size_limit) {}
std::optional<script_value> apply(UserScript* self, std::vector<argument> n, std::optional<script_error>& error) final {
using verifier = Verify<
details::SizeEquals<4>,
details::TypeVerifier<0, int32_t>,
details::TypeVerifier<1, int32_t>,
details::TypeVerifier<2, int32_t>,
details::OctetArrayVerifier<3>
>;
if(not verifier{}.verify(self, n)) {
error = script_error{
.message = "/decode_n takes exactly 3 arguments of type integer and an argument of type array"
};
return std::nullopt;
}
auto& arg = n.front();
script_value target;
if(std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
bad_cryptography::encode_n_parameters params;
{
auto& arg = n[3];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.spin = std::get<int32_t>(target);
}
{
auto& arg = n[2];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.clash = std::get<int32_t>(target);
}
{
auto& arg = n[1];
script_value target;
if (std::holds_alternative<scripting::script_value>(arg)) {
target = std::get<scripting::script_value>(arg);
} else {
target = self->resolve(std::get<scripting::script_variable>(arg).name);
}
params.maim = std::get<int32_t>(target);
}
auto ary = std::get<array>(target);
if(ary.value.size() > string_size_limit) {
error = script_error{
.message = "/decode_n: array is too bit to fit string type"
};
return std::nullopt;
}
std::transform(ary.value.begin(), ary.value.end(), ary.value.begin(), [&](const script_value& value) {
return std::visit(
wizardry::overloaded{
[&](int32_t v) -> script_value { return script_value{bad_cryptography::decode_n_1(v, params)};},
[](auto v) -> script_value { return null{}; }
},
value
);
});
return ary;
}
~fn_decode_n() final = default;
};
interpreter register_crypto_lib(interpreter target, const UserScriptLibraryParameters& params) {
target->registerFunction("string_to_binary", std::make_unique<fn_string_to_binary>(params.array_size_limit));
target->registerFunction("binary_to_string", std::make_unique<fn_binary_to_string>(params.string_size_limit));
target->registerFunction("encode_n", std::make_unique<fn_encode_n>(params.string_size_limit));
target->registerFunction("decode_n", std::make_unique<fn_decode_n>(params.string_size_limit));
return std::move(target);
}
}