First commit.
Some checks failed
Build & Release / Linux-x86_64-Build (push) Successful in 40s
Build & Release / Linux-AARCH64-Build (push) Has been cancelled

This commit is contained in:
2024-01-31 22:28:19 -08:00
commit 1a4a1ecd9c
246 changed files with 42404 additions and 0 deletions

104
src/Base64.cpp Normal file
View File

@@ -0,0 +1,104 @@
#include "ehs/Base64.h"
namespace ehs
{
const char Base64::ascii[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Str_8 Base64::Encode(const Str_8 input)
{
UInt_64 input_length = input.Size();
// Calculate the output length
UInt_64 output_length = 4 * ((input_length + 2) / 3);
// Allocate memory for the output
Str_8 result(output_length);
// Loop through the input and fill the output
for (int i = 0, j = 0; i < input_length;) {
// Take first byte and shift right by 2 bits
UInt_32 octet_a = i < input_length ? input[i++] : 0;
UInt_32 octet_b = i < input_length ? input[i++] : 0;
UInt_32 octet_c = i < input_length ? input[i++] : 0;
UInt_32 triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
// Encode the 24-bits into four 6-bits integers
result[j++] = ascii[(triple >> 3 * 6) & 0x3F];
result[j++] = ascii[(triple >> 2 * 6) & 0x3F];
result[j++] = ascii[(triple >> 1 * 6) & 0x3F];
result[j++] = ascii[(triple >> 0 * 6) & 0x3F];
}
// Add padding '='
if (input_length % 3 == 1) {
result[output_length - 1] = '=';
result[output_length - 2] = '=';
} else if (input_length % 3 == 2) {
result[output_length - 1] = '=';
}
return result;
}
Str_8 Base64::Decode(const Str_8 input)
{
UInt_64 in_len = input.Size();
int i = 0;
int j = 0;
int in_ = 0;
char char_array_4[4], char_array_3[3];
Str_8 ret;
while (in_len-- && ( input[in_] != '=') && IsBase64(input[in_]))
{
char_array_4[i++] = input[in_]; in_++;
if (i ==4)
{
for (i = 0; i <4; i++)
char_array_4[i] = Find(char_array_4[i]);
char_array_3[0] = ( char_array_4[0] << 2 ) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i)
{
for (j = 0; j < i; j++)
char_array_4[j] = Find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
for (j = 0; (j < i - 1); j++)
ret += char_array_3[j];
}
return ret;
}
char Base64::Find(const char c)
{
for (char i = 0; i < (char)sizeof(ascii); ++i)
{
if (ascii[i] == c)
return i;
}
return EHS_SINT_8_MAX;
}
bool Base64::IsBase64(const char c)
{
return (c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || (c == '+') || (c == '/');
}
}

154
src/BaseObj.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include "ehs/BaseObj.h"
namespace ehs
{
BaseObj::~BaseObj()
{
delete[] hierarchy;
}
BaseObj::BaseObj()
: hierarchy(nullptr), hierarchySize(0)
{
AddType("BaseObj");
}
BaseObj::BaseObj(BaseObj&& base) noexcept
: hierarchy(base.hierarchy), hierarchySize(base.hierarchySize)
{
base.hierarchy = nullptr;
base.hierarchySize = 0;
}
BaseObj::BaseObj(const BaseObj& base)
: hierarchy(new Type[base.hierarchySize]), hierarchySize(base.hierarchySize)
{
for (UInt_64 i = 0; i < hierarchySize; i++)
hierarchy[i] = base.hierarchy[i];
}
BaseObj& BaseObj::operator=(BaseObj&& base) noexcept
{
if (this == &base)
return *this;
delete[] hierarchy;
hierarchy = base.hierarchy;
hierarchySize = base.hierarchySize;
base.hierarchy = nullptr;
base.hierarchySize = 0;
return *this;
}
BaseObj& BaseObj::operator=(const BaseObj& base)
{
if (this == &base)
return *this;
delete[] hierarchy;
hierarchy = new Type[base.hierarchySize];
for (UInt_64 i = 0; i < base.hierarchySize; i++)
hierarchy[i] = base.hierarchy[i];
hierarchySize = base.hierarchySize;
return *this;
}
bool BaseObj::operator==(const BaseObj& base) const
{
if (hierarchySize != base.hierarchySize)
return false;
for (UInt_64 i = 0; i < hierarchySize; i++)
if (hierarchy[i] != base.hierarchy[i])
return false;
return true;
}
bool BaseObj::operator!=(const BaseObj& base) const
{
if (hierarchySize != base.hierarchySize)
return true;
for (UInt_64 i = 0; i < hierarchySize; i++)
if (hierarchy[i] != base.hierarchy[i])
return true;
return false;
}
const Type* BaseObj::GetHierarchy() const
{
return hierarchy;
}
UInt_64 BaseObj::GetHierarchySize() const
{
return hierarchySize;
}
bool BaseObj::HasType(UInt_64 typeHashId) const
{
for (UInt_64 i = 0; i < hierarchySize; i++)
if (hierarchy[i] == typeHashId)
return true;
return false;
}
bool BaseObj::HasType(const Char_8* typeId) const
{
return HasType(Type::GenHash(typeId, Type::CalcSize(typeId)));
}
Type BaseObj::GetType() const
{
return hierarchy[0];
}
UInt_64 BaseObj::GetTypeIdSize() const
{
return hierarchy[0].GetSize();
}
const Char_8* BaseObj::GetTypeId() const
{
return hierarchy[0].GetId();
}
UInt_64 BaseObj::GetTypeHashId() const
{
return hierarchy[0].GetHashId();
}
BaseObj* BaseObj::Clone() const
{
return new BaseObj(*this);
}
void BaseObj::AddType(const Char_8* const id)
{
Type newType(id);
for (UInt_64 i = 0; i < hierarchySize; i++)
if (hierarchy[i] == newType)
return;
Type* result = new Type[hierarchySize + 1];
result[0] = (Type&&)newType;
for (UInt_64 i = 0; i < hierarchySize; i++)
result[i + 1] = (Type&&)hierarchy[i];
hierarchySize++;
delete[] hierarchy;
hierarchy = result;
}
}

100
src/Color3.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "ehs/Color3.h"
#include "ehs/Math.h"
namespace ehs
{
Color3::Color3()
: r(0.0f), g(0.0f), b(0.0f)
{
}
Color3::Color3(const float scalar)
: r(Math::Clamp(scalar, 0.0f, 1.0f)), g(Math::Clamp(scalar, 0.0f, 1.0f)), b(Math::Clamp(scalar, 0.0f, 1.0f))
{
}
Color3::Color3(const float r, const float g, const float b)
: r(Math::Clamp(r, 0.0f, 1.0f)), g(Math::Clamp(g, 0.0f, 1.0f)), b(Math::Clamp(b, 0.0f, 1.0f))
{
}
Color3::Color3(const Color3& color)
: r(color.r), g(color.g), b(color.b)
{
}
Color3& Color3::operator=(const float scalar)
{
r = scalar;
g = scalar;
b = scalar;
return *this;
}
Color3& Color3::operator=(const Color3& color)
{
if (this == &color)
return *this;
r = color.r;
g = color.g;
b = color.b;
return *this;
}
bool Color3::operator==(const Color3& color) const
{
return r == color.r && g == color.g && b == color.b;
}
bool Color3::operator!=(const Color3& color) const
{
return r != color.r || g != color.g || b != color.b;
}
float Color3::operator[](const UInt_64 i) const
{
switch (i)
{
case 0:
return r;
case 1:
return g;
case 2:
return b;
default:
return r;
}
}
float& Color3::operator[](const UInt_64 i)
{
switch (i)
{
case 0:
return r;
case 1:
return g;
case 2:
return b;
default:
return r;
}
}
Color3& Color3::operator*=(const Color3& color)
{
r *= color.r;
g *= color.g;
b *= color.b;
return *this;
}
Color3 Color3::operator*(const Color3& color) const
{
return {r * color.r, g * color.g, b * color.b};
}
}

121
src/Color4.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "ehs/Color4.h"
#include "ehs/Math.h"
namespace ehs
{
Color4::Color4()
: r(0.0f), g(0.0f), b(0.0f), a(1.0f)
{
}
Color4::Color4(const float scalar)
: r(Math::Clamp(scalar, 0.0f, 1.0f)), g(Math::Clamp(scalar, 0.0f, 1.0f)), b(Math::Clamp(scalar, 0.0f, 1.0f)), a(1.0f)
{
}
Color4::Color4(const Color3& color)
: r(color.r), g(color.g), b(color.b), a(1.0f)
{
}
Color4::Color4(const float r, const float g, const float b, const float a)
: r(Math::Clamp(r, 0.0f, 1.0f)), g(Math::Clamp(g, 0.0f, 1.0f)), b(Math::Clamp(b, 0.0f, 1.0f)), a(Math::Clamp(a, 0.0f, 1.0f))
{
}
Color4::Color4(const Color4& color)
: r(color.r), g(color.g), b(color.b), a(color.a)
{
}
Color4& Color4::operator=(const float scalar)
{
r = scalar;
g = scalar;
b = scalar;
a = 1.0f;
return *this;
}
Color4& Color4::operator=(const Color3& color)
{
r = color.r;
g = color.g;
b = color.b;
a = 1.0f;
return *this;
}
Color4& Color4::operator=(const Color4& color)
{
if (this == &color)
return *this;
r = color.r;
g = color.g;
b = color.b;
a = color.a;
return *this;
}
bool Color4::operator==(const Color4& color) const
{
return r == color.r && g == color.g && b == color.b && a == color.a;
}
bool Color4::operator!=(const Color4& color) const
{
return r != color.r || g != color.g || b != color.b || a != color.a;
}
float Color4::operator[](const UInt_64 i) const
{
switch (i)
{
case 0:
return r;
case 1:
return g;
case 2:
return b;
case 3:
return a;
default:
return r;
}
}
float& Color4::operator[](const UInt_64 i)
{
switch (i)
{
case 0:
return r;
case 1:
return g;
case 2:
return b;
case 3:
return a;
default:
return r;
}
}
Color4& Color4::operator*=(const Color4& color)
{
r *= color.r;
g *= color.g;
b *= color.b;
return *this;
}
Color4 Color4::operator*(const Color4& color) const
{
return {r * color.r, g * color.g, b * color.b, a};
}
}

5
src/Data.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "ehs/Data.h"
namespace ehs
{
}

77
src/DataType.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "ehs/DataType.h"
namespace ehs
{
DataType FromAudioBitDepth(const UInt_16 bitDepth)
{
switch (bitDepth / 8)
{
case 1:
return DataType::SINT_8;
case 2:
return DataType::SINT_16;
case 3:
return DataType::SINT_24;
case 4:
return DataType::SINT_32;
default:
return DataType::SINT_8;
}
}
UInt_8 ToByteDepth(const DataType type)
{
switch (type)
{
case DataType::LDOUBLE:
return 16;
case DataType::DOUBLE:
case DataType::SINT_64:
case DataType::UINT_64:
return 8;
case DataType::FLOAT:
case DataType::SINT_32:
case DataType::UINT_32:
return 4;
case DataType::SINT_24:
case DataType::UINT_24:
return 3;
case DataType::SINT_16:
case DataType::UINT_16:
return 2;
case DataType::SINT_8:
case DataType::UINT_8:
return 1;
default:
return 0;
}
}
UInt_8 ToBitDepth(const DataType type)
{
switch (type)
{
case DataType::LDOUBLE:
return 128;
case DataType::DOUBLE:
case DataType::SINT_64:
case DataType::UINT_64:
return 64;
case DataType::FLOAT:
case DataType::SINT_32:
case DataType::UINT_32:
return 32;
case DataType::SINT_24:
case DataType::UINT_24:
return 24;
case DataType::SINT_16:
case DataType::UINT_16:
return 16;
case DataType::SINT_8:
case DataType::UINT_8:
return 8;
default:
return 0;
}
}
}

666
src/EHS.cpp Normal file
View File

@@ -0,0 +1,666 @@
#include "ehs/EHS.h"
#include "ehs/Log.h"
#include "ehs/Version.h"
#include "ehs/GarbageCollector.h"
#include "ehs/io/audio/Audio.h"
#include "ehs/io/img/Img.h"
#include "ehs/io/img/PNG.h"
#include "ehs/io/RIFF.h"
#include <zlib.h>
#if defined(EHS_OS_LINUX)
#include <sys/mman.h>
#endif
namespace ehs
{
constexpr Char_32 name_32[] = U"Event Horizon Suite";
constexpr Char_16 name_16[] = L"Event Horizon Suite";
constexpr Char_8 name_8[] = "Event Horizon Suite";
constexpr Char_32 acronym_32[] = U"EHS";
constexpr Char_16 acronym_16[] = L"EHS";
constexpr Char_8 acronym_8[] = "EHS";
constexpr Char_32 versionId_32[] = U"Release";
constexpr Char_16 versionId_16[] = L"Release";
constexpr Char_8 versionId_8[] = "Release";
Str_8 appName;
Str_8 appVerId;
Version appVer;
const Char_32* GetName_32()
{
return name_32;
}
const Char_16* GetName_16()
{
return name_16;
}
const Char_8* GetName_8()
{
return name_8;
}
Str_8 GetAppName_8()
{
return appName;
}
const Char_32* GetAcronym_32()
{
return acronym_32;
}
const Char_16* GetAcronym_16()
{
return acronym_16;
}
const Char_8* GetAcronym_8()
{
return acronym_8;
}
const Char_32* GetVersionId_32()
{
return versionId_32;
}
const Char_16* GetVersionId_16()
{
return versionId_16;
}
const Char_8* GetVersionId_8()
{
return versionId_8;
}
Str_8 GetAppVersionId_8()
{
return appVerId;
}
Version GetVersion()
{
return {1, 2, 0};
}
Version GetAppVersion()
{
return appVer;
}
bool DecodeWAV(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
{
RIFF riff(in);
if (riff.GetType() != "WAVE")
{
EHS_LOG_INT("Error", 0, "Data is not in WAVE format.");
return false;
}
RIFF_Chunk fmt = riff.GetChunk("fmt ");
if (!fmt.IsValid())
{
EHS_LOG_INT("Error", 1, "Wave does not have a format chunk.");
return false;
}
Serializer<> fmtSer = fmt.GetData();
RIFF_Chunk dChunk = riff.GetChunk("data");
if (!dChunk.IsValid())
{
EHS_LOG_INT("Error", 2, "Wave does not have a data chunk.");
return false;
}
UInt_16 compression = fmtSer.Read<UInt_16>();
if (compression == 0x2)
{
EHS_LOG_INT("Error", 3, "Microsoft ADPCM compression unsupported.");
return false;
}
else if (compression == 0x6)
{
EHS_LOG_INT("Error", 4, "ITU G.711 a-law compression unsupported.");
return false;
}
else if (compression == 0x7)
{
EHS_LOG_INT("Error", 5, "ITU G.711 µ-law compression unsupported.");
return false;
}
else if (compression == 0x11)
{
EHS_LOG_INT("Error", 6, "IMA ADPCM compression unsupported.");
return false;
}
else if (compression == 0x16)
{
EHS_LOG_INT("Error", 7, "TU G.723 ADPCM (Yamaha) compression unsupported.");
return false;
}
else if (compression == 0x31)
{
EHS_LOG_INT("Error", 8, "GSM 6.10 compression unsupported.");
return false;
}
else if (compression == 0x40)
{
EHS_LOG_INT("Error", 9, "ITU G.721 ADPCM compression unsupported.");
return false;
}
else if (compression == 0x50)
{
EHS_LOG_INT("Error", 10, "MPEG compression unsupported.");
return false;
}
else if (compression == 0xFFFF)
{
EHS_LOG_INT("Error", 11, "Experimental compression unsupported.");
return false;
}
else if (compression != 0x1 && compression != 0x3)
{
EHS_LOG_INT("Error", 12, "Wave has unknown compression of " + Str_8::FromNum(compression) + ".");
return false;
}
UInt_16 channels = fmtSer.Read<UInt_16>();
UInt_32 sampleRate = fmtSer.Read<UInt_32>();
fmtSer.SetOffset(fmtSer.GetOffset() + 6);
UInt_8 byteDepth = (UInt_8)(fmtSer.Read<UInt_16>() / 8);
DataType dataType;
if (byteDepth == 1)
dataType = DataType::SINT_8;
else if (byteDepth == 2)
dataType = DataType::SINT_16;
else if (byteDepth == 3)
dataType = DataType::SINT_24;
else if (byteDepth == 4 && compression == 0x3)
dataType = DataType::FLOAT;
else if (byteDepth == 4)
dataType = DataType::SINT_32;
else if (byteDepth == 8)
dataType = DataType::SINT_64;
else
return false;
UInt_64 size = dChunk.GetData().Size();
UInt_64 frames = size / byteDepth / channels;
*out = std::move(Audio(out->GetId(), sampleRate, dataType, channels, frames));
Serializer<> dataSer = dChunk.GetData();
for (UInt_32 i = 0; i < dataSer.Size(); i += byteDepth)
{
if (byteDepth == 1)
{
*(SInt_8*)&(*out)[i] = dataSer.Read<SInt_8>();
if ((*out)[i] > *(SInt_8*)out->GetPeak())
out->SetPeak(sizeof(SInt_8), &(*out)[i]);
}
else if (byteDepth == 2)
{
*(SInt_16*)&(*out)[i] = dataSer.Read<SInt_16>();
if (*(SInt_16*)&(*out)[i] > *(SInt_16*)out->GetPeak())
out->SetPeak(sizeof(SInt_16), &(*out)[i]);
}
else if (byteDepth == 3)
{
*(SInt_16*)&(*out)[i + 1] = dataSer.Read<SInt_16>();
(*out)[i] = dataSer.Read<Byte>();
SInt_32 signal = 0;
signal |= (*out)[i];
signal |= (*out)[i + 1] << 8;
signal |= (*out)[i + 2] << 16;
SInt_32 peak = 0;
peak |= out->GetPeak()[0];
peak |= out->GetPeak()[1] << 8;
peak |= out->GetPeak()[2] << 16;
if (signal > peak)
out->SetPeak(3, &(*out)[i]);
}
else if (byteDepth == 4 && compression == 0x3)
{
*(float*)&(*out)[i] = dataSer.Read<float>();
if (*(float*)&(*out)[i] > *(float*)out->GetPeak())
out->SetPeak(sizeof(float), &(*out)[i]);
}
else if (byteDepth == 4)
{
*(SInt_32*)&(*out)[i] = dataSer.Read<SInt_32>();
if (*(SInt_32*)&(*out)[i] > *(SInt_32*)out->GetPeak())
out->SetPeak(sizeof(SInt_32), &(*out)[i]);
}
else if (byteDepth == 8)
{
*(SInt_64*)&(*out)[i] = dataSer.Read<SInt_64>();
if (*(SInt_64*)&(*out)[i] > *(SInt_64*)out->GetPeak())
out->SetPeak(sizeof(SInt_64), &(*out)[i]);
}
}
return true;
}
bool EncodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Audio* in)
{
Serializer<UInt_64> result(codec->GetEndianness());
result.WriteVersion({1, 0, 0});
result.Write(in->GetSampleRate());
result.Write(in->GetDataType());
result.Write(in->GetByteDepth());
result.Write(in->GetChannels());
result.Write(in->GetFrameCount());
UInt_64 size = in->GetSize();
UInt_8 byteDepth = in->GetByteDepth();
result.Resize(result.Size() + size + byteDepth);
Util::Copy(&result[result.GetOffset()], &in[0], size);
result.SetOffset(result.GetOffset() + size);
Util::Copy(&result[result.GetOffset()], in->GetPeak(), byteDepth);
return true;
}
bool DecodeEHA(const ehs::AudioCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Audio* out)
{
Version version = in.ReadVersion();
if (version != Version(1, 0, 0))
{
EHS_LOG_INT("Error", 0, "Incompatible audio file version.");
return false;
}
UInt_64 sampleRate = in.Read<UInt_64>();
DataType dataType = in.Read<DataType>();
UInt_8 byteDepth = in.Read<UInt_8>();
UInt_8 channels = in.Read<UInt_8>();
UInt_64 frames = in.Read<UInt_64>();
*out = Audio(out->GetId(), sampleRate, dataType, channels, frames);
UInt_64 size = out->GetSize();
Util::Copy(&(*out)[0], &in[in.GetOffset()], size);
in.SetOffset(in.GetOffset() + size);
out->SetPeak(byteDepth, &in[in.GetOffset()]);
return true;
}
bool DecodePNG(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
{
PNG png(out->GetId(), in);
PNG_Chunk* ihdr = png.GetChunk("IHDR");
Serializer<UInt_64>* ihdrData = ihdr->GetData();
UInt_32 width = ihdrData->Read<UInt_32>();
UInt_32 height = ihdrData->Read<UInt_32>();
UInt_8 bitDepth = ihdrData->Read<UInt_8>();
UInt_8 colorType = ihdrData->Read<UInt_8>();
if (colorType == 3)
{
EHS_LOG_INT("Error", 1, "Color type of " + Str_8::FromNum(colorType) + " is unsupported.");
return false;
}
UInt_8 channels = 1;
if (colorType == 2)
channels = 3;
else if (colorType == 4)
channels = 2;
else if (colorType == 6)
channels = 4;
*out = Img(out->GetId(), bitDepth, channels, {width, height});
UInt_8 compression = ihdrData->Read<UInt_8>();
if (compression)
{
EHS_LOG_INT("Error", 2, "Compression method of " + Str_8::FromNum(compression) + " is unsupported.");
return false;
}
UInt_8 filter = ihdrData->Read<UInt_8>();
if (filter)
{
EHS_LOG_INT("Error", 3, "Filter method of " + Str_8::FromNum(filter) + " is unsupported.");
return false;
}
UInt_8 interlaced = ihdrData->Read<UInt_8>();
if (interlaced)
{
EHS_LOG_INT("Error", 4, "Interlacing method of " + Str_8::FromNum(interlaced) + " is unsupported.");
return false;
}
UInt_32 scanline = width * (bitDepth / 8) * channels;
UInt_32 scanLineF = scanline + 1;
UInt_32 bufferSize = scanline * height + height;
Byte* buffer = new Byte[bufferSize];
PNG_Chunk* idat = png.GetChunk("IDAT");
Serializer<UInt_64>* idatData = idat->GetData();
z_stream strm = {};
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = idatData->Size();
strm.next_in = *idatData;
strm.avail_out = bufferSize;
strm.next_out = buffer;
int code = inflateInit(&strm);
if (code != Z_OK)
{
EHS_LOG_INT("Error", 5, "Failed to initialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
delete[] buffer;
return false;
}
do
{
code = inflate(&strm, Z_NO_FLUSH);
if (code != Z_STREAM_END && code != Z_OK)
{
EHS_LOG_INT("Error", 6, "Failed to zlib inflate with error #" + Str_8::FromNum(code) + ".");
delete[] buffer;
return false;
}
} while (strm.avail_out);
code = inflateEnd(&strm);
if (code != Z_OK)
{
EHS_LOG_INT("Error", 7, "Failed to uninitialize zlib inflate with error #" + Str_8::FromNum(code) + ".");
delete[] buffer;
return false;
}
for (UInt_32 i = 0, o = 0; i < bufferSize; i += scanLineF, o += scanline)
{
UInt_8 fCode = buffer[i];
if (fCode == 0)
PNG::FilterNone(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
else if (fCode == 1)
PNG::FilterSub(&buffer[i + 1], &(*out)[o], bitDepth, channels, scanline);
else if (fCode == 2)
PNG::FilterUp(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
else if (fCode == 3)
PNG::FilterAverage(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
else if (fCode == 4)
PNG::FilterPaeth(&buffer[i + 1], &(*out)[o - scanline], bitDepth, channels, scanline);
}
delete[] buffer;
return true;
}
bool EncodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& out, const ehs::Img* in)
{
UInt_8 channels = in->GetChannels();
Vec2_u64 resolution = in->GetResolution();
UInt_32 px_len = resolution.x * resolution.y * channels;
UInt_32 px_end = px_len - channels;
Byte index[256];
for (UInt_64 i = 0; i < 64; ++i)
*(UInt_32*)&index[i * 4] = 0;
Byte prevPixel[4] = {0, 0, 0, 255};
Byte pixel[4] = {0, 0, 0, 255};
Serializer<UInt_32> result(Endianness::BE, resolution.x * resolution.y * (channels + 1) + 22);
result.Write('q');
result.Write('o');
result.Write('i');
result.Write('f');
result.Write<UInt_32>(resolution.x);
result.Write<UInt_32>(resolution.y);
result.Write(in->GetChannels());
result.Write(1);
for (UInt_32 px_pos = 0, run = 0; px_pos < px_len; px_pos += channels)
{
if (channels == 4)
{
*(UInt_32*)pixel = *(UInt_32*)&(*in)[px_pos];
}
else
{
pixel[0] = (*in)[px_pos];
pixel[1] = (*in)[px_pos + 1];
pixel[2] = (*in)[px_pos + 2];
}
if (*(UInt_32*)pixel == *(UInt_32*)prevPixel)
{
run++;
if (run == 62 || px_pos == px_end)
{
result.Write<UInt_8>(0xc0 | (run - 1));
run = 0;
}
}
else
{
if (run > 0)
{
result.Write<UInt_8>(0xc0 | (run - 1));
run = 0;
}
UInt_32 index_pos = (prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels;
if (*(UInt_32*)&index[index_pos] == *(UInt_32*)pixel)
{
result.Write<UInt_8>(0x00 | (index_pos / channels));
}
else
{
*(UInt_32*)&index[index_pos] = *(UInt_32*)pixel;
if (pixel[3] == prevPixel[3])
{
SInt_8 vr = pixel[0] - prevPixel[0];
SInt_8 vg = pixel[1] - prevPixel[1];
SInt_8 vb = pixel[2] - prevPixel[2];
SInt_8 vg_r = vr - vg;
SInt_8 vg_b = vb - vg;
if (
vr > -3 && vr < 2 &&
vg > -3 && vg < 2 &&
vb > -3 && vb < 2
)
{
result.Write<UInt_8>(0x40 | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2));
}
else if (
vg_r > -9 && vg_r < 8 &&
vg > -33 && vg < 32 &&
vg_b > -9 && vg_b < 8
)
{
result.Write<UInt_8>(0x80 | (vg + 32));
result.Write<UInt_8>((vg_r + 8) << 4 | (vg_b + 8));
}
else
{
result.Write<UInt_8>(0xfe);
result.Write(pixel[0]);
result.Write(pixel[1]);
result.Write(pixel[2]);
}
}
else
{
result.Write<UInt_8>(0xff);
result.SetEndianness(CPU::GetEndianness());
result.Write(*(UInt_32*)pixel);
result.SetEndianness(Endianness::BE);
}
}
}
*(UInt_32*)prevPixel = *(UInt_32*)pixel;
}
result.Write(0x100000000000000);
return true;
}
bool DecodeQOI(const ehs::ImgCodec* const codec, ehs::Serializer<ehs::UInt_64>& in, ehs::Img* out)
{
Str_8 imgType = in.ReadStr<Char_8, UInt_64>(4);
if (imgType != "qoif")
{
EHS_LOG_INT("Error", 0, "Given data is not in the qoif format.");
return false;
}
UInt_64 width = in.Read<UInt_32>();
UInt_64 height = in.Read<UInt_32>();
UInt_8 channels = in.Read<UInt_8>();
channels = 4;
UInt_8 space = in.Read<UInt_8>();
UInt_8 bitDepth = 8;
UInt_64 size = width * channels * height;
*out = Img(out->GetId(), bitDepth, channels, {width, height});
Byte prevPixel[4] = {0, 0, 0, 255};
Byte index[256];
for (UInt_64 i = 0; i < 64; ++i)
*(UInt_32*)&index[i * 4] = 0;
UInt_32 chunksLen = in.Size() - 8;
for (UInt_32 pos = 0, run = 0; pos < size; pos += channels)
{
if (run > 0)
--run;
else if (in.GetOffset() < chunksLen)
{
UInt_32 chunkType = (UInt_32)in.Read<UInt_8>();
if (chunkType == 0xfe) // RGB
{
prevPixel[0] = in.Read<UInt_8>(); // R-value
prevPixel[1] = in.Read<UInt_8>(); // G-value
prevPixel[2] = in.Read<UInt_8>(); // B-value
}
else if (chunkType == 0xff) // RGBA
{
*(UInt_32*)prevPixel = in.Read<UInt_32>();
}
else if ((chunkType & 0xc0) == 0x00) // Index
{
*(UInt_32*)prevPixel = *(UInt_32*)&index[chunkType * channels];
}
else if ((chunkType & 0xc0) == 0x40) // Diff
{
prevPixel[0] += ((chunkType >> 4) & 0x03) - 2; // R-value
prevPixel[1] += ((chunkType >> 2) & 0x03) - 2; // G-value
prevPixel[2] += (chunkType & 0x03) - 2; // B-value
}
else if ((chunkType & 0xc0) == 0x80) // Luma
{
UInt_32 mod = (UInt_32)in.Read<UInt_8>();
UInt_32 vg = (chunkType & 0x3f) - 32;
prevPixel[0] += vg - 8 + ((mod >> 4) & 0x0f); // R-value
prevPixel[1] += vg; // G-value
prevPixel[2] += vg - 8 + (mod & 0x0f); // B-value
}
else if ((chunkType & 0xc0) == 0xc0) // Run
run = (chunkType & 0x3f);
*(UInt_32*)&index[(prevPixel[0] * 3 + prevPixel[1] * 5 + prevPixel[2] * 7 + prevPixel[3] * 11) % 64 * channels] = *(UInt_32*)prevPixel;
}
if (channels == 4)
{
*((UInt_32*)&(*out)[pos]) = *(UInt_32*)prevPixel;
}
else
{
(*out)[pos] = prevPixel[0];
(*out)[pos + 1] = prevPixel[1];
(*out)[pos + 2] = prevPixel[2];
}
}
return true;
}
}
int main()
{
ehs::Audio::AddCodec({
"Waveform Audio",
"wav",
ehs::Endianness::LE,
nullptr,
ehs::DecodeWAV
});
ehs::Audio::AddCodec({
"Event Horizon Audio",
"eha",
ehs::Endianness::LE,
ehs::EncodeEHA,
ehs::DecodeEHA
});
ehs::Img::AddCodec({
"Portable Network Graphic",
"png",
ehs::Endianness::BE,
nullptr,
ehs::DecodePNG
});
ehs::Img::AddCodec({
"Quite OK Image",
"qoi",
ehs::Endianness::BE,
ehs::EncodeQOI,
ehs::DecodeQOI
});
ehs::GarbageCollector::Start();
const ehs::SInt_32 code = Main(&ehs::appName, &ehs::appVerId, &ehs::appVer);
if (code)
EHS_LOG("Warning", 0, "Executable exited with code #" + ehs::Str_8::FromNum(code) + ".");
ehs::GarbageCollector::Stop();
return code;
}

133
src/GarbageCollector.cpp Normal file
View File

@@ -0,0 +1,133 @@
#include "ehs/GarbageCollector.h"
namespace ehs
{
UInt_32 GarbageCollectionThread(void* params)
{
while (GarbageCollector::IsRunning())
{
GarbageCollector::Poll();
Thread::SleepFor(50);
}
GarbageCollector::Dump();
return 0;
}
Vector<BaseObj*> GarbageCollector::garbage(0, 1000);
UInt_64 GarbageCollector::max = 10;
Thread GarbageCollector::thread;
Mutex GarbageCollector::mutex;
bool GarbageCollector::running = false;
bool GarbageCollector::Has(const BaseObj* obj)
{
for (UInt_64 i = 0; i < garbage.Size(); ++i)
if (garbage[i] == obj)
return true;
return false;
}
void GarbageCollector::Start()
{
if (running)
return;
mutex.Initialize();
thread.Start(GarbageCollectionThread, nullptr);
running = true;
}
void GarbageCollector::Stop()
{
if (!running)
return;
running = false;
thread.Join();
}
void GarbageCollector::Add(BaseObj* obj)
{
if (!obj)
return;
/*
if (Has(obj))
{
EHS_LOG_INT("Warning", 1, obj->GetTypeId() + " object with address of, \"" + Str_8::FromNum<USize>((USize)obj) + "\" is already in garbage.");
return;
}
*/
garbage.Push(obj);
}
void GarbageCollector::SetMax(const UInt_64 newMax)
{
max = newMax;
}
UInt_64 GarbageCollector::GetMax()
{
return max;
}
void GarbageCollector::SetStride(const UInt_64 newStride)
{
Dump();
garbage = Vector<BaseObj*>(0, newStride);
}
UInt_64 GarbageCollector::GetStride()
{
return garbage.Stride();
}
UInt_64 GarbageCollector::Size()
{
return garbage.Size();
}
void GarbageCollector::Poll()
{
if (running)
mutex.Lock();
UInt_64 i = 0;
while (i < garbage.Size())
{
garbage.Swap(i, garbage.End());
delete garbage.Pop();
}
if (running)
mutex.Unlock();
}
void GarbageCollector::Dump()
{
if (running)
mutex.Lock();
for (UInt_64 i = 0; i < garbage.Size(); ++i)
delete garbage[i];
garbage.Clear();
if (running)
mutex.Unlock();
}
bool GarbageCollector::IsRunning()
{
return running;
}
}

124
src/HRNG_ARM64.cpp Normal file
View File

@@ -0,0 +1,124 @@
#include "ehs/HRNG.h"
namespace ehs
{
UInt_64 HRNG::GenerateSeed_u64()
{
return 0;
}
UInt_64 HRNG::Generate_u64(const UInt_64 min, const UInt_64 max)
{
return 0;
}
UInt_64 HRNG::Generate_u64()
{
return 0;
}
SInt_64 HRNG::GenerateSeed_s64()
{
return 0;
}
SInt_64 HRNG::Generate_s64(const SInt_64 min, const SInt_64 max)
{
return 0;
}
SInt_64 HRNG::Generate_s64()
{
return 0;
}
UInt_32 HRNG::GenerateSeed_u32()
{
return 0;
}
UInt_32 HRNG::Generate_u32(const UInt_32 min, const UInt_32 max)
{
return 0;
}
UInt_32 HRNG::Generate_u32()
{
return 0;
}
SInt_32 HRNG::GenerateSeed_s32()
{
return 0;
}
SInt_32 HRNG::Generate_s32(const SInt_32 min, const SInt_32 max)
{
return 0;
}
SInt_32 HRNG::Generate_s32()
{
return 0;
}
UInt_32 HRNG::GenerateSeed_u16()
{
return 0;
}
UInt_16 HRNG::Generate_u16(const UInt_16 min, const UInt_16 max)
{
return 0;
}
UInt_16 HRNG::Generate_u16()
{
return 0;
}
SInt_16 HRNG::GenerateSeed_s16()
{
return 0;
}
SInt_16 HRNG::Generate_s16(const SInt_16 min, const SInt_16 max)
{
return 0;
}
SInt_16 HRNG::Generate_s16()
{
return 0;
}
UInt_8 HRNG::GenerateSeed_u8()
{
return 0;
}
UInt_8 HRNG::Generate_u8(const UInt_8 min, const UInt_8 max)
{
return 0;
}
UInt_8 HRNG::Generate_u8()
{
return 0;
}
SInt_8 HRNG::GenerateSeed_s8()
{
return 0;
}
SInt_8 HRNG::Generate_s8(const SInt_8 min, const SInt_8 max)
{
return 0;
}
SInt_8 HRNG::Generate_s8()
{
return 0;
}
}

169
src/HRNG_GCC.asm Normal file
View File

@@ -0,0 +1,169 @@
global _ZN3ehs4HRNG16GenerateSeed_u64Ev
global _ZN3ehs4HRNG12Generate_u64Emm
global _ZN3ehs4HRNG12Generate_u64Ev
global _ZN3ehs4HRNG16GenerateSeed_s64Ev
global _ZN3ehs4HRNG12Generate_s64Ell
global _ZN3ehs4HRNG12Generate_s64Ev
global _ZN3ehs4HRNG16GenerateSeed_u32Ev
global _ZN3ehs4HRNG12Generate_u32Ejj
global _ZN3ehs4HRNG12Generate_u32Ev
global _ZN3ehs4HRNG16GenerateSeed_s32Ev
global _ZN3ehs4HRNG12Generate_s32Eii
global _ZN3ehs4HRNG12Generate_s32Ev
global _ZN3ehs4HRNG16GenerateSeed_u16Ev
global _ZN3ehs4HRNG12Generate_u16Ett
global _ZN3ehs4HRNG12Generate_u16Ev
global _ZN3ehs4HRNG16GenerateSeed_s16Ev
global _ZN3ehs4HRNG12Generate_s16Ess
global _ZN3ehs4HRNG12Generate_s16Ev
global _ZN3ehs4HRNG15GenerateSeed_u8Ev
global _ZN3ehs4HRNG11Generate_u8Ehh
global _ZN3ehs4HRNG11Generate_u8Ev
global _ZN3ehs4HRNG15GenerateSeed_s8Ev
global _ZN3ehs4HRNG11Generate_s8Eaa
global _ZN3ehs4HRNG11Generate_s8Ev
section .text
_ZN3ehs4HRNG16GenerateSeed_u64Ev:
RDSEED RAX
RET
_ZN3ehs4HRNG12Generate_u64Emm:
RDRAND RAX
SUB RSI, RDI
MOV R8, RSI
XOR RDX, RDX
DIV R8
MOV RAX, RDX
ADD RAX, RDI
RET
_ZN3ehs4HRNG12Generate_u64Ev:
RDRAND RAX
RET
_ZN3ehs4HRNG16GenerateSeed_s64Ev:
RDSEED RAX
RET
_ZN3ehs4HRNG12Generate_s64Ell:
RDRAND RAX
SUB RSI, RDI
MOV R8, RSI
XOR RDX, RDX
DIV R8
MOV RAX, RDX
ADD RAX, RDI
RET
_ZN3ehs4HRNG12Generate_s64Ev:
RDRAND RAX
RET
_ZN3ehs4HRNG16GenerateSeed_u32Ev:
RDSEED EAX
RET
_ZN3ehs4HRNG12Generate_u32Ejj:
RDRAND EAX
SUB ESI, EDI
MOV R8D, ESI
XOR EDX, EDX
DIV R8D
MOV EAX, EDX
ADD EAX, EDI
RET
_ZN3ehs4HRNG12Generate_u32Ev:
RDRAND EAX
RET
_ZN3ehs4HRNG16GenerateSeed_s32Ev:
RDSEED EAX
RET
_ZN3ehs4HRNG12Generate_s32Eii:
RDRAND EAX
SUB ESI, EDI
MOV R8D, ESI
XOR EDX, EDX
DIV R8D
MOV EAX, EDX
ADD EAX, EDI
RET
_ZN3ehs4HRNG12Generate_s32Ev:
RDRAND EAX
RET
_ZN3ehs4HRNG16GenerateSeed_u16Ev:
RDSEED AX
RET
_ZN3ehs4HRNG12Generate_u16Ett:
RDRAND AX
SUB SI, DI
MOV R8W, SI
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, DI
RET
_ZN3ehs4HRNG12Generate_u16Ev:
RDRAND AX
RET
_ZN3ehs4HRNG16GenerateSeed_s16Ev:
RDSEED AX
RET
_ZN3ehs4HRNG12Generate_s16Ess:
RDRAND AX
SUB SI, DI
MOV R8W, SI
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, DI
RET
_ZN3ehs4HRNG12Generate_s16Ev:
RDRAND AX
RET
_ZN3ehs4HRNG15GenerateSeed_u8Ev:
RDSEED AX
RET
_ZN3ehs4HRNG11Generate_u8Ehh:
RDRAND AX
XOR AH, AH
SUB SIL, DIL
MOV R8B, SIL
DIV R8B
MOV AL, AH
ADD AL, DIL
RET
_ZN3ehs4HRNG11Generate_u8Ev:
RDRAND AX
RET
_ZN3ehs4HRNG15GenerateSeed_s8Ev:
RDSEED AX
RET
_ZN3ehs4HRNG11Generate_s8Eaa:
RDRAND AX
XOR AH, AH
SUB SIL, DIL
MOV R8B, SIL
DIV R8B
MOV AL, AH
ADD AL, DIL
RET
_ZN3ehs4HRNG11Generate_s8Ev:
RDRAND AX
RET

169
src/HRNG_MSVC.asm Normal file
View File

@@ -0,0 +1,169 @@
global ?GenerateSeed_u64@HRNG@ehs@@SA_KXZ
global ?Generate_u64@HRNG@ehs@@SA_K_K0@Z
global ?Generate_u64@HRNG@ehs@@SA_KXZ
global ?GenerateSeed_s64@HRNG@ehs@@SA_JXZ
global ?Generate_s64@HRNG@ehs@@SA_J_J0@Z
global ?Generate_s64@HRNG@ehs@@SA_JXZ
global ?GenerateSeed_u32@HRNG@ehs@@SAIXZ
global ?Generate_u32@HRNG@ehs@@SAIII@Z
global ?Generate_u32@HRNG@ehs@@SAIXZ
global ?GenerateSeed_s32@HRNG@ehs@@SAHXZ
global ?Generate_s32@HRNG@ehs@@SAHHH@Z
global ?Generate_s32@HRNG@ehs@@SAHXZ
global ?GenerateSeed_u16@HRNG@ehs@@SAIXZ
global ?Generate_u16@HRNG@ehs@@SAGGG@Z
global ?Generate_u16@HRNG@ehs@@SAGXZ
global ?GenerateSeed_s16@HRNG@ehs@@SAFXZ
global ?Generate_s16@HRNG@ehs@@SAFFF@Z
global ?Generate_s16@HRNG@ehs@@SAFXZ
global ?GenerateSeed_u8@HRNG@ehs@@SAEXZ
global ?Generate_u8@HRNG@ehs@@SAEEE@Z
global ?Generate_u8@HRNG@ehs@@SAEXZ
global ?GenerateSeed_s8@HRNG@ehs@@SACXZ
global ?Generate_s8@HRNG@ehs@@SACCC@Z
global ?Generate_s8@HRNG@ehs@@SACXZ
section .text
?GenerateSeed_u64@HRNG@ehs@@SA_KXZ:
RDSEED RAX
RET
?Generate_u64@HRNG@ehs@@SA_K_K0@Z:
RDRAND RAX
MOV R8, RDX
SUB R8, RCX
XOR RDX, RDX
DIV R8
MOV RAX, RDX
ADD RAX, RCX
RET
?Generate_u64@HRNG@ehs@@SA_KXZ:
RDRAND RAX
RET
?GenerateSeed_s64@HRNG@ehs@@SA_JXZ:
RDSEED RAX
RET
?Generate_s64@HRNG@ehs@@SA_J_J0@Z:
RDRAND RAX
MOV R8, RDX
SUB R8, RCX
XOR RDX, RDX
DIV R8
MOV RAX, RDX
ADD RAX, RCX
RET
?Generate_s64@HRNG@ehs@@SA_JXZ:
RDRAND RAX
RET
?GenerateSeed_u32@HRNG@ehs@@SAIXZ:
RDSEED EAX
RET
?Generate_u32@HRNG@ehs@@SAIII@Z:
RDRAND EAX
MOV R8D, EDX
SUB R8D, ECX
XOR EDX, EDX
DIV R8D
MOV EAX, EDX
ADD EAX, ECX
RET
?Generate_u32@HRNG@ehs@@SAIXZ:
RDRAND EAX
RET
?GenerateSeed_s32@HRNG@ehs@@SAHXZ:
RDSEED EAX
RET
?Generate_s32@HRNG@ehs@@SAHHH@Z:
RDRAND EAX
MOV R8D, EDX
SUB R8D, ECX
XOR EDX, EDX
DIV R8D
MOV EAX, EDX
ADD EAX, ECX
RET
?Generate_s32@HRNG@ehs@@SAHXZ:
RDRAND EAX
RET
?GenerateSeed_u16@HRNG@ehs@@SAIXZ:
RDSEED AX
RET
?Generate_u16@HRNG@ehs@@SAGGG@Z:
RDRAND AX
MOV R8W, DX
SUB R8W, CX
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, CX
RET
?Generate_u16@HRNG@ehs@@SAGXZ:
RDRAND AX
RET
?GenerateSeed_s16@HRNG@ehs@@SAFXZ:
RDSEED AX
RET
?Generate_s16@HRNG@ehs@@SAFFF@Z:
RDRAND AX
MOV R8W, DX
SUB R8W, CX
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, CX
RET
?Generate_s16@HRNG@ehs@@SAFXZ:
RDRAND AX
RET
?GenerateSeed_u8@HRNG@ehs@@SAEXZ:
RDSEED AX
RET
?Generate_u8@HRNG@ehs@@SAEEE@Z:
RDRAND AX
MOV R8W, DX
SUB R8W, CX
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, CX
RET
?Generate_u8@HRNG@ehs@@SAEXZ:
RDRAND AX
RET
?GenerateSeed_s8@HRNG@ehs@@SACXZ:
RDSEED AX
RET
?Generate_s8@HRNG@ehs@@SACCC@Z:
RDRAND AX
MOV R8W, DX
SUB R8W, CX
XOR DX, DX
DIV R8W
MOV AX, DX
ADD AX, CX
RET
?Generate_s8@HRNG@ehs@@SACXZ:
RDRAND AX
RET

149
src/Log.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include "ehs/Log.h"
namespace ehs
{
void (*Log::logCb)(const Log&) = nullptr;
Log Log::lastLog;
void Log::SetCallback(void (*newLogCb)(const Log&))
{
logCb = newLogCb;
}
void Log::Raise(const Log& log)
{
if (logCb)
logCb(log);
lastLog = log;
}
Log Log::GetLastLog()
{
Log result = lastLog;
lastLog = Log();
return result;
}
Log::Log()
: code(0)
{
}
Log::Log(std::initializer_list<Str_8> tags, const UInt_64 code, const Str_8& msg)
: tags(tags.size()), code(code), msg(msg)
{
UInt_64 i = 0;
for (auto v = tags.begin(); v != tags.end(); ++v)
this->tags[i++] = *v;
}
Log::Log(Array<Str_8>& tags, const UInt_64 code, const Str_8& msg)
: tags(tags), code(code), msg(msg)
{
}
Log::Log(const Log& log)
: tags(log.tags), code(log.code), msg(log.msg)
{
}
Log& Log::operator=(const Log& log)
{
if (this == &log)
return *this;
tags = log.tags;
code = log.code;
msg = log.msg;
return *this;
}
/*
bool Log::operator==(const Log log)
{
return src == log.src && type == log.type && code == log.code && msg == log.msg;
}
bool Log::operator!=(const Log log)
{
return src != log.src || type != log.type || code != log.code || msg != log.msg;
}
*/
bool Log::HasTags(const std::initializer_list<Str_8> tags) const
{
UInt_64 i = 0;
UInt_64 c = 0;
for (auto v = tags.begin(); v != tags.end(); ++v)
if (this->tags[i++].GetLower() == v->GetLower())
++c;
if (c == tags.size())
return true;
return false;
}
bool Log::HasTags(const Array<Str_8> &tags) const
{
UInt_64 c = 0;
for (UInt_64 i = 0; i < tags.Size(); ++i)
if (this->tags[i].GetLower() == tags[c].GetLower())
++c;
if (c == tags.Size())
return true;
return false;
}
bool Log::HasTag(const Str_8& tag) const
{
for (UInt_64 i = 0; i < tags.Size(); ++i)
if (tags[i].GetLower() == tag.GetLower())
return true;
return false;
}
Array<Str_8> Log::GetTags() const
{
return tags;
}
UInt_64 Log::GetCode() const
{
return code;
}
Str_8 Log::GetMsg() const
{
return msg;
}
Str_8 Log::ToStr() const
{
Str_8 result = "[";
for (UInt_64 i = 0; i < tags.Size(); ++i)
{
result += tags[i];
if (i != tags.Size() - 1)
result += ", ";
}
result += "](" + Str_8::FromNum(code) + "): " + msg;
return result;
}
bool Log::IsValid() const
{
return tags.Size() && msg.Size();
}
}

91
src/Math.cpp Normal file
View File

@@ -0,0 +1,91 @@
#include "ehs/Math.h"
#include "ehs/system/Architecture.h"
namespace ehs
{
bool Math::AbsCmp(const float a, const float b)
{
return Abs(a - b) <= fltEpsilon;
}
bool Math::AbsCmp(const double a, const double b)
{
return Abs(a - b) <= fltEpsilon;
}
bool Math::RelCmp(const float a, const float b)
{
return Abs(a - b) <= fltEpsilon * Max(Abs(a), Abs(b));
}
bool Math::RelCmp(const double a, const double b)
{
return Abs(a - b) <= fltEpsilon * Max(Abs(a), Abs(b));
}
bool Math::ComCmp(const float a, const float b)
{
return Abs(a - b) <= fltEpsilon * Max(1.0f, Max(Abs(a), Abs(b)));
}
bool Math::ComCmp(const double a, const double b)
{
return Abs(a - b) <= dblEpsilon * Max(1.0, Max(Abs(a), Abs(b)));
}
double Math::Sqrt(const double from)
{
#if defined(EHS_ARCH_X64)
if (CPU::HasAVX())
return Sqrt_AVX(from);
else if (CPU::HasSSE())
return Sqrt_SSE2(from);
double temp = 0.0;
double result = from / 2.0;
while (result != temp)
{
temp = result;
result = (from / temp + temp) / 2.0;
}
return result;
#elif defined(EHS_ARCH_ARM64)
return Sqrt_VFP4(from);
#endif
}
float Math::Sqrt(const float from)
{
#if defined(EHS_ARCH_X64)
if (CPU::HasAVX())
return Sqrt_AVX(from);
else if (CPU::HasSSE())
return Sqrt_SSE(from);
float temp = 0.0f;
float result = from / 2.0f;
while (result != temp)
{
temp = result;
result = (from / temp + temp) / 2.0f;
}
return result;
#elif defined(EHS_ARCH_ARM64)
return Sqrt_VFP4(from);
#endif
}
float Math::Mod(const float from, const float divisor)
{
return from - Trunc(from / divisor) * divisor;
}
double Math::Mod(const double from, const double divisor)
{
return from - Trunc(from / divisor) * divisor;
}
}

61
src/Math_GCC_AMD64.asm Normal file
View File

@@ -0,0 +1,61 @@
global _ZN3ehs4Math8Sqrt_AVXEf
global _ZN3ehs4Math8Sqrt_AVXEd
global _ZN3ehs4Math8Sqrt_SSEEf
global _ZN3ehs4Math9Sqrt_SSE2Ed
global _ZN3ehs4Math4NearEf
global _ZN3ehs4Math4NearEd
global _ZN3ehs4Math5FloorEf
global _ZN3ehs4Math5FloorEd
global _ZN3ehs4Math4CeilEf
global _ZN3ehs4Math4CeilEd
global _ZN3ehs4Math5TruncEf
global _ZN3ehs4Math5TruncEd
section .text
_ZN3ehs4Math8Sqrt_AVXEf:
VSQRTPS XMM0, XMM0
RET
_ZN3ehs4Math8Sqrt_AVXEd:
VSQRTPD XMM0, XMM0
RET
_ZN3ehs4Math8Sqrt_SSEEf:
SQRTPS XMM0, XMM0
RET
_ZN3ehs4Math9Sqrt_SSE2Ed:
SQRTPD XMM0, XMM0
RET
_ZN3ehs4Math4NearEf:
ROUNDPS XMM0, XMM0, 0
RET
_ZN3ehs4Math4NearEd:
ROUNDPD XMM0, XMM0, 0
RET
_ZN3ehs4Math5FloorEf:
ROUNDPS XMM0, XMM0, 1
RET
_ZN3ehs4Math5FloorEd:
ROUNDPD XMM0, XMM0, 1
RET
_ZN3ehs4Math4CeilEf:
ROUNDPS XMM0, XMM0, 2
RET
_ZN3ehs4Math4CeilEd:
ROUNDPD XMM0, XMM0, 2
RET
_ZN3ehs4Math5TruncEf:
ROUNDPS XMM0, XMM0, 3
RET
_ZN3ehs4Math5TruncEd:
ROUNDPD XMM0, XMM0, 3
RET

51
src/Math_GCC_ARM64.s Normal file
View File

@@ -0,0 +1,51 @@
.global _ZN3ehs4Math9Sqrt_VFP4Ef
.global _ZN3ehs4Math9Sqrt_VFP4Ed
.global _ZN3ehs4Math4NearEf
.global _ZN3ehs4Math4NearEd
.global _ZN3ehs4Math5FloorEf
.global _ZN3ehs4Math5FloorEd
.global _ZN3ehs4Math4CeilEf
.global _ZN3ehs4Math4CeilEd
.global _ZN3ehs4Math5TruncEf
.global _ZN3ehs4Math5TruncEd
.section .text
_ZN3ehs4Math9Sqrt_VFP4Ef:
FSQRT S0, S0
RET
_ZN3ehs4Math9Sqrt_VFP4Ed:
FSQRT D0, D0
RET
_ZN3ehs4Math4NearEf:
FRINTN S0, S0
RET
_ZN3ehs4Math4NearEd:
FRINTN D0, D0
RET
_ZN3ehs4Math5FloorEf:
FRINTM S0, S0
RET
_ZN3ehs4Math5FloorEd:
FRINTM D0, D0
RET
_ZN3ehs4Math4CeilEf:
FRINTP S0, S0
RET
_ZN3ehs4Math4CeilEd:
FRINTP D0, D0
RET
_ZN3ehs4Math5TruncEf:
FRINTZ S0, S0
RET
_ZN3ehs4Math5TruncEd:
FRINTZ D0, D0
RET

61
src/Math_MSVC_AMD64.asm Normal file
View File

@@ -0,0 +1,61 @@
global ?Sqrt_AVX@Math@ehs@@CAMM@Z
global ?Sqrt_AVX@Math@ehs@@CANN@Z
global ?Sqrt_SSE@Math@ehs@@CAMM@Z
global ?Sqrt_SSE2@Math@ehs@@CANN@Z
global ?Near@Math@ehs@@SAMM@Z
global ?Near@Math@ehs@@SANN@Z
global ?Floor@Math@ehs@@SAMM@Z
global ?Floor@Math@ehs@@SANN@Z
global ?Ceil@Math@ehs@@SAMM@Z
global ?Ceil@Math@ehs@@SANN@Z
global ?Trunc@Math@ehs@@SAMM@Z
global ?Trunc@Math@ehs@@SANN@Z
section .text
?Sqrt_AVX@Math@ehs@@CAMM@Z:
VSQRTPS XMM0, XMM0
RET
?Sqrt_AVX@Math@ehs@@CANN@Z:
VSQRTPD XMM0, XMM0
RET
?Sqrt_SSE@Math@ehs@@CAMM@Z:
SQRTPS XMM0, XMM0
RET
?Sqrt_SSE2@Math@ehs@@CANN@Z:
SQRTPD XMM0, XMM0
RET
?Near@Math@ehs@@SAMM@Z:
ROUNDPS XMM0, XMM0, 0
RET
?Near@Math@ehs@@SANN@Z:
ROUNDPD XMM0, XMM0, 0
RET
?Floor@Math@ehs@@SAMM@Z:
ROUNDPS XMM0, XMM0, 1
RET
?Floor@Math@ehs@@SANN@Z:
ROUNDPD XMM0, XMM0, 1
RET
?Ceil@Math@ehs@@SAMM@Z:
ROUNDPS XMM0, XMM0, 2
RET
?Ceil@Math@ehs@@SANN@Z:
ROUNDPD XMM0, XMM0, 2
RET
?Trunc@Math@ehs@@SAMM@Z:
ROUNDPS XMM0, XMM0, 3
RET
?Trunc@Math@ehs@@SANN@Z:
ROUNDPD XMM0, XMM0, 3
RET

64
src/PtrData.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include "ehs/PtrData.h"
namespace ehs
{
Vector<PtrData> pointers;
bool HasPtrData(void* data)
{
if (!data)
return false;
for (UInt_64 i = 0; i < pointers.Size(); i++)
if (pointers[i].data == data)
return true;
return false;
}
void AddPtrData(void* data)
{
if (!data)
return;
for (UInt_64 i = 0; i < pointers.Size(); i++)
{
if (pointers[i].data != data)
continue;
pointers[i].references++;
return;
}
pointers.Push({1, data});
}
bool RemovePtrData(void* data)
{
if (!data)
return false;
for (UInt_64 i = 0; i < pointers.Size(); i++)
{
if (pointers[i].data != data)
continue;
if (pointers[i].references == 1)
{
pointers.Swap(i, pointers.End());
pointers.Pop();
return true;
}
else
{
pointers[i].references--;
return false;
}
}
return false;
}
}

5
src/Range.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by Nelso on 3/29/2022.
//
#include "ehs/Range.h"

32
src/StrToHash.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include <ehs/EHS.h>
#include <ehs/Str.h>
#include <ehs/io/Console.h>
ehs::Int_32 Main(ehs::Str_8* appName, ehs::Str_8* appVerId, ehs::Version* appVer)
{
*appName = "StrToHash";
*appVerId = "Release";
*appVer = {1, 0, 0};
ehs::Console::Attach();
ehs::Vector<ehs::Str_8> args = ehs::Console::GetArgs_8();
if (args.Size() > 1)
{
for (ehs::UInt_64 i = 1; i < args.Size(); ++i)
ehs::Console::Write_8("Result " + ehs::Str_8::FromNum(i) + ": " + ehs::Str_8::FromNum(args[i].Hash_64()));
}
else
{
ehs::Console::Write_8("String: ", false);
ehs::Str_8 in = ehs::Console::Read_8();
ehs::Console::Write_8("Result: " + ehs::Str_8::FromNum(in.Hash_64()));
ehs::Console::Read_8();
}
ehs::Console::Free();
return 0;
}

216
src/Task.cpp Normal file
View File

@@ -0,0 +1,216 @@
#include "ehs/Task.h"
namespace ehs
{
UInt_32 TaskThread(void* args)
{
if (!args)
return 1;
Serializer<UInt_64>* data = (Serializer<UInt_64>*)args;
Semaphore* available = data->Read<Semaphore*>();
Semaphore* done = data->Read<Semaphore*>();
Serializer<UInt_64>** cbArgs = data->Read<Serializer<UInt_64>**>();
TaskCb* callback = data->Read<TaskCb*>();
while (true)
{
if (!available->Wait(EHS_INFINITE))
{
done->Signal(1);
return 1;
}
if (!*callback)
{
done->Signal(1);
return 0;
}
(*callback)(*cbArgs);
done->Signal(1);
}
}
Task::~Task()
{
if (!IsValid())
return;
if (!working)
{
*callback = nullptr;
available->Signal(1);
}
else
{
done->Wait(1000);
*callback = nullptr;
available->Signal(1);
}
thread.Join();
delete available;
delete done;
delete *cbArgs;
delete cbArgs;
delete callback;
}
Task::Task()
: working(false), available(nullptr), done(nullptr), cbArgs(nullptr), callback(nullptr), threadArgs(nullptr)
{
Initialize();
}
Task::Task(Task&& task) noexcept
: working(task.working), available(task.available), done(task.done), cbArgs(task.cbArgs),
callback(task.callback), threadArgs(task.threadArgs), thread(std::move(task.thread))
{
task.working = false;
task.available = nullptr;
task.done = nullptr;
task.cbArgs = nullptr;
task.callback = nullptr;
task.threadArgs = nullptr;
}
Task::Task(const Task& task)
: working(false), available(nullptr), done(nullptr), cbArgs(nullptr), callback(nullptr), threadArgs(nullptr)
{
Initialize();
}
Task& Task::operator=(Task&& task) noexcept
{
if (this == &task)
return *this;
Release();
working = task.working;
available = task.available;
done = task.done;
cbArgs = task.cbArgs;
callback = task.callback;
threadArgs = task.threadArgs;
thread = std::move(task.thread);
task.working = false;
task.available = nullptr;
task.done = nullptr;
task.cbArgs = nullptr;
task.callback = nullptr;
task.threadArgs = nullptr;
task.thread = {};
return *this;
}
Task& Task::operator=(const Task& task)
{
if (this == &task)
return *this;
Release();
Initialize();
return *this;
}
void Task::Revalidate()
{
if (!IsValid())
return;
Release();
Initialize();
}
void Task::Initialize()
{
if (IsValid())
return;
working = false;
available = new Semaphore(0);
done = new Semaphore(0);
cbArgs = new Serializer<ehs::UInt_64>*(new Serializer<UInt_64>());
callback = new TaskCb(nullptr);
threadArgs = new Serializer<UInt_64>(Endianness::LE);
threadArgs->Write(available);
threadArgs->Write(done);
threadArgs->Write(cbArgs);
threadArgs->Write(callback);
threadArgs->SetOffset(0);
thread.Start(TaskThread, threadArgs);
}
void Task::Release()
{
if (!IsValid())
return;
if (!working)
{
*callback = nullptr;
available->Signal(1);
}
else
{
done->Wait(1000);
*callback = nullptr;
available->Signal(1);
}
working = false;
thread.Join();
delete available;
available = nullptr;
delete done;
done = nullptr;
delete *cbArgs;
delete cbArgs;
cbArgs = nullptr;
delete callback;
callback = nullptr;
}
bool Task::IsWorking() const
{
return working;
}
void Task::GiveWork(Serializer<UInt_64> args, TaskCb cb)
{
if (working)
{
EHS_LOG_INT("Warning", 0, "Attempted to give work while task is still working.");
return;
}
**cbArgs = std::move(args);
*callback = cb;
working = true;
available->Signal(1);
}
void Task::WaitUntilDone()
{
if (!working)
return;
done->Wait(EHS_INFINITE);
working = false;
}
bool Task::IsValid() const
{
return thread.IsValid() && available && available->IsValid() && done && done->IsValid() && cbArgs && callback;
}
}

136
src/Type.cpp Normal file
View File

@@ -0,0 +1,136 @@
#include "ehs/Type.h"
namespace ehs
{
Type::Type()
: size(0), id(nullptr), hashId(0)
{
}
Type::Type(const Char_8* const id)
: size(CalcSize(id)), id(id), hashId(GenHash(id, size))
{
}
Type::Type(Type&& type) noexcept
: size(type.size), id(type.id), hashId(type.hashId)
{
type.size = 0;
type.id = nullptr;
type.hashId = 0;
}
Type::Type(const Type& type)
: size(type.size), id(type.id), hashId(type.hashId)
{
}
Type& Type::operator=(Type&& type) noexcept
{
if (this == &type)
return *this;
size = type.size;
id = type.id;
hashId = type.hashId;
type.size = 0;
type.id = nullptr;
type.hashId = 0;
return *this;
}
Type& Type::operator=(const Type& type)
{
if (this == &type)
return *this;
size = type.size;
id = type.id;
hashId = type.hashId;
return *this;
}
bool Type::operator==(const Type& type) const
{
return hashId == type.hashId;
}
bool Type::operator!=(const Type& type) const
{
return hashId != type.hashId;
}
bool Type::operator==(const UInt_64 inHashId) const
{
return hashId == inHashId;
}
bool Type::operator!=(const UInt_64 inHashId) const
{
return hashId != inHashId;
}
bool Type::operator==(const Char_8* const inStr) const
{
if (size != CalcSize(inStr))
return false;
return Util::Compare(id, inStr, size);
}
bool Type::operator!=(const Char_8* const inStr) const
{
if (size != CalcSize(inStr))
return true;
return !Util::Compare(id, inStr, size);
}
UInt_64 Type::GetSize() const
{
return size;
}
const Char_8* Type::GetId() const
{
return id;
}
UInt_64 Type::GetHashId() const
{
return hashId;
}
bool Type::IsValid() const
{
return size;
}
UInt_64 Type::CalcSize(const Char_8* const id)
{
UInt_64 result = 0;
while (id[result])
result++;
return result;
}
UInt_64 Type::GenHash(const Char_8* const id, const UInt_64 size)
{
if (!size)
return 0;
const Byte* const bytes = (Byte*)id;
UInt_64 hash = 14695981039346656037ull;
for (UInt_64 i = 0; i < size; ++i)
hash = (hash ^ bytes[i]) * 1099511628211;
return hash;
}
}

57
src/URI.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "ehs/URI.h"
namespace ehs
{
bool IsAN(const Char_8 c)
{
return (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122);
}
Str_8 URI::Encode(const Str_8& in)
{
Str_8 result;
UInt_64 offset = 0;
for (UInt_64 i = 0; i < in.Size(); ++i)
{
if (IsAN(in[i]) || in[i] == '-' || in[i] == '_' || in[i] == '.' || in[i] == '~')
continue;
if (i != offset)
result.Push(&in[offset], i - offset);
result.Push("%" + Str_8::NumToHex(in[i]));
offset = i + 1;
}
if (offset < in.Size())
result.Push(&in[offset], in.Size() - offset);
return result;
}
Str_8 URI::Decode(const Str_8& in)
{
Str_8 result;
UInt_64 offset = 0;
for (UInt_64 i = 0; i < in.Size(); ++i)
{
if (in[i] != '%')
continue;
if (i != offset)
result.Push(&in[offset], i - offset);
result.Push(Str_8::HexToNum<Char_8>({&in[i + 1], 2}));
i += 2;
offset = i + 1;
}
if (offset < in.Size())
result.Push(&in[offset], in.Size() - offset);
return result;
}
}

121
src/Util.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include "ehs/Util.h"
namespace ehs
{
bool Util::Compare(const void* const a, const void* const b, const UInt_64 size)
{
Byte* aBytes = (Byte*)a;
Byte* bBytes = (Byte*)b;
UInt_64 remainder = size;
UInt_64 i = 0;
while (i < size)
{
if (remainder >= sizeof(UInt_64))
{
if (*(UInt_64*)&aBytes[i] != *(UInt_64*)&bBytes[i])
return false;
i += sizeof(UInt_64);
}
else if (remainder >= sizeof(UInt_32))
{
if (*(UInt_32*)&aBytes[i] != *(UInt_32*)&bBytes[i])
return false;
i += sizeof(UInt_32);
}
else if (remainder >= sizeof(UInt_16))
{
if (*(UInt_16*)&aBytes[i] != *(UInt_16*)&bBytes[i])
return false;
i += sizeof(UInt_16);
}
else
{
if (aBytes[i] != bBytes[i])
return false;
i += sizeof(Byte);
}
remainder = size - i;
}
return true;
}
void Util::Copy(void* const out, const void* const in, const UInt_64 size)
{
Byte* outB = (Byte*)out;
Byte* inB = (Byte*)in;
UInt_64 remainder = size;
UInt_64 i = 0;
while (i < size)
{
if (remainder >= sizeof(UInt_64))
{
*(UInt_64*)&outB[i] = *(UInt_64*)&inB[i];
i += sizeof(UInt_64);
}
else if (remainder >= sizeof(UInt_32))
{
*(UInt_32*)&outB[i] = *(UInt_32*)&inB[i];
i += sizeof(UInt_32);
}
else if (remainder >= sizeof(UInt_16))
{
*(UInt_16*)&outB[i] = *(UInt_16*)&inB[i];
i += sizeof(UInt_16);
}
else
{
outB[i++] = inB[i];
}
remainder = size - i;
}
}
void Util::Fill(void* const out, const UInt_64 outSize, const void* const in, const UInt_64 inSize)
{
if (outSize % inSize)
return;
for (UInt_64 i = 0; i < outSize; i += inSize)
Copy(&((Byte*)out)[i], in, inSize);
}
void Util::Zero(void* const in, const UInt_64 size)
{
Byte* inB = (Byte*)in;
UInt_64 remainder = size;
UInt_64 i = 0;
while (i < size)
{
if (remainder >= sizeof(UInt_64))
{
*(UInt_64*)&inB[i] = 0;
i += sizeof(UInt_64);
}
else if (remainder >= sizeof(UInt_32))
{
*(UInt_32*)&inB[i] = 0;
i += sizeof(UInt_32);
}
else if (remainder >= sizeof(UInt_16))
{
*(UInt_16*)&inB[i] = 0;
i += sizeof(UInt_16);
}
else
{
inB[i++] = 0;
}
remainder = size - i;
}
}
}

71
src/Version.cpp Normal file
View File

@@ -0,0 +1,71 @@
#include "ehs/Version.h"
namespace ehs
{
Version::Version()
: major(0), minor(0), patch(0)
{
}
Version::Version(const UInt_32 major, const UInt_32 minor, const UInt_32 patch)
: major(major), minor(minor), patch(patch)
{
}
Version::Version(const Version& version)
: major(version.major), minor(version.minor), patch(version.patch)
{
}
Version& Version::operator=(const Version& version)
{
if (this == &version)
return *this;
major = version.major;
minor = version.minor;
patch = version.patch;
return *this;
}
bool Version::operator==(const Version& version) const
{
return major == version.major && minor == version.minor && patch == version.patch;
}
bool Version::operator!=(const Version& version) const
{
return major != version.major || minor != version.minor || patch != version.patch;
}
unsigned int Version::operator[](const UInt_32 i) const
{
switch (i)
{
case 0:
return major;
case 1:
return minor;
case 2:
return patch;
default:
return major;
}
}
unsigned int& Version::operator[](const UInt_32 i)
{
switch (i)
{
case 0:
return major;
case 1:
return minor;
case 2:
return patch;
default:
return major;
}
}
}

5
src/database/DVar.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "ehs/database/DVar.h"
namespace ehs
{
}

607
src/io/BaseFile.cpp Normal file
View File

@@ -0,0 +1,607 @@
#include "ehs/io/BaseFile.h"
namespace ehs
{
BaseFile::BaseFile()
: mode(Mode::READ_WRITE), disposition(Disposition::OPEN_PERSISTENT)
{
}
BaseFile::BaseFile(const Str_8& filePath, const Mode mode, const Disposition disposition)
: path(filePath), fullName(ParseFullName_8(filePath)),
name(ParseName_8(fullName)), extension(ParseExt_8(fullName)),
mode(mode), disposition(disposition)
{
}
BaseFile::BaseFile(BaseFile&& file) noexcept
: path(std::move(file.path)), fullName(std::move(file.fullName)), name(std::move(file.name)),
extension(std::move(file.extension)), mode(file.mode), disposition(file.disposition)
{
file.mode = Mode::READ_WRITE;
file.disposition = Disposition::OPEN_PERSISTENT;
}
BaseFile& BaseFile::operator=(BaseFile&& file) noexcept
{
if (this == &file)
return *this;
path = std::move(file.path);
fullName = std::move(file.fullName);
name = std::move(file.name);
extension = std::move(file.extension);
mode = file.mode;
disposition = file.disposition;
file.mode = Mode::READ_WRITE;
file.disposition = Disposition::OPEN_PERSISTENT;
return *this;
}
void BaseFile::WriteStr_32(const Char_32* const str, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&((Byte*)str)[total], size - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(size) + ").");
break;
}
total += written;
}
while (total < size);
}
void BaseFile::WriteStr_32(const Str_32& str)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&str.ToBytes()[total], str.Size(true) - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(str.Size()) + ").");
break;
}
total += written;
}
while (total < str.Size(true));
}
void BaseFile::WriteStr_16(const Char_16* const str, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&((Byte*)str)[total], size - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(size) + ").");
break;
}
total += written;
}
while (total < size);
}
void BaseFile::WriteStr_16(const Str_16& str)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&str.ToBytes()[total], str.Size(true) - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(str.Size()) + ").");
break;
}
total += written;
}
while (total < str.Size(true));
}
void BaseFile::WriteStr_8(const Char_8* const str, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&((Byte*)str)[total], size - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(size) + ").");
break;
}
total += written;
}
while (total < size);
}
void BaseFile::WriteStr_8(const Str_8& str)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&str.ToBytes()[total], str.Size(true) - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(str.Size()) + ").");
break;
}
total += written;
}
while (total < str.Size(true));
}
void BaseFile::WriteVector(const Vector<Byte, UInt_64>& vec)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&vec[total], vec.Size() - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(vec.Size()) + ").");
break;
}
total += written;
}
while (total < vec.Size());
}
void BaseFile::WriteArray(const Array<Byte, UInt_64>& arr)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&arr[total], arr.Size() - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(arr.Size()) + ").");
break;
}
total += written;
}
while (total < arr.Size());
}
void BaseFile::WriteSerializer_64(const Serializer<UInt_64>& ser)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&ser[total], ser.Size() - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(ser.Size()) + ").");
break;
}
total += written;
}
while (total < ser.Size());
}
void BaseFile::WriteSerializer_32(const Serializer<UInt_32>& ser)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 written = Write(&ser[total], ser.Size() - total);
if (!written)
{
EHS_LOG_INT("Error", 0, "Failed to write all data (" + Str_8::FromNum(total) + "/" +
Str_8::FromNum(ser.Size()) + ").");
break;
}
total += written;
}
while (total < ser.Size());
}
void BaseFile::ReadStr_32(Char_32* const buffer, UInt_64& size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 read = Read(&((Byte*)buffer)[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
size = total;
}
Str_32 BaseFile::ReadStr_32(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Str_32 result(size / 4);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result.ToBytes()[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
void BaseFile::ReadStr_16(Char_16* const buffer, UInt_64& size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 read = Read(&((Byte*)buffer)[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
size = total;
}
Str_16 BaseFile::ReadStr_16(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Str_16 result(size / 2);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result.ToBytes()[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
void BaseFile::ReadStr_8(Char_8* const buffer, UInt_64& size)
{
if (!IsValid() || IsMapped())
return;
UInt_64 total = 0;
do
{
UInt_64 read = Read((Byte*)&buffer[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
size = total;
}
Str_8 BaseFile::ReadStr_8(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Str_8 result(size);
UInt_64 total = 0;
do
{
UInt_64 read = Read((Byte*)&result[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
Vector<Byte, UInt_64> BaseFile::ReadVector(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Vector<Byte, UInt_64> result(size, 0);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
Array<Byte, UInt_64> BaseFile::ReadArray(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Array<Byte, UInt_64> result(size);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
Serializer<UInt_64> BaseFile::ReadSerializer_64(const Endianness end, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return {};
Serializer<UInt_64> result(end, size);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
Serializer<UInt_32> BaseFile::ReadSerializer_32(const Endianness end, const UInt_32 size)
{
if (!IsValid() || IsMapped())
return {};
Serializer<UInt_32> result(end, size);
UInt_64 total = 0;
do
{
UInt_64 read = Read(&result[total], size - total);
if (!read)
break;
total += read;
}
while (total < size);
result.Resize(total);
return result;
}
Str_8 BaseFile::GetPath() const
{
return path;
}
Str_8 BaseFile::GetFullName() const
{
return fullName;
}
Str_8 BaseFile::GetName() const
{
return name;
}
Str_8 BaseFile::GetExtension() const
{
return extension;
}
void BaseFile::Rename_32(const Str_32& filePath, const Str_32& newName)
{
}
void BaseFile::Rename_16(const Str_16& filePath, const Str_16& newName)
{
}
void BaseFile::Rename_8(const Str_8& filePath, const Str_8& newName)
{
}
Str_32 BaseFile::ParseFullName_32(const Str_32& filePath)
{
UInt_64 index = 0;
if (!filePath.Find(U"/", &index, SearchPattern::RIGHT_LEFT) && !filePath.Find(U"\\", &index, SearchPattern::RIGHT_LEFT))
return filePath;
return filePath.Sub(index);
}
Str_16 BaseFile::ParseFullName_16(const Str_16& filePath)
{
UInt_64 index = 0;
if (!filePath.Find(L"/", &index, SearchPattern::RIGHT_LEFT) && !filePath.Find(L"\\", &index, SearchPattern::RIGHT_LEFT))
return filePath;
return filePath.Sub(index);
}
Str_8 BaseFile::ParseFullName_8(const Str_8& filePath)
{
UInt_64 index = 0;
if (!filePath.Find("/", &index, SearchPattern::RIGHT_LEFT) && !filePath.Find("\\", &index, SearchPattern::RIGHT_LEFT))
return filePath;
return filePath.Sub(index);
}
Str_32 BaseFile::ParseName_32(const Str_32& filePath)
{
UInt_64 index;
Str_32 file = filePath;
if (file.Find(U"/", &index, SearchPattern::RIGHT_LEFT) || file.Find(U"\\", &index, SearchPattern::RIGHT_LEFT))
file = file.Sub(index);
if (!file.Find(U".", &index, SearchPattern::RIGHT_LEFT))
return file;
return file.Sub(0, index - 1);
}
Str_16 BaseFile::ParseName_16(const Str_16& filePath)
{
UInt_64 index;
Str_16 file = filePath;
if (file.Find(L"/", &index, SearchPattern::RIGHT_LEFT) || file.Find(L"\\", &index, SearchPattern::RIGHT_LEFT))
file = file.Sub(index);
if (!file.Find(L".", &index, SearchPattern::RIGHT_LEFT))
return file;
return file.Sub(0, index - 1);
}
Str_8 BaseFile::ParseName_8(const Str_8& filePath)
{
UInt_64 index;
Str_8 file = filePath;
if (file.Find("/", &index, SearchPattern::RIGHT_LEFT) || file.Find("\\", &index, SearchPattern::RIGHT_LEFT))
file = file.Sub(index);
if (!file.Find(".", &index, SearchPattern::RIGHT_LEFT))
return file;
return file.Sub(0, index - 1);
}
Str_32 BaseFile::ParseExt_32(const Str_32& filePath)
{
UInt_64 index = 0;
filePath.Find(U".", &index, SearchPattern::RIGHT_LEFT);
return filePath.Sub(index);
}
Str_16 BaseFile::ParseExt_16(const Str_16& filePath)
{
UInt_64 index = 0;
filePath.Find(L".", &index, SearchPattern::RIGHT_LEFT);
return filePath.Sub(index);
}
Str_8 BaseFile::ParseExt_8(const Str_8& filePath)
{
UInt_64 index = 0;
filePath.Find(".", &index, SearchPattern::RIGHT_LEFT);
return filePath.Sub(index);
}
}

View File

@@ -0,0 +1,49 @@
#include "ehs/io/BaseFileMonitor.h"
namespace ehs
{
BaseFileMonitor::BaseFileMonitor(Str_8 filePath)
: filePath((Str_8&&)filePath)
{
}
BaseFileMonitor::BaseFileMonitor(BaseFileMonitor&& fm) noexcept
: filePath((Str_8&&)fm.filePath)
{
}
BaseFileMonitor::BaseFileMonitor(const BaseFileMonitor& fm)
: filePath(fm.filePath)
{
}
BaseFileMonitor& BaseFileMonitor::operator=(BaseFileMonitor&& fm) noexcept
{
if (this == &fm)
return *this;
filePath = (Str_8&&)fm.filePath;
return *this;
}
BaseFileMonitor& BaseFileMonitor::operator=(const BaseFileMonitor& fm)
{
if (this == &fm)
return *this;
filePath = fm.filePath;
return *this;
}
Str_8 BaseFileMonitor::GetFilePath() const
{
return filePath;
}
bool BaseFileMonitor::IsValid() const
{
return filePath.Size();
}
}

72
src/io/BaseWindow.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "ehs/io/BaseWindow.h"
namespace ehs
{
BaseWindow::BaseWindow()
: created(false), focused(false), cursorVisible(true), cursorConstrained(false),
state(WindowState::NONE)
{
}
BaseWindow::BaseWindow(const BaseWindow &win)
: created(false), focused(false), cursorVisible(true), cursorConstrained(false),
state(WindowState::NONE)
{
}
BaseWindow &BaseWindow::operator=(const BaseWindow &win)
{
if (this == &win)
return *this;
created = false;
focused = false;
cursorPos = {};
cursorVisible = true;
cursorConstrained = false;
state = WindowState::NONE;
ih = {};
return *this;
}
bool BaseWindow::IsCreated() const
{
return created;
}
bool BaseWindow::Poll()
{
return true;
}
bool BaseWindow::HasFocus() const
{
return focused;
}
Vec2_s32 BaseWindow::GetCursorPos() const
{
return cursorPos;
}
bool BaseWindow::IsCursorVisible() const
{
return cursorVisible;
}
bool BaseWindow::IsCursorConstrained() const
{
return cursorConstrained;
}
WindowState BaseWindow::GetState() const
{
return state;
}
const InputHandler* BaseWindow::GetInputHandler() const
{
return &ih;
}
}

134
src/io/COM.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include "io/COM.h"
#include "ehs/Str.h"
#include "ehs/Log.h"
namespace ehs
{
COM::COM()
: port(0), baudRate(9600), byteSize(8), parity(Parity::NONE), stopBits(StopBits::ONE), hdl(nullptr), initialized(false)
{
}
COM::COM(const UInt_8 port, const UInt_32 baudRate, const UInt_8 byteSize, const Parity parity, const StopBits stopBits)
: port(port), baudRate(baudRate), byteSize(byteSize), parity(parity), stopBits(stopBits), hdl(nullptr), initialized(false)
{
}
void COM::Initialize()
{
if (initialized)
return;
hdl = CreateFileW(L"\\\\.\\COM" + Str_16::FromNum(port), GENERIC_READ | GENERIC_WRITE,
0, nullptr, OPEN_EXISTING, 0,
nullptr);
if (hdl == INVALID_HANDLE_VALUE)
{
EHS_LOG_INT("Error", 0, "Failed to create handle at COM" + Str_8::FromNum(port) + " with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
DCB dcb = {};
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hdl, &dcb))
{
EHS_LOG_INT("Error", 1, "Failed to retrieve COM" + Str_8::FromNum(port) + " state with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
return;
}
dcb.BaudRate = (DWORD)baudRate;
dcb.ByteSize = (BYTE)byteSize;
dcb.fParity = (DWORD)parity;
dcb.StopBits = (BYTE)stopBits;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(hdl, &dcb))
{
EHS_LOG_INT("Error", 2, "Failed to set COM" + Str_8::FromNum(port) + " state with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
return;
}
SetCommMask(hdl, EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR | EV_RXFLAG | EV_TXEMPTY);
PurgeComm(hdl, PURGE_RXCLEAR | PURGE_TXCLEAR);
initialized = true;
}
void COM::UnInitialize()
{
if (hdl)
{
if (!CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to close COM" + Str_8::FromNum(port) + " handle with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = nullptr;
}
initialized = false;
}
UInt_32 COM::Wait()
{
UInt_32 event = 0;
if (!WaitCommEvent(hdl, (DWORD*)&event, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed to wait for COM" + Str_8::FromNum(port) + " event with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
}
return event;
}
void COM::Transmit(const Char_8 data)
{
if (!initialized)
return;
if (!TransmitCommChar(hdl, data))
{
EHS_LOG_INT("Error", 0, "Failed to transmit character to COM" + Str_8::FromNum(port) + " with error #" +
Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
}
}
UInt_32 COM::Send(const Char_8* data, const UInt_32 size)
{
UInt_32 sent = 0;
if (!WriteFile(hdl, (void*)data, (DWORD)size, (DWORD*)&sent, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed to receive data from COM" + Str_8::FromNum(port) + " with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
}
return sent;
}
UInt_32 COM::Receive(const Char_8* data, const UInt_32 size)
{
UInt_32 received = 0;
if (!ReadFile(hdl, (void*)data, (DWORD)size, (DWORD*)&received, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed to receive data from COM" + Str_8::FromNum(port) + " with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
}
return received;
}
void COM::Flush()
{
if (!FlushFileBuffers(hdl))
{
EHS_LOG_INT("Error", 0, "Failed to flush data for COM" + Str_8::FromNum(port) + " with error #" + Str_8::FromNum(GetLastError()) + ".");
UnInitialize();
}
}
}

799
src/io/Console.cpp Normal file
View File

@@ -0,0 +1,799 @@
#include "ehs/io/Console.h"
#include "ehs/Log.h"
#include "ehs/io/File.h"
#if defined(EHS_OS_LINUX)
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#endif
namespace ehs
{
ConsoleHdl Console::hdlOut = 0;
ConsoleHdl Console::hdlIn = 0;
#if defined(EHS_OS_WINDOWS)
bool Console::isConsole = true;
#endif
void Console::Attach()
{
#if defined(EHS_OS_WINDOWS)
if (!AttachConsole(ATTACH_PARENT_PROCESS))
{
DWORD code = GetLastError();
if (code == ERROR_INVALID_HANDLE)
return;
}
hdlIn = GetStdHandle(STD_INPUT_HANDLE);
hdlOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (!GetConsoleMode(hdlOut, &mode))
{
if (GetLastError() == ERROR_INVALID_HANDLE)
isConsole = false;
}
else
{
//DWORD code = WaitForSingleObject(hdlIn, 15000);
//if (code == WAIT_FAILED || code == WAIT_TIMEOUT || code == WAIT_ABANDONED)
// EHS_LOG_INT("Error", 0, "Failed to wait for console input.");
isConsole = true;
}
#elif defined(EHS_OS_LINUX)
hdlOut = open("/dev/stdout", O_WRONLY | O_SYNC);
hdlIn = open("/dev/stdin", O_RDONLY);
#else
return;
#endif
}
bool Console::Create()
{
#if defined(EHS_OS_WINDOWS)
if (!AllocConsole())
return false;
hdlIn = GetStdHandle(STD_INPUT_HANDLE);
hdlOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (WaitForSingleObject(hdlIn, EHS_INFINITE) == WAIT_FAILED)
EHS_LOG_INT("Error", 2, "Failed to wait for console input.");
//if (!SetConsoleActiveScreenBuffer(hdlOut))
// EHS_LOG_INT("Error", 3, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
isConsole = true;
#endif
return true;
}
void Console::Free()
{
#if defined(EHS_OS_WINDOWS)
if (!FreeConsole())
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(EHS_OS_LINUX)
int code = close(hdlOut);
if (code == -1)
EHS_LOG_INT("Error", 0, "Failed to free the console output with error #" + Str_8::FromNum(errno) + ".");
code = close(hdlIn);
if (code == -1)
EHS_LOG_INT("Error", 0, "Failed to free the console input with error #" + Str_8::FromNum(errno) + ".");
#endif
hdlOut = 0;
hdlIn = 0;
}
bool Console::CanRead()
{
return hdlIn;
}
bool Console::CanWrite()
{
return hdlOut;
}
void Console::Write_32(const Str_32& str, const bool newLine)
{
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 r = UTF::To_16(str);
if (newLine)
r += L"\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size());
}
else
{
Str_8 r = UTF::To_8(str);
if (newLine)
r += "\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size(true));
}
#elif defined(EHS_OS_LINUX)
Str_32 result = str;
if (newLine)
result += U"\n";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, result, result.Size(true));
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < result.Size(true));
#else
return;
#endif
}
void Console::Write_16(const Str_16& str, const bool newLine)
{
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 r = str;
if (newLine)
r += L"\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size());
}
else
{
Str_8 r = UTF::To_8(str);
if (newLine)
r += "\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteFile(hdlOut, &((Char_8*)r)[offset], (DWORD)r.Size(true) - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size(true));
}
#elif defined(EHS_OS_LINUX)
Str_16 result = str;
if (newLine)
result += L"\n";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, result, result.Size(true));
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < result.Size(true));
#endif
}
void Console::Write_8(const Str_8& str, const bool newLine)
{
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 r = UTF::To_16(str);
if (newLine)
r += L"\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteConsoleW(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size());
}
else
{
Str_8 r = str;
if (newLine)
r += "\r\n";
DWORD offset = 0;
do
{
DWORD written = 0;
if (!WriteFile(hdlOut, &r[offset], (DWORD)r.Size() - offset, &written, nullptr))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size());
}
#elif defined(EHS_OS_LINUX)
Str_8 result = str;
if (newLine)
result += "\n";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, result, result.Size());
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to write to console with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < result.Size());
#endif
}
Str_32 Console::Read_32(const UInt_64 bufferSize)
{
if (!hdlIn)
return U"";
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return U"";
}
offset += read;
}
while (result[offset - 1] != L'\n');
if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return UTF::To_32(result);
}
else
{
Str_8 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return U"";
}
offset += read;
}
while (result[offset - 1] != '\n');
if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return UTF::To_32(result);
}
#elif defined(EHS_OS_LINUX)
Str_32 result;
Str_32 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + ".");
return result;
}
result.Push(input, read);
}
while (input[read - 1] != U'\n');
return result;
#else
return {};
#endif
}
Str_16 Console::Read_16(const UInt_64 bufferSize)
{
if (!hdlIn)
return L"";
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return L"";
}
offset += read;
}
while (result[offset - 1] != L'\n');
if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return result;
}
else
{
Str_8 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return L"";
}
offset += read;
}
while (result[offset - 1] != '\n');
if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return UTF::To_16(result);
}
#elif defined(EHS_OS_LINUX)
Str_16 result;
Str_16 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + ".");
return result;
}
result.Push(input, read);
}
while (input[read - 1] != L'\n');
return result;
#else
return {};
#endif
}
Str_8 Console::Read_8(const UInt_64 bufferSize)
{
if (!hdlIn)
return "";
#if defined(EHS_OS_WINDOWS)
if (isConsole)
{
Str_16 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadConsoleW(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return "";
}
offset += read;
}
while (result[offset - 1] != L'\n');
if (offset >= 2 && result[offset - 2] == L'\r' && result[offset - 1] == L'\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return UTF::To_8(result);
}
else
{
Str_8 result;
DWORD offset = 0;
do
{
result.Resize(result.Size() + bufferSize);
DWORD read = 0;
if (!ReadFile(hdlIn, &result[offset], (DWORD)bufferSize, &read, nullptr))
{
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
return "";
}
offset += read;
}
while (result[offset - 1] != '\n');
if (offset >= 2 && result[offset - 2] == '\r' && result[offset - 1] == '\n')
result.Resize(offset - 2);
else
result.Resize(offset - 1);
return result;
}
#elif defined(EHS_OS_LINUX)
Str_8 result;
Str_8 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
EHS_LOG_INT("Error", 0, "Failed to read from console with error #" + Str_8::FromNum(errno) + ".");
return result;
}
result.Push(input, read);
}
while (input[read - 1] != '\n');
return result.Sub(0, result.Size() - 1);
#else
return {};
#endif
}
void Console::Clear()
{
#if defined(EHS_OS_WINDOWS)
CONSOLE_SCREEN_BUFFER_INFO info = {};
if (!GetConsoleScreenBufferInfo(hdlOut, &info))
return;
DWORD size = info.dwSize.X * info.dwSize.Y;
DWORD written = 0;
if (!FillConsoleOutputCharacterW(hdlOut, L' ', size, {0, 0}, &written))
return;
if (!GetConsoleScreenBufferInfo(hdlOut, &info))
return;
if (!FillConsoleOutputAttribute(hdlOut, info.wAttributes, size, {0, 0}, &written))
return;
SetConsoleCursorPosition(hdlOut, {0, 0});
#elif defined(EHS_OS_LINUX)
const Char_8 code[] = "\033[2J\033[1;1H";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, code, sizeof(code));
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to clear console with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < sizeof(code));
#endif
}
void Console::SetTitle_32(const Str_32& title)
{
#if defined(EHS_OS_WINDOWS)
if (!SetConsoleTitleW(UTF::To_16(title)))
EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(EHS_OS_LINUX)
Str_32 code = U"\033]0;" + title + U"\007";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, code, code.Size(true));
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < code.Size(true));
#endif
}
void Console::SetTitle_16(const Str_16& title)
{
#if defined(EHS_OS_WINDOWS)
if (!SetConsoleTitleW(title))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(EHS_OS_LINUX)
Str_16 code = L"\033]0;" + title + L"\007";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, code, code.Size(true));
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < code.Size(true));
#endif
}
void Console::SetTitle_8(const Str_8& title)
{
#if defined(EHS_OS_WINDOWS)
if (!SetConsoleTitleW(UTF::To_16(title)))
EHS_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(EHS_OS_LINUX)
Str_8 code = "\033]0;" + title + "\007";
UInt_64 offset = 0;
do {
ssize_t written = write(hdlOut, code, code.Size());
if (written == -1)
{
EHS_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(errno) + ".");
return;
}
offset += written;
}
while (offset < code.Size());
#endif
}
Str_32 Console::GetTitle_32()
{
#if defined(EHS_OS_WINDOWS)
Str_16 title(EHS_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH);
title.Resize(size);
return UTF::To_32(title);
#else
return {};
#endif
}
Str_16 Console::GetTitle_16()
{
#if defined(EHS_OS_WINDOWS)
Str_16 title(EHS_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH);
title.Resize(size);
return title;
#else
return {};
#endif
}
Str_8 Console::GetTitle_8()
{
#if defined(EHS_OS_WINDOWS)
Str_16 title(EHS_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], EHS_MAX_PATH);
title.Resize(size);
return UTF::To_8(title);
#else
return {};
#endif
}
Vector<Str_32> Console::GetArgs_32(const UInt_64 bufferSize)
{
#if defined(EHS_OS_WINDOWS)
return UTF::To_32(GetCommandLineW()).Split(U" ");
#elif defined(EHS_OS_LINUX)
File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN);
Array<Byte> data = cmdFile.ReadArray(bufferSize);
cmdFile.Release();
Vector<Str_32> args;
UInt_64 o = 0;
for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8))
{
if (data[i] != '\0')
continue;
args.Push(UTF::To_32((Char_8*)&data[o], i - o));
o = i + sizeof(Char_8);
}
if (o < data.Size())
args.Push(UTF::To_32((Char_8*)&data[o], data.Size() - o - 1));
return args;
#else
return {};
#endif
}
Vector<Str_16> Console::GetArgs_16(const UInt_64 bufferSize)
{
#if defined(EHS_OS_WINDOWS)
return Str_16(GetCommandLineW()).Split(L" ");
#elif defined(EHS_OS_LINUX)
File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN);
Array<Byte> data = cmdFile.ReadArray(bufferSize);
cmdFile.Release();
Vector<Str_16> args;
UInt_64 o = 0;
for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8))
{
if (data[i] != '\0')
continue;
args.Push(UTF::To_16((Char_8*)&data[o], i - o));
o = i + sizeof(Char_8);
}
if (o < data.Size())
args.Push(UTF::To_16((Char_8*)&data[o], data.Size() - o - 1));
return args;
#else
return {};
#endif
}
Vector<Str_8> Console::GetArgs_8(const UInt_64 bufferSize)
{
#if defined(EHS_OS_WINDOWS)
return UTF::To_8(GetCommandLineW()).Split(" ");
#elif defined(EHS_OS_LINUX)
File cmdFile("/proc/self/cmdline", Mode::READ, Disposition::OPEN);
Array<Byte> data = cmdFile.ReadArray(bufferSize);
cmdFile.Release();
Vector<Str_8> args;
UInt_64 o = 0;
for (UInt_64 i = 0; i < data.Size() - 1; i += sizeof(Char_8))
{
if (data[i] != '\0')
continue;
args.Push(Str_8((Char_8*)&data[o], i - o));
o = i + sizeof(Char_8);
}
if (o < data.Size())
args.Push(Str_8((Char_8*)&data[o], data.Size() - o - 1));
return args;
#else
return {};
#endif
}
/*
void* Console::GetHandle()
{
#if defined(EHS_OS_WINDOWS)
void* hdl = FindWindowW(nullptr, GetTitle_16());
if (hdl == nullptr)
EHS_LOG_INT("Error", 0, "Failed to retrieve native handle with error #" + Str_8::FromNum(GetLastError()) + ".");
return hdl;
#else
return nullptr;
#endif
}
*/
}

174
src/io/FileMonitor_UNX.cpp Normal file
View File

@@ -0,0 +1,174 @@
#include "ehs/io/FileMonitor_UNX.h"
#include "ehs/Log.h"
#include <sys/inotify.h>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>
#define BUF_LEN (1024 * (sizeof(inotify_event) + 16))
namespace ehs
{
FileMonitor::~FileMonitor()
{
inotify_rm_watch( hdl, wd);
close(hdl);
}
FileMonitor::FileMonitor()
: hdl(-1), wd(-1)
{
}
FileMonitor::FileMonitor(Str_8 filePath)
: BaseFileMonitor((Str_8&&)filePath), hdl(-1), wd(-1)
{
FileMonitor::Initialize();
}
FileMonitor::FileMonitor(FileMonitor&& fm) noexcept
: BaseFileMonitor((BaseFileMonitor&&)fm), hdl(fm.hdl), wd(fm.wd)
{
fm.hdl = -1;
fm.wd = -1;
}
FileMonitor::FileMonitor(const FileMonitor& fm)
: BaseFileMonitor(fm), hdl(-1), wd(-1)
{
FileMonitor::Initialize();
}
FileMonitor& FileMonitor::operator=(FileMonitor&& fm) noexcept
{
if (this == &fm)
return *this;
Release();
BaseFileMonitor::operator=((BaseFileMonitor&&)fm);
hdl = fm.hdl;
wd = fm.wd;
fm.hdl = -1;
fm.wd = -1;
return *this;
}
FileMonitor& FileMonitor::operator=(const FileMonitor& fm)
{
if (this == &fm)
return *this;
Release();
BaseFileMonitor::operator=(fm);
hdl = -1;
wd = -1;
Initialize();
return *this;
}
void FileMonitor::Initialize()
{
if (!IsValid() || IsInitialized())
return;
hdl = inotify_init();
if (hdl < 0)
{
EHS_LOG_INT("Error", 0, "Failed to initialize inotify.");
return;
}
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
EHS_LOG_INT("Error", 1, "Failed to retrieve flags with error #" + Str_8::FromNum(errno) + ".");
return;
}
flags |= O_NONBLOCK;
if (fcntl(hdl, F_SETFL, flags) == -1)
{
EHS_LOG_INT("Error", 2, "Failed to set flags with error #" + Str_8::FromNum(errno) + ".");
return;
}
wd = inotify_add_watch( hdl, filePath, IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF | IN_ACCESS);
if (wd < 0)
{
EHS_LOG_INT("Error", 3, "Failed to add watch.");
close(hdl);
hdl = -1;
return;
}
}
void FileMonitor::Release()
{
if (!IsValid() || !IsInitialized())
return;
inotify_rm_watch( hdl, wd);
wd = -1;
close(hdl);
hdl = -1;
}
UInt_8 FileMonitor::Poll()
{
UInt_8 mask = EHS_FE_NONE;
if (!IsValid() || !IsInitialized())
return mask;
Byte buffer[BUF_LEN];
SInt_64 length = read(hdl, buffer, BUF_LEN);
if (length < 0)
{
UInt_8 code = errno;
if (code != EWOULDBLOCK)
EHS_LOG_INT("Error", 0, "Failed to read with error #" + Str_8::FromNum(code) + ".");
return mask;
}
UInt_64 i = 0;
while (i < length)
{
inotify_event *event = (inotify_event*)&buffer[i];
if (event->mask & IN_MODIFY)
mask |= EHS_FE_MODIFIED;
if (event->mask & IN_DELETE_SELF)
mask |= EHS_FE_DELETED;
if (event->mask & IN_MOVE_SELF)
mask |= EHS_FE_MOVED;
if (event->mask & IN_ACCESS)
mask |= EHS_FE_OPENED;
i += sizeof(inotify_event) + event->len;
}
if (mask & EHS_FE_DELETED || mask & EHS_FE_MOVED)
Release();
return mask;
}
bool FileMonitor::IsInitialized() const
{
return hdl >= 0 && wd >= 0;
}
}

123
src/io/FileMonitor_W32.cpp Normal file
View File

@@ -0,0 +1,123 @@
#include "io/FileMonitor_W32.h"
#include "ehs/Log.h"
#include "ehs/UTF.h"
#include <chrono>
namespace ehs
{
FileMonitor::~FileMonitor()
{
if (!IsInitialized())
return;
if (!CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to close file at file path, \"" + filePath + "\", with error #" + GetLastError() + ".");
}
FileMonitor::FileMonitor()
: hdl(nullptr), time{}
{
}
FileMonitor::FileMonitor(Str_8 filePath)
: BaseFileMonitor((Str_8&&)filePath), hdl(INVALID_HANDLE_VALUE), time{}
{
FileMonitor::Initialize();
}
FileMonitor::FileMonitor(FileMonitor&& fm) noexcept
: BaseFileMonitor((BaseFileMonitor&&)fm), hdl(fm.hdl), time(fm.time)
{
fm.hdl = INVALID_HANDLE_VALUE;
fm.time = {};
}
FileMonitor::FileMonitor(const FileMonitor& fm)
: BaseFileMonitor(fm), hdl(INVALID_HANDLE_VALUE), time{}
{
FileMonitor::Initialize();
}
FileMonitor& FileMonitor::operator=(FileMonitor&& fm) noexcept
{
if (this == &fm)
return *this;
Release();
BaseFileMonitor::operator=((BaseFileMonitor&&)fm);
hdl = fm.hdl;
time = fm.time;
fm.hdl = INVALID_HANDLE_VALUE;
fm.time = {};
return *this;
}
FileMonitor& FileMonitor::operator=(const FileMonitor& fm)
{
if (this == &fm)
return *this;
Release();
BaseFileMonitor::operator=(fm);
hdl = INVALID_HANDLE_VALUE;
time = {};
Initialize();
return *this;
}
void FileMonitor::Initialize()
{
if (!IsValid() || IsInitialized())
return;
hdl = CreateFileW(UTF::To_16(filePath), GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hdl == INVALID_HANDLE_VALUE)
EHS_LOG_INT("Error", 0, "Failed to open file at file path, \"" + filePath + "\", with error #" + GetLastError() + ".");
}
void FileMonitor::Release()
{
if (!IsValid() || !IsInitialized())
return;
if (!CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to close file at file path, \"" + filePath + "\", with error #" + GetLastError() + ".");
hdl = nullptr;
}
UInt_8 FileMonitor::Poll()
{
UInt_8 mask = EHS_FE_NONE;
FILETIME lastWriteTime = {};
if (!GetFileTime(hdl, nullptr, nullptr, &lastWriteTime))
{
Release();
return mask;
}
if (time.dwLowDateTime == lastWriteTime.dwLowDateTime && time.dwHighDateTime == lastWriteTime.dwHighDateTime)
return mask;
time = lastWriteTime;
mask = EHS_FE_MODIFIED;
return mask;
}
bool FileMonitor::IsInitialized() const
{
return hdl != INVALID_HANDLE_VALUE;
}
}

307
src/io/File_UNX.cpp Normal file
View File

@@ -0,0 +1,307 @@
#include "ehs/io/File_UNX.h"
#include <cstring>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
namespace ehs
{
File::~File()
{
if (map != MAP_FAILED && munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
if (hdl >= 0 && close(hdl) == -1)
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + ".");
}
File::File()
: hdl(-1), map(MAP_FAILED), mapSize(0)
{
}
File::File(const Str_8 &filePath, const Mode mode, const Disposition disposition)
: BaseFile(filePath, mode, disposition), hdl(-1), map(MAP_FAILED), mapSize(0)
{
int linuxMode = 0;
switch (mode)
{
case Mode::READ:
linuxMode = O_RDONLY;
break;
case Mode::WRITE:
linuxMode = O_WRONLY;
break;
case Mode::READ_WRITE:
linuxMode = O_RDWR;
break;
}
int linuxDisp = 0;
switch (disposition)
{
case Disposition::CREATE_PERSISTENT:
linuxDisp = O_CREAT;
break;
case Disposition::CREATE:
linuxDisp = O_CREAT | O_EXCL;
break;
case Disposition::OPEN_PERSISTENT:
linuxDisp = O_CREAT;
break;
case Disposition::OPEN:
linuxDisp = 0;
break;
case Disposition::TRUNCATE:
linuxDisp = O_TRUNC;
break;
}
hdl = open64(path, linuxMode | linuxDisp, S_IRUSR | S_IWUSR);
if (hdl == -1)
{
SInt_32 code = errno;
if (code == EEXIST && (disposition == Disposition::CREATE_PERSISTENT || disposition == Disposition::OPEN_PERSISTENT))
{
hdl = open64(path, linuxMode, S_IRUSR | S_IWUSR);
if (hdl == -1)
EHS_LOG_INT("Error", 0, strerror(errno));
}
else
{
if (code == ENOENT)
EHS_LOG_INT("Error", 0, "File at filepath, \"" + filePath + "\" not found.");
else
EHS_LOG_INT("Error", 0, strerror(code));
}
}
}
File::File(File&& file) noexcept
: BaseFile(std::move(file)), hdl(file.hdl), map(file.map), mapSize(file.mapSize)
{
file.hdl = -1;
file.map = MAP_FAILED;
file.mapSize = 0;
}
File::File(const File &file)
: BaseFile(file), hdl(-1), map(MAP_FAILED), mapSize(0)
{
}
File& File::operator=(File&& file) noexcept
{
if (this == &file)
return *this;
BaseFile::operator=(std::move(file));
hdl = file.hdl;
map = file.map;
mapSize = file.mapSize;
file.hdl = -1;
return *this;
}
File& File::operator=(const File &file)
{
if (this == &file)
return *this;
BaseFile::operator=(file);
hdl = -1;
map = MAP_FAILED;
mapSize = 0;
return *this;
}
File::operator const Byte*() const
{
return (const Byte*)map;
}
File::operator Byte*()
{
return (Byte*)map;
}
void File::Release()
{
if (IsMapped() && munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
map = MAP_FAILED;
mapSize = 0;
if (IsValid() && close(hdl) == -1)
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(errno) + ".");
hdl = -1;
}
bool File::IsMapped() const
{
return map != MAP_FAILED;
}
UInt_64 File::MapSize() const
{
return mapSize;
}
void File::Map(const UInt_64 offset, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
int linuxMode = 0;
switch (mode)
{
case Mode::READ:
linuxMode = PROT_READ;
break;
case Mode::WRITE:
linuxMode = PROT_WRITE;
break;
case Mode::READ_WRITE:
linuxMode = PROT_READ | PROT_WRITE;
break;
}
map = mmap64(nullptr, size, linuxMode, MAP_SHARED, hdl, (off64_t)offset);
if (map == MAP_FAILED)
{
EHS_LOG_INT("Error", 0, "Failed to map with error #" + Str_8::FromNum(errno) + ".");
return;
}
mapSize = size;
}
void File::Unmap()
{
if (!IsValid() || !IsMapped())
return;
if (munmap(map, mapSize) == -1)
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
map = MAP_FAILED;
mapSize = 0;
}
void File::FlushMap()
{
if (!IsValid() || !IsMapped())
return;
if (msync((void*)map, mapSize, MS_SYNC) == -1)
EHS_LOG_INT("Error", 0, "Failed to flush view with error #" + Str_8::FromNum(errno) + ".");
}
UInt_64 File::Write(const Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 written = 0;
written = write(hdl, data, size);
if (written == -1)
EHS_LOG_INT("Error", 0, "Failed to write to file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + ".");
return (UInt_64)written;
}
UInt_64 File::Read(Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 read = 0;
read = ::read(hdl, data, (size_t)size);
if (read == -1)
EHS_LOG_INT("Error", 0, "Failed to read from file, \"" + path + "\", with error #" + Str_8::FromNum(errno) + ".");
return (UInt_64)read;
}
void File::Seek(UInt_64 index)
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, (off64_t)index, SEEK_SET) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::SeekBeginning()
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, 0, SEEK_SET) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::SeekEnd()
{
if (!IsValid() || IsMapped())
return;
if (lseek64(hdl, 0, SEEK_END) == -1)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(errno) + ".");
}
void File::Truncate(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
if (ftruncate64(hdl, (off64_t)size) == -1)
EHS_LOG_INT("Error", 0, "Failed to truncate with error #" + Str_8::FromNum(errno) + ".");
}
UInt_64 File::Size() const
{
struct stat64 info = {};
if (fstat64(hdl, &info) == -1)
EHS_LOG_INT("Error", 0, "Failed to retrieve file size with error #" + Str_8::FromNum(errno) + ".");
return info.st_size;
}
bool File::IsValid() const
{
return hdl >= 0;
}
void File::Rename_32(const Str_32& filePath, const Str_32& newName)
{
Rename_8(UTF::To_8(filePath), UTF::To_8(newName));
}
void File::Rename_16(const Str_16& filePath, const Str_16& newName)
{
Rename_8(UTF::To_8(filePath), UTF::To_8(newName));
}
void File::Rename_8(const Str_8& filePath, const Str_8& newName)
{
UInt_64 index = 0;
Str_8 path;
if (filePath.Find("/", &index, SearchPattern::RIGHT_LEFT) || filePath.Find("\\", &index, SearchPattern::RIGHT_LEFT))
path = filePath.Sub(0, index);
if (rename(filePath, path + newName) == -1)
EHS_LOG_INT("Error", 0, "Failed to rename file with error #" + Str_8::FromNum(errno) + ".");
}
}

339
src/io/File_W32.cpp Normal file
View File

@@ -0,0 +1,339 @@
#include "io/File_W32.h"
namespace ehs
{
File::~File()
{
if (view && !UnmapViewOfFile(view))
EHS_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
if (map != INVALID_HANDLE_VALUE && !CloseHandle(map))
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
if (hdl != INVALID_HANDLE_VALUE && !CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(GetLastError()) + ".");
}
File::File()
: hdl(INVALID_HANDLE_VALUE), map(INVALID_HANDLE_VALUE), view(nullptr), viewSize(0)
{
}
File::File(const Str_8 &filePath, const Mode mode, const Disposition disposition)
: BaseFile(filePath, mode, disposition), hdl(INVALID_HANDLE_VALUE), map(INVALID_HANDLE_VALUE), view(nullptr),
viewSize(0)
{
DWORD winMode = 0;
switch (mode)
{
case Mode::READ:
winMode = GENERIC_READ;
break;
case Mode::WRITE:
winMode = GENERIC_WRITE;
break;
case Mode::READ_WRITE:
winMode = GENERIC_READ | GENERIC_WRITE;
break;
}
DWORD winDisp = 0;
switch (disposition)
{
case Disposition::CREATE_PERSISTENT:
winDisp = CREATE_ALWAYS;
break;
case Disposition::CREATE:
winDisp = CREATE_NEW;
break;
case Disposition::OPEN_PERSISTENT:
winDisp = OPEN_ALWAYS;
break;
case Disposition::OPEN:
winDisp = OPEN_EXISTING;
break;
case Disposition::TRUNCATE:
winDisp = TRUNCATE_EXISTING;
break;
}
hdl = CreateFileW(UTF::To_16(path), winMode, 0, nullptr, winDisp, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hdl == INVALID_HANDLE_VALUE)
{
DWORD code = GetLastError();
if (code == ERROR_FILE_NOT_FOUND)
EHS_LOG_INT("Error", 1, "File not found at path, \"" + path + "\".");
else if (code != ERROR_SUCCESS)
EHS_LOG_INT("Error", 2, "Failed to create handle for file, \"" + path + "\", with error #" + Str_8::FromNum(code) + ".");
return;
}
}
File::File(File&& file) noexcept
: BaseFile(std::move(file)), hdl(file.hdl), map(file.map), view(file.view), viewSize(file.viewSize)
{
file.hdl = INVALID_HANDLE_VALUE;
file.map = INVALID_HANDLE_VALUE;
file.view = nullptr;
file.viewSize = 0;
}
File::File(const File& file)
: BaseFile(file), hdl(INVALID_HANDLE_VALUE), map(INVALID_HANDLE_VALUE), view(nullptr), viewSize(0)
{
}
File& File::operator=(File&& file) noexcept
{
if (this == &file)
return *this;
BaseFile::operator=(std::move(file));
hdl = file.hdl;
map = file.map;
view = file.view;
viewSize = file.viewSize;
file.hdl = INVALID_HANDLE_VALUE;
file.map = INVALID_HANDLE_VALUE;
file.view = nullptr;
file.viewSize = 0;
return *this;
}
File& File::operator=(const File& file)
{
if (this == &file)
return *this;
BaseFile::operator=(file);
hdl = INVALID_HANDLE_VALUE;
map = INVALID_HANDLE_VALUE;
view = nullptr;
viewSize = 0;
return *this;
}
File::operator const Byte*() const
{
return view;
}
File::operator Byte*()
{
return view;
}
void File::Release()
{
if (view && !UnmapViewOfFile(view))
EHS_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
view = nullptr;
viewSize = 0;
if (IsMapped() && !CloseHandle(map))
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
map = INVALID_HANDLE_VALUE;
if (IsValid() && !CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to close file handle with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = INVALID_HANDLE_VALUE;
}
bool File::IsMapped() const
{
return map != INVALID_HANDLE_VALUE && view;
}
UInt_64 File::MapSize() const
{
return viewSize;
}
void File::Map(const UInt_64 offset, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
DWORD winMode = 0;
switch (mode)
{
case Mode::READ:
winMode = PAGE_READONLY;
break;
case Mode::WRITE:
winMode = PAGE_READWRITE;
break;
case Mode::READ_WRITE:
winMode = PAGE_READWRITE;
break;
}
map = CreateFileMappingW(hdl, nullptr, winMode, 0, 0, nullptr);
if (!map)
{
EHS_LOG_INT("Error", 0, "Failed to create map handle with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
switch (mode)
{
case Mode::READ:
winMode = FILE_MAP_READ;
break;
case Mode::WRITE:
winMode = FILE_MAP_WRITE;
break;
case Mode::READ_WRITE:
winMode = FILE_MAP_ALL_ACCESS;
break;
}
view = (Byte*)MapViewOfFile(map, winMode, ((DWORD*)&offset)[1], (DWORD)offset, size);
if (!view)
{
EHS_LOG_INT("Error", 0, "Failed to map view with error #" + Str_8::FromNum(GetLastError()) + ".");
if (!CloseHandle(map))
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
map = INVALID_HANDLE_VALUE;
}
viewSize = size;
}
void File::Unmap()
{
if (!IsValid() || !IsMapped())
return;
if (!UnmapViewOfFile(view))
EHS_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
view = nullptr;
viewSize = 0;
if (!CloseHandle(map))
EHS_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
map = INVALID_HANDLE_VALUE;
}
void File::FlushMap()
{
if (!IsValid() || !IsMapped())
return;
if (!FlushViewOfFile(view, viewSize))
EHS_LOG_INT("Error", 0, "Failed to flush view with error #" + Str_8::FromNum(GetLastError()) + ".");
}
UInt_64 File::Write(const Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 written = 0;
if (!WriteFile(hdl, data, (DWORD)size, (DWORD*)&written, nullptr))
EHS_LOG_INT("Error", 0, "Failed to write to file, \"" + path + "\", with error #" + Str_8::FromNum(GetLastError()) + ".");
return (UInt_64)written;
}
UInt_64 File::Read(Byte *const data, const UInt_64 size)
{
if (!IsValid() || IsMapped())
return 0;
SInt_64 read = 0;
if (!ReadFile(hdl, data, (DWORD)size, (DWORD*)&read, nullptr))
EHS_LOG_INT("Error", 0, "Failed to read from file, \"" + path + "\", with error #" + Str_8::FromNum(GetLastError()) + ".");
return (UInt_64)read;
}
void File::Seek(UInt_64 index)
{
if (!IsValid() || IsMapped())
return;
if (SetFilePointer(hdl, (LONG)index, (PLONG)&((UInt_32*)&index)[1], FILE_BEGIN) == INVALID_SET_FILE_POINTER)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void File::SeekBeginning()
{
if (!IsValid() || IsMapped())
return;
if (SetFilePointer(hdl, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void File::SeekEnd()
{
if (!IsValid() || IsMapped())
return;
if (SetFilePointer(hdl, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER)
EHS_LOG_INT("Error", 0, "Failed to seek with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void File::Truncate(const UInt_64 size)
{
if (!IsValid() || IsMapped())
return;
Seek(size);
if (!::SetEndOfFile(hdl))
EHS_LOG_INT("Error", 0, "Failed to set end of file with error #" + Str_8::FromNum(GetLastError()) + ".");
SeekBeginning();
}
UInt_64 File::Size() const
{
if (!IsValid())
return 0;
LARGE_INTEGER size = {};
if (!GetFileSizeEx(hdl, &size))
EHS_LOG_INT("Error", 0, "Failed to retrieve file size with error #" + Str_8::FromNum(GetLastError()) + ".");
return (UInt_64)size.QuadPart;
}
bool File::IsValid() const
{
return hdl != INVALID_HANDLE_VALUE;
}
void File::Rename_32(const Str_32& filePath, const Str_32& newName)
{
Rename_16(UTF::To_16(filePath), UTF::To_16(newName));
}
void File::Rename_16(const Str_16& filePath, const Str_16& newName)
{
UInt_64 index = 0;
Str_16 path;
if (filePath.Find(L"/", &index, SearchPattern::RIGHT_LEFT) || filePath.Find(L"\\", &index, SearchPattern::RIGHT_LEFT))
path = filePath.Sub(0, index);
if (!MoveFileW(filePath, path + newName))
EHS_LOG_INT("Error", 0, "Failed to rename file with error #" + Str_8::FromNum(GetLastError()) + ".");
}
void File::Rename_8(const Str_8& filePath, const Str_8& newName)
{
Rename_16(UTF::To_16(filePath), UTF::To_16(newName));
}
}

304
src/io/FontAtlas.cpp Normal file
View File

@@ -0,0 +1,304 @@
#include "ehs/io/FontAtlas.h"
#include "ehs/io/File.h"
#include "ehs/Serializer.h"
namespace ehs
{
FontAtlas::~FontAtlas()
{
delete[] atlas;
}
FontAtlas::FontAtlas()
: hashId(0), glyphScale(0), size(0), atlas(nullptr)
{
}
FontAtlas::FontAtlas(const Str_8& filePath)
{
File fontFile(filePath, Mode::READ, Disposition::OPEN);
hashId = fontFile.GetName().Hash_64();
id = fontFile.GetName();
Serializer<UInt_64> fData = fontFile.ReadSerializer_64(Endianness::LE, fontFile.Size());
fontFile.Release();
Version ver = fData.ReadVersion();
if (ver != Version(1, 0, 0))
{
EHS_LOG_INT("Error", 2, "The Event Horizon Font file, \"" + filePath + "\", must be version 1.0.0, but was version " +
Str_8::FromNum(ver.major) + "." + Str_8::FromNum(ver.minor) + "." +
Str_8::FromNum(ver.patch) + ".");
return;
}
glyphScale = fData.Read<UInt_64>();
glyphs.Resize(fData.Read<UInt_64>());
for (UInt_64 i = 0; i < glyphs.Size(); ++i)
glyphs[i] = Glyph(fData);
resolution = fData.ReadVec2<UInt_64>();
size = resolution.x * resolution.y;
atlas = new Byte[size];
fData.ReadArray(atlas, &size);
}
FontAtlas::FontAtlas(FontAtlas&& fa) noexcept
: BaseObj(std::move(fa)), hashId(fa.hashId), id((Str_8&&)fa.id), glyphScale(fa.glyphScale),
glyphs((Array<Glyph>&&)fa.glyphs), resolution(fa.resolution), size(fa.size), atlas(fa.atlas)
{
fa.hashId = 0;
fa.glyphScale = 0;
fa.resolution = {};
fa.size = 0;
fa.atlas = nullptr;
}
FontAtlas::FontAtlas(const FontAtlas& fa)
: BaseObj(fa), hashId(fa.hashId), id(fa.id), glyphScale(fa.glyphScale), glyphs(fa.glyphs),
resolution(fa.resolution), size(fa.size), atlas(new Byte[fa.size])
{
Util::Copy(atlas, fa.atlas, fa.size);
}
FontAtlas& FontAtlas::operator=(FontAtlas&& fa) noexcept
{
if (this == &fa)
return *this;
BaseObj::operator=(std::move(fa));
hashId = fa.hashId;
id = (Str_8&&)fa.id;
glyphScale = fa.glyphScale;
glyphs = (Array<Glyph>&&)fa.glyphs;
resolution = fa.resolution;
size = fa.size;
delete[] atlas;
atlas = fa.atlas;
fa.hashId = 0;
fa.glyphScale = 0;
fa.resolution = {};
fa.size = 0;
fa.atlas = nullptr;
return *this;
}
FontAtlas& FontAtlas::operator=(const FontAtlas& fa)
{
if (this == &fa)
return *this;
BaseObj::operator=(fa);
hashId = fa.hashId;
id = fa.id;
glyphScale = fa.glyphScale;
glyphs = fa.glyphs;
resolution = {};
size = fa.size;
delete[] atlas;
atlas = new Byte[fa.size];
Util::Copy(atlas, fa.atlas, fa.size);
return *this;
}
FontAtlas::operator Byte *() const
{
return atlas;
}
void FontAtlas::Release()
{
hashId = 0;
id = {};
glyphScale = 0;
glyphs.Clear();
resolution = {0, 0};
size = 0;
delete[] atlas;
atlas = nullptr;
}
UInt_64 FontAtlas::GetHashId() const
{
return hashId;
}
Str_8 FontAtlas::GetId() const
{
return id;
}
UInt_64 FontAtlas::GetGlyphScale() const
{
return glyphScale;
}
const Array<Glyph>& FontAtlas::GetGlyphs() const
{
return glyphs;
}
Glyph FontAtlas::GetGlyph(const Char_32 code) const
{
for (UInt_32 i = 0; i < glyphs.Size(); ++i)
if (glyphs[i].GetCode() == code)
return glyphs[i];
return glyphs[0];
}
Vec2_u64 FontAtlas::GetResolution() const
{
return resolution;
}
UInt_64 FontAtlas::GetSize() const
{
return size;
}
bool FontAtlas::IsValid() const
{
return size;
}
Vec2_f FontAtlas::CalculateSize(const Str_8& text) const
{
Vec2_f result;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
result.x += (float)glyph.GetAdvance().x;
if ((float)glyph.GetScale().y > result.y)
result.y = (float)glyph.GetScale().y;
}
return result;
}
float FontAtlas::CalculateWidth(const Str_8 &text) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
result += (float)glyph.GetAdvance().x;
}
return result;
}
float FontAtlas::CalculateHeight(const Str_8& text) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
if ((float)glyph.GetScale().y > result)
result = (float)glyph.GetScale().y;
}
return result;
}
UInt_64 FontAtlas::CalculateIndexAtPoint(const Str_8& text, const Vec2_f& point) const
{
float result = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
float temp = result + (float)glyph.GetAdvance().x;
if (point.x > temp)
result += (float)glyph.GetAdvance().x;
else if (point.x <= temp)
return i;
}
return text.Size();
}
Mesh FontAtlas::Generate(const Anchor anchor, const Str_8& text) const
{
Vec2_f pos;
switch (anchor)
{
case Anchor::BOTTOM_CENTER:
{
pos.x -= CalculateWidth(text) * 0.5f;
break;
}
case Anchor::TOP_LEFT:
{
pos.x -= CalculateWidth(text);
break;
}
case Anchor::TOP_CENTER:
{
pos.x -= CalculateWidth(text) * 0.5f;
break;
}
case Anchor::CENTER_RIGHT:
{
pos.y -= CalculateHeight(text);
break;
}
case Anchor::CENTER:
{
Vec4_f size = CalculateSize(text);
pos.x -= size.x * 0.5f;
pos.y -= size.y;
break;
}
}
Array<Vertex_f> verts(text.Size() * 4);
Array<UInt_32> indices(text.Size() * 6);
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
Vec2_f scale = glyph.GetScale();
float x = pos.x + (float)glyph.GetBearing().x;
float y = pos.y + (float)(GetGlyphScale() - glyph.GetBearing().y);
UInt_32 vertsI = i * 4;
verts[vertsI] = Vertex_f({x, y, 1.0f}, {}, glyph.GetUV().GetPos());
verts[vertsI + 1] = Vertex_f({x, y + scale.y, 1.0f}, {}, Vec2_f(glyph.GetUV().x, glyph.GetUV().h));
verts[vertsI + 2] = Vertex_f({x + scale.x, y, 1.0f}, {}, Vec2_f(glyph.GetUV().w, glyph.GetUV().y));
verts[vertsI + 3] = Vertex_f({x + scale.x, y + scale.y, 1.0f}, {}, glyph.GetUV().GetScale());
UInt_32 indicesI = i * 6;
indices[indicesI] = vertsI;
indices[indicesI + 1] = vertsI + 1;
indices[indicesI + 2] = vertsI + 2;
indices[indicesI + 3] = vertsI + 3;
indices[indicesI + 4] = vertsI + 2;
indices[indicesI + 5] = vertsI + 1;
pos.x += (float)glyph.GetAdvance().x;
}
return {id, (Array<Vertex_f>&&)verts, (Array<UInt_32>&&)indices};
}
}

115
src/io/Glyph.cpp Normal file
View File

@@ -0,0 +1,115 @@
#include "ehs/io/Glyph.h"
namespace ehs
{
Glyph::Glyph()
: code(0)
{
}
Glyph::Glyph(Serializer<>& ser)
: code(ser.Read<Char_32>()), pos(ser.ReadVec2<UInt_64>()), scale(ser.ReadVec2<UInt_64>()),
uv(ser.ReadRect<float>()), bearing(ser.ReadVec2<Int_64>()), advance(ser.ReadVec2<UInt_64>())
{
}
Glyph::Glyph(const Char_32 code)
: code(code)
{
}
Glyph::Glyph(const Glyph& glyph)
: code(glyph.code), pos(glyph.pos), scale(glyph.scale), uv(glyph.uv), bearing(glyph.bearing), advance(glyph.advance)
{
}
Glyph& Glyph::operator=(const Glyph& glyph)
{
if (this == &glyph)
return *this;
code = glyph.code;
pos = glyph.pos;
scale = glyph.scale;
uv = glyph.uv;
bearing = glyph.bearing;
advance = glyph.advance;
return *this;
}
bool Glyph::operator==(const Glyph& glyph) const
{
return code == glyph.code;
}
bool Glyph::operator!=(const Glyph& glyph) const
{
return code != glyph.code;
}
Char_32 Glyph::GetCode() const
{
return code;
}
void Glyph::SetPos(const Vec2_u64& newPos)
{
pos = newPos;
}
Vec2_u64 Glyph::GetPos() const
{
return pos;
}
void Glyph::SetScale(const Vec2_u64& newScale)
{
scale = newScale;
}
Vec2_u64 Glyph::GetScale() const
{
return scale;
}
void Glyph::SetUV(const Rect_f& newUV)
{
uv = newUV;
}
Rect_f Glyph::GetUV() const
{
return uv;
}
void Glyph::SetBearing(const Vec2_64& newBearing)
{
bearing = newBearing;
}
Vec2_32 Glyph::GetBearing() const
{
return bearing;
}
void Glyph::SetAdvance(const Vec2_64& newAdvance)
{
advance = newAdvance;
}
Vec2_32 Glyph::GetAdvance() const
{
return advance;
}
void Glyph::Serialize(Serializer<>& ser) const
{
ser.Write(code);
ser.WriteVec2(pos);
ser.WriteVec2(scale);
ser.WriteRect(uv);
ser.WriteVec2(bearing);
ser.WriteVec2(advance);
}
}

95
src/io/RIFF.cpp Normal file
View File

@@ -0,0 +1,95 @@
#include "ehs/io/RIFF.h"
#include "ehs/io/File.h"
namespace ehs
{
RIFF::RIFF(const Str_8& filePath)
{
File file(filePath, Mode::READ, Disposition::OPEN);
Serializer<UInt_64> data = file.ReadSerializer_64(Endianness::LE, file.Size());
file.Release();
Str_8 riffId = data.ReadStr<Char_8, UInt_64>(4);
if (riffId != "RIFF")
{
EHS_LOG_INT("Error", 0, "File at file path, \"" + filePath + "\", is not a valid RIFF file.");
return;
}
data.SetOffset(data.GetOffset() + 4);
type = data.ReadStr<Char_8, UInt_64>(4);
while (data.GetOffset() < data.Size())
{
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
UInt_32 size = data.Read<UInt_32>();
chunks.Push(RIFF_Chunk(id, Serializer<UInt_64>(Endianness::LE, &data[data.GetOffset()], size)));
data.SetOffset(data.GetOffset() + size);
}
}
RIFF::RIFF(Serializer<>& data)
{
Str_8 riffId = data.ReadStr<Char_8, UInt_64>(4);
if (riffId != "RIFF")
{
EHS_LOG_INT("Error", 0, "Data is not in RIFF format.");
return;
}
data.SetOffset(data.GetOffset() + 4);
type = data.ReadStr<Char_8, UInt_64>(4);
while (data.GetOffset() < data.Size())
{
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
UInt_32 size = data.Read<UInt_32>();
chunks.Push(RIFF_Chunk(id, Serializer<UInt_64>(Endianness::LE, &data[data.GetOffset()], size)));
data.SetOffset(data.GetOffset() + size);
}
}
RIFF::operator const RIFF_Chunk*() const
{
return &chunks[0];
}
Str_8 RIFF::GetType() const
{
return type;
}
bool RIFF::HasChunk(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return true;
return false;
}
bool RIFF::HasChunk(const Str_8& id) const
{
return HasChunk(id.Hash_64());
}
RIFF_Chunk RIFF::GetChunk(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return chunks[i];
return {};
}
RIFF_Chunk RIFF::GetChunk(const Str_8& id) const
{
return GetChunk(id.Hash_64());
}
}

52
src/io/RIFF_Chunk.cpp Normal file
View File

@@ -0,0 +1,52 @@
#include "ehs/io/RIFF_Chunk.h"
namespace ehs
{
RIFF_Chunk::RIFF_Chunk()
: hashId(0)
{
}
RIFF_Chunk::RIFF_Chunk(const Str_8& id, const Serializer<>& data)
: id(id), hashId(id.Hash_64()), data(data)
{
}
Str_8 RIFF_Chunk::GetId() const
{
return id;
}
UInt_64 RIFF_Chunk::GetHashId() const
{
return hashId;
}
Serializer<> RIFF_Chunk::GetData() const
{
return data;
}
bool RIFF_Chunk::IsValid() const
{
return hashId;
}
RIFF_Chunk::RIFF_Chunk(const RIFF_Chunk& chunk)
: id(chunk.id), hashId(chunk.hashId), data(chunk.data)
{
}
RIFF_Chunk& RIFF_Chunk::operator=(const RIFF_Chunk& chunk)
{
if (this == &chunk)
return *this;
id = chunk.id;
hashId = chunk.hashId;
data = chunk.data;
return *this;
}
}

95
src/io/Resource.cpp Normal file
View File

@@ -0,0 +1,95 @@
#include "ehs/io/Resource.h"
namespace ehs
{
Resource::Resource()
: hashId(0)
{
AddType("Resource");
}
Resource::Resource(ehs::Str_8 id)
: hashId(id.Hash_64()), id(std::move(id))
{
AddType("Resource");
}
Resource::Resource(Resource&& rsrc) noexcept
: BaseObj((BaseObj&&)rsrc), hashId(rsrc.hashId), id(std::move(rsrc.id))
{
rsrc.hashId = 0;
}
Resource::Resource(const Resource& rsrc)
: BaseObj(rsrc), hashId(rsrc.hashId), id(rsrc.id)
{
}
Resource& Resource::operator=(Resource&& rsrc) noexcept
{
if (this == &rsrc)
return *this;
BaseObj::operator=((BaseObj&&)rsrc);
hashId = rsrc.hashId;
id = std::move(rsrc.id);
rsrc.hashId = 0;
return *this;
}
Resource& Resource::operator=(const Resource& rsrc)
{
if (this == &rsrc)
return *this;
BaseObj::operator=(rsrc);
hashId = rsrc.hashId;
id = rsrc.id;
return *this;
}
bool Resource::operator==(const ehs::UInt_64 otherHashId) const
{
return hashId == otherHashId;
}
bool Resource::operator!=(const ehs::UInt_64 otherHashId) const
{
return hashId != otherHashId;
}
void Resource::Release()
{
}
void Resource::SetId(ehs::Str_8 newId)
{
hashId = newId.Hash_64();
id = std::move(newId);
}
ehs::UInt_64 Resource::GetHashId() const
{
return hashId;
}
ehs::Str_8 Resource::GetId() const
{
return id;
}
bool Resource::IsValid() const
{
return hashId;
}
Resource* Resource::Clone() const
{
return new Resource(*this);
}
}

720
src/io/Window_W32.cpp Normal file
View File

@@ -0,0 +1,720 @@
#include "io/Window_W32.h"
#include "io/hid/Keyboard.h"
#include "io/hid/Mouse.h"
#include "system/Thread.h"
#include <hidusage.h>
namespace ehs
{
Array<Window*> Window::windows;
LRESULT Window::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Window* win = nullptr;
for (UInt_64 i = 0; i < windows.Size(); ++i)
{
if (hWnd == windows[i]->hdl)
win = windows[i];
}
if (uMsg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
if (!win)
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
if (uMsg == WM_CLOSE)
{
for (UInt_64 i = 0; i < windows.Size(); ++i)
{
if (windows[i]->hdl != hWnd)
continue;
if (windows.Size() > 1)
windows.Swap(i, windows.Size() - 1);
windows.Pop();
break;
}
DestroyWindow(hWnd);
win->hdl = nullptr;
win->Close();
return 0;
//return DefWindowProcW(hWnd, WM_QUIT, 0, lParam);
}
else if (uMsg == WM_SIZE)
{
Vec2<UInt_16> newSize;
newSize[0] = static_cast<UInt_16>(lParam);
newSize[1] = static_cast<UInt_16>(lParam >> 16);
win->OnResized(newSize);
}
else if (uMsg == WM_HIDE)
{
ShowWindow(hWnd, SW_HIDE);
}
else if (uMsg == WM_SHOW)
{
ShowWindow(hWnd, SW_SHOW);
}
else if (uMsg == WM_HIDE_CURSOR)
{
while (::ShowCursor(false) >= 0);
}
else if (uMsg == WM_SHOW_CURSOR)
{
while (::ShowCursor(true) < 0);
}
else if (uMsg == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW));
EndPaint(hWnd, &ps);
}
else if (win->HasFocus() && uMsg == WM_INPUT)
{
UINT dwSize = 0;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
if (dwSize)
{
Byte* data = new Byte[dwSize];
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
{
EHS_LOG_INT("Error", 0, "Getting raw input returned incorrect size.");
delete[] data;
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
RAWINPUT* raw = (RAWINPUT*)data;
if (raw->header.dwType == RIM_TYPEKEYBOARD)
{
Keyboard* keyboard = (Keyboard*)win->ih.GetDevice((UInt_64)raw->header.hDevice);
if (!keyboard)
{
UInt_32 bufferSize;
GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, NULL, &bufferSize);
Char_16* deviceName = new Char_16[bufferSize];
if (GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, deviceName, &bufferSize) < 0)
{
EHS_LOG_INT("Error, 0, "Failed to retrieve device name.");
return;
}
keyboard = new Keyboard(UTF::To_8(deviceName, bufferSize), (UInt_64)raw->header.hDevice);
win->ih.AddDevice(keyboard);
}
const Button button = Keyboard::TranslateScanCode(raw->data.keyboard.MakeCode);
if (raw->data.keyboard.Message == WM_KEYDOWN || raw->data.keyboard.Message == WM_SYSKEYDOWN)
keyboard->ButtonDown(button);
else if (raw->data.keyboard.Message == WM_KEYUP || raw->data.keyboard.Message == WM_SYSKEYUP)
keyboard->ButtonUp(button);
}
else if (raw->header.dwType == RIM_TYPEMOUSE)
{
Mouse* mouse = (Mouse*)win->ih.GetDevice((UInt_64)raw->header.hDevice);
if (!mouse)
{
UInt_32 bufferSize;
GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, NULL, &bufferSize);
Char_16* deviceName = new Char_16[bufferSize];
if (GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, deviceName, &bufferSize) < 0)
{
EHS_LOG_INT("Error, 1, "Failed to retrieve device name.");
return;
}
mouse = new Mouse(UTF::To_8(deviceName, bufferSize), (UInt_64)raw->header.hDevice);
win->ih.AddDevice(mouse);
}
mouse->SetDelta({raw->data.mouse.lLastX, raw->data.mouse.lLastY});
UInt_16 code = raw->data.mouse.usButtonFlags;
if (code == RI_MOUSE_LEFT_BUTTON_DOWN)
mouse->ButtonDown(Mouse::LMB);
else if (code == RI_MOUSE_LEFT_BUTTON_UP)
mouse->ButtonUp(Mouse::LMB);
else if (code == RI_MOUSE_RIGHT_BUTTON_DOWN)
mouse->ButtonDown(Mouse::RMB);
else if (code == RI_MOUSE_RIGHT_BUTTON_UP)
mouse->ButtonUp(Mouse::RMB);
else if (code == RI_MOUSE_MIDDLE_BUTTON_DOWN)
mouse->ButtonDown(Mouse::MMB);
else if (code == RI_MOUSE_MIDDLE_BUTTON_UP)
mouse->ButtonUp(Mouse::MMB);
else if (code == RI_MOUSE_BUTTON_4_DOWN)
mouse->ButtonDown(Mouse::Four);
else if (code == RI_MOUSE_BUTTON_4_UP)
mouse->ButtonUp(Mouse::Four);
else if (code == RI_MOUSE_BUTTON_5_DOWN)
mouse->ButtonDown(Mouse::Five);
else if (code == RI_MOUSE_BUTTON_5_UP)
mouse->ButtonUp(Mouse::Five);
else if (code == RI_MOUSE_WHEEL)
mouse->SetScroll({mouse->GetScroll().x, (SInt_8)raw->data.mouse.usButtonData});
else if (code == RI_MOUSE_HWHEEL)
mouse->SetScroll({(SInt_8)raw->data.mouse.usButtonData, mouse->GetScroll().y});
}
delete[] data;
}
}
else if (uMsg == WM_KILLFOCUS)
{
win->focused = false;
if (!win->cursorVisible)
{
win->SendMsg(WM_SHOW_CURSOR, 0, 0);
}
if (win->cursorConstrained)
{
if (!ClipCursor(nullptr))
EHS_LOG_INT("Error", 0, "Failed to free cursor after losing focus with error #" + Str_8::FromNum(GetLastError()) + ".");
}
win->ih.ResetAllStates();
}
else if (uMsg == WM_SETFOCUS)
{
win->focused = true;
if (!win->cursorVisible)
win->SendMsg(WM_HIDE_CURSOR, 0, 0);
if (win->cursorConstrained)
{
RECT client = {};
if (!GetClientRect(win->GetHdl(), &client))
{
EHS_LOG_INT("Error", 0, "Failed to retrieve client scale with error #" + Str_8::FromNum(GetLastError()) + ".");
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
POINT pos = {};
if (!ClientToScreen(win->GetHdl(), &pos))
{
EHS_LOG_INT("Error", 1, "Failed to retrieve client's absolute position with error #" + Str_8::FromNum(GetLastError()) + ".");
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
client.left = pos.x;
client.top = pos.y;
POINT scale = {client.right, client.bottom};
if (!ClientToScreen(win->GetHdl(), &scale))
{
EHS_LOG_INT("Error", 2, "Failed to retrieve client's absolute scale with error #" + Str_8::FromNum(GetLastError()) + ".");
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
client.right = scale.x;
client.bottom = scale.y;
if (!ClipCursor(&client))
{
EHS_LOG_INT("Error", 3, "Failed to confine cursor with error #" + Str_8::FromNum(GetLastError()) + ".");
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
}
}
else if (uMsg == WM_MOUSEMOVE)
{
win->cursorPos.x = ((SInt_16*)&lParam)[0];
win->cursorPos.y = ((SInt_16*)&lParam)[1];
}
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
Window::~Window()
{
if (!created)
return;
SendMsg(WM_CLOSE, 0, 0);
}
Window::Window()
: owner(0), instance(nullptr), hdl(nullptr)
{
}
Window::Window(const Window& win)
: BaseWindow(win), owner(0), instance(nullptr), hdl(nullptr)
{
}
Window& Window::operator=(const Window& win)
{
if (&win == this)
return *this;
BaseWindow::operator=(win);
owner = 0;
created = false;
focused = false;
instance = nullptr;
hdl = nullptr;
return* this;
}
bool Window::Poll()
{
ih.Poll();
MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE))
{
if (GetMessageW(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
else
return false;
}
BaseWindow::Poll();
return true;
}
void Window::Create_32(const Str_32& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
Create_16(UTF::To_16(title), pos, scale);
}
void Window::Create_16(const Str_16& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
if (created)
return;
owner = Thread::GetCurrentId();
instance = GetModuleHandleW(nullptr);
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = &Window::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = instance;
wcex.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hIconSm = LoadIcon(nullptr, IDI_WINLOGO);
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = title;
if (!RegisterClassExW(&wcex))
EHS_LOG_INT("Error", 0, "Failed to register window.");
hdl = CreateWindowExW(
0,
title,
title,
WS_OVERLAPPEDWINDOW,
pos.x, pos.y, scale.x, scale.y,
nullptr, nullptr,
instance,
nullptr
);
if (!hdl)
{
EHS_LOG_INT("Error", 1, "Failed to create window.");
return;
}
RECT tmp = {
0,
0,
static_cast<LONG>(scale.x),
static_cast<LONG>(scale.y)
};
AdjustWindowRectEx(&tmp, WS_OVERLAPPEDWINDOW, false, 0);
SetWindowPos(hdl, nullptr, 0, 0, tmp.right - tmp.left, tmp.bottom - tmp.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
RAWINPUTDEVICE rid[2];
rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
rid[0].dwFlags = RIDEV_INPUTSINK;
rid[0].hwndTarget = hdl;
rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
rid[1].usUsage = HID_USAGE_GENERIC_KEYBOARD;
rid[1].dwFlags = 0;
rid[1].hwndTarget = hdl;
if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == false)
{
EHS_LOG_INT("Error", 2, "Failed to register raw input devices.");
return;
}
windows.Push(this);
created = true;
OnCreated();
}
void Window::Create_8(const Str_8& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
Create_16(UTF::To_16(title), pos, scale);
}
void Window::Use(HWND windowHdl)
{
hdl = windowHdl;
}
void Window::Close()
{
if (hdl)
SendMsg(WM_CLOSE, 0, 0);
created = false;
}
void Window::Show()
{
SendMsg(WM_SHOW, 0, 0);
}
void Window::Hide()
{
SendMsg(WM_HIDE, 0, 0);
}
void Window::SetTitle_32(const Str_32& title)
{
if (!SetWindowTextW(hdl, UTF::To_16(title)))
EHS_LOG_INT("Error", 0, "Failed to set window title with error #" + Str_8::FromNum(GetLastError()) + ".");
}
Str_32 Window::GetTitle_32()
{
int size = GetWindowTextLengthW(hdl);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
Char_16* buffer = new Char_16[size];
size = GetWindowTextW(hdl, buffer, size);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 1, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
return UTF::To_32(buffer, Str_16::Len(buffer));
}
void Window::SetTitle_16(const Str_16& title)
{
if (!SetWindowTextW(hdl, title))
EHS_LOG_INT("Error", 0, "Failed to set window title with error #" + Str_8::FromNum(GetLastError()) + ".");
}
Str_16 Window::GetTitle_16()
{
int size = GetWindowTextLengthW(hdl);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
Char_16* buffer = new Char_16[size];
size = GetWindowTextW(hdl, buffer, size);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 1, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
return {buffer};
}
void Window::SetTitle_8(const Str_8& title)
{
if (!SetWindowTextW(hdl, UTF::To_16(title)))
EHS_LOG_INT("Error", 0, "Failed to set window title with error #" + Str_8::FromNum(GetLastError()) + ".");
}
Str_8 Window::GetTitle_8()
{
int size = GetWindowTextLengthW(hdl);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
Char_16* buffer = new Char_16[size];
size = GetWindowTextW(hdl, buffer, size);
if (!size)
{
DWORD err = GetLastError();
if (err)
{
EHS_LOG_INT("Error", 1, "Failed to retrieve the window's title length with error #" + Str_8::FromNum(err) + ".");
return {};
}
}
return UTF::To_8(buffer, Str_16::Len(buffer));
}
void Window::SetIcon(const Str_8& filePath)
{
Handle icon = LoadImageW(nullptr, UTF::To_16(filePath), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
if (!icon)
{
EHS_LOG_INT("Error", 0, "Failed to load icon at file path, \"" + filePath + "\" with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
SendMsg(WM_SETICON, ICON_SMALL, (LPARAM)icon);
SendMsg(WM_SETICON, ICON_BIG, (LPARAM)icon);
}
HWND Window::GetHdl() const
{
return hdl;
}
HWND Window::GetAvailableHdl()
{
for (UInt_64 i = 0; i < windows.Size(); ++i)
if (windows[i])
return windows[i]->hdl;
return nullptr;
}
HINSTANCE Window::GetInst() const
{
return instance;
}
void Window::ToggleEnabled(bool toggle)
{
if (!created)
return;
EnableWindow(hdl, toggle);
}
bool Window::IsEnabled()
{
if (!created)
return false;
return IsWindowEnabled(hdl);
}
void Window::SetPos(int x, int y)
{
if (!created)
return;
SetWindowPos(hdl, nullptr, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
Vec2<Int_32> Window::GetPos()
{
if (!created)
return {};
RECT tmp = {};
GetWindowRect(hdl, &tmp);
return {(Int_32)tmp.left, (Int_32)tmp.top};
}
void Window::SetClientSize(const Vec2<UInt_32>& size)
{
if (!created)
return;
RECT rect = {
0,
0,
static_cast<LONG>(size[0]),
static_cast<LONG>(size[1])
};
DWORD exStyle = (DWORD)GetWindowLongPtr(hdl, GWL_EXSTYLE);
DWORD style = (DWORD)GetWindowLongPtr(hdl, GWL_STYLE);
AdjustWindowRectEx(&rect, style, false, exStyle);
SetWindowPos(hdl, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
Vec2<UInt_32> Window::GetClientSize()
{
RECT rect = {};
if (!GetClientRect(hdl, &rect))
EHS_LOG_INT("Error", 0, "Failed to retrieve client size with error #" + Str_8::FromNum(GetLastError()) + ".");
return {(UInt_32)rect.right, (UInt_32)rect.bottom};
}
void Window::OnResized(const Vec2<UInt_32>& newSize)
{
}
void Window::SetSize(int w, int h)
{
if (!created)
return;
SetWindowPos(hdl, nullptr, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
Vec2<Int_32> Window::GetSize()
{
if (!created)
return {};
RECT tmp = {};
GetWindowRect(hdl, &tmp);
return {(Int_32)(tmp.right - tmp.left), (Int_32)(tmp.bottom - tmp.top)};
}
void Window::ShowCursor(bool toggle)
{
SendMsg(toggle ? WM_SHOW_CURSOR : WM_HIDE_CURSOR, 0, 0);
cursorVisible = toggle;
}
void Window::ConstrainCursor(const bool toggle)
{
if (toggle)
{
RECT client = {};
if (!GetClientRect(GetHdl(), &client))
{
EHS_LOG_INT("Error", 0, "Failed to retrieve client scale with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
POINT pos = {};
if (!ClientToScreen(GetHdl(), &pos))
{
EHS_LOG_INT("Error", 1, "Failed to retrieve client's absolute position with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
client.left = pos.x;
client.top = pos.y;
POINT scale = {client.right, client.bottom};
if (!ClientToScreen(GetHdl(), &scale))
{
EHS_LOG_INT("Error", 2, "Failed to retrieve client's absolute scale with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
client.right = scale.x;
client.bottom = scale.y;
if (!ClipCursor(&client))
{
EHS_LOG_INT("Error", 3, "Failed to confine cursor with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
}
else
{
ClipCursor(nullptr);
}
cursorConstrained = toggle;
}
void Window::SendMsg(const UINT msg, const WPARAM wParam, const LPARAM lParam)
{
if (!hdl)
return;
if (Thread::GetCurrentId() == owner)
PostMessageW(hdl, msg, wParam, lParam);
else
SendMessageW(hdl, msg, wParam, lParam);
}
}

224
src/io/Window_Way.cpp Normal file
View File

@@ -0,0 +1,224 @@
#include "io/Window_Way.h"
namespace ehs
{
void Window::SurfaceConfigure(void* data, xdg_surface* xdg_surface, UInt_32 serial)
{
xdg_surface_ack_configure(xdg_surface, serial);
}
void Window::ShellPing(void* data, xdg_wm_base* shell, UInt_32 serial)
{
xdg_wm_base_pong(shell, serial);
}
void Window::RegistryHandler(void* data, wl_registry* registry, UInt_32 id, const char* interface, UInt_32 version)
{
Serializer<UInt_64>* ser = (Serializer<UInt_64>*)data;
if (Str_8::Cmp(interface, "wl_compositor"))
{
ser->SetOffset(0);
wl_compositor** comp = ser->Read<wl_compositor**>();
*comp = (wl_compositor*)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
}
if (Str_8::Cmp(interface, "xdg_wm_base"))
{
ser->SetOffset(sizeof(void*));
xdg_wm_base** base = ser->Read<xdg_wm_base**>();
*base = (xdg_wm_base*)wl_registry_bind(registry, id, &xdg_wm_base_interface, 1);
}
}
void Window::RegistryRemoved(void* data, wl_registry* registry, UInt_32 id)
{
}
Window::~Window()
{
xdg_toplevel_destroy(xdgToplevel);
xdg_surface_destroy(xdgSurface);
xdg_wm_base_destroy(xdgShell);
wl_surface_destroy(surface);
wl_compositor_destroy(compositor);
wl_registry_destroy(registry);
wl_display_disconnect(display);
}
Window::Window()
: display(nullptr), registry(nullptr), compositor(nullptr) , surface(nullptr)
{
}
void Window::Create_32(const Str_32& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
Create_8(UTF::To_8(title), pos, scale);
}
void Window::Create_16(const Str_16& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
Create_8(UTF::To_8(title), pos, scale);
}
void Window::Create_8(const Str_8& title, const Vec2_s32& pos, const Vec2_u32 scale)
{
display = wl_display_connect(nullptr);
if (!display)
{
EHS_LOG_INT("Error", 0, "Failed to connect to display server.");
return;
}
Serializer<UInt_64> data(Endianness::LE);
data.Write(&compositor);
data.Write(&xdgShell);
static constexpr wl_registry_listener registry_listener = {
RegistryHandler,
RegistryRemoved
};
registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, &data);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (!compositor || !xdgShell)
{
EHS_LOG_INT("Error", 1, "Can't find required interfaces.");
return;
}
static constexpr xdg_wm_base_listener xdg_shell_listener = {ShellPing};
xdg_wm_base_add_listener(xdgShell, &xdg_shell_listener, nullptr);
surface = wl_compositor_create_surface(compositor);
if (!surface)
{
EHS_LOG_INT("Error", 2, "Can't create surface.");
return;
}
xdgSurface = xdg_wm_base_get_xdg_surface(xdgShell, surface);
xdgToplevel = xdg_surface_get_toplevel(xdgSurface);
static constexpr xdg_surface_listener surfaceListener = {SurfaceConfigure};
xdg_surface_add_listener(xdgSurface, &surfaceListener, nullptr);
xdg_toplevel_set_title(xdgToplevel, title);
wl_surface_commit(surface);
}
void Window::OnCreated()
{
}
void Window::Close()
{
xdg_toplevel_destroy(xdgToplevel);
xdgToplevel = nullptr;
xdg_surface_destroy(xdgSurface);
xdgSurface = nullptr;
xdg_wm_base_destroy(xdgShell);
xdgShell = nullptr;
wl_surface_destroy(surface);
surface = nullptr;
wl_compositor_destroy(compositor);
compositor = nullptr;
wl_registry_destroy(registry);
registry = nullptr;
wl_display_disconnect(display);
display = nullptr;
}
void Window::Show()
{
}
void Window::Hide()
{
}
bool Window::Poll()
{
wl_display_dispatch(display);
return true;
}
void Window::ShowCursor(bool toggle)
{
}
void Window::ConstrainCursor(const bool constrain)
{
}
void Window::SetTitle_32(const Str_32& newTitle)
{
}
Str_32 Window::GetTitle_32() const
{
return {};
}
void Window::SetTitle_16(const Str_16& newTitle)
{
}
Str_16 Window::GetTitle_16() const
{
return {};
}
void Window::SetTitle_8(const Str_8& newTitle)
{
}
Str_8 Window::GetTitle_8() const
{
return {};
}
void Window::SetPos(const Vec2_s32& newPos)
{
}
Vec2_s32 Window::GetPos() const
{
return {};
}
void Window::SetScale(const Vec2_u32& newScale)
{
}
Vec2_u32 Window::GetScale() const
{
return {};
}
Serializer<UInt_64> Window::GetClipboard()
{
return {};
}
void Window::SetClipboard(Serializer<UInt_64> data)
{
}
void Window::SetCursorImg(const CursorImg img)
{
}
}

735
src/io/Window_XCB.cpp Normal file
View File

@@ -0,0 +1,735 @@
#include "ehs/io/Window_XCB.h"
#include "ehs/UTF.h"
#include "ehs/Vec2.h"
#include "ehs/io/hid/Keyboard.h"
#include "ehs/io/hid/Mouse.h"
#include "ehs/io/Console.h"
#include <cstddef>
#include <cstdlib>
#include <xcb/xfixes.h>
#include <xcb/xcb_cursor.h>
namespace ehs
{
Window::~Window()
{
if (hdl)
xcb_destroy_window(server, hdl);
if (server)
xcb_disconnect(server);
}
Window::Window()
: server(nullptr), screen(nullptr), hdl(0), masks{}, extOpCode(0), events{XCB_ATOM_NONE, XCB_ATOM_NONE}
{
}
Window::Window(Window&& win) noexcept
: BaseWindow((BaseWindow&&)win), server(win.server), screen(win.screen), hdl(win.hdl),
masks{win.masks[0], win.masks[1]}, events((Vector<xcb_generic_event_t*>)win.events), extOpCode(win.extOpCode),
clipboard((Serializer<UInt_64>&&)win.clipboard)
{
win.server = nullptr;
win.screen = nullptr;
win.hdl = 0;
win.masks[0] = 0;
win.masks[1] = 0;
win.extOpCode = 0;
}
Window::Window(const Window& win)
: BaseWindow(win), server(nullptr), screen(nullptr), hdl(0), masks{}, extOpCode(0),
events{XCB_ATOM_NONE, XCB_ATOM_NONE}
{
}
Window& Window::operator=(Window&& win) noexcept
{
if (this == &win)
return *this;
Close();
BaseWindow::operator=((BaseWindow&&)win);
server = win.server;
screen = win.screen;
hdl = win.hdl;
masks[0] = win.masks[0];
masks[1] = win.masks[1];
extOpCode = win.extOpCode;
events = (Vector<xcb_generic_event_t*>&&)win.events;
clipboard = (Serializer<UInt_64>&&)win.clipboard;
win.server = nullptr;
win.screen = nullptr;
win.hdl = 0;
win.masks[0] = 0;
win.masks[1] = 0;
win.extOpCode = 0;
return *this;
}
Window& Window::operator=(const Window& win)
{
if (this == &win)
return *this;
Close();
BaseWindow::operator=(win);
server = nullptr;
screen = nullptr;
hdl = 0;
masks[0] = 0;
masks[1] = 0;
extOpCode = 0;
events = {};
clipboard = {};
return *this;
}
void Window::Create_32(const Str_32 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
{
Create_8(UTF::To_8(title), pos, scale);
}
void Window::Create_16(const Str_16 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
{
Create_8(UTF::To_8(title), pos, scale);
}
void Window::Create_8(const Str_8 &title, const Vec2_s32 &pos, const Vec2_u32 scale)
{
if (created)
return;
server = xcb_connect(nullptr, nullptr);
if (xcb_connection_has_error(server))
{
EHS_LOG_INT("Error", 0, "Failed to connect to display server.");
return;
}
screen = xcb_setup_roots_iterator(xcb_get_setup(server)).data;
hdl = xcb_generate_id(server);
UInt_32 values[2] = {
screen->white_pixel,
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_FOCUS_CHANGE
};
xcb_create_window(
server,
screen->root_depth,
hdl,
screen->root,
(SInt_16)pos.x, (SInt_16)pos.y,
scale.x, scale.y, 1,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
values
);
SetTitle_8(title);
xcb_atom_t proto = RetrieveAtom(false, "WM_PROTOCOLS");
masks[0] = RetrieveAtom(true, "WM_DELETE_WINDOW");
masks[1] = RetrieveAtom(true, "_NET_WM_PING");
xcb_change_property(server, XCB_PROP_MODE_REPLACE, hdl, proto, XCB_ATOM_ATOM, 32, 2, masks);
const xcb_query_extension_reply_t *extension = xcb_get_extension_data(server, &xcb_input_id);
if (!extension)
{
xcb_disconnect(server);
EHS_LOG_INT("Warning", 1, "Failed to query for XCB XInput extension.");
return;
}
if (!extension->present)
{
xcb_disconnect(server);
EHS_LOG_INT("Warning", 2, "XCB XInput extension is not available.");
return;
}
struct XInputMask
{
xcb_input_event_mask_t iem;
UInt_32 flags;
};
XInputMask rootMask = {};
rootMask.iem.deviceid = XCB_INPUT_DEVICE_ALL;
rootMask.iem.mask_len = 1;
rootMask.flags = XCB_INPUT_XI_EVENT_MASK_RAW_MOTION | XCB_INPUT_XI_EVENT_MASK_RAW_KEY_PRESS |
XCB_INPUT_XI_EVENT_MASK_RAW_KEY_RELEASE | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS |
XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE;
xcb_input_xi_select_events(server, screen->root, 1, &rootMask.iem);
XInputMask winMask = {};
winMask.iem.deviceid = XCB_INPUT_DEVICE_ALL;
winMask.iem.mask_len = 1;
winMask.flags = XCB_INPUT_XI_EVENT_MASK_MOTION;
xcb_input_xi_select_events(server, hdl, 1, &winMask.iem);
QueryPrimaryDevices();
xcb_map_window(server, hdl);
xcb_flush(server);
created = true;
OnCreated();
}
void Window::Close()
{
if (hdl)
{
xcb_destroy_window(server, hdl);
hdl = 0;
}
if (server)
{
xcb_disconnect(server);
server = nullptr;
}
created = false;
}
void Window::Show()
{
if (!IsCreated())
return;
xcb_map_window(server, hdl);
xcb_flush(server);
}
void Window::Hide()
{
if (!IsCreated())
return;
xcb_unmap_window(server, hdl);
xcb_flush(server);
}
bool Window::Poll()
{
ih.Poll();
xcb_generic_event_t* event = nullptr;
while ((event = RetrieveEvent()))
{
switch (event->response_type & ~0x80)
{
case XCB_CLIENT_MESSAGE:
{
xcb_client_message_event_t* cEvent = (xcb_client_message_event_t*)event;
if (cEvent->data.data32[0] == masks[0]) // WM_DELETE_WINDOW
{
xcb_disconnect(server);
server = nullptr;
screen = nullptr;
hdl = 0;
free(event);
return false;
}
else if (cEvent->data.data32[0] == masks[1]) // _NET_WM_PING
{
cEvent->window = screen->root;
xcb_send_event(server, true, hdl,
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
(const char*) &cEvent);
}
break;
}
case XCB_FOCUS_IN:
{
focused = true;
break;
}
case XCB_FOCUS_OUT:
{
ih.ResetAllStates();
focused = false;
break;
}
case XCB_SELECTION_REQUEST:
{
const xcb_selection_request_event_t* req_event = (xcb_selection_request_event_t*)event;
// Change the property of the requestor window with the data
xcb_change_property(server, XCB_PROP_MODE_REPLACE, req_event->requestor, req_event->property,
XCB_ATOM_STRING, 8, clipboard.Size(), clipboard);
// Send a SelectionNotify event to the requestor
xcb_selection_notify_event_t notify_event = {};
notify_event.response_type = XCB_SELECTION_NOTIFY;
notify_event.requestor = req_event->requestor;
notify_event.selection = req_event->selection;
notify_event.target = req_event->target;
notify_event.property = req_event->property;
notify_event.time = req_event->time;
xcb_send_event(server, false, req_event->requestor, XCB_EVENT_MASK_NO_EVENT, (char*)&notify_event);
xcb_flush(server);
break;
}
case XCB_GE_GENERIC:
{
xcb_ge_event_t* ge = (xcb_ge_event_t*)event;
switch (ge->event_type)
{
case XCB_INPUT_MOTION:
{
xcb_input_motion_event_t *motion_event = (xcb_input_motion_event_t *)ge;
cursorPos = {motion_event->event_x >> 16, motion_event->event_y >> 16};
break;
}
case XCB_INPUT_RAW_MOTION:
{
const xcb_input_raw_motion_event_t* rm = (xcb_input_raw_motion_event_t*)ge;
int axis_len = xcb_input_raw_button_press_axisvalues_length(rm);
if (axis_len != 2)
break;
xcb_input_fp3232_t *pos = xcb_input_raw_button_press_axisvalues_raw(rm);
Mouse* device = (Mouse*)ih.GetDevice(rm->deviceid);
if (!device)
{
device = new Mouse(QueryDeviceName(rm->deviceid), rm->deviceid);
ih.AddDevice(device);
}
device->SetDelta({pos[0].integral, pos[1].integral});
break;
}
case XCB_INPUT_RAW_BUTTON_PRESS:
{
const xcb_input_raw_button_press_event_t* bpEvent = (xcb_input_raw_button_press_event_t*)event;
UInt_32 code = bpEvent->detail;
Button button = Mouse::TranslateXCB(code);
Mouse* device = (Mouse*)ih.GetDevice(bpEvent->deviceid);
if (!device)
{
device = new Mouse(QueryDeviceName(bpEvent->deviceid), bpEvent->deviceid);
ih.AddDevice(device);
}
device->ButtonDown(button);
break;
}
case XCB_INPUT_RAW_BUTTON_RELEASE:
{
const xcb_input_raw_button_release_event_t* bpEvent = (xcb_input_raw_button_release_event_t*) event;
UInt_32 code = bpEvent->detail;
Button button = Mouse::TranslateXCB(code);
Mouse* device = (Mouse*)ih.GetDevice(bpEvent->deviceid);
if (!device)
{
device = new Mouse(QueryDeviceName(bpEvent->deviceid), bpEvent->deviceid);
ih.AddDevice(device);
}
device->ButtonUp(button);
break;
}
case XCB_INPUT_RAW_KEY_PRESS:
{
const xcb_input_raw_key_press_event_t* kpEvent = (xcb_input_raw_key_press_event_t*)event;
UInt_32 code = kpEvent->detail - 8;
Button button = Keyboard::TranslateScanCode(code);
Keyboard* device = (Keyboard*)ih.GetDevice(kpEvent->deviceid);
if (!device)
{
device = new Keyboard(QueryDeviceName(kpEvent->deviceid), kpEvent->deviceid);
ih.AddDevice(device);
}
device->ButtonDown(button);
break;
}
case XCB_INPUT_RAW_KEY_RELEASE:
{
const xcb_input_raw_key_release_event_t* kpEvent = (xcb_input_raw_key_release_event_t*)event;
UInt_32 code = kpEvent->detail - 8;
Button button = Keyboard::TranslateScanCode(code);
Keyboard* device = (Keyboard*)ih.GetDevice(kpEvent->deviceid);
if (!device)
{
device = new Keyboard(QueryDeviceName(kpEvent->deviceid), kpEvent->deviceid);
ih.AddDevice(device);
}
device->ButtonUp(button);
break;
}
default:
{
break;
}
}
}
default:
{
break;
}
}
}
free(event);
BaseWindow::Poll();
return true;
}
void Window::ShowCursor(bool toggle)
{
xcb_xfixes_query_version(server, 4, 0);
if (toggle)
xcb_xfixes_show_cursor(server, hdl);
else
xcb_xfixes_hide_cursor(server, hdl);
xcb_flush(server);
cursorVisible = toggle;
}
void Window::ConstrainCursor(const bool constrain)
{
if (constrain)
{
xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(
server,
true,
hdl,
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
hdl,
XCB_NONE,
XCB_CURRENT_TIME
);
xcb_grab_pointer_reply_t* reply = xcb_grab_pointer_reply(server, cookie, nullptr);
if (!reply || reply->status != XCB_GRAB_STATUS_SUCCESS)
{
free(reply);
EHS_LOG_INT("Error", 0, "Failed to constrain cursor.");
return;
}
free(reply);
}
else
{
xcb_ungrab_pointer(server, XCB_CURRENT_TIME);
xcb_flush(server);
}
cursorConstrained = constrain;
}
void Window::SetTitle_32(const Str_32& newTitle)
{
SetTitle_8(UTF::To_8(newTitle));
}
Str_32 Window::GetTitle_32() const
{
return UTF::To_32(GetTitle_8());
}
void Window::SetTitle_16(const Str_16& newTitle)
{
SetTitle_8(UTF::To_8(newTitle));
}
Str_16 Window::GetTitle_16() const
{
return UTF::To_16(GetTitle_8());
}
void Window::SetTitle_8(const Str_8 &newTitle)
{
xcb_change_property(server, XCB_PROP_MODE_REPLACE, hdl, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, newTitle.Size(), &newTitle[0]);
}
Str_8 Window::GetTitle_8() const
{
xcb_get_property_reply_t* reply = RetrieveProp(XCB_ATOM_WM_NAME, XCB_ATOM_STRING);
Str_8 result((char*)xcb_get_property_value(reply), xcb_get_property_value_length(reply));
free(reply);
return result;
}
void Window::SetPos(const Vec2_s32& newPos)
{
xcb_configure_window(server, hdl, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &((Byte*)&newPos)[offsetof(Vec2_s32, x)]);
xcb_flush(server);
}
Vec2_s32 Window::GetPos() const
{
Vec2_s32 result;
const xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(server, hdl);
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(server, geom_cookie, nullptr);
if (!geom)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve window position.");
return result;
}
result = {geom->x, geom->y};
free(geom);
return {};
}
void Window::SetScale(const Vec2_u32& newScale)
{
xcb_configure_window(server, hdl, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, &((Byte*)&newScale)[offsetof(Vec2_u32, x)]);
xcb_flush(server);
}
Vec2_u32 Window::GetScale() const
{
Vec2_s32 result;
const xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(server, hdl);
xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(server, geom_cookie, nullptr);
if (!geom)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve window scale.");
return result;
}
result = {geom->width, geom->height};
free(geom);
return result;
}
Serializer<UInt_64> Window::GetClipboard()
{
Serializer<UInt_64> result;
const xcb_atom_t clipboard_atom = RetrieveAtom(false, "CLIPBOARD");
const xcb_atom_t utf8_string_atom = RetrieveAtom(false, "STRING");
const xcb_atom_t property_atom = RetrieveAtom(true, "MATHISART");
if (clipboard_atom == XCB_ATOM_NONE || utf8_string_atom == XCB_ATOM_NONE || property_atom == XCB_ATOM_NONE)
{
EHS_LOG_INT("Error", 1, "Failed to retrieve atoms.");
return result;
}
xcb_convert_selection(server, hdl, clipboard_atom, utf8_string_atom,
property_atom, XCB_CURRENT_TIME);
xcb_flush(server);
//events.Insert(0, xcb_wait_for_event(server));
const xcb_get_property_cookie_t prop_cookie = xcb_get_property(server, 0, hdl,
property_atom, utf8_string_atom, 0, UINT32_MAX / 4);
if (xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(server, prop_cookie, nullptr); prop_reply)
{
result = Serializer<UInt_64>(Endianness::LE, (Byte*)xcb_get_property_value(prop_reply),
xcb_get_property_value_length(prop_reply), 0);
free(prop_reply);
}
return result;
}
void Window::SetClipboard(Serializer<UInt_64> data)
{
if (clipboard == data)
return;
clipboard = (Serializer<UInt_64>&&)data;
const xcb_atom_t clipboard_atom = RetrieveAtom(false, "CLIPBOARD");
if (clipboard_atom == XCB_ATOM_NONE)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve atom.");
return;
}
xcb_set_selection_owner(server, hdl, clipboard_atom, XCB_CURRENT_TIME);
xcb_flush(server);
}
void Window::SetCursorImg(const CursorImg img)
{
xcb_cursor_t text_cursor = XCB_NONE;
if (img == CursorImg::DEFAULT)
{
xcb_change_window_attributes(server, hdl, XCB_CW_CURSOR, &text_cursor);
xcb_flush(server);
}
if (img == CursorImg::I_BEAM)
{
xcb_cursor_context_t *cursor_context;
xcb_cursor_context_new(server, xcb_setup_roots_iterator(xcb_get_setup(server)).data, &cursor_context);
text_cursor = xcb_cursor_load_cursor(cursor_context, "xterm");
xcb_change_window_attributes(server, hdl, XCB_CW_CURSOR, &text_cursor);
xcb_cursor_context_free(cursor_context);
xcb_flush(server);
}
}
xcb_connection_t *Window::GetServer()
{
return server;
}
xcb_generic_event_t* Window::RetrieveEvent()
{
if (events.Size())
{
xcb_generic_event_t* event = events[0];
events.Remove(0);
return event;
}
else
return xcb_poll_for_event(server);
}
xcb_atom_t Window::RetrieveAtom(const bool create, const Str_8& name) const
{
xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(server, xcb_intern_atom(server, !create,
name.Size(), name), nullptr);
if (!reply)
return XCB_ATOM_NONE;
const xcb_atom_t atom = reply->atom;
free(reply);
return atom;
}
xcb_get_property_reply_t *Window::RetrieveProp(const xcb_atom_t prop, const xcb_atom_t type) const
{
return xcb_get_property_reply(server, xcb_get_property(server, false, hdl, prop, type, 0, 0), nullptr);
}
void Window::QueryPrimaryDevices()
{
xcb_input_xi_query_device_cookie_t device_cookie = xcb_input_xi_query_device(server, XCB_INPUT_DEVICE_ALL);
xcb_input_xi_query_device_reply_t *device_reply = xcb_input_xi_query_device_reply(server, device_cookie, nullptr);
if (!device_reply)
{
EHS_LOG_INT("Error", 0, "Failed to query primary devices.");
return;
}
xcb_input_xi_device_info_iterator_t device_iter = xcb_input_xi_query_device_infos_iterator(device_reply);
for (; device_iter.rem; xcb_input_xi_device_info_next(&device_iter))
{
xcb_input_xi_device_info_t *device_info = device_iter.data;
Str_8 name(xcb_input_xi_device_info_name(device_info),
xcb_input_xi_device_info_name_length(device_info));
if (device_info->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER)
ih.AddDevice(new Mouse(name, device_info->deviceid));
if (device_info->type == XCB_INPUT_DEVICE_TYPE_MASTER_KEYBOARD)
ih.AddDevice(new Keyboard(name, device_info->deviceid));
}
free(device_reply);
}
Str_8 Window::QueryDeviceName(const UInt_16 id)
{
Str_8 result;
xcb_input_xi_query_device_cookie_t device_cookie = xcb_input_xi_query_device(server, id);
xcb_input_xi_query_device_reply_t *device_reply = xcb_input_xi_query_device_reply(server, device_cookie, nullptr);
if (!device_reply)
{
EHS_LOG_INT("Error", 0, "Failed to query device name from the id, \"" + Str_8::FromNum(id) + "\".");
return result;
}
xcb_input_xi_device_info_iterator_t device_iter = xcb_input_xi_query_device_infos_iterator(device_reply);
for (; device_iter.rem; xcb_input_xi_device_info_next(&device_iter))
{
xcb_input_xi_device_info_t *device_info = device_iter.data;
result = Str_8(xcb_input_xi_device_info_name(device_info),
xcb_input_xi_device_info_name_length(device_info));
}
free(device_reply);
return result;
}
}

1951
src/io/audio/Audio.cpp Normal file

File diff suppressed because it is too large Load Diff

109
src/io/audio/AudioCodec.cpp Normal file
View File

@@ -0,0 +1,109 @@
#include "ehs/io/audio/AudioCodec.h"
namespace ehs
{
AudioCodec::AudioCodec()
: hashExt(0), endianness(Endianness::LE), encodeCb(nullptr), decodeCb(nullptr)
{
}
AudioCodec::AudioCodec(Str_8 id, Str_8 ext, const Endianness end,
bool (* encodeCb)(const AudioCodec* const, Serializer<UInt_64>&, const Audio*),
bool (* decodeCb)(const AudioCodec* const, Serializer<UInt_64>&, Audio*))
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encodeCb(encodeCb), decodeCb(decodeCb)
{
}
AudioCodec::AudioCodec(AudioCodec&& codec) noexcept
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
encodeCb(codec.encodeCb), decodeCb(codec.decodeCb)
{
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
}
AudioCodec::AudioCodec(const AudioCodec& codec)
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encodeCb(codec.encodeCb),
decodeCb(codec.decodeCb)
{
}
AudioCodec& AudioCodec::operator=(AudioCodec&& codec) noexcept
{
if (this == &codec)
return *this;
id = std::move(codec.id);
hashExt = codec.hashExt;
ext = std::move(codec.ext);
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
return *this;
}
AudioCodec& AudioCodec::operator=(const AudioCodec& codec)
{
if (this == &codec)
return *this;
id = codec.id;
hashExt = codec.hashExt;
ext = codec.ext;
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
return *this;
}
Str_8 AudioCodec::GetId() const
{
return id;
}
UInt_64 AudioCodec::GetHashExt() const
{
return hashExt;
}
Str_8 AudioCodec::GetExt() const
{
return ext;
}
Endianness AudioCodec::GetEndianness() const
{
return endianness;
}
bool AudioCodec::Encode(Serializer<UInt_64>& out, const Audio* in) const
{
if (!encodeCb)
{
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
return false;
}
return encodeCb(this, out, in);
}
bool AudioCodec::Decode(Serializer<UInt_64>& in, Audio* out) const
{
if (!decodeCb)
{
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
return false;
}
return decodeCb(this, in, out);
}
}

View File

@@ -0,0 +1,383 @@
#include "ehs/io/audio/AudioDevice_ALSA.h"
#include "ehs/EHS.h"
#include "ehs/Log.h"
namespace ehs
{
AudioDevice::~AudioDevice()
{
if (!hdl)
return;
snd_pcm_drain(hdl);
snd_pcm_close(hdl);
}
AudioDevice::AudioDevice()
: hdl(nullptr)
{
}
AudioDevice::AudioDevice(AudioDevice&& device) noexcept
: BaseAudioDevice(device), hdl(device.hdl)
{
device.hdl = nullptr;
}
AudioDevice::AudioDevice(const AudioDevice& device)
: BaseAudioDevice(device), hdl(nullptr)
{
}
AudioDevice& AudioDevice::operator=(AudioDevice&& device) noexcept
{
if (this == &device)
return *this;
BaseAudioDevice::operator=(device);
hdl = device.hdl;
device.hdl = nullptr;
return *this;
}
AudioDevice& AudioDevice::operator=(const AudioDevice& device)
{
if (this == &device)
return *this;
BaseAudioDevice::operator=(device);
hdl = nullptr;
return *this;
}
void AudioDevice::Release()
{
if (!IsValid())
return;
snd_pcm_drain(hdl);
snd_pcm_close(hdl);
hdl = nullptr;
}
void AudioDevice::OpenStream()
{
if (streaming)
return;
snd_pcm_hw_params_t* params;
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(hdl, params);
if (snd_pcm_hw_params_set_access(hdl, params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
{
EHS_LOG_INT("Error", 0, "Failed to set access.");
return;
}
if (bitDepth)
{
snd_pcm_format_t format;
switch (dataType)
{
case DataType::FLOAT:
{
format = SND_PCM_FORMAT_FLOAT;
break;
}
case DataType::SINT_32:
{
format = SND_PCM_FORMAT_S32;
break;
}
case DataType::SINT_24:
{
format = SND_PCM_FORMAT_S24;
break;
}
case DataType::SINT_16:
{
format = SND_PCM_FORMAT_S16;
break;
}
case DataType::SINT_8:
{
format = SND_PCM_FORMAT_S8;
break;
}
default:
{
EHS_LOG_INT("Error", 0, "Invalid data type.");
return;
}
}
snd_pcm_hw_params_set_format(hdl, params, format);
}
if (channels)
{
if (snd_pcm_hw_params_set_channels_near(hdl, params, &channels) < 0)
{
EHS_LOG_INT("Error", 1, "Failed to set channels.");
return;
}
}
if (sampleRate)
{
if (snd_pcm_hw_params_set_rate_near(hdl, params, &sampleRate, nullptr) < 0)
{
EHS_LOG_INT("Error", 2, "Failed to set sample rate.");
return;
}
}
if (snd_pcm_hw_params_set_period_time_near(hdl, params, &period, nullptr) < 0)
{
EHS_LOG_INT("Error", 3, "Failed to set period.");
return;
}
if (snd_pcm_hw_params_set_buffer_time_near(hdl, params, &latency, nullptr) < 0)
{
EHS_LOG_INT("Error", 4, "Failed to set latency.");
return;
}
if (snd_pcm_hw_params(hdl, params) < 0)
{
EHS_LOG_INT("Error", 5, "Failed to apply hardware parameters.");
return;
}
if (!bitDepth)
{
snd_pcm_format_t format;
if (snd_pcm_hw_params_get_format(params, &format) < 0)
{
EHS_LOG_INT("Error", 6, "Failed to retrieve audio device properties.");
return;
}
switch (format)
{
case SND_PCM_FORMAT_FLOAT:
{
dataType = DataType::FLOAT;
bitDepth = 32;
break;
}
case SND_PCM_FORMAT_S32:
{
dataType = DataType::SINT_32;
bitDepth = 32;
break;
}
case SND_PCM_FORMAT_S24:
{
dataType = DataType::SINT_24;
bitDepth = 24;
break;
}
case SND_PCM_FORMAT_S16:
{
dataType = DataType::SINT_16;
bitDepth = 16;
break;
}
case SND_PCM_FORMAT_S8:
{
dataType = DataType::SINT_8;
bitDepth = 8;
break;
}
default:
{
EHS_LOG_INT("Error", 7, "Format unsupported.");
break;
}
}
}
if (!channels)
{
if (snd_pcm_hw_params_get_channels(params, &channels) < 0)
{
EHS_LOG_INT("Error", 8, "Failed to retrieve channel count.");
return;
}
}
if (!sampleRate)
{
int dir;
if (snd_pcm_hw_params_get_rate(params, &sampleRate, &dir) < 0)
{
EHS_LOG_INT("Error", 9, "Failed to retrieve sample rate.");
return;
}
}
if (snd_pcm_hw_params_get_buffer_size(params, &maxFrames) < 0)
{
EHS_LOG_INT("Error", 10, "Failed to retrieve buffer size.");
}
snd_pcm_sw_params_t* swParams = nullptr;
snd_pcm_sw_params_alloca(&swParams);
if (snd_pcm_sw_params_current(hdl, swParams) < 0)
{
EHS_LOG_INT("Error", 11, "Failed to retrieve software parameters.");
return;
}
if (snd_pcm_sw_params_set_silence_threshold(hdl, swParams, maxFrames) < 0)
{
EHS_LOG_INT("Error", 12, "Failed to set silence threshold.");
return;
}
if (snd_pcm_sw_params_set_silence_size(hdl, swParams, maxFrames) < 0)
{
EHS_LOG_INT("Error", 12, "Failed to set silence size.");
return;
}
if (snd_pcm_sw_params(hdl, swParams) < 0)
{
EHS_LOG_INT("Error", 13, "Failed to set software parameters.");
return;
}
if (snd_pcm_prepare(hdl) < 0)
{
EHS_LOG_INT("Error", 14, "Failed to prepare audio stream.");
return;
}
streaming = true;
}
void AudioDevice::CloseStream()
{
if (!streaming)
return;
snd_pcm_drain(hdl);
streaming = false;
}
UInt_64 AudioDevice::GetAvailFrames() const
{
snd_pcm_state_t state = snd_pcm_state(hdl);
if (state == SND_PCM_STATE_XRUN)
{
EHS_LOG_INT("Warning", 0, "Buffer overrun/underrun occurred.");
if (snd_pcm_recover(hdl, -EPIPE, 0) < 0)
{
EHS_LOG_INT("Error", 1, "Failed to recover from buffer overrun/underrun.");
return 0;
}
return GetAvailFrames();
}
else if (state == SND_PCM_STATE_PREPARED)
{
if (snd_pcm_start(hdl) < 0)
{
EHS_LOG_INT("Error", 2, "Failed to start audio stream.");
return 0;
}
return GetAvailFrames();
}
snd_pcm_sframes_t frames = snd_pcm_avail_update(hdl);
if (frames < 0)
{
if (frames == -EPIPE)
{
EHS_LOG_INT("Warning", 3, "Buffer overrun/underrun occurred.");
if (snd_pcm_recover(hdl, -EPIPE, 1) < 0)
{
EHS_LOG_INT("Error", 4, "Failed to recover from buffer overrun/underrun.");
return 0;
}
return GetAvailFrames();
}
else
{
EHS_LOG_INT("Error", 5, "Failed to retrieve available frames with error #" + Str_8::FromNum(frames) + ".");
return 0;
}
}
return frames;
}
Byte* AudioDevice::Map(UInt_64* offset, UInt_64* frames)
{
const snd_pcm_channel_area_t* areas;
if (snd_pcm_mmap_begin(hdl, &areas, offset, frames) < 0)
{
EHS_LOG_INT("Error", 0, "Failed to map audio buffer.");
return nullptr;
}
return (Byte*)areas->addr + areas->first / 8;
}
void AudioDevice::UnMap(const UInt_64 offset, const UInt_64 frames)
{
snd_pcm_sframes_t committed = snd_pcm_mmap_commit(hdl, offset, frames);
if (committed < 0)
{
EHS_LOG_INT("Error", 0, "Failed to commit mapped audio buffer.");
return;
}
}
bool AudioDevice::IsValid() const
{
return hdl;
}
AudioDevice AudioDevice::GetDefault(const AudioDeviceType type)
{
AudioDevice result;
snd_pcm_stream_t rType;
if (type == AudioDeviceType::INPUT)
{
rType = SND_PCM_STREAM_CAPTURE;
}
else if (type == AudioDeviceType::OUTPUT)
{
rType = SND_PCM_STREAM_PLAYBACK;
}
else
{
EHS_LOG_INT("Error", 0, "Wrong value for the audio device type.");
return {};
}
snd_pcm_open(&result.hdl, "default", rType, SND_PCM_NONBLOCK);
result.type = AudioDeviceType::OUTPUT;
return result;
}
Array<AudioDevice> AudioDevice::Get(const AudioDeviceType type, const AudioDeviceState state)
{
return {};
}
}

View File

@@ -0,0 +1,581 @@
#include "io/audio/AudioDevice_W32.h"
#include "ehs/Log.h"
namespace ehs
{
AudioDevice::~AudioDevice()
{
if (hdl)
{
hdl->Release();
hdl = nullptr;
}
}
AudioDevice::AudioDevice()
: hdl(nullptr), client(nullptr), playbackClient(nullptr), captureClient(nullptr)
{
}
AudioDevice::AudioDevice(AudioDevice&& device) noexcept
: BaseAudioDevice(device), hdl(device.hdl), client(device.client), playbackClient(device.playbackClient),
captureClient(device.captureClient)
{
device.hdl = nullptr;
device.client = nullptr;
device.playbackClient = nullptr;
device.captureClient = nullptr;
}
AudioDevice::AudioDevice(const AudioDevice& device)
: BaseAudioDevice(device), hdl(nullptr), client(nullptr), playbackClient(nullptr),
captureClient(nullptr)
{
}
AudioDevice& AudioDevice::operator=(AudioDevice&& device) noexcept
{
if (this == &device)
return *this;
BaseAudioDevice::operator=(device);
hdl = device.hdl;
client = device.client;
playbackClient = device.playbackClient;
captureClient = device.captureClient;
device.hdl = nullptr;
device.client = nullptr;
device.playbackClient = nullptr;
device.captureClient = nullptr;
return *this;
}
AudioDevice& AudioDevice::operator=(const AudioDevice& device)
{
if (this == &device)
return *this;
BaseAudioDevice::operator=(device);
hdl = nullptr;
client = nullptr;
playbackClient = nullptr;
captureClient = nullptr;
return *this;
}
void AudioDevice::Release()
{
if (captureClient)
{
captureClient->Release();
captureClient = nullptr;
}
if (playbackClient)
{
playbackClient->Release();
playbackClient = nullptr;
}
if (hdl)
{
HRESULT r = client->Stop();
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to stop audio with error #" + Str_8::FromNum(r) + ".");
return;
}
hdl->Release();
hdl = nullptr;
}
}
void AudioDevice::OpenStream()
{
if (streaming)
return;
HRESULT r = hdl->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, (void**)&client);
if (FAILED(r))
EHS_LOG_INT("Error", 0, "Failed to create audio client with error #" + Str_8::FromNum(r) + ".");
WAVEFORMATEXTENSIBLE* format;
client->GetMixFormat((WAVEFORMATEX**)&format);
if (bitDepth)
{
if (dataType == DataType::FLOAT)
format->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
else
format->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
format->Format.wBitsPerSample = bitDepth;
}
else
{
if (format->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
dataType = DataType::FLOAT;
else
dataType = FromAudioBitDepth(format->Format.wBitsPerSample);
bitDepth = format->Format.wBitsPerSample;
}
if (sampleRate)
format->Format.nSamplesPerSec = sampleRate;
else
sampleRate = format->Format.nSamplesPerSec;
if (channels)
format->Format.nChannels = channels;
else
channels = format->Format.nChannels;
format->Format.nBlockAlign = bitDepth / 8 * channels;
format->Format.nAvgBytesPerSec = format->Format.nBlockAlign * sampleRate;
WAVEFORMATEX* match = {};
r = client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*)format, &match);
if (FAILED(r))
{
if (r == AUDCLNT_E_UNSUPPORTED_FORMAT)
{
EHS_LOG_INT("Error", 1,
"The audio device, \"" + GetName_8() + "\" doesn't support the format {" +
Str_8::FromNum(format->Format.wBitsPerSample) + "-bit, " +
Str_8::FromNum(format->Format.nSamplesPerSec) + "Hz, " +
Str_8::FromNum(format->Format.nChannels) + " Channels}."
);
}
else
EHS_LOG_INT("Error", 2, "Failed to retrieve supported audio format with error #" + Str_8::FromNum(r) + ".");
return;
}
if (match)
{
EHS_LOG_INT("Error", 3,
"The audio device, \"" + GetName_8() + "\" doesn't support the format {" +
Str_8::FromNum(format->Format.wBitsPerSample) + "-bit, " +
Str_8::FromNum(format->Format.nSamplesPerSec) + "Hz, " +
Str_8::FromNum(format->Format.nChannels) + " Channels}. Closest format, {" +
Str_8::FromNum(match->wBitsPerSample) + "-bit Max, " +
Str_8::FromNum(match->nSamplesPerSec) + "Hz Max, " +
Str_8::FromNum(match->nChannels) + " Channels Min}."
);
return;
}
r = client->Initialize(
AUDCLNT_SHAREMODE_SHARED,
0,
latency * 10,
period * 10,
(WAVEFORMATEX*)format,
nullptr
);
if (r == AUDCLNT_E_ALREADY_INITIALIZED)
{
EHS_LOG_INT("Error", 5, "Audio client is already initialized.");
return;
}
else if (r == AUDCLNT_E_WRONG_ENDPOINT_TYPE)
{
EHS_LOG_INT("Error", 6, "The AUDCLNT_STREAMFLAGS_LOOPBACK flag is set but the endpoint device is a capture device, not a rendering device.");
return;
}
else if (r == AUDCLNT_E_BUFFER_SIZE_ERROR)
{
EHS_LOG_INT("Error", 7, "Indicates that the buffer duration value requested by an exclusive-mode client is out of range. The requested duration value for pull mode must not be greater than 5000 milliseconds; for push mode the duration value must not be greater than 2 seconds.");
return;
}
else if (r == AUDCLNT_E_CPUUSAGE_EXCEEDED)
{
EHS_LOG_INT("Error", 8, "The audio endpoint device has been unplugged, or the audio hardware or associated hardware resources have been reconfigured, disabled, removed, or otherwise made unavailable for use.");
return;
}
else if (r == AUDCLNT_E_DEVICE_IN_USE)
{
EHS_LOG_INT("Error", 9, "The endpoint device is already in use. Either the device is being used in exclusive mode, or the device is being used in shared mode and the caller asked to use the device in exclusive mode.");
return;
}
else if (r == AUDCLNT_E_ENDPOINT_CREATE_FAILED)
{
EHS_LOG_INT("Error", 10, "The method failed to create the audio endpoint for the render or the capture device. This can occur if the audio endpoint device has been unplugged, or the audio hardware or associated hardware resources have been reconfigured, disabled, removed, or otherwise made unavailable for use.");
return;
}
else if (r == AUDCLNT_E_INVALID_DEVICE_PERIOD)
{
EHS_LOG_INT("Error", 11, "Indicates that the device period requested by an exclusive-mode client is greater than 5000 milliseconds.");
return;
}
else if (r == AUDCLNT_E_UNSUPPORTED_FORMAT)
{
EHS_LOG_INT("Error", 12, "The audio engine (shared mode) or audio endpoint device (exclusive mode) does not support the specified format.");
return;
}
else if (r == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED)
{
EHS_LOG_INT("Error", 13, "The caller is requesting exclusive-mode use of the endpoint device, but the user has disabled exclusive-mode use of the device.");
return;
}
else if (r == AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL)
{
EHS_LOG_INT("Error", 14, "The AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag is set but parameters hnsBufferDuration and hnsPeriodicity are not equal.");
return;
}
else if (r == AUDCLNT_E_SERVICE_NOT_RUNNING)
{
EHS_LOG_INT("Error", 15, "The Windows audio service is not running.");
return;
}
else if (r == E_POINTER)
{
EHS_LOG_INT("Error", 16, "Parameter pFormat is NULL.");
return;
}
else if (r == E_INVALIDARG)
{
EHS_LOG_INT("Error", 17, "Parameter pFormat points to an invalid format description; or the AUDCLNT_STREAMFLAGS_LOOPBACK flag is set but ShareMode is not equal to AUDCLNT_SHAREMODE_SHARED; or the AUDCLNT_STREAMFLAGS_CROSSPROCESS flag is set but ShareMode is equal to AUDCLNT_SHAREMODE_EXCLUSIVE.\n"
"A prior call to SetClientProperties was made with an invalid category for audio/render streams.");
return;
}
else if (r == E_OUTOFMEMORY)
{
EHS_LOG_INT("Error", 18, "Out of memory.");
return;
}
else if (FAILED(r))
{
EHS_LOG_INT("Error", 19, "Failed to initialize audio stream with error #" + Str_8::FromNum(r) + ".");
return;
}
if (type == AudioDeviceType::OUTPUT)
{
r = client->GetService(__uuidof(IAudioRenderClient), (void**)&playbackClient);
if (FAILED(r))
{
EHS_LOG_INT("Error", 27, "Failed to retrieve audio render client with error #" + Str_8::FromNum(r) + ".");
return;
}
}
else if (type == AudioDeviceType::INPUT)
{
r = client->GetService(__uuidof(IAudioCaptureClient), (void**)&captureClient);
if (FAILED(r))
{
EHS_LOG_INT("Error", 28, "Failed to retrieve audio capture client with error #" + Str_8::FromNum(r) + ".");
return;
}
}
r = client->GetBufferSize((UINT32*)&maxFrames);
if (FAILED(r))
{
EHS_LOG_INT("Error", 29, "Failed to retrieve buffer size with error #" + Str_8::FromNum(r) + ".");
return;
}
r = client->Start();
if (FAILED(r))
{
EHS_LOG_INT("Error", 30, "Failed to start audio with error #" + Str_8::FromNum(r) + ".");
return;
}
streaming = true;
}
void AudioDevice::CloseStream()
{
if (!streaming)
return;
if (playbackClient)
{
playbackClient->Release();
playbackClient = nullptr;
}
if (captureClient)
{
captureClient->Release();
captureClient = nullptr;
}
if (hdl)
{
HRESULT r = client->Stop();
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to stop audio with error #" + Str_8::FromNum(r) + ".");
return;
}
client->Release();
client = nullptr;
}
streaming = false;
}
UInt_64 AudioDevice::GetAvailFrames() const
{
if (!IsValid() || !streaming)
return 0;
UInt_32 sampleSize = 0;
if (playbackClient)
{
HRESULT r = client->GetCurrentPadding(&sampleSize);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 1, "Failed to retrieve samples padding with error #" + Str_8::FromNum(r) + ".");
sampleSize = maxFrames - sampleSize;
}
else if (captureClient)
{
HRESULT r = captureClient->GetNextPacketSize(&sampleSize);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 1, "Failed to retrieve samples size with error #" + Str_8::FromNum(r) + ".");
}
return sampleSize;
}
Byte* AudioDevice::Map(UInt_64* offset, UInt_64* frames)
{
Byte* buffer = nullptr;
if (!IsValid())
return buffer;
HRESULT r = client->GetCurrentPadding((UINT32*)&offset);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 1, "Failed to retrieve samples padding with error #" + Str_8::FromNum(r) + ".");
if (playbackClient)
{
r = playbackClient->GetBuffer(*frames, &buffer);
if (r == AUDCLNT_E_BUFFER_TOO_LARGE)
EHS_LOG_INT("Error", 0, "The given frame size, " + Str_8::FromNum(*frames) + ", must be less than or equal to, " + Str_8::FromNum(maxFrames - *offset) + ".");
else if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 1, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 2, "Failed to retrieve buffer with error #" + Str_8::FromNum(r) + ".");
}
else if (captureClient)
{
UInt_32 flags = 0;
r = captureClient->GetBuffer(&buffer, (UINT32*)frames, (DWORD*)&flags, nullptr, nullptr);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 1, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 2, "Failed to retrieve buffer with error #" + Str_8::FromNum(r) + ".");
}
return buffer;
}
void AudioDevice::UnMap(const UInt_64 offset, const UInt_64 frames)
{
if (!IsValid() || !streaming)
return;
if (playbackClient)
{
HRESULT r = playbackClient->ReleaseBuffer(frames, 0);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 1, "Failed to release buffer with error #" + Str_8::FromNum(r) + ".");
}
else if (captureClient)
{
HRESULT r = captureClient->ReleaseBuffer(frames);
if (r == AUDCLNT_E_DEVICE_INVALIDATED)
EHS_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
EHS_LOG_INT("Error", 1, "Failed to release buffer with error #" + Str_8::FromNum(r) + ".");
}
}
Str_32 AudioDevice::GetInterfaceName_32() const
{
return UTF::To_32(GetInterfaceName_16());
}
Str_16 AudioDevice::GetInterfaceName_16() const
{
IPropertyStore* pProps = nullptr;
HRESULT r = hdl->OpenPropertyStore(STGM_READ, &pProps);
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to retrieve interface name with error #" + Str_8::FromNum(r) + ".");
return nullptr;
}
PROPVARIANT varName = {};
PropVariantInit(&varName);
pProps->GetValue(PKEY_DeviceInterface_FriendlyName, &varName);
Str_16 name((wchar_t*)varName.pwszVal);
PropVariantClear(&varName);
pProps->Release();
return name;
}
Str_8 AudioDevice::GetInterfaceName_8() const
{
return UTF::To_8(GetInterfaceName_16());
}
Str_32 AudioDevice::GetName_32() const
{
return UTF::To_32(GetName_16());
}
Str_16 AudioDevice::GetName_16() const
{
IPropertyStore* pProps = nullptr;
HRESULT r = hdl->OpenPropertyStore(STGM_READ, &pProps);
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to retrieve name with error #" + Str_8::FromNum(r) + ".");
return nullptr;
}
PROPVARIANT varName = {};
PropVariantInit(&varName);
pProps->GetValue(PKEY_Device_FriendlyName, &varName);
Str_16 name((wchar_t*)varName.pwszVal);
PropVariantClear(&varName);
pProps->Release();
return name;
}
Str_8 AudioDevice::GetName_8() const
{
return UTF::To_8(GetName_16());
}
bool AudioDevice::IsValid() const
{
return hdl;
}
AudioDevice AudioDevice::GetDefault(const AudioDeviceType type)
{
AudioDevice result;
HRESULT r = CoInitialize(nullptr);
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to initialize COM with error #" + Str_8::FromNum(r) + ".");
return result;
}
IMMDeviceEnumerator* enumerator = nullptr;
r = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&enumerator);
if (FAILED(r))
{
EHS_LOG_INT("Error", 1, "Failed to initialize WASAPI with error #" + Str_8::FromNum(r) + ".");
return result;
}
IMMDevice* deviceHdl = nullptr;
r = enumerator->GetDefaultAudioEndpoint((EDataFlow)type, eConsole, &deviceHdl);
if (FAILED(r))
{
EHS_LOG_INT("Error", 2, "Failed to retrieve default audio output device with error #" + Str_8::FromNum(r) + ".");
return result;
}
result.hdl = deviceHdl;
result.type = type;
enumerator->Release();
return result;
}
Array<AudioDevice> AudioDevice::Get(const AudioDeviceType type, const AudioDeviceState state)
{
Array<AudioDevice> devices;
HRESULT r = CoInitialize(nullptr);
if (FAILED(r))
{
EHS_LOG_INT("Error", 0, "Failed to initialize COM with error #" + Str_8::FromNum(r) + ".");
return devices;
}
IMMDeviceEnumerator* enumerator = nullptr;
r = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&enumerator);
if (FAILED(r))
{
EHS_LOG_INT("Error", 1, "Failed to initialize WASAPI with error #" + Str_8::FromNum(r) + ".");
return devices;
}
IMMDeviceCollection* collection = nullptr;
r = enumerator->EnumAudioEndpoints((EDataFlow)type, (DWORD)state, &collection);
if (FAILED(r))
{
EHS_LOG_INT("Error", 2, "Failed to retrieve audio device collection with error #" + Str_8::FromNum(r) + ".");
return devices;
}
UInt_32 count = 0;
r = collection->GetCount((UINT*)&count);
if (FAILED(r))
{
EHS_LOG_INT("Error", 3, "Failed to retrieve audio device count with error #" + Str_8::FromNum(r) + ".");
return devices;
}
devices.Resize(count);
for (UInt_32 i = 0; i < count; ++i)
{
IMMDevice* deviceHdl = nullptr;
r = collection->Item(i, &deviceHdl);
if (FAILED(r))
{
EHS_LOG_INT("Error", 4, "Failed to retrieve audio device with error #" + Str_8::FromNum(r) + ".");
return devices;
}
devices[i].hdl = deviceHdl;
devices[i].type = type;
}
enumerator->Release();
return devices;
}
}

View File

@@ -0,0 +1,171 @@
#include "ehs/io/audio/BaseAudioDevice.h"
namespace ehs
{
BaseAudioDevice::BaseAudioDevice()
: type(AudioDeviceType::ALL), dataType(DataType::SINT_8), bitDepth(0), sampleRate(0), channels(0),
period(20000), latency(150000), maxFrames(0), streaming(false)
{
}
BaseAudioDevice::BaseAudioDevice(const BaseAudioDevice& device)
: type(device.type), dataType(device.dataType), bitDepth(device.bitDepth), sampleRate(device.sampleRate),
channels(device.channels), period(device.period), latency(device.latency), maxFrames(0), streaming(false)
{
}
BaseAudioDevice& BaseAudioDevice::operator=(const BaseAudioDevice& device)
{
if (this == &device)
return *this;
type = device.type;
dataType = device.dataType;
bitDepth = device.bitDepth;
sampleRate = device.sampleRate;
channels = device.channels;
period = device.period;
latency = device.latency;
maxFrames = device.maxFrames;
streaming = false;
return *this;
}
void BaseAudioDevice::Release()
{
}
void BaseAudioDevice::OpenStream()
{
}
void BaseAudioDevice::CloseStream()
{
}
UInt_64 BaseAudioDevice::GetAvailFrames() const
{
return 0;
}
Byte* BaseAudioDevice::Map(UInt_64* offset, UInt_64* frames)
{
return nullptr;
}
void BaseAudioDevice::UnMap(const UInt_64 offset, const UInt_64 frames)
{
}
AudioDeviceType BaseAudioDevice::GetType() const
{
return type;
}
void BaseAudioDevice::SetDataType(const DataType newDataType)
{
if (streaming)
return;
dataType = newDataType;
bitDepth = ToBitDepth(newDataType);
}
DataType BaseAudioDevice::GetDataType() const
{
return dataType;
}
UInt_8 BaseAudioDevice::GetByteDepth() const
{
return bitDepth / 8;
}
UInt_16 BaseAudioDevice::GetBitDepth() const
{
return bitDepth;
}
void BaseAudioDevice::SetSampleRate(const UInt_32 newSampleRate)
{
if (streaming)
return;
sampleRate = newSampleRate;
}
UInt_32 BaseAudioDevice::GetSampleRate() const
{
return sampleRate;
}
void BaseAudioDevice::SetChannels(const UInt_32 newChannels)
{
if (streaming)
return;
channels = newChannels;
}
UInt_16 BaseAudioDevice::GetChannels() const
{
return channels;
}
UInt_32 BaseAudioDevice::GetFrameSize() const
{
return bitDepth / 8 * channels;
}
void BaseAudioDevice::SetPeriod(const UInt_32 newPeriod)
{
if (streaming)
return;
period = newPeriod;
}
UInt_32 BaseAudioDevice::GetPeriod() const
{
return period;
}
void BaseAudioDevice::SetLatency(const UInt_32 newLatency)
{
if (streaming)
return;
latency = newLatency;
}
UInt_32 BaseAudioDevice::GetLatency() const
{
return latency;
}
UInt_64 BaseAudioDevice::GetMaxFrames() const
{
return maxFrames;
}
bool BaseAudioDevice::IsStreaming() const
{
return streaming;
}
bool BaseAudioDevice::IsValid() const
{
return false;
}
BaseAudioDevice BaseAudioDevice::GetDefault(const AudioDeviceType type)
{
return {};
}
Array<BaseAudioDevice> BaseAudioDevice::Get(const AudioDeviceType type, const AudioDeviceState state)
{
return {};
}
}

50
src/io/hid/Button.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "ehs/io/hid/Button.h"
namespace ehs
{
Button::Button()
: hash(0)
{
}
Button::Button(const Str_8& name)
: name(name), hash(name.Hash_32())
{
}
Button::Button(const Button& key)
: name(key.name), hash(key.hash)
{
}
Button& Button::operator=(const Button& key)
{
if (this == &key)
return *this;
name = key.name;
hash = key.hash;
return *this;
}
bool Button::operator==(const Button& key) const
{
return key.hash == hash;
}
bool Button::operator!=(const Button& key) const
{
return key.hash != hash;
}
Str_8 Button::GetName() const
{
return name;
}
UInt_32 Button::GetHash() const
{
return hash;
}
}

View File

@@ -0,0 +1,87 @@
#include "ehs/io/hid/ButtonState.h"
namespace ehs
{
ButtonState::ButtonState()
: state(State::RELEASED), pressed(false), threshold(1.0f)
{
}
ButtonState::ButtonState(const Button& button, const State state)
: button(button), state(state), pressed(true), threshold(1.0f)
{
}
ButtonState::ButtonState(const ButtonState& bs)
: button(bs.button), state(bs.state), pressed(bs.pressed), threshold(bs.threshold)
{
}
ButtonState& ButtonState::operator=(const ButtonState& bs)
{
if (this == &bs)
return *this;
button = bs.button;
state = bs.state;
pressed = bs.pressed;
threshold = bs.threshold;
return *this;
}
bool ButtonState::operator==(const Button& other) const
{
return button == other;
}
bool ButtonState::operator!=(const Button& other) const
{
return button != other;
}
bool ButtonState::operator==(const State otherState) const
{
return state == otherState;
}
bool ButtonState::operator!=(const State otherState) const
{
return state != otherState;
}
Button ButtonState::GetButton() const
{
return button;
}
void ButtonState::SetState(State newState)
{
state = newState;
}
State ButtonState::GetState() const
{
return state;
}
void ButtonState::SetPressed(bool value)
{
pressed = value;
}
bool ButtonState::IsPressed() const
{
return pressed;
}
void ButtonState::SetThreshold(const float newThreshold)
{
threshold = newThreshold;
}
float ButtonState::GetThreshold() const
{
return 1.0f;
}
}

296
src/io/hid/HID.cpp Normal file
View File

@@ -0,0 +1,296 @@
#include "ehs/io/hid/HID.h"
namespace ehs
{
HID::HID()
: type(EHS_HID_UNKNOWN), id(0)
{
}
HID::HID(const UInt_8 type, Str_8 name, const UInt_64 id)
: type(type), name((Str_8&&)name), id(id)
{
}
HID::HID(HID&& hid) noexcept
: type(hid.type), name((Str_8&&)hid.name), id(hid.id), states((Array<ButtonState>&&)hid.states)
{
hid.type = EHS_HID_UNKNOWN;
hid.id = 0;
}
HID::HID(const HID& hid)
: type(hid.type), name(hid.name), id(hid.id), states(hid.states)
{
}
HID& HID::operator=(HID&& hid) noexcept
{
if (this == &hid)
return *this;
type = hid.type;
name = (Str_8&&)hid.name;
id = hid.id;
states = (Array<ButtonState>&&)hid.states;
hid.type = EHS_HID_UNKNOWN;
hid.id = 0;
return *this;
}
HID& HID::operator=(const HID& hid)
{
if (this == &hid)
return *this;
type = hid.type;
name = hid.name;
id = hid.id;
states = hid.states;
return *this;
}
bool HID::operator==(const HID& other) const
{
return type == other.type && hashName == other.hashName;
}
bool HID::operator!=(const HID& other) const
{
return type != other.type || hashName != other.hashName;
}
bool HID::operator==(const UInt_64 otherId) const
{
return id == otherId;
}
bool HID::operator!=(const UInt_64 otherId) const
{
return id != otherId;
}
void HID::Poll()
{
for (UInt_64 i = 0; i < states.Size(); ++i)
{
if (states[i].IsPressed())
{
if (states[i].GetState() == State::RELEASED)
states[i].SetState(State::TOUCHED);
else
states[i].SetState(State::PRESSED);
}
else
{
if (states[i].GetState() == State::PRESSED || states[i].GetState() == State::TOUCHED)
states[i].SetState(State::JUST_RELEASED);
else
states[i].SetState(State::RELEASED);
}
}
}
UInt_8 HID::GetType() const
{
return type;
}
Str_8 HID::GetName() const
{
return name;
}
UInt_64 HID::GetId() const
{
return id;
}
void HID::ReleaseAll()
{
for (UInt_64 i = 0; i < states.Size(); ++i)
states[i].SetPressed(false);
}
Vector<const ButtonState*> HID::GetAllTouched() const
{
Vector<const ButtonState*> result(0, states.Size() + 1);
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::TOUCHED)
result.Push(&states[i]);
return result;
}
const ButtonState* HID::IsTouched(const Button& button) const
{
const ButtonState* state = GetState(button);
if (!state || *state != State::TOUCHED)
return nullptr;
return state;
}
const ButtonState* HID::IsTouched() const
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::TOUCHED)
return &states[i];
return nullptr;
}
Vector<const ButtonState*> HID::GetAllDown() const
{
Vector<const ButtonState*> result(0, states.Size() + 1);
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::PRESSED || states[i] == State::TOUCHED)
result.Push(&states[i]);
return result;
}
const ButtonState* HID::IsDown(const Button& button) const
{
const ButtonState* state = GetState(button);
if (!state || (*state != State::PRESSED && *state != State::TOUCHED))
return nullptr;
return state;
}
const ButtonState* HID::IsDown() const
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::PRESSED || states[i] == State::TOUCHED)
return &states[i];
return nullptr;
}
Vector<const ButtonState*> HID::GetAllJustReleased() const
{
Vector<const ButtonState*> result(0, states.Size() + 1);
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::JUST_RELEASED)
result.Push(&states[i]);
return result;
}
const ButtonState* HID::IsJustReleased(const Button& button) const
{
const ButtonState* state = GetState(button);
if (!state || *state != State::JUST_RELEASED)
return nullptr;
return state;
}
const ButtonState* HID::IsJustReleased() const
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::JUST_RELEASED)
return &states[i];
return nullptr;
}
Vector<const ButtonState*> HID::GetAllUp() const
{
Vector<const ButtonState*> result(0, states.Size() + 1);
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::RELEASED || states[i] == State::JUST_RELEASED)
result.Push(&states[i]);
return result;
}
const ButtonState* HID::IsUp(const Button& button) const
{
const ButtonState* state = GetState(button);
if (!state || (*state != State::RELEASED && *state != State::JUST_RELEASED))
return nullptr;
return state;
}
const ButtonState* HID::IsUp() const
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i] == State::RELEASED || states[i] == State::JUST_RELEASED)
return &states[i];
return nullptr;
}
void HID::ButtonDown(const Button& button)
{
if (ButtonState* state = GetState(button); state)
state->SetPressed(true);
else
states.Push(ButtonState(button, State::RELEASED));
}
void HID::ButtonUp(const Button& button)
{
if (ButtonState* state = GetState(button); state)
state->SetPressed(false);
else
states.Push(ButtonState(button, State::JUST_RELEASED));
}
const ButtonState* HID::GetState(const Button& button) const
{
for (UInt_64 i = 0; i < states.Size(); ++i)
if (states[i] == button)
return &states[i];
return nullptr;
}
bool HID::IsValid() const
{
return id;
}
HID* HID::Clone() const
{
return new HID(*this);
}
bool HID::HasState(const Button& button) const
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i].GetButton() == button)
return true;
return false;
}
bool HID::AddState(const ButtonState& state)
{
if (HasState(state.GetButton()))
return false;
states.Push(state);
return true;
}
ButtonState* HID::GetState(const Button& button)
{
for (UInt_64 i = 0; i < states.Size(); i++)
if (states[i].GetButton() == button)
return &states[i];
return nullptr;
}
}

160
src/io/hid/Input.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "ehs/io/hid/Input.h"
namespace ehs
{
Input::~Input()
{
for (UInt_64 i = 0; i < handlers.Size(); i++)
delete handlers[i];
}
Input::Input()
: initalized(false)
{
}
Input::Input(Input&& input) noexcept
: handlers((Array<InputHandler*>&&)input.handlers), initalized(input.initalized)
{
input.initalized = false;
}
Input::Input(const Input& input)
: initalized(false)
{
}
Input& Input::operator=(Input&& input) noexcept
{
if (this == &input)
return *this;
handlers = (Array<InputHandler*>&&)input.handlers;
initalized = input.initalized;
input.initalized = false;
return *this;
}
Input& Input::operator=(const Input& input)
{
if (this == &input)
return *this;
for (UInt_64 i = 0; i < handlers.Size(); i++)
delete handlers;
handlers = Array<InputHandler*>();
initalized = false;
return *this;
}
void Input::Initialize()
{
if (initalized)
return;
UInt_64 i = 0;
while (i < handlers.Size())
{
if (!handlers[i]->Initialize())
{
if (i != handlers.Size() - 1)
handlers.Swap(i, handlers.End());
delete handlers.Pop();
continue;
}
i++;
}
initalized = true;
}
void Input::Release()
{
if (!initalized)
return;
UInt_64 i = 0;
while (i < handlers.Size())
{
if (!handlers[i]->Release())
{
if (i != handlers.Size() - 1)
handlers.Swap(i, handlers.End());
delete handlers.Pop();
continue;
}
i++;
}
initalized = false;
}
void Input::Poll()
{
for (UInt_64 i = 0; i < handlers.Size(); i++)
handlers[i]->Poll();
}
bool Input::HasHandler(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < handlers.Size(); i++)
if (*handlers[i] == hashId)
return true;
return false;
}
bool Input::HasHandler(const Str_8& id) const
{
return HasHandler(id.Hash_64());
}
bool Input::AddHandler(InputHandler* handler)
{
if (HasHandler(handler->GetHashId()))
return false;
if (initalized)
{
bool hInitialized = handler->Initialize();
if (!hInitialized)
{
delete handler;
return false;
}
}
handlers.Push(handler);
return true;
}
const InputHandler* Input::GetHandler(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < handlers.Size(); i++)
if (*handlers[i] == hashId)
return handlers[i];
return nullptr;
}
const InputHandler* Input::GetHandler(const Str_8& id) const
{
return GetHandler(id.Hash_64());
}
bool Input::IsInitialized() const
{
return initalized;
}
}

160
src/io/hid/InputHandler.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "ehs/io/hid/InputHandler.h"
namespace ehs
{
InputHandler::~InputHandler()
{
for (UInt_64 i = 0; i < devices.Size(); i++)
delete devices[i];
}
InputHandler::InputHandler()
: hashId(0)
{
}
InputHandler::InputHandler(Str_8 id)
: hashId(id.Hash_64()), id((Str_8&&)id)
{
}
InputHandler::InputHandler(InputHandler&& ih) noexcept
: hashId(ih.hashId), id((Str_8&&)ih.id), devices((Array<HID*>&&)ih.devices)
{
ih.hashId = 0;
}
InputHandler::InputHandler(const InputHandler& ih)
: hashId(ih.hashId), id(ih.id), devices(ih.devices.Size())
{
for (UInt_64 i = 0; i < devices.Size(); i++)
devices[i] = ih.devices[i]->Clone();
}
InputHandler& InputHandler::operator=(InputHandler&& ih) noexcept
{
if (this == &ih)
return *this;
hashId = ih.hashId;
id = (Str_8&&)ih.id;
devices = (Array<HID*>&&)ih.devices;
ih.hashId = 0;
return *this;
}
InputHandler& InputHandler::operator=(const InputHandler& ih)
{
if (this == &ih)
return *this;
for (UInt_64 i = 0; i < devices.Size(); i++)
delete devices[i];
hashId = ih.hashId;
id = ih.id;
devices = Array<HID*>(ih.devices.Size());
for (UInt_64 i = 0; i < devices.Size(); i++)
devices[i] = ih.devices[i]->Clone();
return *this;
}
bool InputHandler::operator==(const UInt_64 otherHashId)
{
return hashId == otherHashId;
}
bool InputHandler::operator!=(const UInt_64 otherHashId)
{
return hashId != otherHashId;
}
bool InputHandler::Initialize()
{
if (IsInitialized())
return false;
return true;
}
bool InputHandler::Release()
{
if (!IsInitialized())
return false;
for (UInt_64 i = 0; i < devices.Size(); i++)
delete devices[i];
devices.Clear();
return true;
}
void InputHandler::Poll()
{
for (UInt_64 i = 0; i < devices.Size(); i++)
devices[i]->Poll();
}
UInt_64 InputHandler::GetHashId() const
{
return hashId;
}
Str_8 InputHandler::GetId() const
{
return id;
}
void InputHandler::ResetAllStates()
{
for (UInt_64 i = 0; i < devices.Size(); i++)
devices[i]->ReleaseAll();
}
bool InputHandler::HasDevice(const UInt_64 id) const
{
for (UInt_64 i = 0; i < devices.Size(); i++)
if (*devices[i] == id)
return true;
return false;
}
bool InputHandler::AddDevice(HID* device)
{
if (HasDevice(device->GetId()))
return false;
devices.Push(device);
return true;
}
HID* InputHandler::GetDevice(const UInt_64 id) const
{
for (UInt_64 i = 0; i < devices.Size(); i++)
if (*devices[i] == id)
return devices[i];
return nullptr;
}
HID* InputHandler::GetDeviceByType(const UInt_8 type) const
{
for (UInt_64 i = 0; i < devices.Size(); i++)
if (devices[i]->GetType() == type)
return devices[i];
return nullptr;
}
bool InputHandler::IsInitialized() const
{
return false;
}
}

507
src/io/hid/Keyboard.cpp Normal file
View File

@@ -0,0 +1,507 @@
#include "ehs/io/hid/Keyboard.h"
namespace ehs
{
Keyboard::Keyboard()
{
}
Keyboard::Keyboard(Str_8 name, const UInt_64 id)
: HID(EHS_HID_KEYBOARD, (Str_8&&)name, id)
{
}
Keyboard::Keyboard(const Keyboard& hid)
: HID(hid)
{
}
Keyboard& Keyboard::operator=(const Keyboard& hid)
{
if (this == &hid)
return *this;
HID::operator=(hid);
return *this;
}
void Keyboard::Poll()
{
HID::Poll();
}
Keyboard* Keyboard::Clone() const
{
return new Keyboard(*this);
}
const Button Keyboard::Unknown("Unknown");
const Button Keyboard::Escape("Escape Button");
const Button Keyboard::Backspace("Backspace Button");
const Button Keyboard::Enter("Enter Button");
const Button Keyboard::LShift("Left Shift Button");
const Button Keyboard::RShift("Right Shift Button");
const Button Keyboard::LAlt("Left Alt Button");
const Button Keyboard::RAlt("Right Alt Button");
const Button Keyboard::LCtrl("Left Control Button");
const Button Keyboard::RCtrl("Right Control Button");
const Button Keyboard::Space("Space Button");
const Button Keyboard::A("A Button");
const Button Keyboard::B("B Button");
const Button Keyboard::C("C Button");
const Button Keyboard::D("D Button");
const Button Keyboard::E("E Button");
const Button Keyboard::F("F Button");
const Button Keyboard::G("G Button");
const Button Keyboard::H("H Button");
const Button Keyboard::I("I Button");
const Button Keyboard::J("J Button");
const Button Keyboard::K("K Button");
const Button Keyboard::L("L Button");
const Button Keyboard::M("M Button");
const Button Keyboard::N("N Button");
const Button Keyboard::O("O Button");
const Button Keyboard::P("P Button");
const Button Keyboard::Q("Q Button");
const Button Keyboard::R("R Button");
const Button Keyboard::S("S Button");
const Button Keyboard::T("T Button");
const Button Keyboard::U("U Button");
const Button Keyboard::V("V Button");
const Button Keyboard::W("W Button");
const Button Keyboard::X("X Button");
const Button Keyboard::Y("Y Button");
const Button Keyboard::Z("Z Button");
const Button Keyboard::One("One Button");
const Button Keyboard::Two("Two Button");
const Button Keyboard::Three("Three Button");
const Button Keyboard::Four("Four Button");
const Button Keyboard::Five("Five Button");
const Button Keyboard::Six("Six Button");
const Button Keyboard::Seven("Seven Button");
const Button Keyboard::Eight("Eight Button");
const Button Keyboard::Nine("Nine Button");
const Button Keyboard::Zero("Zero Button");
const Button Keyboard::Equals("Equals Button");
const Button Keyboard::Minus("Minus Button");
const Button Keyboard::Tilde("Tilde Button");
const Button Keyboard::BackSlash("Back Slash Button");
const Button Keyboard::LeftSquareBracket("Left Square Bracket Button");
const Button Keyboard::RightSquareBracket("Right Square Bracket Button");
const Button Keyboard::SemiColon("Semi-Colon Button");
const Button Keyboard::Apostrophe("Apostrophe Button");
const Button Keyboard::Comma("Comma Button");
const Button Keyboard::Period("Period Button");
const Button Keyboard::ForwardSlash("Forward Slash Button");
const Button Keyboard::F1("Function 1 Button");
const Button Keyboard::F2("Function 2 Button");
const Button Keyboard::F3("Function 3 Button");
const Button Keyboard::F4("Function 4 Button");
const Button Keyboard::F5("Function 5 Button");
const Button Keyboard::F6("Function 6 Button");
const Button Keyboard::F7("Function 7 Button");
const Button Keyboard::F8("Function 8 Button");
const Button Keyboard::F9("Function 9 Button");
const Button Keyboard::F10("Function 10 Button");
const Button Keyboard::F11("Function 11 Button");
const Button Keyboard::F12("Function 12 Button");
const Button Keyboard::F13("Function 13 Button");
const Button Keyboard::F14("Function 14 Button");
const Button Keyboard::F15("Function 15 Button");
const Button Keyboard::F16("Function 16 Button");
const Button Keyboard::F17("Function 17 Button");
const Button Keyboard::F18("Function 18 Button");
const Button Keyboard::F19("Function 19 Button");
const Button Keyboard::F20("Function 20 Button");
const Button Keyboard::F21("Function 21 Button");
const Button Keyboard::F22("Function 22 Button");
const Button Keyboard::F23("Function 23 Button");
const Button Keyboard::F24("Function 24 Button");
const Button Keyboard::Left("Left Arrow Button");
const Button Keyboard::Right("Right Arrow Button");
const Button Keyboard::Up("Up Arrow Button");
const Button Keyboard::Down("Down Arrow Button");
Button Keyboard::TranslateScanCode(const UInt_32 code)
{
switch (code)
{
case 1:
return Keyboard::Escape;
case 14:
return Keyboard::Backspace;
case 28:
return Keyboard::Enter;
case 0x2A:
return Keyboard::LShift;
case 0x36:
return Keyboard::RShift;
case 56:
return Keyboard::LAlt;
case 100:
return Keyboard::RAlt;
case 29:
return Keyboard::LCtrl;
case 97:
return Keyboard::RCtrl;
case 57:
return Keyboard::Space;
case 30:
return Keyboard::A;
case 48:
return Keyboard::B;
case 46:
return Keyboard::C;
case 32:
return Keyboard::D;
case 18:
return Keyboard::E;
case 33:
return Keyboard::F;
case 34:
return Keyboard::G;
case 35:
return Keyboard::H;
case 23:
return Keyboard::I;
case 36:
return Keyboard::J;
case 37:
return Keyboard::K;
case 38:
return Keyboard::L;
case 50:
return Keyboard::M;
case 49:
return Keyboard::N;
case 24:
return Keyboard::O;
case 25:
return Keyboard::P;
case 16:
return Keyboard::Q;
case 19:
return Keyboard::R;
case 31:
return Keyboard::S;
case 20:
return Keyboard::T;
case 22:
return Keyboard::U;
case 47:
return Keyboard::V;
case 17:
return Keyboard::W;
case 45:
return Keyboard::X;
case 21:
return Keyboard::Y;
case 44:
return Keyboard::Z;
case 2:
return Keyboard::One;
case 3:
return Keyboard::Two;
case 4:
return Keyboard::Three;
case 5:
return Keyboard::Four;
case 6:
return Keyboard::Five;
case 7:
return Keyboard::Six;
case 8:
return Keyboard::Seven;
case 9:
return Keyboard::Eight;
case 10:
return Keyboard::Nine;
case 11:
return Keyboard::Zero;
case 12:
return Keyboard::Minus;
case 13:
return Keyboard::Equals;
case 41:
return Keyboard::Tilde;
case 43:
return Keyboard::BackSlash;
case 26:
return Keyboard::LeftSquareBracket;
case 27:
return Keyboard::RightSquareBracket;
case 39:
return Keyboard::SemiColon;
case 40:
return Keyboard::Apostrophe;
case 51:
return Keyboard::Comma;
case 52:
return Keyboard::Period;
case 53:
return Keyboard::ForwardSlash;
case 59:
return Keyboard::F1;
case 60:
return Keyboard::F2;
case 61:
return Keyboard::F3;
case 62:
return Keyboard::F4;
case 63:
return Keyboard::F5;
case 64:
return Keyboard::F6;
case 65:
return Keyboard::F7;
case 66:
return Keyboard::F8;
case 67:
return Keyboard::F9;
case 68:
return Keyboard::F10;
case 69:
return Keyboard::F11;
case 70:
return Keyboard::F12;
case 71:
return Keyboard::F13;
case 72:
return Keyboard::F14;
case 73:
return Keyboard::F15;
case 74:
return Keyboard::F16;
case 75:
return Keyboard::F17;
case 76:
return Keyboard::F18;
case 77:
return Keyboard::F19;
case 78:
return Keyboard::F20;
case 79:
return Keyboard::F21;
case 80:
return Keyboard::F22;
case 81:
return Keyboard::F23;
case 82:
return Keyboard::F24;
case 105:
return Keyboard::Left;
case 106:
return Keyboard::Right;
case 103:
return Keyboard::Up;
case 108:
return Keyboard::Down;
default:
return Keyboard::Unknown;
}
}
Char_8 Keyboard::TranslateToEnglish_8(const bool shifted, const Button& button)
{
if (shifted)
{
if (button == A)
return 'A';
else if (button == B)
return 'B';
else if (button == C)
return 'C';
else if (button == D)
return 'D';
else if (button == E)
return 'E';
else if (button == F)
return 'F';
else if (button == G)
return 'G';
else if (button == H)
return 'H';
else if (button == I)
return 'I';
else if (button == J)
return 'J';
else if (button == K)
return 'K';
else if (button == L)
return 'L';
else if (button == M)
return 'M';
else if (button == N)
return 'N';
else if (button == O)
return 'O';
else if (button == P)
return 'P';
else if (button == Q)
return 'Q';
else if (button == Q)
return 'R';
else if (button == S)
return 'S';
else if (button == T)
return 'T';
else if (button == U)
return 'U';
else if (button == V)
return 'V';
else if (button == W)
return 'W';
else if (button == X)
return 'X';
else if (button == Y)
return 'Y';
else if (button == Z)
return 'Z';
else if (button == Two)
return '@';
else if (button == Three)
return '#';
else if (button == Four)
return '$';
else if (button == Five)
return '%';
else if (button == Six)
return '^';
else if (button == Seven)
return '&';
else if (button == Eight)
return '*';
else if (button == Nine)
return '(';
else if (button == Zero)
return ')';
else if (button == One)
return '!';
else if (button == Minus)
return '_';
else if (button == Equals)
return '+';
else if (button == Tilde)
return '~';
else if (button == BackSlash)
return '|';
else if (button == LeftSquareBracket)
return '{';
else if (button == RightSquareBracket)
return '}';
else if (button == SemiColon)
return ':';
else if (button == Apostrophe)
return '"';
else if (button == Comma)
return '<';
else if (button == Period)
return '>';
else if (button == ForwardSlash)
return '?';
}
else
{
if (button == A)
return 'a';
else if (button == B)
return 'b';
else if (button == C)
return 'c';
else if (button == D)
return 'd';
else if (button == E)
return 'e';
else if (button == F)
return 'f';
else if (button == G)
return 'g';
else if (button == H)
return 'h';
else if (button == I)
return 'i';
else if (button == J)
return 'j';
else if (button == K)
return 'k';
else if (button == L)
return 'l';
else if (button == M)
return 'm';
else if (button == N)
return 'n';
else if (button == O)
return 'o';
else if (button == P)
return 'p';
else if (button == Q)
return 'q';
else if (button == R)
return 'r';
else if (button == S)
return 's';
else if (button == T)
return 't';
else if (button == U)
return 'u';
else if (button == V)
return 'v';
else if (button == W)
return 'w';
else if (button == X)
return 'x';
else if (button == Y)
return 'y';
else if (button == Z)
return 'z';
else if (button == One)
return '1';
else if (button == Two)
return '2';
else if (button == Three)
return '3';
else if (button == Four)
return '4';
else if (button == Five)
return '5';
else if (button == Six)
return '6';
else if (button == Seven)
return '7';
else if (button == Eight)
return '8';
else if (button == Nine)
return '9';
else if (button == Zero)
return '0';
else if (button == Minus)
return '-';
else if (button == Equals)
return '=';
else if (button == Tilde)
return '`';
else if (button == BackSlash)
return '\\';
else if (button == LeftSquareBracket)
return '[';
else if (button == RightSquareBracket)
return ']';
else if (button == SemiColon)
return ';';
else if (button == Apostrophe)
return '\'';
else if (button == Comma)
return ',';
else if (button == Period)
return '.';
else if (button == ForwardSlash)
return '/';
}
if (button == Space)
return ' ';
else
return 0x00;
}
}

88
src/io/hid/Mouse.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "ehs/io/hid/Mouse.h"
namespace ehs
{
Mouse::Mouse()
{
}
Mouse::Mouse(Str_8 name, const UInt_64 id)
: HID(EHS_HID_MOUSE, (Str_8&&)name, id)
{
}
Mouse::Mouse(const Mouse& hid)
: HID(hid), delta(hid.delta)
{
}
Mouse& Mouse::operator=(const Mouse& hid)
{
if (this == &hid)
return *this;
HID::operator=(hid);
delta = hid.delta;
return *this;
}
void Mouse::Poll()
{
delta = {};
HID::Poll();
}
void Mouse::SetDelta(const Vec2_s32& newDelta)
{
delta = newDelta;
}
Vec2_s32 Mouse::GetDelta() const
{
return delta;
}
Mouse* Mouse::Clone() const
{
return new Mouse(*this);
}
const Button Mouse::Unknown("Unknown");
const Button Mouse::LMB("Left Mouse Button");
const Button Mouse::MMB("Middle Mouse Button");
const Button Mouse::RMB("Right Mouse Button");
const Button Mouse::Four("Mouse Button Four");
const Button Mouse::Five("Mouse Button Five");
const Button Mouse::ScrollUp("Scroll Up");
const Button Mouse::ScrollDown("Scroll Down");
const Button Mouse::ScrollLeft("Scroll Left");
const Button Mouse::ScrollRight("Scroll Right");
const Button Mouse::Back("Back Mouse Button");
const Button Mouse::Forward("Forward Mouse Button");
Button Mouse::TranslateXCB(const UInt_32 code)
{
switch (code)
{
case 1:
return Mouse::LMB;
case 2:
return Mouse::MMB;
case 3:
return Mouse::RMB;
case 4:
return Mouse::ScrollUp;
case 5:
return Mouse::ScrollDown;
case 8:
return Mouse::Back;
case 9:
return Mouse::Forward;
default:
return Mouse::Unknown;
}
}
}

1488
src/io/img/Img.cpp Normal file

File diff suppressed because it is too large Load Diff

110
src/io/img/ImgCodec.cpp Normal file
View File

@@ -0,0 +1,110 @@
#include "ehs/io/img/ImgCodec.h"
#include "ehs/io/img/Img.h"
namespace ehs
{
ImgCodec::ImgCodec()
: hashExt(0), endianness(Endianness::LE), encodeCb(nullptr), decodeCb(nullptr)
{
}
ImgCodec::ImgCodec(Str_8 id, Str_8 ext, const Endianness end,
bool (* encodeCb)(const ImgCodec* const, Serializer<UInt_64>&, const Img*),
bool (* decodeCb)(const ImgCodec* const, Serializer<UInt_64>&, Img*))
: id(std::move(id)), hashExt(ext.Hash_64()), ext(std::move(ext)), endianness(end), encodeCb(encodeCb), decodeCb(decodeCb)
{
}
ImgCodec::ImgCodec(ImgCodec&& codec) noexcept
: id(std::move(codec.id)), hashExt(codec.hashExt), ext(std::move(codec.ext)), endianness(codec.endianness),
encodeCb(codec.encodeCb), decodeCb(codec.decodeCb)
{
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
}
ImgCodec::ImgCodec(const ImgCodec& codec)
: id(codec.id), hashExt(codec.hashExt), ext(codec.ext), endianness(codec.endianness), encodeCb(codec.encodeCb),
decodeCb(codec.decodeCb)
{
}
ImgCodec& ImgCodec::operator=(ImgCodec&& codec) noexcept
{
if (this == &codec)
return *this;
id = std::move(codec.id);
hashExt = codec.hashExt;
ext = std::move(codec.ext);
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
codec.hashExt = 0;
codec.endianness = Endianness::LE;
codec.encodeCb = nullptr;
codec.decodeCb = nullptr;
return *this;
}
ImgCodec& ImgCodec::operator=(const ImgCodec& codec)
{
if (this == &codec)
return *this;
id = codec.id;
hashExt = codec.hashExt;
ext = codec.ext;
endianness = codec.endianness;
encodeCb = codec.encodeCb;
decodeCb = codec.decodeCb;
return *this;
}
Str_8 ImgCodec::GetId() const
{
return id;
}
UInt_64 ImgCodec::GetHashExt() const
{
return hashExt;
}
Str_8 ImgCodec::GetExt() const
{
return ext;
}
Endianness ImgCodec::GetEndianness() const
{
return endianness;
}
bool ImgCodec::Encode(Serializer<UInt_64>& out, const Img* in) const
{
if (!encodeCb)
{
EHS_LOG_INT("Error", 0, "Encoding is not supported for the " + id + " format.");
return false;
}
return encodeCb(this, out, in);
}
bool ImgCodec::Decode(Serializer<UInt_64>& in, Img* out) const
{
if (!decodeCb)
{
EHS_LOG_INT("Error", 0, "Decoding is not supported for the " + id + " format.");
return false;
}
return decodeCb(this, in, out);
}
}

232
src/io/img/PNG.cpp Normal file
View File

@@ -0,0 +1,232 @@
#include "ehs/io/img/PNG.h"
namespace ehs
{
Array<Byte, UInt_64> pngSeq = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
PNG::PNG()
: hashId(0)
{
}
PNG::PNG(const Str_8& filePath)
{
id = File::ParseName_8(filePath);
hashId = id.Hash_64();
File file(filePath, Mode::READ, Disposition::OPEN);
Serializer<UInt_64> data = file.ReadSerializer_64(Endianness::BE, file.Size());
file.Release();
Array<Byte, UInt_64> seq = data.ReadArray<Byte, UInt_64>(8);
if (seq != pngSeq)
{
EHS_LOG_INT("Error", 0, "File at file path, \"" + filePath + "\", is not a valid PNG file.");
return;
}
while (data.GetOffset() < data.Size())
{
UInt_32 length = data.Read<UInt_32>();
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
Serializer<UInt_64> chunkData(Endianness::BE, &data[data.GetOffset()], length);
data.SetOffset(data.GetOffset() + length);
Byte crc[4];
UInt_64 crcSize = 4;
data.ReadArray(crc, &crcSize);
PNG_Chunk* chunk = GetChunk(id);
if (chunk)
{
chunk->GetData()->SetOffset(chunk->GetData()->Size());
chunk->GetData()->WriteSer(chunkData);
chunk->GetData()->SetOffset(0);
}
else
chunks.Push(PNG_Chunk(id, chunkData, crc));
}
}
PNG::PNG(const Str_8& id, Serializer<UInt_64>& data)
: id(id), hashId(id.Hash_64())
{
Array<Byte, UInt_64> seq = data.ReadArray<Byte, UInt_64>(8);
if (seq != pngSeq)
return;
while (data.GetOffset() < data.Size())
{
UInt_32 length = data.Read<UInt_32>();
Str_8 id = data.ReadStr<Char_8, UInt_64>(4);
Serializer<UInt_64> chunkData(Endianness::BE, &data[data.GetOffset()], length);
data.SetOffset(data.GetOffset() + length);
Byte crc[4];
UInt_64 crcSize = 4;
data.ReadArray(crc, &crcSize);
PNG_Chunk* chunk = GetChunk(id);
if (chunk)
{
chunk->GetData()->SetOffset(chunk->GetData()->Size());
chunk->GetData()->WriteSer(chunkData);
chunk->GetData()->SetOffset(0);
}
else
chunks.Push(PNG_Chunk(id, chunkData, crc));
}
}
PNG::PNG(const PNG& png)
: id(png.id), hashId(png.hashId), chunks(png.chunks)
{
}
PNG& PNG::operator=(const PNG& png)
{
if (this == &png)
return *this;
id = png.id;
hashId = png.hashId;
chunks = png.chunks;
return *this;
}
bool PNG::HasChunk(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return true;
return false;
}
bool PNG::HasChunk(const Str_8& id) const
{
return HasChunk(id.Hash_64());
}
PNG_Chunk* PNG::GetChunk(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < chunks.Size(); ++i)
if (chunks[i].GetHashId() == hashId)
return &chunks[i];
return nullptr;
}
PNG_Chunk* PNG::GetChunk(const Str_8& id)
{
return GetChunk(id.Hash_64());
}
bool PNG::IsPNG(Serializer<UInt_32>& data)
{
UInt_32 oldOffset = data.GetOffset();
data.SetOffset(0);
Array<Byte, UInt_32> seq = data.ReadArray<Byte, UInt_32>(8);
if (seq != pngSeq)
return false;
data.SetOffset(oldOffset);
return true;
}
void PNG::FilterNone(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
for (UInt_32 i = 0; i < scanline; i += bytes)
for (UInt_8 b = 0; b < bytes; ++b)
out[i + b] = in[i + bytes - 1 - b];
}
void PNG::FilterSub(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
if (i >= pxSize)
out[i + b] = in[i + bytes - 1 - b] + out[i - pxSize + b];
else
out[i + b] = in[i + bytes - 1 - b];
}
}
}
void PNG::FilterUp(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
for (UInt_32 i = 0; i < scanline; i += bytes)
for (UInt_8 b = 0; b < bytes; ++b)
out[scanline + i + b] = in[i + bytes - 1 - b] + out[i + b];
}
void PNG::FilterAverage(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
Byte prevPx = 0;
if (i >= pxSize)
prevPx = out[scanline + i - pxSize + b];
out[scanline + i + b] = in[i + bytes - 1 - b] + (Byte)Math::Floor(((float)prevPx + (float)out[i + b]) / 2.0f);
}
}
}
void PNG::FilterPaeth(const Byte* const in, Byte* const out, const UInt_8 bitDepth, const UInt_8 channels, const UInt_32 scanline)
{
UInt_8 bytes = bitDepth / 8;
UInt_8 pxSize = bytes * channels;
for (UInt_32 i = 0; i < scanline; i += bytes)
{
for (UInt_8 b = 0; b < bytes; ++b)
{
if (i >= pxSize)
out[scanline + i + b] = in[i + bytes - 1 - b] + PaethPredictor(out[scanline + i - pxSize + b], out[i + b], out[i - pxSize + b]);
else
out[scanline + i + b] = in[i + bytes - 1 - b] + out[i + b];
}
}
}
Byte PNG::PaethPredictor(const Byte a, const Byte b, const Byte c)
{
SInt_16 p = a + b - c;
SInt_16 pa = Math::Abs(p - a);
SInt_16 pb = Math::Abs(p - b);
SInt_16 pc = Math::Abs(p - c);
if (pa <= pb && pa <= pc)
return a;
else if (pb <= pc)
return b;
else
return c;
}
}

55
src/io/img/PNG_Chunk.cpp Normal file
View File

@@ -0,0 +1,55 @@
#include "ehs/io/img/PNG_Chunk.h"
namespace ehs
{
PNG_Chunk::PNG_Chunk()
: hashId(0), crc{0x0, 0x0, 0x0, 0x0}
{
}
PNG_Chunk::PNG_Chunk(const Str_8& id, const Serializer<UInt_64>& data, const Byte crc[4])
: id(id), hashId(id.Hash_64()), data(data), crc{crc[0], crc[1], crc[2], crc[3]}
{
}
PNG_Chunk::PNG_Chunk(const PNG_Chunk& chunk)
: id(chunk.id), hashId(chunk.hashId), data(chunk.data), crc{chunk.crc[0], chunk.crc[1], chunk.crc[2], chunk.crc[3]}
{
}
PNG_Chunk& PNG_Chunk::operator=(const PNG_Chunk& chunk)
{
if (this == &chunk)
return *this;
id = chunk.id;
hashId = chunk.hashId;
data = chunk.data;
crc[0] = chunk.crc[0];
crc[1] = chunk.crc[1];
crc[2] = chunk.crc[2];
crc[3] = chunk.crc[3];
return *this;
}
Str_8 PNG_Chunk::GetId() const
{
return id;
}
UInt_64 PNG_Chunk::GetHashId() const
{
return hashId;
}
Serializer<UInt_64>* PNG_Chunk::GetData()
{
return &data;
}
const unsigned char* PNG_Chunk::GetCRC() const
{
return crc;
}
}

91
src/io/model/AnimBone.cpp Normal file
View File

@@ -0,0 +1,91 @@
#include "ehs/io/model/AnimBone.h"
#include <algorithm>
namespace ehs
{
AnimBone::AnimBone()
: boneId(0xFF)
{
}
AnimBone::AnimBone(const UInt_8 boneId)
: boneId(boneId)
{
}
AnimBone::AnimBone(const UInt_8 boneId, const UInt_64 size)
: boneId(boneId), keyFrames(size)
{
}
AnimBone::AnimBone(const UInt_8 boneId, Array<KeyFrame> keyFrames)
: boneId(boneId), keyFrames(std::move(keyFrames))
{
}
AnimBone::AnimBone(const AnimBone& anim)
: boneId(anim.boneId), keyFrames(anim.keyFrames)
{
}
AnimBone::AnimBone(AnimBone&& anim) noexcept
: boneId(anim.boneId), keyFrames(std::move(anim.keyFrames))
{
anim.boneId = 0xFF;
}
AnimBone& AnimBone::operator=(AnimBone&& anim) noexcept
{
if (this == &anim)
return *this;
boneId = anim.boneId;
keyFrames = std::move(anim.keyFrames);
anim.boneId = 0xFF;
return *this;
}
AnimBone& AnimBone::operator=(const AnimBone& anim)
{
if (this == &anim)
return *this;
boneId = anim.boneId;
keyFrames = anim.keyFrames;
return *this;
}
UInt_8 AnimBone::GetBoneId() const
{
return boneId;
}
Array<KeyFrame> AnimBone::GetKeyFrames() const
{
return keyFrames;
}
Array<KeyFrame>& AnimBone::GetKeyFrames()
{
return keyFrames;
}
float AnimBone::GetPrevAndNext(KeyFrame& prev, KeyFrame& next, const float elapsed) const
{
prev = keyFrames[0];
next = keyFrames[0];
for (UInt_64 i = 1; i < keyFrames.Size(); ++i)
{
next = keyFrames[i];
if (keyFrames[i].GetTimeStamp() > elapsed)
break;
prev = keyFrames[i];
}
return (elapsed - prev.GetTimeStamp()) / (next.GetTimeStamp() - prev.GetTimeStamp());
}
}

130
src/io/model/Animation.cpp Normal file
View File

@@ -0,0 +1,130 @@
#include "ehs/io/model/Animation.h"
namespace ehs
{
Animation::Animation()
: hashId(0), duration(0.0f)
{
}
Animation::Animation(Str_8 id, const float duration)
: hashId(id.Hash_64()), id(std::move(id)), duration(duration)
{
}
Animation::Animation(Str_8 id, const float duration, UInt_64 size)
: hashId(id.Hash_64()), id(std::move(id)), duration(duration), animated(size)
{
}
Animation::Animation(Str_8 id, const float duration, Array<AnimBone> animated)
: hashId(id.Hash_64()), id(std::move(id)), duration(duration), animated(std::move(animated))
{
}
Animation::Animation(Animation&& anim) noexcept
: hashId(anim.hashId), id(std::move(anim.id)), duration(anim.duration), animated(std::move(anim.animated))
{
anim.hashId = 0;
anim.duration = 0.0f;
}
Animation::Animation(const Animation& anim)
: hashId(anim.hashId), id(anim.id), duration(anim.duration), animated(anim.animated)
{
}
Animation& Animation::operator=(Animation&& anim) noexcept
{
if (this == &anim)
return *this;
hashId = anim.hashId;
id = std::move(anim.id);
duration = anim.duration;
animated = std::move(anim.animated);
anim.hashId = 0;
anim.duration = 0.0f;
return *this;
}
Animation& Animation::operator=(const Animation& anim)
{
if (this == &anim)
return *this;
hashId = anim.hashId;
id = anim.id;
duration = anim.duration;
animated = anim.animated;
return *this;
}
UInt_64 Animation::GetHashId() const
{
return hashId;
}
void Animation::SetId(Str_8 newId)
{
hashId = newId.Hash_64();
id = std::move(newId);
}
Str_8 Animation::GetId() const
{
return id;
}
float Animation::GetDuration() const
{
return duration;
}
Array<AnimBone> Animation::GetAnimated() const
{
return animated;
}
Array<AnimBone>& Animation::GetAnimated()
{
return animated;
}
Array<Mat4_f> Animation::Interpolate(const UInt_64 boneCount, const float elapsed) const
{
Array<Mat4_f> result(boneCount);
for (UInt_64 i = 0; i < result.Size(); ++i)
result[i] = Mat4_f::Identity();
if (elapsed == 0.0f)
{
for (UInt_64 i = 0; i < animated.Size(); ++i)
{
Array<KeyFrame> keyFrames = animated[i].GetKeyFrames();
if (!keyFrames.Size())
continue;
result[animated[i].GetBoneId()] = keyFrames[0].GetTrans();
}
}
else
{
for (UInt_64 i = 0; i < animated.Size(); ++i)
{
KeyFrame prev;
KeyFrame next;
float perc = animated[i].GetPrevAndNext(prev, next, elapsed);
if (prev.GetNum() == next.GetNum() || perc <= 0.0f)
result[animated[i].GetBoneId()] = prev.GetTrans();
else
result[animated[i].GetBoneId()] = KeyFrame::Interpolate(prev, next, perc);
}
}
return result;
}
}

240
src/io/model/Bone.cpp Normal file
View File

@@ -0,0 +1,240 @@
#include "ehs/io/model/Bone.h"
namespace ehs
{
Bone::Bone()
: hashName(0), id(0), animTrans(Mat4_f::Identity())
{
}
Bone::Bone(Str_8 name, const UInt_8 id, const Mat4_f& localBindTrans, const Mat4_f& invBindTrans)
: hashName(name.Hash_64()), name(std::move(name)), id(id), animTrans(Mat4_f::Identity()),
localBindTrans(localBindTrans), invBindTrans(invBindTrans)
{
}
Bone::Bone(Bone&& bone) noexcept
: hashName(bone.hashName), name(std::move(bone.name)), id(bone.id), animTrans(bone.animTrans),
localBindTrans(bone.localBindTrans), invBindTrans(bone.invBindTrans), children(std::move(bone.children))
{
bone.hashName = 0;
bone.id = 0xFF;
bone.animTrans = Mat4_f::Identity();
bone.localBindTrans = {};
bone.invBindTrans = {};
}
Bone::Bone(const Bone& bone)
: hashName(bone.hashName), name(bone.name), id(bone.id), animTrans(bone.animTrans), localBindTrans(bone.localBindTrans),
invBindTrans(bone.invBindTrans), children(bone.children)
{
}
Bone& Bone::operator=(Bone&& bone) noexcept
{
if (this == &bone)
return *this;
hashName = bone.hashName;
name = std::move(bone.name);
id = bone.id;
animTrans = bone.animTrans;
localBindTrans = bone.localBindTrans;
invBindTrans = bone.invBindTrans;
children = std::move(bone.children);
bone.hashName = 0;
bone.id = 0;
bone.animTrans = Mat4_f::Identity();
bone.localBindTrans = {};
bone.invBindTrans = {};
return *this;
}
Bone& Bone::operator=(const Bone& bone)
{
if (this == &bone)
return *this;
hashName = bone.hashName;
name = bone.name;
id = bone.id;
animTrans = bone.animTrans;
localBindTrans = bone.localBindTrans;
invBindTrans = bone.invBindTrans;
children = bone.children;
return *this;
}
UInt_64 Bone::GetHashName() const
{
return hashName;
}
void Bone::SetName(Str_8 newId)
{
hashName = newId.Hash_64();
name = std::move(newId);
}
Str_8 Bone::GetName() const
{
return id;
}
UInt_8 Bone::GetId() const
{
return id;
}
void Bone::SetAnimTrans(const Mat4_f& newTrans)
{
animTrans = newTrans;
}
Mat4_f Bone::GetAnimTrans() const
{
return animTrans;
}
void Bone::GetAnimTransRec(Array<Mat4_f>& output) const
{
output[id] = animTrans;
for (UInt_64 i = 0; i < children.Size(); ++i)
children[i].GetAnimTransRec(output);
}
Mat4_f Bone::GetLocalBindTrans() const
{
return localBindTrans;
}
Mat4_f Bone::GetInvBindTrans() const
{
return invBindTrans;
}
UInt_8 Bone::GetBoneCount() const
{
UInt_8 count = 1;
for (UInt_64 i = 0; i < children.Size(); ++i)
count += children[i].GetBoneCount();
return count;
}
bool Bone::HasBone(const UInt_64 hashName, const UInt_8 id) const
{
if (this->hashName == hashName && this->id == id)
return true;
bool result = false;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].HasBone(hashName, id);
return result;
}
bool Bone::HasBone(const UInt_64 hashName) const
{
if (this->hashName == hashName)
return true;
bool result = false;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].HasBone(hashName);
return result;
}
bool Bone::HasBone(const UInt_8 id) const
{
if (this->id == id)
return true;
bool result = false;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].HasBone(id);
return result;
}
bool Bone::AddBone(Bone child)
{
if (HasBone(child.hashName, child.id))
return false;
children.Push(std::move(child));
return true;
}
const Bone* Bone::GetBone(const UInt_64 hashName) const
{
if (this->hashName == hashName)
return this;
const Bone* result = nullptr;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].GetBone(hashName);
return result;
}
Bone* Bone::GetBone(const UInt_64 hashName)
{
if (this->hashName == hashName)
return this;
Bone* result = nullptr;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].GetBone(hashName);
return result;
}
const Bone* Bone::GetBone(const UInt_8 id) const
{
if (this->id == id)
return this;
const Bone* result = nullptr;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].GetBone(id);
return result;
}
Bone* Bone::GetBone(const UInt_8 id)
{
if (this->id == id)
return this;
Bone* result = nullptr;
for (UInt_64 i = 0; i < children.Size(); ++i)
result = children[i].GetBone(id);
return result;
}
const Array<Bone>& Bone::GetChildren() const
{
return children;
}
Array<Bone>& Bone::GetChildren()
{
return children;
}
}

102
src/io/model/KeyFrame.cpp Normal file
View File

@@ -0,0 +1,102 @@
#include "ehs/io/model/KeyFrame.h"
#include <algorithm>
namespace ehs
{
KeyFrame::KeyFrame()
: num(0.0f), timeStamp(0.0f), scale(1.0f), trans(Mat4_f::Identity())
{
}
KeyFrame::KeyFrame(const float num, const float timeStamp, const Vec3_f& pos, const Quat_f& rot, const Vec3_f& scale)
: num(num), timeStamp(timeStamp), pos(pos), rot(rot), scale(scale),
trans(Mat4_f::Translate(pos) * rot.ToMatrix() * Mat4_f::Scale(scale))
{
}
KeyFrame::KeyFrame(const float num, const float timeStamp)
: num(num), timeStamp(timeStamp), scale(1.0f), trans(Mat4_f::Identity())
{
}
KeyFrame::KeyFrame(const KeyFrame& kf)
: num(kf.num), timeStamp(kf.timeStamp), pos(kf.pos), rot(kf.rot), scale(kf.scale), trans(kf.trans)
{
}
KeyFrame& KeyFrame::operator=(const KeyFrame& kf)
{
if (this == &kf)
return *this;
num = kf.num;
timeStamp = kf.timeStamp;
pos = kf.pos;
rot = kf.rot;
scale = kf.scale;
trans = kf.trans;
return *this;
}
float KeyFrame::GetNum() const
{
return num;
}
float KeyFrame::GetTimeStamp() const
{
return timeStamp;
}
void KeyFrame::SetPos(const Vec3_f& newPos)
{
pos = newPos;
}
Vec3_f KeyFrame::GetPos() const
{
return pos;
}
void KeyFrame::SetRot(const Quat_f& newRot)
{
rot = newRot;
}
Quat_f KeyFrame::GetRot() const
{
return rot;
}
void KeyFrame::SetScale(const Vec3_f& newScale)
{
scale = newScale;
}
Vec3_f KeyFrame::GetScale() const
{
return scale;
}
void KeyFrame::CalculateTransform()
{
trans = Mat4_f::Translate(pos) * rot.ToMatrix() * Mat4_f::Scale(scale);
}
Mat4_f KeyFrame::GetTrans() const
{
return trans;
}
Mat4_f KeyFrame::Interpolate(const KeyFrame& prev, const KeyFrame& next, const float percentage)
{
Vec3_f newPos = Vec3_f::Lerp(prev.pos, next.pos, percentage);
Quat_f newRot = Quat_f::Slerp(prev.rot, next.rot, percentage).GetNormalized();
Vec3_f newScale = Vec3_f::Lerp(prev.scale, next.scale, percentage);
Mat4_f newTrans = Mat4_f::Translate(newPos) * newRot.ToMatrix() * Mat4_f::Scale(newScale);
return newTrans;
}
}

164
src/io/model/Mesh.cpp Normal file
View File

@@ -0,0 +1,164 @@
#include "ehs/io/model/Mesh.h"
namespace ehs
{
Mesh::Mesh()
: hashId(0)
{
AddType("Mesh");
}
Mesh::Mesh(Str_8 id, Array<Vertex_f> vertices, Array<UInt_32> indices)
: hashId(id.Hash_64()), id((Str_8&&)id), vertices((Array<Vertex_f>&&)vertices),
indices((Array<UInt_32>&&)indices)
{
AddType("Mesh");
}
Mesh::Mesh(Str_8 id, Array<Vertex_f> vertices)
: hashId(id.Hash_64()), id((Str_8&&)id), vertices((Array<Vertex_f>&&)vertices)
{
AddType("Mesh");
}
Mesh::Mesh(Mesh&& mesh) noexcept
: BaseObj((BaseObj&&)mesh), hashId(mesh.hashId), id((Str_8&&)mesh.id), vertices((Array<Vertex_f>&&)mesh.vertices),
indices((Array<UInt_32>&&)mesh.indices)
{
mesh.hashId = 0;
}
Mesh::Mesh(const Mesh& mesh)
: BaseObj((BaseObj&&)mesh), hashId(mesh.hashId), id(mesh.id), vertices(mesh.vertices), indices(mesh.indices)
{
}
Mesh& Mesh::operator=(Mesh&& mesh) noexcept
{
if (this == &mesh)
return *this;
BaseObj::operator=((BaseObj&&)mesh);
hashId = mesh.hashId;
id = (Str_8&&)mesh.id;
vertices = (Array<Vertex_f>&&)mesh.vertices;
indices = (Array<UInt_32>&&)mesh.indices;
mesh.hashId = 0;
return *this;
}
Mesh& Mesh::operator=(const Mesh& mesh)
{
if (this == &mesh)
return *this;
BaseObj::operator=(mesh);
hashId = mesh.hashId;
id = mesh.id;
vertices = mesh.vertices;
indices = mesh.indices;
return *this;
}
void Mesh::Release()
{
vertices.Clear();
indices.Clear();
}
UInt_64 Mesh::GetHashId() const
{
return hashId;
}
void Mesh::SetId(Str_8 newId)
{
hashId = newId.Hash_64();
id = (Str_8&&)newId;
}
Str_8 Mesh::GetId() const
{
return id;
}
void Mesh::SetVertices(const Array<Vertex_f>& newVertices)
{
vertices = newVertices;
}
const Array<Vertex_f>& Mesh::GetVertices() const
{
return vertices;
}
Array<Vertex_f>& Mesh::GetVertices()
{
return vertices;
}
void Mesh::SetIndices(const Array<UInt_32>& newIndices)
{
indices = newIndices;
}
bool Mesh::HasIndices() const
{
return indices.Size();
}
const Array<UInt_32>& Mesh::GetIndices() const
{
return indices;
}
Array<UInt_32>& Mesh::GetIndices()
{
return indices;
}
void Mesh::Calculate()
{
if (indices.Size())
for (UInt_64 i = 0; i < indices.Size(); i += 3)
Calculate(vertices[indices[i]], vertices[indices[i + 1]], vertices[indices[i + 2]]);
else
for (UInt_64 i = 0; i < vertices.Size(); i += 3)
Calculate(vertices[i], vertices[i + 1], vertices[i + 2]);
}
void Mesh::Calculate(Vertex_f& vert1, Vertex_f& vert2, Vertex_f& vert3)
{
Vec3_f edge1 = vert2.pos - vert1.pos;
Vec3_f edge2 = vert3.pos - vert1.pos;
Vec2_f deltaUV1 = vert2.uv - vert1.uv;
Vec2_f deltaUV2 = vert3.uv - vert1.uv;
float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
Vec3_f tan(
f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x),
f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y),
f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z)
);
vert1.tan = tan;
vert2.tan = tan;
vert3.tan = tan;
Vec3_f bTan(
f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x),
f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y),
f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z)
);
vert1.bTan = bTan;
vert2.bTan = bTan;
vert3.bTan = bTan;
}
}

275
src/io/model/Model.cpp Normal file
View File

@@ -0,0 +1,275 @@
#include "ehs/io/model/Model.h"
namespace ehs
{
Model::Model()
: hashId(0)
{
AddType("Model");
}
Model::Model(const Str_8& filePath)
{
AddType("Model");
File file(filePath, Mode::READ, Disposition::OPEN);
hashId = file.GetName().Hash_64();
id = file.GetName();
if (file.GetExtension() == "ehm")
{
FromEHM(file);
}
}
Model::Model(Str_8 id, Array<Mesh> meshes, Bone skeleton, Array<Animation> animations)
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton),
animations((Array<Animation>&&)animations)
{
AddType("Model");
}
Model::Model(Str_8 id, Array<Mesh> meshes, Bone skeleton)
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes), skeleton((Bone&&)skeleton)
{
AddType("Model");
}
Model::Model(Str_8 id, Array<Mesh> meshes)
: hashId(id.Hash_64()), id((Str_8&&)id), meshes((Array<Mesh>&&)meshes)
{
AddType("Model");
}
Model::Model(Model&& model) noexcept
: BaseObj((BaseObj&&)model), hashId(model.hashId), id((Str_8&&)model.id), meshes((Array<Mesh>&&)model.meshes),
skeleton((Bone&&)model.skeleton), animations((Array<Animation>&&)model.animations)
{
}
Model& Model::operator=(Model&& model) noexcept
{
if (this == &model)
return *this;
BaseObj::operator=((BaseObj&&)model);
hashId = model.hashId;
id = (Str_8&&)model.id;
meshes = (Array<Mesh>&&)model.meshes;
skeleton = (Bone&&)model.skeleton;
animations = (Array<Animation>&&)model.animations;
model.hashId = 0;
return *this;
}
void Model::Release()
{
meshes.Clear();
skeleton = {};
animations.Clear();
}
UInt_64 Model::GetHashId() const
{
return hashId;
}
void Model::SetId(Str_8 newId)
{
hashId = newId.Hash_64();
id = (Str_8&&)newId;
}
Str_8 Model::GetId() const
{
return id;
}
const Array<Mesh>& Model::GetMeshes() const
{
return meshes;
}
Array<Mesh>& Model::GetMeshes()
{
return meshes;
}
Mesh* Model::GetMesh(const UInt_64 inHashId)
{
for (UInt_64 i = 0; i < meshes.Size(); ++i)
if (meshes[i].GetHashId() == inHashId)
return &meshes[i];
return nullptr;
}
Mesh* Model::GetMesh(const Str_8& inId)
{
return GetMesh(inId.Hash_64());
}
const Bone& Model::GetSkeleton() const
{
return skeleton;
}
Bone& Model::GetSkeleton()
{
return skeleton;
}
Animation* Model::GetAnimation(const UInt_64 inHashId)
{
for (UInt_64 i = 0; i < animations.Size(); ++i)
if (animations[i].GetHashId() == inHashId)
return &animations[i];
return nullptr;
}
const Array<Animation>& Model::GetAnimations() const
{
return animations;
}
Array<Animation>& Model::GetAnimations()
{
return animations;
}
void Model::Calculate()
{
for (UInt_64 i = 0; i < meshes.Size(); ++i)
meshes[i].Calculate();
}
void Model::Export(const Str_8& filePath, const ModelEncoding encoding)
{
File file(filePath, Mode::WRITE, Disposition::OPEN_PERSISTENT);
switch (encoding)
{
case ModelEncoding::EHM:
{
ToEHM(file);
break;
}
}
}
void Model::ToEHM(File& file)
{
Serializer<UInt_64> data(Endianness::LE);
data.WriteVersion({1, 0, 0});
data.Write<UInt_64>(meshes.Size());
for (UInt_64 i = 0; i < meshes.Size(); ++i)
{
data.WriteStr(meshes[i].GetId());
Array<Vertex_f> vertices = meshes[i].GetVertices();
data.Write<UInt_64>(vertices.Size());
for (UInt_64 v = 0; v < vertices.Size(); ++v)
{
data.WriteVec3(vertices[v].pos);
data.WriteVec3(vertices[v].normal);
data.WriteVec2(vertices[v].uv);
}
}
file.WriteSerializer_64(data);
file.Truncate(data.Size());
}
void Model::FromEHM(File& file)
{
Serializer<UInt_64> data = file.ReadSerializer_64(Endianness::LE, file.Size());
Version ver = data.ReadVersion();
if (ver != Version(1, 0, 0))
{
EHS_LOG_INT("Error", 0, "Cannot decode EHM file version " + Str_8::FromNum(ver.major) + "." +
Str_8::FromNum(ver.minor) + "." + Str_8::FromNum(ver.patch) +
", must be version 0.0.0.");
return;
}
meshes.Resize(data.Read<UInt_64>());
for (UInt_64 i = 0; i < meshes.Size(); ++i)
{
meshes[i].SetId(data.ReadStr<Char_8, UInt_64>());
Array<Vertex_f>& vertices = meshes[i].GetVertices();
vertices.Resize(data.Read<UInt_64>());
for (UInt_64 v = 0; v < vertices.Size(); ++v)
{
vertices[v].pos = data.ReadVec3<float>();
vertices[v].normal = data.ReadVec3<float>();
vertices[v].uv = data.ReadVec2<float>();
vertices[v].bones = data.ReadVec4<UInt_8>();
vertices[v].weights = data.ReadVec4<float>();
}
meshes[i].SetIndices(data.ReadArray<UInt_32, UInt_64>());
UInt_8 boneCount = data.Read<UInt_8>();
for (UInt_8 b = 0; b < boneCount; ++b)
{
Str_8 name = data.ReadStr<Char_8, UInt_64>();
UInt_8 parentId = data.Read<UInt_8>();
Mat4_f localBindTrans = data.ReadMat4<float>();
Mat4_f invBindTrans = data.ReadMat4<float>();
if (b == 0)
{
skeleton = {name, b, localBindTrans, invBindTrans};
}
else
{
Bone* parent = skeleton.GetBone(parentId);
if (!parent)
{
EHS_LOG_INT("Error", 0, "Invalid bone order.");
return;
}
parent->AddBone({name, b, localBindTrans, invBindTrans});
}
}
animations = Array<Animation>(data.Read<UInt_64>());
for (UInt_64 a = 0; a < animations.Size(); ++a)
{
Str_8 animId = data.ReadStr<Char_8, UInt_64>();
float duration = data.Read<float>();
animations[a] = Animation(animId, duration, data.Read<UInt_8>());
Array<AnimBone>& animated = animations[a].GetAnimated();
for (UInt_8 ba = 0; ba < (UInt_8)animated.Size(); ++ba)
{
UInt_8 boneId = data.Read<UInt_8>();
animated[ba] = AnimBone(boneId, data.Read<UInt_64>());
Array<KeyFrame>& keyFrames = animated[ba].GetKeyFrames();
for (UInt_64 kf = 0; kf < keyFrames.Size(); ++kf)
{
float num = data.Read<float>();
float timeStamp = data.Read<float>();
Vec3_f pos = data.ReadVec3<float>();
Quat_f rot = data.ReadQuat<float>();
Vec3_f scale = data.ReadVec3<float>();
keyFrames[kf] = KeyFrame(num, timeStamp, pos, rot, scale);
}
}
}
}
}
}

View File

@@ -0,0 +1,14 @@
#include "ehs/io/model/PropertyChange.h"
namespace ehs
{
PropertyChange::PropertyChange()
: type(ChangeType::INVALID), value(0.0f)
{
}
PropertyChange::PropertyChange(const ChangeType type, const float value)
: type(type), value(value)
{
}
}

336
src/io/socket/BaseTCP.cpp Normal file
View File

@@ -0,0 +1,336 @@
#include "ehs/io/socket/BaseTCP.h"
#include "ehs/Log.h"
namespace ehs
{
BaseTCP::BaseTCP()
: addrType(AddrType::IPV6), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP::BaseTCP(const AddrType addrType)
: addrType(addrType), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP::BaseTCP(BaseTCP&& tcp) noexcept
: addrType(tcp.addrType), localAddr(std::move(tcp.localAddr)), localPort(tcp.localPort),
remoteHostName(std::move(tcp.remoteHostName)), remoteAddr(std::move(tcp.remoteAddr)), remotePort(tcp.remotePort),
connection(tcp.connection), bound(tcp.bound), listening(tcp.listening), connected(tcp.connected)
{
}
BaseTCP::BaseTCP(const BaseTCP& tcp)
: addrType(tcp.addrType), localPort(0), remotePort(0), connection(false), bound(false), listening(false),
connected(false)
{
}
BaseTCP& BaseTCP::operator=(BaseTCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
addrType = tcp.addrType;
localAddr = std::move(tcp.localAddr);
localPort = tcp.localPort;
remoteHostName = std::move(tcp.remoteHostName);
remoteAddr = std::move(tcp.remoteAddr);
remotePort = tcp.remotePort;
connection = tcp.connection;
bound = tcp.bound;
listening = tcp.listening;
connected = tcp.connected;
tcp.addrType = AddrType::IPV6;
tcp.localPort = 0;
tcp.remotePort = 0;
tcp.connection = false;
tcp.bound = false;
tcp.listening = false;
tcp.connected = false;
return *this;
}
BaseTCP& BaseTCP::operator=(const BaseTCP& tcp)
{
if (this == &tcp)
return *this;
addrType = tcp.addrType;
localAddr = Str_8();
localPort = 0;
remoteHostName = Str_8();
remoteAddr = Str_8();
remotePort = 0;
connection = false;
bound = false;
listening = false;
connected = false;
return *this;
}
void BaseTCP::SendStr(const Str_8& str)
{
if (!IsValid())
return;
UInt_64 offset = 0;
UInt_64 size = str.Size(true);
while (offset < size)
{
UInt_64 sent = Send((Byte*)&str[offset], size - offset);
if (!sent)
{
EHS_LOG_INT("Error", 0, "Failed to send data.");
return;
}
offset += sent;
}
}
void BaseTCP::SendRes(const Response& res)
{
if (!IsValid())
return;
SendStr(res.FormResult());
}
void BaseTCP::SendReq(Request& req)
{
if (!IsValid())
return;
req.AddToHeader("Host", remoteHostName);
SendStr(req.FormResult());
}
Response BaseTCP::RecvRes()
{
if (!IsValid())
return {};
Str_8 header = RecvHeader();
if (!header.Size())
return {};
Response response(header);
Str_8 encoding = response.GetHeader("Transfer-Encoding");
if (!encoding.Size())
{
int bodySize = response.GetHeader("content-length").ToDecimal<int>();
if (!bodySize)
return response;
response.SetBody(RecvBody(bodySize));
}
else if (encoding == "chunked")
{
Str_8 body;
UInt_64 chunkSize = RecvChunkSize();
while (chunkSize)
{
body += RecvChunk(chunkSize);
chunkSize = RecvChunkSize();
}
response.SetBody(body);
}
return response;
}
Request BaseTCP::RecvReq()
{
if (!IsValid())
return {};
Str_8 header = RecvHeader();
if (!header.Size())
return {};
Request request(header);
if (request.GetVerb() == Verb::GET)
return request;
Str_8 encoding = request.GetHeader("Transfer-Encoding");
if (!encoding.Size())
{
int bodySize = request.GetHeader("Content-Length").ToDecimal<int>();
if (!bodySize)
return request;
request.SetBody(RecvBody(bodySize));
}
else if (encoding == "chunked")
{
Str_8 body;
UInt_64 chunkSize = RecvChunkSize();
while (chunkSize)
{
body += RecvChunk(chunkSize);
chunkSize = RecvChunkSize();
}
request.SetBody(body);
}
return request;
}
AddrType BaseTCP::GetAddressType() const
{
return addrType;
}
Str_8 BaseTCP::GetLocalAddress() const
{
return localAddr;
}
unsigned short BaseTCP::GetLocalPort() const
{
return localPort;
}
Str_8 BaseTCP::GetRemoteAddress() const
{
return remoteAddr;
}
unsigned short BaseTCP::GetRemotePort() const
{
return remotePort;
}
bool BaseTCP::IsConnection() const
{
return connection;
}
bool BaseTCP::IsBound() const
{
return bound;
}
bool BaseTCP::IsListening() const
{
return listening;
}
bool BaseTCP::IsConnected() const
{
return connected;
}
Str_8 BaseTCP::RecvHeader()
{
Byte buffer[MaxHeaderSize];
UInt_64 offset = 0;
while (true)
{
UInt_64 received = Receive(&buffer[offset], 1);
if (!received)
{
return {};
}
else if (buffer[offset] == '\n' && offset - 3 && buffer[offset - 1] == '\r' && buffer[offset - 2] == '\n' && buffer[offset - 3] == '\r')
{
offset -= 3;
break;
}
offset += received;
}
return {(Char_8*)buffer, (UInt_64)offset};
}
Str_8 BaseTCP::RecvBody(const UInt_64 contentLength)
{
Str_8 buffer(contentLength);
UInt_64 offset = 0;
while (offset < contentLength)
{
UInt_64 received = Receive((Byte*)&buffer[offset], contentLength - offset);
if (!received)
{
EHS_LOG_INT("Error", 0, "Failed to receive data.");
return {};
}
offset += received;
}
return buffer;
}
UInt_64 BaseTCP::RecvChunkSize()
{
Str_8 hexSize(10);
UInt_64 offset = 0;
bool cr = false;
while (true)
{
UInt_64 received = Receive((Byte*)&hexSize[offset], 1);
if (!received)
{
EHS_LOG_INT("Error", 0, "Failed to receive data.");
return 0;
}
else if (hexSize[offset] == '\r')
cr = true;
else if (cr && hexSize[offset] == '\n')
break;
++offset;
}
if (hexSize[0] == '0')
Receive((Byte*)&hexSize[offset + 1], 2);
hexSize.Resize(offset - 1);
return hexSize.HexToNum<UInt_64>();
}
Str_8 BaseTCP::RecvChunk(const UInt_64 chunkSize)
{
Str_8 buffer(chunkSize + 2);
UInt_64 offset = 0;
while (offset < chunkSize + 2)
{
UInt_64 received = Receive((Byte*)&buffer[offset], chunkSize + 2 - offset);
if (!received)
{
EHS_LOG_INT("Error", 0, "Failed to receive data.");
return {};
}
offset += received;
}
buffer.Resize(offset - 2);
return buffer;
}
}

77
src/io/socket/BaseUDP.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include "ehs/io/socket/BaseUDP.h"
namespace ehs
{
BaseUDP::BaseUDP()
: type(AddrType::IPV6), port(0), bound(false)
{
}
BaseUDP::BaseUDP(const AddrType type)
: type(type), port(0), bound(false)
{
}
BaseUDP::BaseUDP(BaseUDP&& udp) noexcept
: type(udp.type), address(std::move(udp.address)), port(udp.port), bound(true)
{
udp.type = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
}
BaseUDP::BaseUDP(const BaseUDP& udp)
: type(udp.type), address(udp.address), port(udp.port), bound(false)
{
}
BaseUDP& BaseUDP::operator=(BaseUDP&& udp) noexcept
{
if (this == &udp)
return *this;
type = udp.type;
address = std::move(udp.address);
port = udp.port;
bound = udp.bound;
udp.type = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
return *this;
}
BaseUDP& BaseUDP::operator=(const BaseUDP& udp)
{
if (this == &udp)
return *this;
type = udp.type;
address = udp.address;
port = udp.port;
bound = false;
return *this;
}
bool BaseUDP::IsBound() const
{
return bound;
}
AddrType BaseUDP::GetLocalAddressType() const
{
return type;
}
Str_8 BaseUDP::GetLocalAddress() const
{
return address;
}
UInt_16 BaseUDP::GetLocalPort() const
{
return port;
}
}

75
src/io/socket/DNS.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "ehs/io/socket/DNS.h"
#include "ehs/Log.h"
#if defined(EHS_OS_WINDOWS)
#include <WinSock2.h>
#include <WS2tcpip.h>
#elif defined(EHS_OS_LINUX)
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
namespace ehs
{
Str_8 DNS::Resolve(const AddrType addrType, const Str_8& hostName)
{
#if defined(EHS_OS_WINDOWS)
WSADATA data = {};
Int_32 wsaCode = WSAStartup(MAKEWORD(2, 2), &data);
if (wsaCode)
{
EHS_LOG_INT("Error", 0, "Failed to start WSA with error #" + Str_8::FromNum(wsaCode) + ".");
return {};
}
#endif
addrinfo hints = {};
if (addrType == AddrType::IPV6)
hints.ai_family = AF_INET6;
else if (addrType == AddrType::IPV4)
hints.ai_family = AF_INET;
addrinfo* result = nullptr;
Int_32 code = getaddrinfo(hostName, nullptr, &hints, &result);
if (code)
{
EHS_LOG_INT("Error", 1, "Failed to resolve host with error #" + Str_8::FromNum(code) + ".");
return {};
}
#if defined(EHS_OS_WINDOWS)
if (WSACleanup() == SOCKET_ERROR)
{
EHS_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return {};
}
#endif
if (addrType == AddrType::IPV6)
{
Char_8 ipResult[INET6_ADDRSTRLEN];
inet_ntop(result->ai_family, &((sockaddr_in6*)result->ai_addr)->sin6_addr, ipResult, INET6_ADDRSTRLEN);
freeaddrinfo(result);
return ipResult;
}
else if (addrType == AddrType::IPV4)
{
Char_8 ipResult[INET_ADDRSTRLEN];
inet_ntop(result->ai_family, &((sockaddr_in*)result->ai_addr)->sin_addr, ipResult, INET_ADDRSTRLEN);
freeaddrinfo(result);
return ipResult;
}
return {};
}
}

337
src/io/socket/Request.cpp Normal file
View File

@@ -0,0 +1,337 @@
#include "ehs/io/socket/Request.h"
#include "ehs/Base64.h"
namespace ehs
{
Request::Request()
: verb(Verb::GET), cType(ContentType::NONE)
{
}
Request::Request(const Verb verb, const Str_8& rsrc)
: verb(verb), rsrc(rsrc), cType(ContentType::NONE)
{
}
Request::Request(const char* data, const UInt_64 size)
: verb(Verb::POST), cType(ContentType::NONE)
{
ReadData(Str_8(data, size));
}
Request::Request(const Str_8& data)
: verb(Verb::POST), cType(ContentType::NONE)
{
ReadData(data);
}
Request& Request::operator=(const Request &req)
{
if (this == &req)
return *this;
verb = req.verb;
rsrc = req.rsrc;
queries = req.queries;
header = req.header;
cType = req.cType;
body = req.body;
return* this;
}
Verb Request::GetVerb() const
{
return verb;
}
void Request::SetContentType(const ContentType cType)
{
if (body.Size())
body.Resize(0);
this->cType = cType;
}
ContentType Request::GetContentType() const
{
return cType;
}
void Request::SetResource(const Str_8& rsrc)
{
this->rsrc = rsrc;
}
Str_8 Request::GetResource() const
{
return rsrc;
}
void Request::AddQuery(const Str_8& var, const Str_8& value)
{
queries.Push(var + "=" + value);
}
Str_8 Request::GetQuery(const Str_8& var)
{
for (UInt_64 i = 0; i < queries.Size(); ++i)
{
Vector<Str_8> data = queries[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Vector<Str_8> Request::GetQueries() const
{
return queries;
}
void Request::BasicAuth(const Str_8& id, const Str_8& secret)
{
AddToHeader("Authorization", Str_8("Basic ") + Base64::Encode(id + ":" + secret));
}
void Request::BearerAuth(const Str_8& token)
{
AddToHeader("Authorization", "Bearer " + token);
}
void Request::BearerAuth(const Str_8& token, const Str_8& clientId)
{
AddToHeader("Authorization", "Bearer " + token);
AddToHeader("Client-Id", clientId);
}
void Request::BotAuth(const Str_8& token)
{
AddToHeader("Authorization", "Bot " + token);
}
void Request::AddToHeader(const Str_8& var, const Str_8& value)
{
header.Push(var + ": " + value);
}
Str_8 Request::GetHeader(const Str_8& var) const
{
for (UInt_64 i = 0; i < header.Size(); ++i)
{
Vector<Str_8> data = header[i].Split(": ");
if (data[0] == var)
return data[1];
}
return "";
}
Vector<Str_8> Request::GetHeader() const
{
return header;
}
void Request::AddToBody(const Str_8& var, const Str_8& value)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += var;
if (cType == ContentType::APP_FORMURLENCODED)
body += "=";
body += value;
}
void Request::AddToBody(const Str_8& data)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += data;
}
void Request::SetBody(const Str_8& body)
{
this->body = body;
}
Str_8 Request::GetVar(const Str_8& var) const
{
Vector<Str_8> vars;
if (cType == ContentType::APP_FORMURLENCODED)
vars = body.Split("&");
for (UInt_64 i = 0; i < vars.Size(); ++i)
{
Vector<Str_8> data = vars[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Str_8 Request::GetBody() const
{
return body;
}
Json Request::GetJson() const
{
return {body, 5};
}
Str_8 Request::FormResult() const
{
Str_8 result = VerbToStr(verb) + " " + rsrc;
if (queries.Size())
result += "?" + queries[0];
for (UInt_64 i = 1; i < queries.Size(); ++i)
result += "&" + queries[i];
result += " HTTP/1.1\r\n";
for (UInt_64 i = 0; i < header.Size(); ++i)
{
result += header[i] + "\r\n";
}
result += "Content-Type: " + ContentTypeToStr(cType) + "\r\n";
if (verb == Verb::GET)
result += "\r\n";
else
result += "Content-Length: " + Str_8::FromNum(body.Size()) + "\r\n\r\n" + body;
return result;
}
bool Request::IsValid() const
{
return rsrc.Size() || queries.Size() || header.Size() || body.Size();
}
Str_8 Request::VerbToStr(const Verb verb)
{
switch (verb)
{
case Verb::POST:
return "POST";
case Verb::GET:
return "GET";
case Verb::PUT:
return "PUT";
case Verb::DEL:
return "DELETE";
default:
return "";
}
}
Str_8 Request::ContentTypeToStr(const ContentType cType)
{
switch (cType)
{
case ContentType::APP_MULTIPART_FORMDATA:
return "multipart/form-data";
case ContentType::APP_FORMURLENCODED:
return "application/x-www-form-urlencoded";
case ContentType::APP_JAVASCRIPT:
return "application/javascript";
case ContentType::APP_JSON:
return "application/json";
case ContentType::APP_XML:
return "application/xml";
case ContentType::TEXT_PLAIN:
return "text/plain";
case ContentType::TEXT_HTML:
return "text/html";
case ContentType::TEXT_XML:
return "text/xml";
default:
return "";
}
}
ContentType Request::StrToContentType(const Str_8& value)
{
if (value == "multipart/form-data")
return ContentType::APP_MULTIPART_FORMDATA;
else if (value == "application/x-www-form-urlencoded")
return ContentType::APP_FORMURLENCODED;
else if (value == "application/javascript")
return ContentType::APP_JAVASCRIPT;
else if (value == "application/json")
return ContentType::APP_JSON;
else if (value == "application/xml")
return ContentType::APP_XML;
else if (value == "text/plain")
return ContentType::TEXT_PLAIN;
else if (value == "text/html")
return ContentType::TEXT_HTML;
else if (value == "text/xml")
return ContentType::TEXT_XML;
else
return ContentType::NONE;
}
void Request::ReadData(const Str_8& data)
{
Vector<Str_8> lines = data.Split("\r\n");
Vector<Str_8> meta = lines[0].Split(" ");
if (meta[0] == "POST")
verb = Verb::POST;
else if (meta[0] == "GET")
verb = Verb::GET;
else if (meta[0] == "PUT")
verb = Verb::PUT;
UInt_64 queryIndex = 0;
if (meta[1].Find("?", &queryIndex))
{
rsrc = meta[1].Sub(0, queryIndex);
cType = ContentType::APP_FORMURLENCODED;
queries = meta[1].Sub(queryIndex + 1).Split("&");
}
else
{
rsrc = meta[1];
}
for (UInt_64 i = 1; i < lines.Size(); ++i)
{
if (!lines[i].Size())
break;
Vector<Str_8> var = lines[i].Split(": ");
if (var[0] == "Content-Type")
{
cType = StrToContentType(var[1]);
continue;
}
if (var[0] == "Content-Length")
continue;
header.Push(lines[i]);
}
}
}

403
src/io/socket/Response.cpp Normal file
View File

@@ -0,0 +1,403 @@
#include "ehs/io/socket/Response.h"
namespace ehs
{
Response::Response(const UInt_32 code, const Str_8& server)
: code(code), server(server), cType(ContentType::NONE)
{
}
Response::Response(const char* data, const UInt_64 size)
: code(0), cType(ContentType::NONE)
{
ReadData(Str_8(data, size));
}
Response::Response(const Str_8& data)
: code(0), cType(ContentType::NONE)
{
ReadData(data);
}
Response::Response()
: code(0), cType(ContentType::NONE)
{
}
Response& Response::operator=(const Response& res)
{
if (this == &res)
return *this;
code = res.code;
server = res.server;
cType = res.cType;
header = res.header;
body = res.body;
return *this;
}
void Response::SetCode(const UInt_32 code)
{
this->code = code;
}
UInt_32 Response::GetCode() const
{
return code;
}
void Response::SetServer(const Str_8& server)
{
this->server = server;
}
Str_8 Response::GetServer() const
{
return server;
}
void Response::SetContentType(const ContentType cType)
{
this->cType = cType;
}
ContentType Response::GetContentType() const
{
return cType;
}
void Response::AddToHeader(const Str_8& var, const Str_8& value)
{
header.Push(var + ": " + value);
}
Str_8 Response::GetHeader(const Str_8& var) const
{
Str_8 lIdentity = var.GetLower();
for (UInt_64 i = 0; i < header.Size(); ++i)
{
Vector<Str_8> data = header[i].Split(": ");
if (data[0].GetLower() == lIdentity)
return data[1];
}
return "";
}
Vector<Str_8> Response::GetHeader() const
{
return header;
}
void Response::AddToBody(const Str_8& var, const Str_8& value)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += var;
if (cType == ContentType::APP_FORMURLENCODED)
body += "=";
body += value;
}
void Response::AddToBody(const Str_8& data)
{
if (body.Size())
{
if (cType == ContentType::APP_FORMURLENCODED)
body.Push('&');
}
body += data;
}
void Response::SetBody(const Str_8& body)
{
this->body = body;
}
Str_8 Response::GetVar(const Str_8& var) const
{
Vector<Str_8> vars;
if (cType == ContentType::APP_FORMURLENCODED)
vars = body.Split("&");
for (UInt_64 i = 0; i < vars.Size(); ++i)
{
Vector<Str_8> data = vars[i].Split("=");
if (data[0] == var)
return data[1];
}
return "";
}
Str_8 Response::GetBody() const
{
return body;
}
Json Response::GetJson() const
{
return {body, 5};
}
Str_8 Response::FormResult() const
{
Str_8 result = "HTTP/1.1 " + Str_8::FromNum(code) + " " + CodeToStr(code) + "\r\nServer: " + server + "\r\n";
for (UInt_64 i = 0; i < header.Size(); ++i)
{
if (header[i].Find("Content-Length", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
else if (header[i].Find("Server", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
else if (header[i].Find("Content-Type", nullptr, SearchPattern::LEFT_RIGHT, IndexResult::ENDING))
continue;
result += header[i] + "\r\n";
}
result += "Content-Type: " + ContentTypeToStr(cType) + "\r\nContent-Length: " + Str_8::FromNum(body.Size()) + "\r\n\r\n" + body;
return result;
}
bool Response::IsValid() const
{
return server.Size() || header.Size() || body.Size();
}
Str_8 Response::CodeToStr(const UInt_32 code)
{
if (code == 100)
return "Continue";
else if (code == 101)
return "Switching Protocols";
else if (code == 102)
return "Processing (WebDAV)";
else if (code == 200)
return "OK";
else if (code == 201)
return "Created";
else if (code == 202)
return "Accepted";
else if (code == 203)
return "Non-Authoritative Information";
else if (code == 204)
return "No Content";
else if (code == 205)
return "Reset Content";
else if (code == 206)
return "Partial Content";
else if (code == 207)
return "Multi-Status (WebDAV)";
else if (code == 208)
return "Already Reported (WebDAV)";
else if (code == 226)
return "IM Used";
else if (code == 300)
return "Multiple Choices";
else if (code == 301)
return "Moved Permanently";
else if (code == 302)
return "Found";
else if (code == 303)
return "See Others";
else if (code == 304)
return "Not Modified";
else if (code == 305)
return "Use Proxy";
else if (code == 306)
return "(Unused)";
else if (code == 307)
return "Temporary Redirect";
else if (code == 308)
return "Permanent Redirect (experimental)";
else if (code == 400)
return "Bad Request";
else if (code == 401)
return "Unauthorized";
else if (code == 402)
return "Payment Required";
else if (code == 403)
return "Forbidden";
else if (code == 404)
return "Not Found";
else if (code == 405)
return "Method Not Allowed";
else if (code == 406)
return "Not Acceptable";
else if (code == 407)
return "Proxy Authentication Required";
else if (code == 408)
return "Request Timeout";
else if (code == 409)
return "Conflict";
else if (code == 410)
return "Gone";
else if (code == 411)
return "Length Required";
else if (code == 412)
return "Precondition Failed";
else if (code == 413)
return "Request Entity Too Large";
else if (code == 414)
return "Request-URI Too Long";
else if (code == 415)
return "Unsupported Media Type";
else if (code == 416)
return "Requested Range Not Satisfiable";
else if (code == 417)
return "Expectation Failed";
else if (code == 418)
return "I'm a teapot (RFC 2324)";
else if (code == 420)
return "Enhance Your Calm (Twitter)";
else if (code == 422)
return "Unprocessable Entity (WebDAV)";
else if (code == 423)
return "Locked (WebDAV)";
else if (code == 424)
return "Failed Dependency (Nginx)";
else if (code == 425)
return "Reserved for WebDAV";
else if (code == 426)
return "Upgrade Required";
else if (code == 428)
return "Precondition Required";
else if (code == 429)
return "Too Many Requests";
else if (code == 431)
return "Request Header Fields Too Large";
else if (code == 444)
return "No Response (Nginx)";
else if (code == 449)
return "Retry With (Microsoft)";
else if (code == 450)
return "Blocked by Windows Parental Controls (Microsoft)";
else if (code == 451)
return "Unavailable For Legal Reasons";
else if (code == 499)
return "Client Closed Request (Nginx)";
else if (code == 500)
return "Internal Server Error";
else if (code == 501)
return "Not Implemented";
else if (code == 502)
return "Bad Gateway";
else if (code == 503)
return "Service Unavailable";
else if (code == 504)
return "Gateway Timeout";
else if (code == 505)
return "HTTP Version Not Supported";
else if (code == 506)
return "Variant Also Negotiates (Experimental)";
else if (code == 507)
return "Insufficient Storage (WebDAV)";
else if (code == 508)
return "Loop Detected (WebDAV)";
else if (code == 509)
return "Bandwidth Limit Exceeded (Apache)";
else if (code == 510)
return "Not Extended";
else if (code == 511)
return "Network Authentication Required";
else if (code == 598)
return "Network read timeout error";
else if (code == 599)
return "Network connect timeout error";
else
return "Unused Status Code";
}
Str_8 Response::ContentTypeToStr(const ContentType cType)
{
switch (cType)
{
case ContentType::APP_MULTIPART_FORMDATA:
return "multipart/form-data";
case ContentType::APP_FORMURLENCODED:
return "application/x-www-form-urlencoded";
case ContentType::APP_JAVASCRIPT:
return "application/javascript";
case ContentType::APP_JSON:
return "application/json";
case ContentType::APP_XML:
return "application/xml";
case ContentType::TEXT_PLAIN:
return "text/plain";
case ContentType::TEXT_HTML:
return "text/html";
case ContentType::TEXT_XML:
return "text/xml";
default:
return "";
}
}
ContentType Response::StrToContentType(const Str_8& value)
{
if (value == "multipart/form-data")
return ContentType::APP_MULTIPART_FORMDATA;
else if (value == "application/x-www-form-urlencoded")
return ContentType::APP_FORMURLENCODED;
else if (value == "application/javascript")
return ContentType::APP_JAVASCRIPT;
else if (value == "application/json")
return ContentType::APP_JSON;
else if (value == "application/xml")
return ContentType::APP_XML;
else if (value == "text/plain")
return ContentType::TEXT_PLAIN;
else if (value == "text/html")
return ContentType::TEXT_HTML;
else if (value == "text/xml")
return ContentType::TEXT_XML;
else
return ContentType::NONE;
}
void Response::ReadData(const Str_8& data)
{
Vector<Str_8> lines = data.Split("\r\n");
Vector<Str_8> meta = lines[0].Split(" ");
code = meta[1].ToDecimal<UInt_32>();
for (UInt_64 i = 1; i < lines.Size(); ++i)
{
if (!lines[i].Size())
break;
Vector<Str_8> var = lines[i].Split(": ");
if (var[0].GetLower() == "server")
{
server = var[1];
continue;
}
else if (var[0].GetLower() == "content-type")
{
Vector<Str_8> ctData = var[1].Split(";");
cType = StrToContentType(ctData[0].GetLower());
continue;
}
header.Push(lines[i]);
}
}
}

236
src/io/socket/SSL.cpp Normal file
View File

@@ -0,0 +1,236 @@
#include "ehs/io/socket/SSL.h"
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
namespace ehs
{
SSL::~SSL()
{
if (!IsValid())
return;
if (sslHdl)
{
if (connection)
SSL_shutdown(sslHdl);
SSL_free(sslHdl);
}
if (ctx)
SSL_CTX_free(ctx);
}
SSL::SSL()
: ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const AddrType type)
: TCP(type), ctx(nullptr), sslHdl(nullptr)
{
SSL::Initialize();
}
SSL::SSL(TCP&& tcp) noexcept
: TCP(std::move(tcp)), ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const TCP& tcp)
: TCP(tcp), ctx(nullptr), sslHdl(nullptr)
{
}
SSL::SSL(const SSL& ssl)
: TCP(ssl), ctx(nullptr), sslHdl(nullptr)
{
}
SSL& SSL::operator=(const SSL& ssl)
{
if (this == &ssl)
return *this;
TCP::operator=(ssl);
ctx = nullptr;
sslHdl = nullptr;
return *this;
}
void SSL::Initialize()
{
TCP::Initialize();
if (IsValid())
return;
SSL_library_init();
}
void SSL::Release()
{
TCP::Release();
if (!IsValid())
return;
if (sslHdl)
{
if (connection)
SSL_shutdown(sslHdl);
SSL_free(sslHdl);
sslHdl = nullptr;
}
if (ctx)
{
SSL_CTX_free(ctx);
ctx = nullptr;
}
}
void SSL::Bind(const Str_8& address, unsigned short port)
{
if (bound)
return;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_server_method());
sslHdl = SSL_new(ctx);
SSL_set_fd(sslHdl, hdl);
TCP::Bind(address, port);
}
SSL* SSL::Accept()
{
if (!bound)
return nullptr;
TCP* tcp = TCP::Accept();
SSL* client = new SSL(std::move(*tcp));
delete tcp;
client->ctx = nullptr;
client->sslHdl = SSL_new(ctx);
SSL_set_fd(client->sslHdl, client->hdl);
int err = SSL_accept(client->sslHdl);
if (!err)
{
EHS_LOG_INT("Error", 0, "Failed SSL handshake with error #" + Str_8::FromNum(SSL_get_error(client->sslHdl, err)) + ".");
return {};
}
return client;
}
void SSL::Connect(const Str_8& address, const UInt_16 port)
{
if (bound)
return;
TCP::Connect(address, port);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
sslHdl = SSL_new(ctx);
SSL_set_fd(sslHdl, hdl);
SSL_connect(sslHdl);
}
UInt_64 SSL::Send(const Byte* const buffer, const UInt_32 size)
{
int written = SSL_write(sslHdl, buffer, (int)size);
if (written <= 0)
{
int code = SSL_get_error(sslHdl, written);
ERR_print_errors_fp(stderr);
EHS_LOG_INT("Error", 0, "Failed to send data with error #" + Str_8::FromNum(code) + ".");
return 0;
}
return written;
}
UInt_64 SSL::Receive(Byte* const buffer, const UInt_32 size)
{
int received = SSL_read(sslHdl, buffer, (int)size);
if (received <= 0)
{
int code = SSL_get_error(sslHdl, received);
ERR_print_errors_fp(stderr);
EHS_LOG_INT("Error", 0, "Failed to receive data with error #" + Str_8::FromNum(code) + ".");
return 0;
}
return received;
}
void SSL::UseCertificate(const Byte* data, const UInt_64 size)
{
X509 *cert = d2i_X509(nullptr, &data, (long)size);
if (!cert)
{
EHS_LOG_INT("Error", 0, "Invalid certificate.");
return;
}
if (SSL_CTX_use_certificate(ctx, cert) != 1)
{
EHS_LOG_INT("Error", 1, "Failed to use certificate.");
return;
}
X509_free(cert);
}
void SSL::UsePrivateKey(const Byte* data, const UInt_64 size)
{
EVP_PKEY *key = d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &data, (long)size);
if (!key)
{
EHS_LOG_INT("Error", 0, "Invalid private key.");
return;
}
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
{
EHS_LOG_INT("Error", 1, "Failed to use private key.");
return;
}
EVP_PKEY_free(key);
}
bool SSL::IsValid()
{
return TCP::IsValid() && sslHdl;
}
}

1316
src/io/socket/Socket.cpp Normal file

File diff suppressed because it is too large Load Diff

478
src/io/socket/TCP_BSD.cpp Normal file
View File

@@ -0,0 +1,478 @@
#include "ehs/io/socket/TCP_BSD.h"
#include "ehs/io/socket/DNS.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
namespace ehs
{
TCP::~TCP()
{
if (hdl == EHS_INVALID_SOCKET)
return;
if (connection)
{
if (shutdown(hdl, SHUT_RDWR) == -1)
EHS_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
EHS_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
TCP::TCP()
: hdl(EHS_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(EHS_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = EHS_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(EHS_INVALID_SOCKET)
{
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(std::move(tcp));
hdl = tcp.hdl;
tcp.hdl = EHS_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = EHS_INVALID_SOCKET;
return *this;
}
void TCP::Initialize()
{
if (IsValid())
return;
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
else
return;
if (hdl == EHS_INVALID_SOCKET)
{
UInt_32 code = errno;
EHS_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
}
}
void TCP::Release()
{
if (!IsValid())
return;
if (connection)
{
if (shutdown(hdl, SHUT_RDWR) == -1)
EHS_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
EHS_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
connection = false;
bound = false;
listening = false;
connected = false;
hdl = EHS_INVALID_SOCKET;
}
void TCP::Bind(const Str_8& address, unsigned short port)
{
if (!IsValid() || bound || connection)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->localAddr = address;
this->localPort = port;
bound = true;
}
void TCP::Listen()
{
if (connection || !IsValid() || !bound || listening)
return;
int code = listen(hdl, SOMAXCONN);
if (code == -1)
{
EHS_LOG_INT("Error", 0, "Failed to listen with error #" + Str_8::FromNum(errno) + ".");
return;
}
listening = true;
}
TCP* TCP::Accept()
{
if (connection || !IsValid() || !bound || !listening)
return nullptr;
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in6);
TCP* client = new TCP();
client->addrType = addrType;
client->localAddr = localAddr;
client->localPort = localPort;
client->connection = true;
client->hdl = accept(hdl, (sockaddr*)&remote, &addrLen);
if (client->hdl == EHS_INVALID_SOCKET)
{
if (errno != EWOULDBLOCK)
EHS_LOG_INT("Error", 0, "Failed to accept client with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
EHS_LOG_INT("Error", 1, "Failed to convert IPv6 address with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
EHS_LOG_INT("Error", 1, "Failed to convert IPv4 address with error #" + Str_8::FromNum(errno) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return client;
}
void TCP::Connect(const Str_8& address, const unsigned short port)
{
if (connection || !IsValid() || listening)
return;
remoteHostName = address;
remoteAddr = DNS::Resolve(addrType, address);
remotePort = port;
if (addrType == AddrType::IPV6)
Connect_v6(remoteAddr, port);
else if (addrType == AddrType::IPV4)
Connect_v4(remoteAddr, port);
connected = true;
}
UInt_64 TCP::Send(const Byte *const buffer, const UInt_32 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
EHS_LOG_INT("Error", 1, "Attempted to send while socket is not connected or a connection.");
return 0;
}
SInt_64 sent = send(hdl, (char*)buffer, size, 0);
if (sent == -1)
{
int err = errno;
if (err == ECONNRESET)
{
Release();
EHS_LOG_INT("Information", 0, "Connection dropped.");
}
else
EHS_LOG_INT("Error", 1, "Failed to send with error #" + Str_8::FromNum(err) + ".");
return 0;
}
return (UInt_64)sent;
}
UInt_64 TCP::Receive(Byte* const buffer, const UInt_32 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
EHS_LOG_INT("Error", 1, "Attempted to receive while socket is not connected or a connection.");
return 0;
}
SInt_64 received = recv(hdl, (char*)buffer, size, 0);
if (received == -1)
{
int err = errno;
if (err == ECONNRESET)
{
Release();
EHS_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err != EWOULDBLOCK)
{
EHS_LOG_INT("Error", 2, "Failed to receive with error #" + Str_8::FromNum(err) + ".");
}
return 0;
}
return (UInt_64)received;
}
void TCP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve flags.");
return;
}
if (blocking)
flags ^= O_NONBLOCK;
else
flags |= O_NONBLOCK;
if (fcntl(hdl, F_SETFL, flags) == -1)
EHS_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(errno) + ".");
}
bool TCP::IsBlocking() const
{
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
EHS_LOG_INT("Error", 0, "Failed to retrieve flags.");
return true;
}
return !(flags & O_NONBLOCK);
}
bool TCP::IsValid() const
{
return hdl != EHS_INVALID_SOCKET;
}
void TCP::Bind_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void TCP::Bind_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
{
result.sin_addr.s_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void TCP::Connect_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
int err = errno;
if (err == ETIMEDOUT)
{
EHS_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
EHS_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
void TCP::Connect_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
int err = errno;
if (err == ETIMEDOUT)
{
EHS_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
EHS_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
};

500
src/io/socket/TCP_W32.cpp Normal file
View File

@@ -0,0 +1,500 @@
#include "io/socket/TCP_W32.h"
#include "io/socket/DNS.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace ehs
{
TCP::~TCP()
{
if (hdl == EHS_INVALID_SOCKET)
return;
Int_32 code;
if (connection)
{
code = shutdown(hdl, SD_SEND);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (!connection && WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
TCP::TCP()
: hdl(EHS_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(EHS_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = EHS_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(EHS_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = tcp.hdl;
tcp.hdl = EHS_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = EHS_INVALID_SOCKET;
TCP::Initialize();
return *this;
}
void TCP::Initialize()
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
EHS_LOG_INT("Error", 0, "WSAStartup failed with the error #" + Str_8::FromNum(code) + ".");
return;
}
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
else
return;
if (hdl == EHS_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
}
void TCP::Release()
{
if (!IsValid())
return;
Int_32 code;
if (connection)
{
code = shutdown(hdl, SD_SEND);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = EHS_INVALID_SOCKET;
if (!connection && WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
connection = false;
bound = false;
listening = false;
connected = false;
}
void TCP::Bind(const Str_8& address, unsigned short port)
{
if (!IsValid() || bound || connection)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->localAddr = address;
this->localPort = port;
bound = true;
}
void TCP::Listen()
{
if (connection || !IsValid() || !bound || listening)
return;
int code = listen(hdl, SOMAXCONN);
if (code == -1)
{
EHS_LOG_INT("Error", 0, "Failed to listen with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
listening = true;
}
TCP* TCP::Accept()
{
if (connection || !IsValid() || !bound || !listening)
return nullptr;
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in6);
TCP* client = new TCP();
client->addrType = addrType;
client->localAddr = localAddr;
client->localPort = localPort;
client->connection = true;
client->hdl = accept(hdl, (sockaddr*)&remote, (int*)&addrLen);
if (client->hdl == EHS_INVALID_SOCKET)
{
Int_32 code = WSAGetLastError();
if (code != WSAEWOULDBLOCK)
EHS_LOG_INT("Error", 0, "Failed to accept client with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
delete client;
return nullptr;
}
client->remoteAddr = tmpAddr;
client->remotePort = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return client;
}
void TCP::Connect(const Str_8& address, const unsigned short port)
{
if (connection || !IsValid() || listening)
return;
remoteHostName = address;
remoteAddr = DNS::Resolve(addrType, address);
remotePort = port;
if (addrType == AddrType::IPV6)
Connect_v6(remoteAddr, port);
else if (addrType == AddrType::IPV4)
Connect_v4(remoteAddr, port);
connected = true;
}
UInt_64 TCP::Send(const Byte *const buffer, const UInt_32 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
EHS_LOG_INT("Error", 1, "Attempted to send while socket is not connected or a connection.");
return 0;
}
SInt_64 sent = (SInt_64)send(hdl, (char*)buffer, (int)size, 0);
if (sent == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
Release();
EHS_LOG_INT("Information", 0, "Connection dropped.");
}
else
EHS_LOG_INT("Error", 1, "Failed to send with error #" + Str_8::FromNum(err) + ".");
return 0;
}
return (UInt_64)sent;
}
UInt_64 TCP::Receive(Byte* const buffer, const UInt_32 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
EHS_LOG_INT("Error", 1, "Attempted to receive while socket is not connected or a connection.");
return 0;
}
SInt_64 received = (SInt_64)recv(hdl, (char*)buffer, (int)size, 0);
if (received == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
Release();
EHS_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err == WSAECONNABORTED)
{
EHS_LOG_INT("Information", 1, "Receiving timed-out.");
}
else if (err != WSAEWOULDBLOCK)
{
EHS_LOG_INT("Error", 2, "Failed to receive with error #" + Str_8::FromNum(err) + ".");
}
return 0;
}
return (UInt_64)received;
}
void TCP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
u_long r = (u_long)!blocking;
int result = ioctlsocket(hdl, FIONBIO, &r);
if (result != NO_ERROR)
EHS_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(result) + ".");
}
bool TCP::IsBlocking() const
{
u_long r = 0;
if (ioctlsocket(hdl, FIONREAD, &r) == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool TCP::IsValid() const
{
return hdl != EHS_INVALID_SOCKET;
}
void TCP::Bind_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void TCP::Bind_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.S_un.S_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void TCP::Connect_v6(const Str_8& address, unsigned short port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
int code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAETIMEDOUT)
{
EHS_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
EHS_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
void TCP::Connect_v4(const Str_8& address, unsigned short port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
code = connect(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAETIMEDOUT)
{
EHS_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
EHS_LOG_INT("Error", 3, "Failed to connect with error #" + Str_8::FromNum(err) + ".");
}
return;
}
}
}

362
src/io/socket/UDP_BSD.cpp Normal file
View File

@@ -0,0 +1,362 @@
#include "ehs/io/socket/UDP_BSD.h"
#include "ehs/Log.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
namespace ehs
{
UDP::~UDP()
{
if (hdl == EHS_INVALID_SOCKET)
return;
Int_32 code = close(hdl);
if (code == -1)
EHS_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
UDP::UDP()
: hdl(EHS_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(EHS_INVALID_SOCKET)
{
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
else
return;
if (hdl == EHS_INVALID_SOCKET)
{
UInt_32 code = errno;
EHS_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
return;
}
}
UDP::UDP(UDP&& udp) noexcept
: BaseUDP(std::move(udp)), hdl(udp.hdl)
{
udp.hdl = EHS_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(EHS_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = EHS_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = EHS_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = close(hdl);
if (code == -1)
EHS_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
hdl = EHS_INVALID_SOCKET;
bound = false;
}
void UDP::Bind(const AddrType type, const Str_8& address, const UInt_16 port)
{
if (!IsValid() || bound)
return;
if (type == AddrType::IPV6)
Bind_v6(address, port);
else if (type == AddrType::IPV4)
Bind_v4(address, port);
this->address = address;
this->port = port;
bound = true;
}
UInt_64 UDP::Send(const AddrType type, const Str_8& address, const UInt_16 port, const Byte *const data, const UInt_64 size)
{
if (type == AddrType::IPV6)
return Send_v6(address, port, data, size);
else if (type == AddrType::IPV4)
return Send_v4(address, port, data, size);
return 0;
}
UInt_64 UDP::Receive(AddrType* const type, Str_8* const address, UInt_16* const port, Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in6);
SInt_64 received;
received = recvfrom(hdl, data, size, 0, (sockaddr*)&remote, &addrLen);
if (received == -1)
{
int code = errno;
if (code != ECONNRESET && code != EWOULDBLOCK)
{
Release();
EHS_LOG_INT("Error", 1, "Failed to receive with error #" + Str_8::FromNum(code) + ".");
}
return 0;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = errno;
EHS_LOG_INT("Error", 2, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*type = AddrType::IPV6;
*address = tmpAddr;
*port = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = errno;
EHS_LOG_INT("Error", 2, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*type = AddrType::IPV4;
*address = tmpAddr;
*port = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return received;
}
void UDP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
if (fcntl(hdl, F_SETFL, O_NONBLOCK, blocking) == -1)
EHS_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(errno) + ".");
}
bool UDP::IsBlocking() const
{
return (bool)fcntl(hdl, F_GETFL, O_NONBLOCK);
}
bool UDP::IsValid() const
{
return hdl != EHS_INVALID_SOCKET;
}
void UDP::Bind_v6(const Str_8& address, const UInt_16 port) const
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
void UDP::Bind_v4(const Str_8& address, const UInt_16 port) const
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.s_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == -1)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
UInt_64 UDP::Send_v6(const Str_8& address, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
SInt_64 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in6));
if (sent == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
UInt_64 UDP::Send_v4(const Str_8& address, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
SInt_64 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in));
if (sent == -1)
{
Int_32 dCode = errno;
EHS_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
}

380
src/io/socket/UDP_W32.cpp Normal file
View File

@@ -0,0 +1,380 @@
#include "io/socket/UDP_W32.h"
#include "ehs/Log.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace ehs
{
UDP::~UDP()
{
if (hdl == EHS_INVALID_SOCKET)
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 1, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
UDP::UDP()
: hdl(EHS_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(EHS_INVALID_SOCKET)
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
EHS_LOG_INT("Error", 0, "WSAStartup failed with the error #" + Str_8::FromNum(code) + ".");
return;
}
if (addrType == AddrType::IPV6)
hdl = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
else if (addrType == AddrType::IPV4)
hdl = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
else
return;
if (hdl == EHS_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
UDP::UDP(UDP&& udp) noexcept
: BaseUDP(std::move(udp)), hdl(udp.hdl)
{
udp.hdl = EHS_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(EHS_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = EHS_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = EHS_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = EHS_INVALID_SOCKET;
if (WSACleanup() == SOCKET_ERROR)
EHS_LOG_INT("Error", 1, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
bound = false;
}
void UDP::Bind(const Str_8& address, const UInt_16 port)
{
if (!IsValid() || bound)
return;
if (addrType == AddrType::IPV6)
Bind_v6(address, port);
else if (addrType == AddrType::IPV4)
Bind_v4(address, port);
this->address = address;
this->port = port;
bound = true;
}
UInt_64 UDP::Send(const Str_8& address, const UInt_16 port, const Byte *const data, const UInt_64 size)
{
if (addrType == AddrType::IPV6)
return Send_v6(address, port, data, size);
else if (addrType == AddrType::IPV4)
return Send_v4(address, port, data, size);
return 0;
}
UInt_64 UDP::Receive(Str_8* const address, UInt_16* const port, Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
sockaddr_in6 remote = {};
UInt_32 addrLen = sizeof(sockaddr_in);
SInt_64 received = recvfrom(hdl, (char*)data, (int)size, 0, (sockaddr*)&remote, (int*)&addrLen);
if (received == SOCKET_ERROR)
{
int code = WSAGetLastError();
if (code != WSAECONNRESET && code != WSAEWOULDBLOCK)
{
Release();
EHS_LOG_INT("Error", 1, "Failed to receive with error #" + Str_8::FromNum(code) + ".");
}
return 0;
}
if (addrLen == sizeof(sockaddr_in6))
{
char tmpAddr[INET6_ADDRSTRLEN];
if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 2, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(remote.sin6_port);
}
else if (addrLen == sizeof(sockaddr_in))
{
char tmpAddr[INET_ADDRSTRLEN];
if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN))
{
Int_32 code = WSAGetLastError();
EHS_LOG_INT("Error", 2, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + ".");
return received;
}
*address = tmpAddr;
*port = ntohs(((sockaddr_in*)&remote)->sin_port);
}
return received;
}
void UDP::SetBlocking(const bool blocking)
{
if (!IsValid())
{
EHS_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
u_long r = (u_long)!blocking;
int result = ioctlsocket(hdl, FIONBIO, &r);
if (result != NO_ERROR)
EHS_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(result) + ".");
}
bool UDP::IsBlocking() const
{
u_long r = 0;
if (ioctlsocket(hdl, FIONREAD, &r) == SOCKET_ERROR)
EHS_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool UDP::IsValid() const
{
return hdl != EHS_INVALID_SOCKET;
}
void UDP::Bind_v6(const Str_8& address, const UInt_16 port)
{
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
if (address.Size())
{
Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin6_addr = in6addr_any;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6));
if (code == SOCKET_ERROR)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
void UDP::Bind_v4(const Str_8& address, const UInt_16 port)
{
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
if (address.Size())
{
int code = inet_pton(AF_INET, address, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return;
}
}
else
{
result.sin_addr.S_un.S_addr = INADDR_ANY;
}
int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in));
if (code == SOCKET_ERROR)
{
EHS_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
return;
}
}
UInt_64 UDP::Send_v6(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in6 result = {};
result.sin6_family = AF_INET6;
result.sin6_port = htons(port);
Int_32 code = inet_pton(AF_INET6, addr, &result.sin6_addr);
if (!code)
{
EHS_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
Int_32 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in6));
if (sent == SOCKET_ERROR)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
UInt_64 UDP::Send_v4(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
EHS_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
sockaddr_in result = {};
result.sin_family = AF_INET;
result.sin_port = htons(port);
int code = inet_pton(AF_INET, addr, &result.sin_addr);
if (!code)
{
EHS_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
int sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in));
if (sent == SOCKET_ERROR)
{
Int_32 dCode = WSAGetLastError();
EHS_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
}

View File

@@ -0,0 +1,653 @@
#include "ehs/io/socket/rest/Spotify.h"
#include "ehs/io/socket/DNS.h"
#include "ehs/system/System.h"
#include "ehs/URI.h"
namespace ehs
{
const Str_8 Spotify::trackUriPrefix = "https://open.spotify.com/track/";
Spotify::~Spotify()
{
client.Release();
}
Spotify::Spotify()
: forceVerify(false)
{
}
Spotify::Spotify(const Str_8& clientId, const Str_8& secret, const Str_8& redURI, const Array<Str_8>& scopes, const bool forceVerify)
: client(AddrType::IPV4), clientId(clientId), secret(secret), redURI(redURI), scopes(scopes), forceVerify(forceVerify)
{
}
bool Spotify::Authorize()
{
Str_8 scopesFinal;
for (UInt_64 i = 0; i < scopes.Size(); ++i)
{
scopesFinal += scopes[i];
if (i < scopes.Size() - 1)
scopesFinal += "%20";
}
Str_8 rURI = URI::Encode(redURI);
Str_8 uri = "https://accounts.spotify.com/authorize?client_id=" + clientId + "&redirect_uri=" + rURI +
"&response_type=code&show_dialog=" + (forceVerify ? "true" : "false") + "&scope=" +
scopesFinal;
TCP server(AddrType::IPV4);
server.Initialize();
server.Bind(DNS::Resolve(server.GetAddressType(), "localhost"), 65534);
server.Listen();
System::OpenURI(uri);
TCP* cbClient = server.Accept();
Request cbReq = cbClient->RecvReq();
if (cbReq.GetResource() != "/callback")
{
Response resp(423, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody("<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Hostile Information Received</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
return false;
}
Response resp(200, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody("<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Authentication Successful</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
server.Release();
SSL accounts(AddrType::IPV4);
accounts.Initialize();
accounts.Connect("accounts.spotify.com", SSL::HTTPS_Port);
Request authReq(Verb::POST, "/api/token");
authReq.SetContentType(ContentType::APP_FORMURLENCODED);
authReq.BasicAuth(clientId, secret);
authReq.AddToBody("grant_type", "authorization_code");
authReq.AddToBody("code", cbReq.GetQuery("code"));
authReq.AddToBody("redirect_uri", rURI);
accounts.SendReq(authReq);
Response authRes = accounts.RecvRes();
accounts.Release();
if (authRes.GetCode() == 400)
{
EHS_LOG_INT("Error", 0, "Could not authorize with Spotify because the client id was invalid.");
return false;
}
else if (authRes.GetCode() == 403)
{
EHS_LOG_INT("Error", 1, "Could not authorize with Spotify because the secret was invalid.");
return false;
}
else if (authRes.GetCode() != 200)
{
EHS_LOG_INT("Error", 2, "Could not authorize with Spotify with code " + Str_8::FromNum(authRes.GetCode()) + ".");
return false;
}
Json authResJson = authRes.GetJson();
JsonObj* value = (JsonObj*)authResJson.GetValue();
if (!value)
return false;
JsonVar* tokenVar = value->GetVar("access_token");
if (!tokenVar)
return false;
JsonVar* rTokenVar = value->GetVar("refresh_token");
if (!rTokenVar)
return false;
token = ((JsonStr*)tokenVar->GetValue())->value;
rToken = ((JsonStr*)rTokenVar->GetValue())->value;
return true;
}
UInt_32 Spotify::SetVolume(const UInt_8 level)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/volume");
req.AddQuery("volume_percent", Str_8::FromNum(level));
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Play()
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/play");
req.BearerAuth(token);
client.Release();
client.Initialize();
client.Connect("", SSL::HTTPS_Port);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Pause()
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/pause");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SetRepeat(const SpotifyState state)
{
StartConnection();
Str_8 result;
switch (state)
{
case SpotifyState::TRACK:
result = "track";
break;
case SpotifyState::CONTEXT:
result = "context";
break;
case SpotifyState::OFF:
result = "off";
break;
}
Request req(Verb::PUT, "/v1/me/player/repeat");
req.AddQuery("state", result);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SetShuffle(const bool state)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/repeat");
req.AddQuery("state", state ? "true" : "false");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::SearchTrack(Vector<Str_8>& artists, Str_8& id, Str_8& name)
{
StartConnection();
Request req(Verb::GET, "/v1/search");
Str_8 q = "artist%3A";
for (UInt_64 i = 0; i < artists.Size(); ++i)
{
q += artists[i].ReplaceAll(" ", "+");
if (i != artists.Size() - 1)
q += "%2C+";
}
q += "+track%3A" + name.ReplaceAll(" ", "+");
req.AddQuery("q", q);
req.AddQuery("type", "track");
req.AddQuery("limit", "1");
req.AddQuery("offset", "0");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return SearchTrack(artists, name, id);
}
Json body = res.GetJson();
JsonNum* total = (JsonNum*)body.RetrieveValue("tracks.total");
if (!total || total->value == 0.0f)
return 0;
JsonObj* item = (JsonObj*)body.RetrieveValue("tracks.items[0]");
if (!item)
return 0;
JsonVar* artistsVar = item->GetVar("artists");
if (!artistsVar)
return 0;
JsonArray* artistsArray = (JsonArray*)artistsVar->GetValue();
if (!artistsArray)
return 0;
JsonVar* trackIdVar = item->GetVar("id");
if (!trackIdVar)
return 0;
JsonStr* trackIdValue = (JsonStr*)trackIdVar->GetValue();
if (!trackIdValue)
return 0;
JsonVar* trackNameVar = item->GetVar("name");
if (!trackNameVar)
return 0;
JsonStr* trackNameValue = (JsonStr*)trackNameVar->GetValue();
if (!trackNameValue)
return 0;
artists.Resize(artistsArray->Size());
for (UInt_64 i = 0; i < artistsArray->Size(); ++i)
{
JsonObj* artistObj = (JsonObj*)(*artistsArray)[i];
JsonVar* artistNameVar = artistObj->GetVar("name");
JsonStr* artistNameValue = (JsonStr*)artistNameVar->GetValue();
artists[i] = artistNameValue->value;
}
id = trackIdValue->value;
name = trackNameValue->value;
return res.GetCode();
}
UInt_32 Spotify::GetPlayingTrack(Vector<Str_8>& artists, Str_8& id, Str_8& name)
{
StartConnection();
Request req(Verb::GET, "/v1/me/player/currently-playing");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return GetPlayingTrack(artists, id, name);
}
Json result = res.GetJson();
JsonObj* itemObj = (JsonObj*)result.RetrieveValue("item");
if (!itemObj)
return {};
JsonVar* artistsVar = itemObj->GetVar("artists");
if (!artistsVar)
return 0;
JsonArray* artistsArray = (JsonArray*)artistsVar->GetValue();
if (!artistsArray)
return 0;
JsonVar* trackIdVar = itemObj->GetVar("id");
if (!trackIdVar)
return 0;
JsonStr* trackIdValue = (JsonStr*)trackIdVar->GetValue();
if (!trackIdValue)
return 0;
JsonVar* trackNameVar = itemObj->GetVar("name");
if (!trackNameVar)
return 0;
JsonStr* trackNameValue = (JsonStr*)trackNameVar->GetValue();
if (!trackNameValue)
return 0;
artists.Resize(artistsArray->Size());
for (UInt_64 i = 0; i < artists.Size(); ++i)
{
JsonObj* artistObj = (JsonObj*)(*artistsArray)[i];
JsonVar* artistNameVar = artistObj->GetVar("name");
JsonStr* artistNameValue = (JsonStr*)artistNameVar->GetValue();
artists[i] = artistNameValue->value;
}
id = trackIdValue->value;
name = trackNameValue->value;
return res.GetCode();
}
UInt_32 Spotify::GetQueue(Array<Track>& tracks)
{
StartConnection();
Request req(Verb::GET, "/v1/me/player/queue");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return GetQueue(tracks);
}
Json json = res.GetJson();
JsonObj* root = (JsonObj*)json.GetValue();
JsonVar* currentVar = root->GetVar("currently_playing");
if (!currentVar->GetValue())
return res.GetCode();
JsonObj* currentObj = (JsonObj*)currentVar->GetValue();
JsonArray* cArtists = (JsonArray*)currentObj->GetVar("artists")->GetValue();
JsonArray* queue = (JsonArray*)root->GetVar("queue")->GetValue();
tracks.Resize(queue->Size() + 1);
tracks[0].artists.Resize(cArtists->Size());
for (UInt_64 i = 0; i < cArtists->Size(); ++i)
tracks[0].artists[i] = ((JsonStr*)((JsonObj*)(*cArtists)[i])->GetVar("name")->GetValue())->value;
tracks[0].id = ((JsonStr*)currentObj->GetVar("id")->GetValue())->value;
tracks[0].name = ((JsonStr*)currentObj->GetVar("name")->GetValue())->value;
for (UInt_64 i = 1; i < queue->Size(); ++i)
{
JsonObj* trackObj = (JsonObj*)(*queue)[i - 1];
JsonArray* artists = (JsonArray*)trackObj->GetVar("artists")->GetValue();
tracks[i].artists.Resize(artists->Size());
for (UInt_64 a = 0; a < artists->Size(); ++a)
tracks[i].artists[a] = ((JsonStr*)((JsonObj*)(*artists)[a])->GetVar("name")->GetValue())->value;
tracks[i].id = ((JsonStr*)trackObj->GetVar("id")->GetValue())->value;
tracks[i].name = ((JsonStr*)trackObj->GetVar("name")->GetValue())->value;
}
return res.GetCode();
}
UInt_32 Spotify::QueueTrack(const Str_8& id)
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/queue");
req.AddQuery("uri", "spotify:track:" + id);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return QueueTrack(id);
}
return res.GetCode();
}
UInt_32 Spotify::AddTracks(const Str_8& playlistId, const Array<Str_8>& trackIds, const UInt_32 pos)
{
StartConnection();
JsonObj obj(0);
JsonArray tracks(trackIds.Size(), 0);
for (UInt_64 i = 0; i < trackIds.Size(); ++i)
tracks[i] = (JsonBase*)new JsonStr("spotify:track:" + trackIds[i]);
obj.AddVar({"uris", tracks});
obj.AddVar({"position", (float)pos});
Json json(obj);
Request req(Verb::POST, "/v1/playlists/" + playlistId + "/tracks");
req.BearerAuth(token);
req.SetContentType(ContentType::APP_JSON);
req.SetBody(json.ToStr(true));
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return AddTracks(playlistId, trackIds, pos);
}
return res.GetCode();
}
UInt_32 Spotify::AddTrack(const Str_8& playlistId, const Str_8& trackId, const UInt_32 pos)
{
StartConnection();
Request req(Verb::POST, "/v1/playlists/" + playlistId + "/tracks");
req.AddQuery("position", Str_8::FromNum(pos));
req.AddQuery("uris", "spotify:track:" + trackId);
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return AddTrack(playlistId, trackId, pos);
}
return res.GetCode();
}
UInt_32 Spotify::Skip()
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/next");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Skip();
}
return res.GetCode();
}
UInt_32 Spotify::Previous()
{
StartConnection();
Request req(Verb::POST, "/v1/me/player/previous");
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Previous();
}
return res.GetCode();
}
UInt_32 Spotify::Seek(const UInt_32 pos)
{
StartConnection();
Request req(Verb::PUT, "/v1/me/player/seek");
req.AddQuery("position_ms", Str_8::FromNum(pos));
req.BearerAuth(token);
client.SendReq(req);
Response res = client.RecvRes();
if (res.GetCode() == 401)
{
ReAuthorize();
return Seek(pos);
}
return res.GetCode();
}
void Spotify::StartConnection()
{
client.Release();
client.Initialize();
client.Connect("api.spotify.com", SSL::HTTPS_Port);
}
bool Spotify::ReAuthorize()
{
SSL accounts;
accounts.Initialize();
accounts.Connect("accounts.spotify.com", SSL::HTTPS_Port);
Request reAuth(Verb::POST, "/api/token");
reAuth.SetContentType(ContentType::APP_FORMURLENCODED);
reAuth.BasicAuth(clientId, secret);
reAuth.AddToBody("grant_type", "refresh_token");
reAuth.AddToBody("refresh_token", rToken);
accounts.SendReq(reAuth);
Response res = accounts.RecvRes();
accounts.Release();
if (res.GetCode() != 200)
{
EHS_LOG_INT("Error", 0, "Failed to reauthorize with Spotify with code #" + Str_8::FromNum(res.GetCode()) + ".");
client.Release();
return false;
}
Json json = res.GetJson();
JsonObj* obj = (JsonObj*)json.GetValue();
JsonVar* tokenVar = obj->GetVar("access_token");
if (!tokenVar)
return false;
token = ((JsonStr*)tokenVar->GetValue())->value;
return true;
}
bool Spotify::IsActive() const
{
return client.IsConnected();
}
Str_8 Spotify::GetClientId() const
{
return clientId;
}
Str_8 Spotify::GetSecret() const
{
return secret;
}
Str_8 Spotify::GetRedURI() const
{
return redURI;
}
bool Spotify::IsVerificationForced() const
{
return forceVerify;
}
}

View File

@@ -0,0 +1,150 @@
#include "ehs/io/socket/rest/Twitch.h"
#include "ehs/io/socket/DNS.h"
#include "ehs/system/System.h"
#include "ehs/URI.h"
namespace ehs
{
Twitch::~Twitch()
{
client.Release();
}
Twitch::Twitch()
: forceVerify(false)
{
}
Twitch::Twitch(const Str_8& clientId, const Str_8& secret, const Str_8& redURI, const Array<Str_8>& scopes, const bool forceVerify)
: client(AddrType::IPV4), clientId(clientId), secret(secret), redURI(redURI), scopes(scopes), forceVerify(forceVerify)
{
}
bool Twitch::Authorize()
{
Str_8 scopesFinal;
for (UInt_64 i = 0; i < scopes.Size(); ++i)
{
scopesFinal += scopes[i];
if (i < scopes.Size() - 1)
scopesFinal += "%20";
}
Str_8 rURI = URI::Encode(redURI);
Str_8 uri = "https://id.twitch.tv/oauth2/authorize?client_id=" + clientId + "&redirect_uri=" + rURI +
"&response_type=code&force_verify=" + (forceVerify ? "true" : "false") + "&scope=" +
scopesFinal;
TCP server(AddrType::IPV4);
server.Bind(DNS::Resolve(client.GetAddressType(), "localhost"), 65535);
server.Listen();
System::OpenURI(uri);
TCP* cbClient = server.Accept();
Request cbReq = cbClient->RecvReq();
if (cbReq.GetResource() != "/callback")
{
Response resp(423, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody(
"<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Hostile Information Received</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
return false;
}
Response resp(200, "Event Horizon");
resp.SetContentType(ContentType::TEXT_HTML);
resp.SetBody(
"<!DOCTYPE html><html><head><title>LWE Response</title><link rel=\"icon\" type=\"image/png\" href=\"https://cdn3.iconfinder.com/data/icons/contour-animals-2/512/wolf-512.png\" /></head><body>Authentication Successful</body></html>");
cbClient->SendRes(resp);
cbClient->Release();
server.Release();
client.Initialize();
client.Connect("id.twitch.tv", SSL::HTTPS_Port);
Request authReq(Verb::POST, "/oauth2/token");
authReq.SetContentType(ContentType::APP_FORMURLENCODED);
authReq.AddToBody("client_id", clientId);
authReq.AddToBody("client_secret", secret);
authReq.AddToBody("code", cbReq.GetQuery("code"));
authReq.AddToBody("grant_type", "authorization_code");
authReq.AddToBody("redirect_uri", redURI);
client.SendReq(authReq);
Response authRes = client.RecvRes();
if (authRes.GetCode() == 400)
{
client.Release();
EHS_LOG_INT("Error", 0, "Could not authorize with Twitch because the client id was invalid.");
return false;
} else if (authRes.GetCode() == 403)
{
client.Release();
EHS_LOG_INT("Error", 1, "Could not authorize with Twitch because the secret was invalid.");
return false;
} else if (authRes.GetCode() != 200)
{
client.Release();
EHS_LOG_INT("Error", 2, "Could not authorize with Twitch.");
return false;
}
Json authResJson = authRes.GetJson();
JsonObj* value = (JsonObj*) authResJson.GetValue();
if (!value)
return false;
JsonVar* var = value->GetVar("access_token");
if (!var)
return false;
token = ((JsonStr*) var->GetValue())->value;
return true;
}
Str_8 Twitch::GetClientId() const
{
return clientId;
}
Str_8 Twitch::GetSecret() const
{
return secret;
}
Str_8 Twitch::GetRedURI() const
{
return redURI;
}
bool Twitch::IsVerificationForced() const
{
return forceVerify;
}
Str_8 Twitch::GetToken() const
{
return token;
}
}

View File

@@ -0,0 +1,177 @@
#include "ehs/io/socket/rest/TwitchChat.h"
#include "ehs/io/socket/DNS.h"
#include "ehs/io/Console.h"
namespace ehs
{
TwitchChat::~TwitchChat()
{
UnInitialize();
}
TwitchChat::TwitchChat()
: initialized(false)
{
}
TwitchChat::TwitchChat(const Str_8& username)
: username(username), initialized(false)
{
}
TwitchChat::TwitchChat(const Str_8& username, const Str_8& token)
: username(username), token(token), initialized(false)
{
}
TwitchChat::TwitchChat(const TwitchChat& chat)
: username(chat.username), token(chat.token), initialized(false)
{
}
TwitchChat& TwitchChat::operator=(const TwitchChat& chat)
{
if (this == &chat)
return *this;
client = TCP();
username = chat.username;
token = chat.token;
channel = Str_8();
initialized = false;
return *this;
}
void TwitchChat::SetToken(const Str_8& newToken)
{
token = newToken;
}
void TwitchChat::Initialize()
{
if (initialized)
return;
client = TCP(ehs::AddrType::IPV4);
client.Connect(DNS::Resolve(AddrType::IPV4, "irc.chat.twitch.tv"), 6667);
client.SetBlocking(false);
Str_8 r("PASS oauth:" + token + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
r = "NICK " + username + "\r\n";
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
initialized = true;
}
void TwitchChat::UnInitialize()
{
if (!initialized)
return;
client.Release();
initialized = false;
}
void TwitchChat::JoinChannel(const Str_8& newChannel)
{
if (!initialized || channel == newChannel)
return;
channel = newChannel;
Str_8 r("Join #" + newChannel + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::LeaveChannel()
{
if (!initialized)
return;
Str_8 r("PART #" + channel + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::SendPong()
{
if (!initialized)
return;
Str_8 r("PONG :tmi.twitch.tv\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
void TwitchChat::SendMsg(const Str_8& msg)
{
if (!initialized)
return;
Str_8 r("PRIVMSG #" + channel + " :" + msg + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
//irc.SendStr(":" + username + "!" + username + "@" + username + ".tmi.twitch.tv PRIVMSG #" + username + " :" + msg + "\r\n");
}
void TwitchChat::WhisperMsg(const Str_8& user, const Str_8& msg)
{
if (!initialized)
return;
Str_8 r("PRIVMSG #jtv :/w " + user + " " + msg + "\r\n");
Console::Write_8("< " + r, false);
client.Send(r.ToBytes(), (int) r.Size());
}
Str_8 TwitchChat::RecvMsg()
{
Str_8 result;
Byte received[1024];
UInt_64 recvSize = 0;
do
{
recvSize = client.Receive(received, 1024);
if (recvSize)
result.Push((Char_8*) received, recvSize);
else
break;
} while (!result.Find("\r\n", nullptr, SearchPattern::RIGHT_LEFT));
return result;
}
Str_8 TwitchChat::GetUsername() const
{
return username;
}
Str_8 TwitchChat::GetChannel() const
{
return channel;
}
}

183
src/io/xdg-shell-protocol.c Normal file
View File

@@ -0,0 +1,183 @@
/* Generated by wayland-scanner 1.22.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 6,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 6,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 6,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 6,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 6,
3, xdg_popup_requests,
3, xdg_popup_events,
};

487
src/json/Json.cpp Normal file
View File

@@ -0,0 +1,487 @@
#include "ehs/json/Json.h"
#include "ehs/Log.h"
namespace ehs
{
Json::~Json()
{
delete value;
}
Json::Json()
: value(nullptr)
{
}
Json::Json(const JsonBase& value)
: value(new JsonBase(value))
{
}
Json::Json(const JsonObj& value)
: value((JsonBase*)new JsonObj(value))
{
}
Json::Json(const JsonArray& value)
: value((JsonBase*)new JsonArray(value))
{
}
Json::Json(const JsonBool& value)
: value((JsonBase*)new JsonBool(value))
{
}
Json::Json(const JsonNum& value)
: value((JsonBase*)new JsonNum(value))
{
}
Json::Json(const JsonStr& value)
: value((JsonBase*)new JsonStr(value))
{
}
Json::Json(const char* data, const UInt_64 size, const UInt_64 extra)
: value(nullptr)
{
Parse({data, size}, extra);
}
Json::Json(const Str_8& data, const UInt_64 extra)
: value(nullptr)
{
Parse(data, extra);
}
Json::Json(Json&& json) noexcept
: value(json.value)
{
json.value = nullptr;
}
Json::Json(const Json& json)
: value(nullptr)
{
if (!json.value)
return;
switch (json.value->GetType())
{
case JsonType::OBJ:
value = (JsonBase*)new JsonObj(*(JsonObj*)json.value);
break;
case JsonType::ARRAY:
value = (JsonBase*)new JsonArray(*(JsonArray*)json.value);
break;
case JsonType::BOOL:
value = (JsonBase*)new JsonBool(*(JsonBool*)json.value);
break;
case JsonType::NUM:
value = (JsonBase*)new JsonNum(*(JsonNum*)json.value);
break;
case JsonType::STR:
value = (JsonBase*)new JsonStr(*(JsonStr*)json.value);
break;
default:
value = new JsonBase();
break;
}
}
Json& Json::operator=(Json&& json) noexcept
{
if (this == &json)
return *this;
delete value;
value = json.value;
json.value = nullptr;
return *this;
}
Json& Json::operator=(const Json& json)
{
if (this == &json)
return *this;
delete value;
value = nullptr;
if (!json.value)
return *this;
switch (json.value->GetType())
{
case JsonType::OBJ:
value = (JsonBase*)new JsonObj(*(JsonObj*)json.value);
break;
case JsonType::ARRAY:
value = (JsonBase*)new JsonArray(*(JsonArray*)json.value);
break;
case JsonType::BOOL:
value = (JsonBase*)new JsonBool(*(JsonBool*)json.value);
break;
case JsonType::NUM:
value = (JsonBase*)new JsonNum(*(JsonNum*)json.value);
break;
case JsonType::STR:
value = (JsonBase*)new JsonStr(*(JsonStr*)json.value);
break;
default:
value = new JsonBase();
break;
}
return *this;
}
JsonBase* Json::GetValue()
{
return value;
}
JsonBase* Json::RetrieveValue(const Str_8& access)
{
if (!value || !access.Size())
return nullptr;
Vector<Str_8> levels = ParseAccess(access);
JsonBase* hierarchy = value;
for (UInt_64 i = 0; i < levels.Size(); ++i)
{
if (hierarchy->GetType() == JsonType::ARRAY)
{
if (levels[i][0] >= '0' && levels[i][0] <= '9')
{
hierarchy = (*((JsonArray*)hierarchy))[levels[i].ToDecimal<UInt_64>()];
}
else
return nullptr;
}
else if (hierarchy->GetType() == JsonType::OBJ)
{
if (levels[i][0] < '0' || levels[i][0] > '9')
{
JsonVar* var = ((JsonObj*)hierarchy)->GetVar(levels[i]);
if (!var || !var->GetValue())
return nullptr;
hierarchy = var->GetValue();
}
else
return nullptr;
}
else
return nullptr;
}
return hierarchy;
}
Str_8 Json::ToStr(const bool compact) const
{
return value->ToStr(0, compact);
}
Vector<Str_8> Json::ParseAccess(const Str_8& access)
{
bool isIndex = false;
const Char_8* start = &access[0];
const Char_8* end = &access[access.Size() - 1];
Vector<Str_8> levels(0, 5);
for (const Char_8* i = &access[0]; i <= end; ++i)
{
if (*i == '[')
{
if (i - start)
levels.Push(Str_8(start, i - start));
start = i + 1;
isIndex = true;
}
else if (*i == ']')
{
if (!isIndex)
{
EHS_LOG_INT("Error", 0, "Index has ended, but never started.");
return levels;
}
if (i - start)
levels.Push(Str_8(start, i - start));
else
{
EHS_LOG_INT("Error", 1, "Index has no value.");
return levels;
}
start = i + 1;
isIndex = false;
}
else if (isIndex && (*i < '0' || *i > '9'))
{
EHS_LOG_INT("Error", 2, "Index has an invalid character, \"" + Str_8(i, 1) + "\". Index must be a whole number.");
return levels;
}
else if (*i == '.')
{
if (i - start)
levels.Push(Str_8(start, i - start));
start = i + 1;
}
else if (!isIndex && *i != '-' && *i != '_' && (*i < 'A' || *i > 'Z') && (*i < 'a' || *i > 'z'))
{
EHS_LOG_INT("Error", 3, "Member variable has an invalid character, \"" + Str_8(i, 1) + "\".");
return levels;
}
}
if (end + 1 - start)
levels.Push(Str_8(start, end + 1 - start));
return levels;
}
void Json::ParseValue(JsonVar* var, const Char_8** begin, const Char_8* end, const UInt_64 extra)
{
const Char_8* start = nullptr;
bool isStr = false;
for (; *begin <= end; ++(*begin))
{
if (**begin == '\"')
{
if (start)
{
if (*begin - start)
((JsonStr*)var->GetValue())->value = Str_8(start, *begin - start);
++(*begin);
return;
}
else
{
start = *begin + 1;
isStr = true;
var->SetValue(JsonStr());
}
}
else if (!start && **begin == '{')
{
++(*begin);
JsonObj obj(extra);
ParseObject(&obj, begin, end, extra);
var->SetValue(obj);
return;
}
else if (!start && **begin == '[')
{
++(*begin);
JsonArray arr(extra);
ParseArray(&arr, begin, end, extra);
var->SetValue(arr);
return;
}
else if (!start && **begin != ' ' && **begin != ',' && **begin != '\r' && **begin != '\n' && **begin != '\t')
{
start = *begin;
}
else if (start && !isStr && (**begin == '\t' || **begin == '\r' || **begin == '\n' || (!var->GetValue() && **begin == ' ') || **begin == ',' || **begin == '}' || **begin == ']'))
{
Str_8 result(start, *begin - start);
if (result == "true")
var->SetValue(true);
else if (result == "false")
var->SetValue(false);
else if (result == "null")
var->SetValue(JsonBase());
else if (result.IsNum())
var->SetValue(result.ToFloat());
return;
}
}
}
JsonVar Json::ParseVar(const Char_8** begin, const Char_8* end, const UInt_64 extra)
{
JsonVar var;
const Char_8* start = nullptr;
for (; *begin <= end; ++(*begin))
{
if (**begin == '}' || **begin == ']')
{
++(*begin);
return var;
}
else if (**begin == '"')
{
if (start)
{
var = JsonVar(Str_8(start, *begin - start));
start = nullptr;
}
else
start = *begin + 1;
}
else if (!start && **begin == ':')
{
if (var.GetHashId())
{
++(*begin);
ParseValue(&var, begin, end, extra);
return var;
}
}
}
return var;
}
void Json::ParseObject(JsonObj* obj, const Char_8** begin, const Char_8* end, const UInt_64 extra)
{
JsonVar var;
do
{
var = ParseVar(begin, end, extra);
}
while(obj->AddVar(var));
}
void Json::ParseArray(JsonArray* arr, const Char_8** begin, const Char_8* end, const UInt_64 extra)
{
const Char_8* start = nullptr;
for (; *begin <= end; ++(*begin))
{
if (**begin == '}' || **begin == ']')
{
++(*begin);
return;
}
else if (**begin == '\"')
{
if (start)
{
if (*begin - start)
arr->Push(start, *begin - start);
start = nullptr;
++(*begin);
continue;
}
else
start = *begin + 1;
}
else if (!start && **begin == '{')
{
++(*begin);
JsonObj obj(extra);
ParseObject(&obj, begin, end, extra);
arr->Push(obj);
continue;
}
else if (!start && **begin == '[')
{
++(*begin);
JsonArray array(extra);
ParseArray(&array, begin, end, extra);
arr->Push(array);
continue;
}
else if (!start && **begin != ' ' && **begin != ',' && **begin != '\r' && **begin != '\n' && **begin != '\t')
{
start = *begin;
}
else if (start && *start != '\"' && (**begin == '\t' || **begin == '\r' || **begin == '\n' || **begin == ' ' || **begin == ',' || **begin == '}' || **begin == ']'))
{
Str_8 result(start, *begin - start);
if (result == "true")
arr->Push(true);
else if (result == "false")
arr->Push(false);
else if (result == "null")
arr->Push(JsonBase());
else if (result.IsNum())
arr->Push(result.ToFloat());
continue;
}
}
}
void Json::Parse(const Str_8& data, const UInt_64 extra)
{
const Char_8* start = nullptr;
const Char_8* end = &data[data.Size() - 1];
for (const Char_8* i = &data[0]; i <= end; ++i)
{
if (*i == '}' || *i == ']')
{
++i;
return;
}
else if (*i == '\"')
{
if (start)
{
if (i - start)
value = new JsonStr(start, i - start);
++i;
return;
}
else
start = i + 1;
}
else if (!start && *i == '{')
{
++i;
JsonObj* obj = new JsonObj(extra);
ParseObject(obj, &i, end, extra);
value = obj;
return;
}
else if (!start && *i == '[')
{
++i;
JsonArray* arr = new JsonArray(extra);
ParseArray(arr, &i, end, extra);
value = arr;
return;
}
else if (!start && *i != ' ' && *i != ',' && *i != '\r' && *i != '\n' && *i != '\t')
{
start = i;
}
else if (start && *start != '\"' && (*i == '\t' || *i == '\r' || *i == '\n' || *i == ' ' || *i == ',' || *i == '}' || *i == ']'))
{
Str_8 result(start, i - start);
if (result == "true")
value = new JsonBool(true);
else if (result == "false")
value = new JsonBool(false);
else if (result == "null")
value = new JsonBase();
else if (result.IsNum())
value = new JsonNum(result.ToFloat());
return;
}
}
}
}

528
src/json/JsonArray.cpp Normal file
View File

@@ -0,0 +1,528 @@
#include "ehs/json/JsonArray.h"
#include "ehs/json/JsonObj.h"
#include "ehs/json/JsonBool.h"
#include "ehs/json/JsonNum.h"
#include "ehs/json/JsonStr.h"
namespace ehs
{
JsonArray::~JsonArray()
{
for (UInt_64 i = 0; i < size; ++i)
delete data[i];
delete[] data;
}
JsonArray::JsonArray()
: JsonBase(JsonType::ARRAY), size(0), extra(0), rawSize(0), data(nullptr)
{
}
JsonArray::JsonArray(const UInt_64 extra)
: JsonBase(JsonType::ARRAY), size(0), extra(extra), rawSize(extra), data(new JsonBase*[rawSize])
{
}
JsonArray::JsonArray(const UInt_64 size, const UInt_64 extra)
: JsonBase(JsonType::ARRAY), size(size), extra(extra), rawSize(size + extra), data(new JsonBase*[rawSize])
{
}
JsonArray::JsonArray(JsonArray&& ja) noexcept
: JsonBase(ja), size(ja.size), extra(ja.extra), rawSize(ja.rawSize), data(ja.data)
{
ja.size = 0;
ja.extra = 0;
ja.rawSize = 0;
ja.data = nullptr;
}
JsonArray::JsonArray(const JsonArray& ja)
: JsonBase(ja), size(ja.size), extra(ja.extra), rawSize(ja.rawSize), data(new JsonBase*[ja.rawSize])
{
for (UInt_64 i = 0; i < size; ++i)
{
switch (ja.data[i]->GetType())
{
case JsonType::OBJ:
data[i] = (JsonBase*)new JsonObj(*(JsonObj*)ja.data[i]);
break;
case JsonType::ARRAY:
data[i] = (JsonBase*)new JsonArray(*(JsonArray*)ja.data[i]);
break;
case JsonType::BOOL:
data[i] = (JsonBase*)new JsonBool(*(JsonBool*)ja.data[i]);
break;
case JsonType::NUM:
data[i] = (JsonBase*)new JsonNum(*(JsonNum*)ja.data[i]);
break;
case JsonType::STR:
data[i] = (JsonBase*)new JsonStr(*(JsonStr*)ja.data[i]);
break;
default:
data[i] = new JsonBase();
break;
}
}
}
JsonArray& JsonArray::operator=(JsonArray&& ja) noexcept
{
if (this == &ja)
return *this;
JsonBase::operator=(ja);
size = ja.size;
extra = ja.extra;
rawSize = ja.rawSize;
delete[] data;
data = ja.data;
ja.size = 0;
ja.extra = 0;
ja.rawSize = 0;
ja.data = nullptr;
return *this;
}
JsonArray& JsonArray::operator=(const JsonArray& ja)
{
if (this == &ja)
return *this;
JsonBase::operator=(ja);
size = ja.size;
extra = ja.size;
rawSize = ja.rawSize;
delete[] data;
data = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < ja.size; ++i)
{
switch (ja.data[i]->GetType())
{
case JsonType::OBJ:
data[i] = (JsonBase*)new JsonObj(*(JsonObj*)ja.data[i]);
break;
case JsonType::ARRAY:
data[i] = (JsonBase*)new JsonArray(*(JsonArray*)ja.data[i]);
break;
case JsonType::BOOL:
data[i] = (JsonBase*)new JsonBool(*(JsonBool*)ja.data[i]);
break;
case JsonType::NUM:
data[i] = (JsonBase*)new JsonNum(*(JsonNum*)ja.data[i]);
break;
case JsonType::STR:
data[i] = (JsonBase*)new JsonStr(*(JsonStr*)ja.data[i]);
break;
default:
data[i] = new JsonBase(JsonType::NULLOBJ);
break;
}
}
return *this;
}
JsonArray::operator JsonBase* const *() const
{
return data;
}
JsonArray::operator JsonBase**()
{
return data;
}
UInt_64 JsonArray::RawSize() const
{
return rawSize;
}
UInt_64 JsonArray::Extra() const
{
return extra;
}
UInt_64 JsonArray::Size() const
{
return size;
}
void JsonArray::Insert(const UInt_64 index, const JsonBase* const value)
{
if (size + 1 >= rawSize)
rawSize = size + extra;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < index; ++i)
result[i] = data[i];
switch (value->GetType())
{
case JsonType::OBJ:
result[index] = (JsonBase*)new JsonObj(*(JsonObj*)value);
break;
case JsonType::ARRAY:
result[index] = (JsonBase*)new JsonArray(*(JsonArray*)value);
break;
case JsonType::BOOL:
result[index] = (JsonBase*)new JsonBool(*(JsonBool*)value);
break;
case JsonType::NUM:
result[index] = (JsonBase*)new JsonNum(*(JsonNum*)value);
break;
case JsonType::STR:
result[index] = (JsonBase*)new JsonStr(*(JsonStr*)value);
break;
default:
result[index] = new JsonBase(JsonType::NULLOBJ);
break;
}
for (UInt_64 i = index; i < size; ++i)
result[i + 1] = data[i];
delete[] data;
data = result;
++size;
}
void JsonArray::Push(const JsonBase* const value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
switch (value->GetType())
{
case JsonType::OBJ:
result[size++] = (JsonBase*)new JsonObj(*(JsonObj*)value);
break;
case JsonType::ARRAY:
result[size++] = (JsonBase*)new JsonArray(*(JsonArray*)value);
break;
case JsonType::BOOL:
result[size++] = (JsonBase*)new JsonBool(*(JsonBool*)value);
break;
case JsonType::NUM:
result[size++] = (JsonBase*)new JsonNum(*(JsonNum*)value);
break;
case JsonType::STR:
result[size++] = (JsonBase*)new JsonStr(*(JsonStr*)value);
break;
default:
result[size++] = new JsonBase(JsonType::NULLOBJ);
break;
}
delete[] data;
data = result;
}
else
{
switch (value->GetType())
{
case JsonType::OBJ:
data[size++] = (JsonBase*)new JsonObj(*(JsonObj*)value);
break;
case JsonType::ARRAY:
data[size++] = (JsonBase*)new JsonArray(*(JsonArray*)value);
break;
case JsonType::BOOL:
data[size++] = (JsonBase*)new JsonBool(*(JsonBool*)value);
break;
case JsonType::NUM:
data[size++] = (JsonBase*)new JsonNum(*(JsonNum*)value);
break;
case JsonType::STR:
data[size++] = (JsonBase*)new JsonStr(*(JsonStr*)value);
break;
default:
data[size++] = new JsonBase(JsonType::NULLOBJ);
break;
}
}
}
void JsonArray::Push(const JsonBase& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = new JsonBase(value);
delete[] data;
data = result;
}
else
{
data[size++] = new JsonBase(value);
}
}
void JsonArray::Push(const JsonObj& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonObj(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonObj(value);
}
}
void JsonArray::Push(const JsonArray& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonArray(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonArray(value);
}
}
void JsonArray::Push(const JsonBool& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonBool(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonBool(value);
}
}
void JsonArray::Push(const bool value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonBool(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonBool(value);
}
}
void JsonArray::Push(const JsonNum& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonNum(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonNum(value);
}
}
void JsonArray::Push(const float value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonNum(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonNum(value);
}
}
void JsonArray::Push(const JsonStr& value)
{
if (size + 1 > rawSize)
{
rawSize = size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
result[size++] = (JsonBase*)new JsonStr(value);
delete[] data;
data = result;
}
else
{
data[size++] = (JsonBase*)new JsonStr(value);
}
}
void JsonArray::Push(const Char_8* value, const UInt_64 size)
{
if (this->size + 1 > rawSize)
{
rawSize = this->size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < this->size; ++i)
result[i] = data[i];
result[this->size++] = (JsonBase*)new JsonStr(Str_8(value, size));
delete[] data;
data = result;
}
else
{
data[this->size++] = (JsonBase*)new JsonStr(Str_8(value, size));
}
}
void JsonArray::Push(const Str_8& value)
{
if (this->size + 1 > rawSize)
{
rawSize = this->size + extra + 1;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < this->size; ++i)
result[i] = data[i];
result[this->size++] = (JsonBase*)new JsonStr(value);
delete[] data;
data = result;
}
else
{
data[this->size++] = (JsonBase*)new JsonStr(value);
}
}
void JsonArray::Pop()
{
if (rawSize - --size >= extra * 2)
rawSize -= extra;
JsonBase** result = new JsonBase*[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = data[i];
delete[] data;
data = result;
}
Str_8 JsonArray::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result = "[";
if (!compact)
result += "\r\n";
for (UInt_64 i = 0; i < size; ++i)
{
if (!compact && (data[i]->GetType() == JsonType::OBJ || data[i]->GetType() == JsonType::ARRAY))
{
for (UInt_64 l = 0; l < level + 1; ++l)
result += "\t";
}
result += data[i]->ToStr(level + 1, compact);
if (i < size - 1)
result += ",";
if (!compact)
result += "\r\n";
}
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += "]";
return result;
}
}

24
src/json/JsonBase.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include "ehs/json/JsonBase.h"
namespace ehs
{
JsonBase::JsonBase()
: type(JsonType::NULLOBJ)
{
}
JsonBase::JsonBase(const JsonType type)
: type(type)
{
}
JsonType JsonBase::GetType() const
{
return type;
}
Str_8 JsonBase::ToStr(const UInt_64 level, const bool compact) const
{
return {};
}
}

39
src/json/JsonBool.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "ehs/json/JsonBool.h"
namespace ehs
{
JsonBool::JsonBool()
: JsonBase(JsonType::BOOL), value(false)
{
}
JsonBool::JsonBool(const bool value)
: JsonBase(JsonType::BOOL), value(value)
{
}
JsonBool::operator bool() const
{
return value;
}
JsonBool::operator bool&()
{
return value;
}
Str_8 JsonBool::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result;
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += value ? "true" : "false";
return result;
}
}

93
src/json/JsonNum.cpp Normal file
View File

@@ -0,0 +1,93 @@
#include "ehs/json/JsonNum.h"
namespace ehs
{
JsonNum::JsonNum()
: JsonBase(JsonType::NUM), value(0.0f)
{
}
JsonNum::JsonNum(const SInt_64 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const UInt_64 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const SInt_32 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const UInt_32 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const SInt_16 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const UInt_16 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const SInt_8 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const UInt_8 value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const double value)
: JsonBase(JsonType::NUM), value((float)value)
{
}
JsonNum::JsonNum(const float value)
: JsonBase(JsonType::NUM), value(value)
{
}
JsonNum::operator float() const
{
return value;
}
JsonNum::operator float&()
{
return value;
}
Str_8 JsonNum::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result;
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += Str_8::FromNum(value);
return result;
}
}

201
src/json/JsonObj.cpp Normal file
View File

@@ -0,0 +1,201 @@
#include "ehs/json/JsonObj.h"
#include "ehs/json/JsonVar.h"
namespace ehs
{
JsonObj::~JsonObj()
{
delete[] vars;
}
JsonObj::JsonObj()
: JsonBase(JsonType::OBJ), size(0), extra(0), rawSize(0), vars(nullptr)
{
}
JsonObj::JsonObj(const UInt_64 size, const UInt_64 extra)
: JsonBase(JsonType::OBJ), size(size), extra(extra), rawSize(size + extra), vars(new JsonVar[size + extra])
{
}
JsonObj::JsonObj(const UInt_64 extra)
: JsonBase(JsonType::OBJ), size(0), extra(extra), rawSize(extra), vars(new JsonVar[extra])
{
}
JsonObj::JsonObj(JsonObj&& value) noexcept
: JsonBase(value), size(value.size), extra(value.extra), rawSize(value.rawSize), vars(value.vars)
{
value.size = 0;
value.extra = 0;
value.rawSize = 0;
value.vars = nullptr;
}
JsonObj::JsonObj(const JsonObj& value)
: JsonBase(value), size(value.size), extra(value.extra), rawSize(value.rawSize), vars(new JsonVar[value.rawSize])
{
for (UInt_64 i = 0; i < size; ++i)
vars[i] = value.vars[i];
}
JsonObj& JsonObj::operator=(JsonObj&& value) noexcept
{
if (this == &value)
return *this;
JsonBase::operator=(value);
size = value.size;
extra = value.extra;
rawSize = value.rawSize;
delete[] vars;
vars = value.vars;
value.size = 0;
value.extra = 0;
value.rawSize = 0;
value.vars = nullptr;
return *this;
}
JsonObj& JsonObj::operator=(const JsonObj& value)
{
if (this == &value)
return *this;
JsonBase::operator=(value);
size = value.size;
extra = value.extra;
rawSize = value.rawSize;
delete[] vars;
vars = new JsonVar[value.rawSize];
for (UInt_64 i = 0; i < value.rawSize; ++i)
vars[i] = value.vars[i];
return *this;
}
JsonObj::operator const JsonVar*() const
{
return vars;
}
JsonObj::operator JsonVar*()
{
return vars;
}
UInt_64 JsonObj::Size() const
{
return size;
}
UInt_64 JsonObj::Extra() const
{
return extra;
}
UInt_64 JsonObj::RawSize() const
{
return rawSize;
}
bool JsonObj::HasVar(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < size; ++i)
if (vars[i].GetHashId() == hashId)
return true;
return false;
}
bool JsonObj::HasVar(const Str_8& identifier) const
{
return HasVar(identifier.Hash_64());
}
bool JsonObj::AddVar(const JsonVar& var)
{
if (!var.GetHashId() || HasVar(var.GetHashId()))
return false;
if (size + 1 > rawSize)
{
rawSize += extra ? extra : 1;
JsonVar* result = new JsonVar[rawSize];
for (UInt_64 i = 0; i < size; ++i)
result[i] = vars[i];
delete[] vars;
vars = result;
}
vars[size++] = var;
return true;
}
const JsonVar* JsonObj::GetVar(const UInt_64 hashId) const
{
for (UInt_64 i = 0; i < size; ++i)
if (vars[i].GetHashId() == hashId)
return &vars[i];
return nullptr;
}
const JsonVar* JsonObj::GetVar(const Str_8& identifier) const
{
return GetVar(identifier.Hash_64());
}
JsonVar* JsonObj::GetVar(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < size; ++i)
if (vars[i].GetHashId() == hashId)
return &vars[i];
return nullptr;
}
JsonVar* JsonObj::GetVar(const Str_8& identifier)
{
return GetVar(identifier.Hash_64());
}
Str_8 JsonObj::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result;
result += "{";
if (!compact)
result += "\r\n";
for (UInt_64 i = 0; i < size; ++i)
{
result += vars[i].ToStr(level + 1, compact);
if (i < size - 1)
result += ",";
if (!compact)
result += "\r\n";
}
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += "}";
return result;
}
}

62
src/json/JsonStr.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include "ehs/json/JsonStr.h"
namespace ehs
{
JsonStr::JsonStr()
: JsonBase(JsonType::STR)
{
}
JsonStr::JsonStr(Str_8 value)
: JsonBase(JsonType::STR), value(std::move(value))
{
}
JsonStr::JsonStr(const Char_8* value, const UInt_64 size)
: JsonBase(JsonType::STR), value(value, size)
{
}
JsonStr::JsonStr(JsonStr&& js) noexcept
: JsonBase(js), value(std::move(js.value))
{
}
JsonStr& JsonStr::operator=(JsonStr&& js) noexcept
{
if (this == &js)
return *this;
JsonBase::operator=(js);
value = std::move(js.value);
return *this;
}
JsonStr::operator Str_8() const
{
return value;
}
JsonStr::operator Str_8&()
{
return value;
}
Str_8 JsonStr::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result;
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += "\"" + value + "\"";
return result;
}
}

369
src/json/JsonVar.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include "ehs/json/JsonVar.h"
#include "ehs/json/JsonBase.h"
#include "ehs/json/JsonObj.h"
#include "ehs/json/JsonArray.h"
#include "ehs/json/JsonBool.h"
#include "ehs/json/JsonNum.h"
#include "ehs/json/JsonStr.h"
namespace ehs
{
JsonVar::~JsonVar()
{
delete value;
}
JsonVar::JsonVar()
: hashId(0), value(nullptr)
{
}
JsonVar::JsonVar(Str_8 id)
: hashId(id.Hash_64()), id(std::move(id)), value(nullptr)
{
}
JsonVar::JsonVar(Str_8 id, const JsonBase* const value)
: hashId(id.Hash_64()), id(std::move(id))
{
switch (value->GetType())
{
case JsonType::OBJ:
this->value = (JsonBase*)new JsonObj(*(JsonObj*)value);
break;
case JsonType::ARRAY:
this->value = (JsonBase*)new JsonArray(*(JsonArray*)value);
break;
case JsonType::BOOL:
this->value = (JsonBase*)new JsonBool(*(JsonBool*)value);
break;
case JsonType::NUM:
this->value = (JsonBase*)new JsonNum(*(JsonNum*)value);
break;
case JsonType::STR:
this->value = (JsonBase*)new JsonStr(*(JsonStr*)value);
break;
default:
this->value = new JsonBase(JsonType::NULLOBJ);
break;
}
}
JsonVar::JsonVar(Str_8 id, const JsonBase& value)
: hashId(id.Hash_64()), id(std::move(id)), value(new JsonBase(value))
{
}
JsonVar::JsonVar(Str_8 id, const JsonObj& value)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonObj(value))
{
}
JsonVar::JsonVar(Str_8 id, const JsonArray& value)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonArray(value))
{
}
JsonVar::JsonVar(Str_8 id, const JsonBool& value)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonBool(value))
{
}
JsonVar::JsonVar(Str_8 id, const bool boolean)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonBool(boolean))
{
}
JsonVar::JsonVar(Str_8 id, const JsonNum& value)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(value))
{
}
JsonVar::JsonVar(Str_8 id, const SInt_64 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const UInt_64 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const SInt_32 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const UInt_32 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const SInt_16 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const UInt_16 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const SInt_8 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const UInt_8 num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const double num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const float num)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonNum(num))
{
}
JsonVar::JsonVar(Str_8 id, const JsonStr& value)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonStr(value))
{
}
JsonVar::JsonVar(Str_8 id, const Char_8* str, const UInt_64 size)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonStr(str, size))
{
}
JsonVar::JsonVar(Str_8 id, Str_8 str)
: hashId(id.Hash_64()), id(std::move(id)), value((JsonBase*)new JsonStr(std::move(str)))
{
}
JsonVar::JsonVar(JsonVar&& var) noexcept
: hashId(var.hashId), id(std::move(var.id)), value(var.value)
{
var.hashId = 0;
var.value = nullptr;
}
JsonVar::JsonVar(const JsonVar& var)
: hashId(var.hashId), id(var.id), value(nullptr)
{
if (!var.value)
return;
switch (var.value->GetType())
{
case JsonType::OBJ:
value = (JsonBase*)new JsonObj(*(JsonObj*)var.value);
break;
case JsonType::ARRAY:
value = (JsonBase*)new JsonArray(*(JsonArray*)var.value);
break;
case JsonType::BOOL:
value = (JsonBase*)new JsonBool(*(JsonBool*)var.value);
break;
case JsonType::NUM:
value = (JsonBase*)new JsonNum(*(JsonNum*)var.value);
break;
case JsonType::STR:
value = (JsonBase*)new JsonStr(*(JsonStr*)var.value);
break;
default:
value = new JsonBase();
break;
}
}
JsonVar& JsonVar::operator=(JsonVar&& var) noexcept
{
if (this == &var)
return *this;
hashId = var.hashId;
id = std::move(var.id);
delete value;
value = var.value;
var.hashId = 0;
var.value = nullptr;
return *this;
}
JsonVar& JsonVar::operator=(const JsonVar& var)
{
if (this == &var)
return *this;
hashId = var.hashId;
id = var.id;
delete value;
value = nullptr;
if (!var.value)
return *this;
switch (var.value->GetType())
{
case JsonType::OBJ:
value = (JsonBase*)new JsonObj(*(JsonObj*)var.value);
break;
case JsonType::ARRAY:
value = (JsonBase*)new JsonArray(*(JsonArray*)var.value);
break;
case JsonType::BOOL:
value = (JsonBase*)new JsonBool(*(JsonBool*)var.value);
break;
case JsonType::NUM:
value = (JsonBase*)new JsonNum(*(JsonNum*)var.value);
break;
case JsonType::STR:
value = (JsonBase*)new JsonStr(*(JsonStr*)var.value);
break;
default:
value = new JsonBase();
break;
}
return *this;
}
UInt_64 JsonVar::GetHashId() const
{
return hashId;
}
Str_8 JsonVar::GetId() const
{
return id;
}
void JsonVar::SetValue(const JsonBase* const newValue)
{
if (!newValue)
return;
delete value;
switch (newValue->GetType())
{
case JsonType::OBJ:
value = (JsonBase*)new JsonObj(*(JsonObj*)newValue);
break;
case JsonType::ARRAY:
value = (JsonBase*)new JsonArray(*(JsonArray*)newValue);
break;
case JsonType::BOOL:
value = (JsonBase*)new JsonBool(*(JsonBool*)newValue);
break;
case JsonType::NUM:
value = (JsonBase*)new JsonNum(*(JsonNum*)newValue);
break;
case JsonType::STR:
value = (JsonBase*)new JsonStr(*(JsonStr*)newValue);
break;
default:
value = new JsonBase();
break;
}
}
void JsonVar::SetValue(const JsonBase& newValue)
{
delete value;
value = new JsonBase(newValue);
}
void JsonVar::SetValue(const JsonObj& newValue)
{
delete value;
value = (JsonBase*)new JsonObj(newValue);
}
void JsonVar::SetValue(const JsonArray& newValue)
{
delete value;
value = (JsonBase*)new JsonArray(newValue);
}
void JsonVar::SetValue(const JsonBool& newValue)
{
delete value;
value = (JsonBase*)new JsonBool(newValue);
}
void JsonVar::SetValue(const bool newValue)
{
delete value;
value = (JsonBase*)new JsonBool(newValue);
}
void JsonVar::SetValue(const JsonNum& newValue)
{
delete value;
value = (JsonBase*)new JsonNum(newValue);
}
void JsonVar::SetValue(const float newValue)
{
delete value;
value = (JsonBase*)new JsonNum(newValue);
}
void JsonVar::SetValue(const JsonStr& newValue)
{
delete value;
value = (JsonBase*)new JsonStr(newValue);
}
void JsonVar::SetValue(const Char_8* newValue, const UInt_64 size)
{
delete value;
value = (JsonBase*)new JsonStr(newValue, size);
}
void JsonVar::SetValue(const Str_8& newValue)
{
delete value;
value = (JsonBase*)new JsonStr(newValue);
}
const JsonBase* JsonVar::GetValue() const
{
return value;
}
JsonBase* JsonVar::GetValue()
{
return value;
}
Str_8 JsonVar::ToStr(const UInt_64 level, const bool compact) const
{
Str_8 result;
if (!compact)
{
for (UInt_64 l = 0; l < level; ++l)
result += "\t";
}
result += "\"" + id + "\":";
if (!compact)
result += " ";
if (value->GetType() == JsonType::OBJ || value->GetType() == JsonType::ARRAY)
result += value->ToStr(level, compact);
else
result += value->ToStr(0, compact);
return result;
}
}

55
src/system/BaseMutex.cpp Normal file
View File

@@ -0,0 +1,55 @@
#include "ehs/system/BaseMutex.h"
namespace ehs
{
BaseMutex::~BaseMutex()
{
}
BaseMutex::BaseMutex()
: initialized(false), locked(false)
{
}
BaseMutex::BaseMutex(const BaseMutex& mutex)
: initialized(false), locked(false)
{
}
BaseMutex& BaseMutex::operator=(const BaseMutex& mutex)
{
if (this == &mutex)
return *this;
initialized = mutex.initialized;
locked = mutex.locked;
return *this;
}
void BaseMutex::Initialize()
{
}
void BaseMutex::UnInitialize()
{
}
bool BaseMutex::IsInitialized() const
{
return initialized;
}
void BaseMutex::Lock()
{
}
void BaseMutex::Unlock()
{
}
bool BaseMutex::IsLocked() const
{
return locked;
}
}

48
src/system/BaseOpen.cpp Normal file
View File

@@ -0,0 +1,48 @@
#include "ehs/system/BaseOpen.h"
namespace ehs
{
BaseOpen::BaseOpen()
{
}
BaseOpen::BaseOpen(Str_8 filePath)
: filePath((Str_8&&)filePath)
{
}
BaseOpen::BaseOpen(BaseOpen&& bo) noexcept
: filePath((Str_8&&)bo.filePath)
{
}
BaseOpen::BaseOpen(const BaseOpen& bo)
: filePath(bo.filePath)
{
}
BaseOpen& BaseOpen::operator=(BaseOpen&& bo) noexcept
{
if (this == &bo)
return *this;
filePath = (Str_8&&)bo.filePath;
return *this;
}
BaseOpen& BaseOpen::operator=(const BaseOpen& bo)
{
if (this == &bo)
return *this;
filePath = bo.filePath;
return *this;
}
Str_8 BaseOpen::GetFilePath() const
{
return filePath;
}
}

View File

@@ -0,0 +1,61 @@
#include "ehs/system/BaseSemaphore.h"
namespace ehs
{
BaseSemaphore::BaseSemaphore()
: initial(0)
{
}
BaseSemaphore::BaseSemaphore(Str_8 name, const UInt_32 initial)
: name(std::move(name)), initial(initial)
{
}
BaseSemaphore::BaseSemaphore(const UInt_32 initial)
: initial(initial)
{
}
BaseSemaphore::BaseSemaphore(BaseSemaphore&& sem) noexcept
: name(std::move(sem.name)), initial(sem.initial)
{
}
BaseSemaphore::BaseSemaphore(const BaseSemaphore& sem)
: name(sem.name), initial(sem.initial)
{
}
BaseSemaphore& BaseSemaphore::operator=(const BaseSemaphore& sem)
{
if (this == &sem)
return *this;
name = sem.name;
initial = sem.initial;
return *this;
}
BaseSemaphore& BaseSemaphore::operator=(BaseSemaphore&& sem) noexcept
{
if (this == &sem)
return *this;
name = std::move(sem.name);
initial = sem.initial;
return *this;
}
Str_8 BaseSemaphore::GetName() const
{
return name;
}
UInt_32 BaseSemaphore::GetInitial() const
{
return initial;
}
}

View File

@@ -0,0 +1,8 @@
#include "ehs/system/BaseSystem.h"
namespace ehs
{
void BaseSystem::OpenURI(const Str_8& uri)
{
}
}

561
src/system/CPU.cpp Normal file
View File

@@ -0,0 +1,561 @@
#include "ehs/system/CPU.h"
#include "ehs/Log.h"
#include "ehs/io/File.h"
#include "ehs/json/Json.h"
#include "ehs/system/Thread.h"
namespace ehs
{
#ifdef EHS_OS_LINUX
UInt_64 CPU::TSC_Freq = 0;
#endif
Architecture CPU::GetArchitecture()
{
#if defined(EHS_ARCH_X64)
return Architecture::X64;
#elif defined(EHS_ARCH_ARM64)
return Architecture::ARM64;
#else
return Architecture::UNKNOWN;
#endif
}
UInt_8 CPU::PointerSize()
{
return sizeof(void*);
}
Endianness CPU::GetEndianness()
{
#if defined(EHS_LITTLE_ENDIAN)
return Endianness::LE;
#elif defined(EHS_BIG_ENDIAN)
return Endianness::BE;
#else
UInt_16 tmp = 1;
if (((Byte*)&tmp)[0] == 1)
return Endianness::LE;
return Endianness::BE;
#endif
}
UInt_64 CPU::GetTSC_Freq()
{
#if defined(EHS_OS_WINDOWS)
LARGE_INTEGER frequency = {};
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
#elif defined(EHS_OS_LINUX)
if (!TSC_Freq)
TSC_Freq = RetrieveTSC_Freq();
return TSC_Freq;
#endif
return 0;
}
UInt_64 CPU::GetTSC()
{
#if defined(EHS_OS_WINDOWS)
LARGE_INTEGER count = {};
QueryPerformanceCounter(&count);
return count.QuadPart;
#elif defined(EHS_OS_LINUX)
TSC tsc;
RDTSCP(&tsc);
#if defined(EHS_ARCH_X64)
UInt_64 result = 0;
#if defined(EHS_LITTLE_ENDIAN)
((UInt_32*)&result)[0] = tsc.lowCount;
((UInt_32*)&result)[1] = tsc.highCount;
#elif defined(EHS_BIG_ENDIAN)
((UInt_32*)&result)[0] = tsc.highCount;
((UInt_32*)&result)[1] = tsc.lowCount;
#endif
return result;
#elif defined(EHS_ARCH_X86)
return tsc.lowPart;
#endif
#endif
return 0;
}
UInt_8 CPU::GetSteppingId()
{
return (UInt_8)GetInfoBits() & 0x00001111;
}
UInt_8 CPU::GetModelId()
{
return (UInt_8)GetInfoBits() & 0x11110000;
}
UInt_8 CPU::GetFamilyId()
{
return (UInt_8)(GetInfoBits() >> 8) & 0x00001111;
}
UInt_8 CPU::GetProcessorTypeId()
{
return (UInt_8)(GetInfoBits() >> 12) & 0x00000011;
}
UInt_8 CPU::GetExtModelId()
{
return (UInt_8)(GetInfoBits() >> 16) & 0x00001111;
}
UInt_8 CPU::GetExtFamilyId()
{
return (UInt_8)(GetInfoBits() >> 20);
}
bool CPU::HasFPU()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000001;
}
bool CPU::HasVME()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000010;
}
bool CPU::HasDE()
{
return GetFeatureBits_1() & 0b00000000000000000000000000000100;
}
bool CPU::HasPSE()
{
return GetFeatureBits_1() & 0b00000000000000000000000000001000;
}
bool CPU::HasTSC()
{
return GetFeatureBits_1() & 0b00000000000000000000000000010000;
}
bool CPU::HasMSR()
{
return GetFeatureBits_1() & 0b00000000000000000000000000100000;
}
bool CPU::HasPAE()
{
return GetFeatureBits_1() & 0b00000000000000000000000001000000;
}
bool CPU::HasMCE()
{
return GetFeatureBits_1() & 0b00000000000000000000000010000000;
}
bool CPU::HasCX8()
{
return GetFeatureBits_1() & 0b00000000000000000000000100000000;
}
bool CPU::HasAPIC()
{
return GetFeatureBits_1() & 0b00000000000000000000001000000000;
}
bool CPU::HasSEP()
{
return GetFeatureBits_1() & 0b00000000000000000000100000000000;
}
bool CPU::HasMTRR()
{
return GetFeatureBits_1() & 0b00000000000000000001000000000000;
}
bool CPU::HasPGE()
{
return GetFeatureBits_1() & 0b00000000000000000010000000000000;
}
bool CPU::HasMCA()
{
return GetFeatureBits_1() & 0b00000000000000000100000000000000;
}
bool CPU::HasCMOV()
{
return GetFeatureBits_1() & 0b00000000000000001000000000000000;
}
bool CPU::HasPAT()
{
return GetFeatureBits_1() & 0b00000000000000010000000000000000;
}
bool CPU::HasPSE_36()
{
return GetFeatureBits_1() & 0b00000000000000100000000000000000;
}
bool CPU::HasPSN()
{
return GetFeatureBits_1() & 0b00000000000001000000000000000000;
}
bool CPU::HasCLFSH()
{
return GetFeatureBits_1() & 0b00000000000010000000000000000000;
}
bool CPU::HasDS()
{
return GetFeatureBits_1() & 0b00000000001000000000000000000000;
}
bool CPU::HasACPI()
{
return GetFeatureBits_1() & 0b00000000010000000000000000000000;
}
bool CPU::HasMMX()
{
return GetFeatureBits_1() & 0b00000000100000000000000000000000;
}
bool CPU::HasFXSR()
{
return GetFeatureBits_1() & 0b00000001000000000000000000000000;
}
bool CPU::HasSSE()
{
return GetFeatureBits_1() & 0b00000010000000000000000000000000;
}
bool CPU::HasSSE2()
{
return GetFeatureBits_1() & 0b00000100000000000000000000000000;
}
bool CPU::HasSS()
{
return GetFeatureBits_1() & 0b00001000000000000000000000000000;
}
bool CPU::HasHTT()
{
return GetFeatureBits_1() & 0b00010000000000000000000000000000;
}
bool CPU::HasTM()
{
return GetFeatureBits_1() & 0b00100000000000000000000000000000;
}
bool CPU::HasIA64()
{
return GetFeatureBits_1() & 0b01000000000000000000000000000000;
}
bool CPU::HasPBE()
{
return GetFeatureBits_1() & 0b10000000000000000000000000000000;
}
bool CPU::HasSSE3()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000001;
}
bool CPU::HasPCLMULQDQ()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000010;
}
bool CPU::HasDTES64()
{
return GetFeatureBits_2() & 0b00000000000000000000000000000100;
}
bool CPU::HasMONITOR()
{
return GetFeatureBits_2() & 0b00000000000000000000000000001000;
}
bool CPU::HasDS_CPL()
{
return GetFeatureBits_2() & 0b00000000000000000000000000010000;
}
bool CPU::HasVMX()
{
return GetFeatureBits_2() & 0b00000000000000000000000000100000;
}
bool CPU::HasSMX()
{
return GetFeatureBits_2() & 0b00000000000000000000000001000000;
}
bool CPU::HasEST()
{
return GetFeatureBits_2() & 0b00000000000000000000000010000000;
}
bool CPU::HasTM2()
{
return GetFeatureBits_2() & 0b00000000000000000000000100000000;
}
bool CPU::HasSSSE3()
{
return GetFeatureBits_2() & 0b00000000000000000000001000000000;
}
bool CPU::HasCNXT_ID()
{
return GetFeatureBits_2() & 0b00000000000000000000010000000000;
}
bool CPU::HasSDBG()
{
return GetFeatureBits_2() & 0b00000000000000000000100000000000;
}
bool CPU::HasFMA()
{
return GetFeatureBits_2() & 0b00000000000000000001000000000000;
}
bool CPU::HasCX16()
{
return GetFeatureBits_2() & 0b00000000000000000010000000000000;
}
bool CPU::HasXTPR()
{
return GetFeatureBits_2() & 0b00000000000000000100000000000000;
}
bool CPU::HasPDCM()
{
return GetFeatureBits_2() & 0b00000000000000001000000000000000;
}
bool CPU::HasPCID()
{
return GetFeatureBits_2() & 0b00000000000000100000000000000000;
}
bool CPU::HasDCA()
{
return GetFeatureBits_2() & 0b00000000000001000000000000000000;
}
bool CPU::HasSSE4_1()
{
return GetFeatureBits_2() & 0b00000000000010000000000000000000;
}
bool CPU::HasSSE4_2()
{
return GetFeatureBits_2() & 0b00000000000100000000000000000000;
}
bool CPU::HasX2APIC()
{
return GetFeatureBits_2() & 0b00000000001000000000000000000000;
}
bool CPU::HasMOVBE()
{
return GetFeatureBits_2() & 0b00000000010000000000000000000000;
}
bool CPU::HasPOPCNT()
{
return GetFeatureBits_2() & 0b00000000100000000000000000000000;
}
bool CPU::HasTSC_DEADLINE()
{
return GetFeatureBits_2() & 0b00000001000000000000000000000000;
}
bool CPU::HasAES()
{
return GetFeatureBits_2() & 0b00000010000000000000000000000000;
}
bool CPU::HasXSAVE()
{
return GetFeatureBits_2() & 0b00000100000000000000000000000000;
}
bool CPU::HasOSXSAVE()
{
return GetFeatureBits_2() & 0b00001000000000000000000000000000;
}
bool CPU::HasAVX()
{
return GetFeatureBits_2() & 0b00010000000000000000000000000000;
}
bool CPU::HasF16C()
{
return GetFeatureBits_2() & 0b00100000000000000000000000000000;
}
bool CPU::HasRDRND()
{
return GetFeatureBits_2() & 0b01000000000000000000000000000000;
}
bool CPU::HasHYPERVISOR()
{
return GetFeatureBits_2() & 0b10000000000000000000000000000000;
}
bool CPU::HasAVX2()
{
return GetExtFeatureBits_1() & 0b00000000000000000000000000100000;
}
bool CPU::HasRDSEED()
{
return GetExtFeatureBits_1() & 0b00000000000001000000000000000000;
}
bool CPU::HasADX()
{
return GetExtFeatureBits_1() & 0b00000000000010000000000000000000;
}
/*
Str_8 CPU::ToStr()
{
return "Manufacturer: " + GetManufacturer() + "\r\n" +
"Brand: " + GetBrand() + "\r\n" +
"Stepping Id: " + Str_8::FromNum(GetSteppingId()) + "\r\n" +
"GpuModel Id: " + Str_8::FromNum(GetModelId()) + "\r\n" +
"Family Id: " + Str_8::FromNum(GetFamilyId()) + "\r\n" +
"Processor Type Id: " + Str_8::FromNum(GetProcessorTypeId()) + "\r\n" +
"Extended GpuModel Id: " + Str_8::FromNum(GetExtModelId()) + "\r\n" +
"Extended Family Id: " + Str_8::FromNum(GetExtFamilyId()) + "\r\n" +
"Has FPU: " + Str_8::FromNum((UInt_8)HasFPU()) + "\r\n" +
"Has SSE: " + Str_8::FromNum((UInt_8)HasSSE()) + "\r\n" +
"Has SSE 2: " + Str_8::FromNum((UInt_8)HasSSE2()) + "\r\n" +
"Has SSE 3: " + Str_8::FromNum((UInt_8)HasSSE3()) + "\r\n" +
"Has SSSE 3: " + Str_8::FromNum((UInt_8)HasSSSE3()) + "\r\n" +
"Has SSE 4.1: " + Str_8::FromNum((UInt_8)HasSSE4_1()) + "\r\n" +
"Has SSE 4.2: " + Str_8::FromNum((UInt_8)HasSSE4_2()) + "\r\n" +
"Has AVX: " + Str_8::FromNum((UInt_8)HasAVX()) + "\r\n" +
"Has RDRND: " + Str_8::FromNum((UInt_8)HasRDRND()) + "\r\n" +
"Has AVX 2: " + Str_8::FromNum((UInt_8)HasAVX2()) + "\r\n" +
"Has ADX: " + Str_8::FromNum((UInt_8)HasADX()) + "\r\n" +
"Has RDSEED: " + Str_8::FromNum((UInt_8)HasRDSEED());
}
*/
UInt_64 CPU::RetrieveTSC_Freq()
{
File tscDatabase("TSC_Frequencies.json", Mode::READ_WRITE, Disposition::CREATE_PERSISTENT);
if (tscDatabase.Size())
{
Json json(tscDatabase.ReadStr_8(tscDatabase.Size()), 5);
JsonObj* root = (JsonObj*)json.GetValue();
Char_8 manu[13];
manu[12] = 0;
GetManufacturer(manu);
JsonVar* jManu = root->GetVar(manu);
if (jManu)
{
JsonObj* joManu = (JsonObj*)jManu->GetValue();
Char_8 brand[48];
GetBrand(brand);
JsonVar* jBrand = joManu->GetVar(brand);
if (jBrand)
{
tscDatabase.Release();
return (UInt_64)*(JsonNum*)jBrand->GetValue();
}
else
{
UInt_64 tscFreq = CalculateTSC_Freq();
joManu->AddVar({brand, tscFreq});
tscDatabase.SeekBeginning();
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
}
else
{
UInt_64 tscFreq = CalculateTSC_Freq();
Char_8 brand[48];
GetBrand(brand);
JsonObj cpus(1, 0);
cpus[0] = JsonVar(brand, tscFreq);
JsonVar tmp({brand, cpus});
root->AddVar(tmp);
tscDatabase.SeekBeginning();
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
}
UInt_64 tscFreq = CalculateTSC_Freq();
Char_8 manu[13];
manu[12] = 0;
GetManufacturer(manu);
Char_8 brand[49];
brand[48] = 0;
GetBrand(brand);
JsonObj jManu(1, 0);
jManu[0] = JsonVar(brand, tscFreq);
JsonObj root(1, 0);
root[0] = JsonVar(manu, jManu);
Json json(root);
tscDatabase.WriteStr_8(json.ToStr(false));
tscDatabase.Release();
return tscFreq;
}
UInt_64 CPU::CalculateTSC_Freq()
{
UInt_64 result = GetTSC();
Thread::SleepFor(10000);
return (GetTSC() - result) / 10;
}
}

46
src/system/CPU_ARM64.cpp Normal file
View File

@@ -0,0 +1,46 @@
#include "ehs/system/CPU.h"
namespace ehs
{
void CPU::RDTSCP(TSC* tsc)
{
}
void CPU::GetManufacturer(Char_8* input)
{
}
UInt_32 CPU::GetInfoBits()
{
return 0;
}
UInt_32 CPU::GetFeatureBits_1()
{
return 0;
}
UInt_32 CPU::GetFeatureBits_2()
{
return 0;
}
UInt_32 CPU::GetExtFeatureBits_1()
{
return 0;
}
UInt_32 CPU::GetExtFeatureBits_2()
{
return 0;
}
UInt_32 CPU::GetExtFeatureBits_3()
{
return 0;
}
void CPU::GetBrand(Char_8* input)
{
}
}

View File

@@ -0,0 +1,132 @@
global _ZN3ehs3CPU6RDTSCPEPNS_3TSCE
global _ZN3ehs3CPU15GetManufacturerEPc
global _ZN3ehs3CPU11GetInfoBitsEv
global _ZN3ehs3CPU16GetFeatureBits_1Ev
global _ZN3ehs3CPU16GetFeatureBits_2Ev
global _ZN3ehs3CPU19GetExtFeatureBits_1Ev
global _ZN3ehs3CPU19GetExtFeatureBits_2Ev
global _ZN3ehs3CPU19GetExtFeatureBits_3Ev
global _ZN3ehs3CPU8GetBrandEPc
section .text
_ZN3ehs3CPU6RDTSCPEPNS_3TSCE:
RDTSCP
MOV DWORD [RDI], ECX
MOV DWORD [RDI + 4], EDX
MOV DWORD [RDI + 8], EAX
RET
_ZN3ehs3CPU15GetManufacturerEPc:
PUSH RBX
XOR EAX, EAX
CPUID
MOV DWORD [RDI], EBX
MOV DWORD [RDI + 4], EDX
MOV DWORD [RDI + 8], ECX
POP RBX
RET
_ZN3ehs3CPU11GetInfoBitsEv:
PUSH RBX
MOV EAX, 1
CPUID
POP RBX
RET
_ZN3ehs3CPU16GetFeatureBits_1Ev:
PUSH RBX
MOV EAX, 1
CPUID
MOV EAX, EDX
POP RBX
RET
_ZN3ehs3CPU16GetFeatureBits_2Ev:
PUSH RBX
MOV EAX, 1
CPUID
MOV EAX, ECX
POP RBX
RET
_ZN3ehs3CPU19GetExtFeatureBits_1Ev:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, EBX
POP RBX
RET
_ZN3ehs3CPU19GetExtFeatureBits_2Ev:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, ECX
POP RBX
RET
_ZN3ehs3CPU19GetExtFeatureBits_3Ev:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, EDX
POP RBX
RET
_ZN3ehs3CPU8GetBrandEPc:
PUSH RBX
MOV EAX, 80000002h
CPUID
MOV DWORD [RDI], EAX
MOV DWORD [RDI + 4], EBX
MOV DWORD [RDI + 8], ECX
MOV DWORD [RDI + 12], EDX
MOV EAX, 80000003h
CPUID
MOV DWORD [RDI + 16], EAX
MOV DWORD [RDI + 20], EBX
MOV DWORD [RDI + 24], ECX
MOV DWORD [RDI + 28], EDX
MOV EAX, 80000004h
CPUID
MOV DWORD [RDI + 32], EAX
MOV DWORD [RDI + 36], EBX
MOV DWORD [RDI + 40], ECX
MOV DWORD [RDI + 44], EDX
POP RBX
RET

View File

@@ -0,0 +1,127 @@
global ?GetManufacturer@CPU@ehs@@SAXPEAD@Z
global ?GetInfoBits@CPU@ehs@@SAIXZ
global ?GetFeatureBits_1@CPU@ehs@@SAIXZ
global ?GetFeatureBits_2@CPU@ehs@@SAIXZ
global ?GetExtFeatureBits_1@CPU@ehs@@SAIXZ
global ?GetExtFeatureBits_2@CPU@ehs@@SAKXZ
global ?GetExtFeatureBits_3@CPU@ehs@@SAKXZ
global ?GetBrand@CPU@ehs@@SAXPEAD@Z
section .text
?GetManufacturer@CPU@ehs@@SAXPEAD@Z:
PUSH RBX
XOR EAX, EAX
MOV R8, RCX
CPUID
MOV DWORD [R8], EBX
MOV DWORD [R8 + 4], EDX
MOV DWORD [R8 + 8], ECX
POP RBX
RET
?GetInfoBits@CPU@ehs@@SAIXZ:
PUSH RBX
MOV EAX, 1
CPUID
POP RBX
RET
?GetFeatureBits_1@CPU@ehs@@SAIXZ:
PUSH RBX
MOV EAX, 1
CPUID
MOV EAX, EDX
POP RBX
RET
?GetFeatureBits_2@CPU@ehs@@SAIXZ:
PUSH RBX
MOV EAX, 1
CPUID
MOV EAX, ECX
POP RBX
RET
?GetExtFeatureBits_1@CPU@ehs@@SAIXZ:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, EBX
POP RBX
RET
?GetExtFeatureBits_2@CPU@ehs@@SAKXZ:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, ECX
POP RBX
RET
?GetExtFeatureBits_3@CPU@ehs@@SAKXZ:
PUSH RBX
MOV EAX, 7
XOR ECX, ECX
CPUID
MOV EAX, EDX
POP RBX
RET
?GetBrand@CPU@ehs@@SAXPEAD@Z:
PUSH RBX
MOV R8, RCX
MOV EAX, 80000002h
CPUID
MOV DWORD [R8], EAX
MOV DWORD [R8 + 4], EBX
MOV DWORD [R8 + 8], ECX
MOV DWORD [R8 + 12], EDX
MOV EAX, 80000003h
CPUID
MOV DWORD [R8 + 16], EAX
MOV DWORD [R8 + 20], EBX
MOV DWORD [R8 + 24], ECX
MOV DWORD [R8 + 28], EDX
MOV EAX, 80000004h
CPUID
MOV DWORD [R8 + 32], EAX
MOV DWORD [R8 + 36], EBX
MOV DWORD [R8 + 40], ECX
MOV DWORD [R8 + 44], EDX
POP RBX
RET

32
src/system/FileSystem.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include "ehs/system/FileSystem.h"
#include "ehs/Log.h"
#include <unistd.h>
#include <cstring>
#include <cerrno>
namespace ehs
{
void FileSystem::SetWorkingDir(const Str_8& dir)
{
int code = chdir(dir);
if (code == -1)
EHS_LOG_INT("Error", 0, strerror(errno));
}
Str_8 FileSystem::GetWorkingDir()
{
char result[EHS_MAX_PATH];
if (!getcwd(result, EHS_MAX_PATH))
EHS_LOG_INT("Error", 0, strerror(errno));
return result;
}
void FileSystem::SetOwner(const Str_8& dir, const UInt_32 userId, const UInt_32 groupId)
{
if (chown(dir, userId, groupId) == -1)
EHS_LOG_INT("Error", 0, strerror(errno));
}
}

76
src/system/Mutex_PT.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include "ehs/system/Mutex_PT.h"
namespace ehs
{
Mutex::~Mutex()
{
if (!initialized)
return;
pthread_mutex_destroy(&hdl);
}
Mutex::Mutex()
: hdl{}
{
}
Mutex::Mutex(const Mutex& mutex)
: BaseMutex(mutex), hdl{}
{
}
Mutex& Mutex::operator=(const Mutex& mutex)
{
if (this == &mutex)
return *this;
BaseMutex::operator=(mutex);
hdl = {};
return *this;
}
void Mutex::Initialize()
{
if (initialized)
return;
pthread_mutex_t hdl = {};
int code = pthread_mutex_init(&hdl, nullptr);
initialized = true;
}
void Mutex::UnInitialize()
{
if (!initialized)
return;
pthread_mutex_destroy(&hdl);
initialized = false;
}
void Mutex::Lock()
{
if (locked)
return;
pthread_mutex_lock(&hdl);
locked = true;
}
void Mutex::Unlock()
{
if (!locked)
return;
pthread_mutex_unlock(&hdl);
locked = false;
}
}

88
src/system/Mutex_W32.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "system/Mutex_W32.h"
#include "ehs/Str.h"
#include "ehs/Log.h"
namespace ehs
{
Mutex::~Mutex()
{
if (!initialized)
return;
if (!CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to uninitialize mutex with error #" + Str_8::FromNum(GetLastError()) + ".");
}
Mutex::Mutex()
: hdl(nullptr)
{
}
Mutex::Mutex(const Mutex& mutex)
: BaseMutex(mutex), hdl(nullptr)
{
}
Mutex& Mutex::operator=(const Mutex& mutex)
{
if (this == &mutex)
return *this;
BaseMutex::operator=(mutex);
hdl = nullptr;
return *this;
}
void Mutex::Initialize()
{
if (initialized)
return;
hdl = CreateMutexW(nullptr, FALSE, nullptr);
if (!hdl)
{
EHS_LOG_INT("Error", 0, "Failed to create mutex with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
initialized = true;
}
void Mutex::UnInitialize()
{
if (!initialized)
return;
if (!CloseHandle(hdl))
EHS_LOG_INT("Error", 0, "Failed to uninitialize mutex with error #" + Str_8::FromNum(GetLastError()) + ".");
initialized = false;
}
void Mutex::Lock()
{
if (locked)
return;
if (WaitForSingleObject(hdl, EHS_INFINITE) == WAIT_FAILED)
{
EHS_LOG_INT("Error", 0, "Failed to lock mutex with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
locked = true;
}
void Mutex::Unlock()
{
if (!locked)
return;
if (!ReleaseMutex(hdl))
EHS_LOG_INT("Error", 0, "Failed to unlock mutex with error #" + Str_8::FromNum(GetLastError()) + ".");
locked = false;
}
}

117
src/system/Open_UNX.cpp Normal file
View File

@@ -0,0 +1,117 @@
#include "ehs/system/Open_UNX.h"
#include "ehs/Log.h"
#include <dlfcn.h>
namespace ehs
{
Open::~Open()
{
if (!Open::IsInitialize())
return;
if (dlclose(hdl))
EHS_LOG_INT("Error", 0, "Failed to close.");
}
Open::Open()
: hdl(nullptr)
{
}
Open::Open(Str_8 filePath)
: BaseOpen((Str_8&&)filePath), hdl(nullptr)
{
Open::Initialize();
}
Open::Open(Open&& o) noexcept
: BaseOpen((BaseOpen&&)o), hdl(o.hdl)
{
o.hdl = nullptr;
}
Open::Open(const Open& o)
: BaseOpen(o), hdl(nullptr)
{
Open::Initialize();
}
Open& Open::operator=(Open&& o) noexcept
{
if (this == &o)
return *this;
Open::Release();
BaseOpen::operator=((BaseOpen&&)o);
hdl = o.hdl;
o.hdl = nullptr;
return *this;
}
Open& Open::operator=(const Open& o)
{
if (this == &o)
return *this;
Open::Release();
BaseOpen::operator=(o);
hdl = nullptr;
Open::Initialize();
return *this;
}
void Open::Initialize()
{
if (IsInitialize())
return;
hdl = dlopen(filePath, RTLD_LAZY);
if (!hdl)
{
EHS_LOG_INT("Error", 0, dlerror());
return;
}
}
void Open::Release()
{
if (!IsInitialize())
return;
if (dlclose(hdl))
EHS_LOG_INT("Error", 0, "Failed to close.");
hdl = nullptr;
}
void* Open::Retrieve(Str_8 symbol)
{
if (!IsInitialize())
return nullptr;
void* func = dlsym(hdl, symbol);
if (!func)
{
dlerror();
EHS_LOG_INT("Error", 0, "Undefined symbol, \"" + symbol + "\".");
Release();
return nullptr;
}
return func;
}
bool Open::IsInitialize() const
{
return hdl;
}
}

Some files were not shown because too many files have changed in this diff Show More