На самом деле, она и не заканчивалась, просто я вот вчера пошёл в магазин ну типа в пятёрочку тут есть у меня недалеко на углу улицы и короче вот я пошёл иду такой а мне навстречу сам илон макс правда я не шучу реально илон маз к идёт такой и я ему такой привет а он такой тоже здравствуйте я спрашиваю типа как там с теслой и спайс икс а он перебивает меня и говорит смотри сейчас будет фокус ну я такой ладно и он типа раз и взрывается нахуй пиздец я тогда умер кстати
303 lines
8.6 KiB
C++
303 lines
8.6 KiB
C++
/*
|
|
* KLDR.hpp
|
|
* Copyright (c) 2023 Cyclone Team. Licensed under GNU GPLv3-only terms.
|
|
*
|
|
*/
|
|
|
|
#ifndef LIBSTADIUM_KLDR_HPP
|
|
#define LIBSTADIUM_KLDR_HPP
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <random>
|
|
#include <exception>
|
|
|
|
|
|
|
|
namespace Stadium::v1 {
|
|
|
|
|
|
|
|
enum KLDRDefaultKeys : uint8_t {
|
|
Data = 0x01, // Main data of event
|
|
ObjectID = 0x02, // ID of object in local context
|
|
SrcEventAuthor = 0x03, // Source author of event
|
|
PrevEvent = 0x04, // ID of previous event, logically connected to this
|
|
NextEvent = 0x05, // ID of next event
|
|
BatchNumber = 0x06, // Number of event in chain of events
|
|
Path = 0x07, // Path to requested/uploaded resource
|
|
Power = 0x08, // Access right to object
|
|
ServerSession = 0x09, // ID of server-side session
|
|
// Crypto-related
|
|
CryptoAlgos = 0x11, // Array of used cryptography algos
|
|
CryptoKeyID = 0x12, // ID of crypto key used for data encryption in this event
|
|
SignedDataHash = 0x13 // Signed by sender hash of data
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
* KLDR stands for "Key-Length-Data-Repeat".
|
|
* Schematically, binary array with KLDR-formatted data looks like this.
|
|
* Single cell:
|
|
* [key: 1 or 2 bytes][length of data: 1/2/4 bytes][data: <length of data> bytes]
|
|
* Whole array:
|
|
* [cell 1][cell 2]...[cell n]
|
|
*
|
|
* Suffix "F" in function name stands for "Fast", i.e. it is unsafe, but fast version.
|
|
*
|
|
* This can be more optimized for performance with cost of more memory usage.
|
|
*/
|
|
template <typename KeyT = uint8_t, typename LengthT = uint16_t>
|
|
class KLDRArray {
|
|
private:
|
|
std::vector<KeyT> Keys;
|
|
std::vector<LengthT> Lengths;
|
|
std::vector<char*> Values;
|
|
|
|
public:
|
|
// Constructor
|
|
KLDRArray () {}; // TODO: check used types and/or parse given char array/vector
|
|
|
|
// Destructor
|
|
~KLDRArray () {
|
|
// Freeing all pointers if vector is not empty
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
delete[] this->Values[i];
|
|
}
|
|
}
|
|
|
|
// Move operator WARNING: есть шанс, что я тут сделал ложно, ибо мб мув просто продлевает время жизни вместо перемещения. Ассигнмента тоже касается
|
|
KLDRArray (KLDRArray&& src) : Keys(std::move(src.Keys)), Lengths(std::move(src.Lengths)), Values(std::move(src.Values)) {}
|
|
|
|
// Move assignment operator
|
|
KLDRArray& operator= (KLDRArray&& src) {
|
|
if (this == &src)
|
|
return *this;
|
|
|
|
this->Keys = std::move(src.Keys);
|
|
this->Lengths = std::move(src.Lengths);
|
|
this->Values = std::move(src.Values);
|
|
return *this;
|
|
}
|
|
|
|
// Copy operator (creating deep copy)
|
|
KLDRArray (KLDRArray& src) : Keys(src.Keys), Lengths(src.Lengths)
|
|
{
|
|
size_t valSize = 0;
|
|
for (size_t i = 0; i < src.Values.size(); i++) {
|
|
valSize = src.Lengths[i];
|
|
this->Values.push_back(new char[valSize]);
|
|
std::copy(src.Values[i], src.Values[i] + valSize, this->Values[i]);
|
|
}
|
|
}
|
|
|
|
// Copy assignment operator (creating deep copy)
|
|
KLDRArray& operator= (const KLDRArray& src) {
|
|
if (this == &src)
|
|
return *this;
|
|
|
|
this->Keys = src.Keys;
|
|
this->Lengths = src.Lengths;
|
|
size_t valSize = 0;
|
|
for (size_t i = 0; i < src.Values.size(); i++) {
|
|
valSize = src.Lengths[i];
|
|
this->Values.push_back(new char[valSize]);
|
|
std::copy(src.Values[i], src.Values[i] + valSize, this->Values[i]);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Write data to PREALLOCATED char array
|
|
// WARNING: unsafe and probably UB (may be i test this later but who knows)
|
|
void AsArrayF (char* arr) {
|
|
char* ptr = arr;
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
std::copy((char*)&this->Keys[i], (char*)(&this->Keys[i] + sizeof(KeyT)), ptr);
|
|
ptr += sizeof(KeyT);
|
|
std::copy((char*)&this->Lengths[i], (char*)(&this->Lengths[i] + sizeof(LengthT)), ptr);
|
|
ptr += sizeof(LengthT);
|
|
std::copy(this->Values[i], this->Values[i] + this->Lengths[i], ptr);
|
|
ptr += this->Lengths[i];
|
|
}
|
|
}
|
|
|
|
// Return contents as char vector
|
|
std::vector<char> AsArray () const {
|
|
std::vector<char> result;
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
for (uint j = 0; j < sizeof(KeyT); j++)
|
|
result.push_back(((char*)(&this->Keys[i]))[j]);
|
|
for (uint j = 0; j < sizeof(LengthT); j++)
|
|
result.push_back(((char*)(&this->Lengths[i]))[j]);
|
|
for (uint j = 0; j < this->Lengths[i]; j++)
|
|
result.push_back(((char*)this->Values[i])[j]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Print all contents of array to stdout
|
|
void Print () const {
|
|
printf(
|
|
"[KLDRArray] Object at: %lu; "
|
|
"KeyT size: %lu; "
|
|
"LengthT size: %lu; "
|
|
"Elements amount: %lu\n",
|
|
(size_t)this,
|
|
sizeof(KeyT),
|
|
sizeof(LengthT),
|
|
this->CellsAmount()
|
|
);
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
printf("\tKey: ");
|
|
switch (this->Keys[i]) {
|
|
case v1::KLDRDefaultKeys::Data:
|
|
printf("Data");
|
|
break;
|
|
case v1::KLDRDefaultKeys::ObjectID:
|
|
printf("ObjectID");
|
|
break;
|
|
case v1::KLDRDefaultKeys::SrcEventAuthor:
|
|
printf("SrcEventAuthor");
|
|
break;
|
|
case v1::KLDRDefaultKeys::PrevEvent:
|
|
printf("PrevEvent");
|
|
break;
|
|
case v1::KLDRDefaultKeys::NextEvent:
|
|
printf("NextEvent");
|
|
break;
|
|
case v1::KLDRDefaultKeys::BatchNumber:
|
|
printf("BatchNumber");
|
|
break;
|
|
case v1::KLDRDefaultKeys::Path:
|
|
printf("Path");
|
|
break;
|
|
case v1::KLDRDefaultKeys::Power:
|
|
printf("Power");
|
|
break;
|
|
case v1::KLDRDefaultKeys::ServerSession:
|
|
printf("ServerSession");
|
|
break;
|
|
case v1::KLDRDefaultKeys::CryptoAlgos:
|
|
printf("CryptoAlgos");
|
|
break;
|
|
case v1::KLDRDefaultKeys::CryptoKeyID:
|
|
printf("CryptoKeyID");
|
|
break;
|
|
case v1::KLDRDefaultKeys::SignedDataHash:
|
|
printf("SignedDataHash");
|
|
break;
|
|
default:
|
|
printf("0x%.2X", (KeyT)this->Keys[i]);
|
|
}
|
|
printf("; Length: %u; ", (uint)this->Lengths[i]);
|
|
printf("ValuePtr: %lu; Value: ", (uint64_t)this->Values[i]);
|
|
for (LengthT j = 0; j < this->Lengths[i]; j++)
|
|
printf("%.2X ", ((uint8_t*)this->Values[i])[j]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
// Get amount of cells in array
|
|
inline size_t CellsAmount () const {
|
|
return this->Keys.size();
|
|
}
|
|
|
|
// Get size of all data in array as if they in packed condition
|
|
size_t FlatSize () const {
|
|
size_t result = this->Keys.size() * sizeof(KeyT) + this->Lengths.size() * sizeof(LengthT);
|
|
for (size_t i = 0; i < this->CellsAmount(); i++)
|
|
result += this->Lengths[i];
|
|
return result;
|
|
}
|
|
|
|
// If there are specified key
|
|
bool KeyExists (KeyT key) const {
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
if (this->Keys[i] == key) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Add new cell to array, fast version without key checks, data will be copied
|
|
void AddF (KeyT key, LengthT length, char* data) {
|
|
this->Keys.push_back(key);
|
|
this->Lengths.push_back(length);
|
|
char* newData = new char[length];
|
|
std::copy(data, data + length, newData);
|
|
this->Values.push_back(newData);
|
|
}
|
|
|
|
// Add new cell to array, but only if key is unique
|
|
void Add (KeyT key, LengthT length, char* data) {
|
|
if (this->KeyExists(key))
|
|
throw std::invalid_argument("supplied key already exist");
|
|
this->AddF(key, length, data);
|
|
}
|
|
|
|
// Get just pointer to value from array by key
|
|
char* Get (KeyT key) const {
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
if (this->Keys[i] == key) {
|
|
return this->Values[i];
|
|
}
|
|
}
|
|
throw std::invalid_argument("invalid KLDRArray key");
|
|
}
|
|
|
|
// Get pointer to value and length from array by key
|
|
char* Get (KeyT key, LengthT* length) const {
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
if (this->Keys[i] == key) {
|
|
*length = this->Lengths[i];
|
|
return this->Values[i];
|
|
}
|
|
}
|
|
throw std::invalid_argument("invalid KLDRArray key");
|
|
}
|
|
|
|
// TODO: get copy of value
|
|
|
|
// Delete cell from array by key
|
|
void Del (KeyT key) {
|
|
for (size_t i = 0; i < this->CellsAmount(); i++) {
|
|
if (this->Keys[i] == key) {
|
|
this->Keys.erase(this->Keys.begin() + i);
|
|
this->Lengths.erase(this->Lengths.begin() + i);
|
|
this->Values.erase(this->Values.begin() + i);
|
|
return;
|
|
}
|
|
}
|
|
throw std::invalid_argument("invalid KLDRArray key");
|
|
}
|
|
|
|
// Shuffle array
|
|
void Shuffle () {
|
|
size_t elements = this->CellsAmount();
|
|
std::random_device seed;
|
|
std::mt19937 gen{seed()};
|
|
std::uniform_int_distribution<size_t> dist{0, elements-1};
|
|
size_t pickedIndex = 0;
|
|
for (size_t i = 0; i < elements; i++) {
|
|
do
|
|
pickedIndex = dist(gen);
|
|
while (pickedIndex == i);
|
|
std::swap(this->Keys[i], this->Keys[pickedIndex]);
|
|
std::swap(this->Lengths[i], this->Lengths[pickedIndex]);
|
|
std::swap(this->Values[i], this->Values[pickedIndex]);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif |