First commit.

This commit is contained in:
2023-12-17 03:29:08 -08:00
commit 09ced8e899
255 changed files with 45001 additions and 0 deletions

1929
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 "../../../include/IO/Audio/AudioCodec.h"
namespace lwe
{
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)
{
LWE_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)
{
LWE_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 "../../../include/IO/Audio/AudioDevice_ALSA.h"
#include "../../../include/EHS.h"
#include "../../../include/Log.h"
namespace lwe
{
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)
{
LWE_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:
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "Failed to set channels.");
return;
}
}
if (sampleRate)
{
if (snd_pcm_hw_params_set_rate_near(hdl, params, &sampleRate, nullptr) < 0)
{
LWE_LOG_INT("Error", 2, "Failed to set sample rate.");
return;
}
}
if (snd_pcm_hw_params_set_period_time_near(hdl, params, &period, nullptr) < 0)
{
LWE_LOG_INT("Error", 3, "Failed to set period.");
return;
}
if (snd_pcm_hw_params_set_buffer_time_near(hdl, params, &latency, nullptr) < 0)
{
LWE_LOG_INT("Error", 4, "Failed to set latency.");
return;
}
if (snd_pcm_hw_params(hdl, params) < 0)
{
LWE_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)
{
LWE_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:
{
LWE_LOG_INT("Error", 7, "Format unsupported.");
break;
}
}
}
if (!channels)
{
if (snd_pcm_hw_params_get_channels(params, &channels) < 0)
{
LWE_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)
{
LWE_LOG_INT("Error", 9, "Failed to retrieve sample rate.");
return;
}
}
if (snd_pcm_hw_params_get_buffer_size(params, &maxFrames) < 0)
{
LWE_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)
{
LWE_LOG_INT("Error", 11, "Failed to retrieve software parameters.");
return;
}
if (snd_pcm_sw_params_set_silence_threshold(hdl, swParams, maxFrames) < 0)
{
LWE_LOG_INT("Error", 12, "Failed to set silence threshold.");
return;
}
if (snd_pcm_sw_params_set_silence_size(hdl, swParams, maxFrames) < 0)
{
LWE_LOG_INT("Error", 12, "Failed to set silence size.");
return;
}
if (snd_pcm_sw_params(hdl, swParams) < 0)
{
LWE_LOG_INT("Error", 13, "Failed to set software parameters.");
return;
}
if (snd_pcm_prepare(hdl) < 0)
{
LWE_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)
{
LWE_LOG_INT("Warning", 0, "Buffer overrun/underrun occurred.");
if (snd_pcm_recover(hdl, -EPIPE, 0) < 0)
{
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Warning", 3, "Buffer overrun/underrun occurred.");
if (snd_pcm_recover(hdl, -EPIPE, 1) < 0)
{
LWE_LOG_INT("Error", 4, "Failed to recover from buffer overrun/underrun.");
return 0;
}
return GetAvailFrames();
}
else
{
LWE_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)
{
LWE_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)
{
LWE_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
{
LWE_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 "../../../include/IO/Audio/AudioDevice_W32.h"
#include "../../../include/Log.h"
namespace lwe
{
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))
{
LWE_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))
LWE_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)
{
LWE_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
LWE_LOG_INT("Error", 2, "Failed to retrieve supported audio format with error #" + Str_8::FromNum(r) + ".");
return;
}
if (match)
{
LWE_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)
{
LWE_LOG_INT("Error", 5, "Audio client is already initialized.");
return;
}
else if (r == AUDCLNT_E_WRONG_ENDPOINT_TYPE)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 15, "The Windows audio service is not running.");
return;
}
else if (r == E_POINTER)
{
LWE_LOG_INT("Error", 16, "Parameter pFormat is NULL.");
return;
}
else if (r == E_INVALIDARG)
{
LWE_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)
{
LWE_LOG_INT("Error", 18, "Out of memory.");
return;
}
else if (FAILED(r))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_LOG_INT("Error", 29, "Failed to retrieve buffer size with error #" + Str_8::FromNum(r) + ".");
return;
}
r = client->Start();
if (FAILED(r))
{
LWE_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))
{
LWE_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)
LWE_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_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)
LWE_LOG_INT("Error", 1, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_LOG_INT("Error", 1, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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)
LWE_LOG_INT("Error", 0, "The audio device has been invalidated.");
else if (FAILED(r))
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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 "../../../include/IO/Audio/BaseAudioDevice.h"
namespace lwe
{
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 {};
}
}

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

@@ -0,0 +1,607 @@
#include "../../include/IO/BaseFile.h"
namespace lwe
{
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(ProcessFullName_8(filePath)),
name(ProcessName_8(fullName)), extension(ProcessExt_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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::ProcessFullName_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::ProcessFullName_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::ProcessFullName_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::ProcessName_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::ProcessName_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::ProcessName_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::ProcessExt_32(const Str_32& filePath)
{
UInt_64 index = 0;
filePath.Find(U".", &index, SearchPattern::RIGHT_LEFT);
return filePath.Sub(index);
}
Str_16 BaseFile::ProcessExt_16(const Str_16& filePath)
{
UInt_64 index = 0;
filePath.Find(L".", &index, SearchPattern::RIGHT_LEFT);
return filePath.Sub(index);
}
Str_8 BaseFile::ProcessExt_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 "../../include/IO/BaseFileMonitor.h"
namespace lwe
{
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 "../../include/IO/BaseWindow.h"
namespace lwe
{
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 "../../include/IO/COM.h"
#include "../../include/Str.h"
#include "../../include/Log.h"
namespace lwe
{
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)
{
LWE_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))
{
LWE_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))
{
LWE_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))
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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 "../../include/IO/Console.h"
#include "../../include/Log.h"
#include "../../include/IO/File.h"
#if defined(LWE_OS_LINUX)
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#endif
namespace lwe
{
ConsoleHdl Console::hdlOut = 0;
ConsoleHdl Console::hdlIn = 0;
#if defined(LWE_OS_WINDOWS)
bool Console::isConsole = true;
#endif
void Console::Attach()
{
#if defined(LWE_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)
// LWE_LOG_INT("Error", 0, "Failed to wait for console input.");
isConsole = true;
}
#elif defined(LWE_OS_LINUX)
hdlOut = open("/dev/stdout", O_WRONLY | O_SYNC);
hdlIn = open("/dev/stdin", O_RDONLY);
#else
return;
#endif
}
bool Console::Create()
{
#if defined(LWE_OS_WINDOWS)
if (!AllocConsole())
return false;
hdlIn = GetStdHandle(STD_INPUT_HANDLE);
hdlOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (WaitForSingleObject(hdlIn, LWE_INFINITE) == WAIT_FAILED)
LWE_LOG_INT("Error", 2, "Failed to wait for console input.");
//if (!SetConsoleActiveScreenBuffer(hdlOut))
// LWE_LOG_INT("Error", 3, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
isConsole = true;
#endif
return true;
}
void Console::Free()
{
#if defined(LWE_OS_WINDOWS)
if (!FreeConsole())
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(LWE_OS_LINUX)
int code = close(hdlOut);
if (code == -1)
LWE_LOG_INT("Error", 0, "Failed to free the console output with error #" + Str_8::FromNum(errno) + ".");
code = close(hdlIn);
if (code == -1)
LWE_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(LWE_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))
LWE_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))
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size(true));
}
#elif defined(LWE_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)
{
LWE_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(LWE_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))
LWE_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))
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size(true));
}
#elif defined(LWE_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)
{
LWE_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(LWE_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))
LWE_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))
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
offset += written;
}
while (offset < r.Size());
}
#elif defined(LWE_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)
{
LWE_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(LWE_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))
{
LWE_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))
{
LWE_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(LWE_OS_LINUX)
Str_32 result;
Str_32 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
LWE_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(LWE_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))
{
LWE_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))
{
LWE_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(LWE_OS_LINUX)
Str_16 result;
Str_16 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
LWE_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(LWE_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))
{
LWE_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))
{
LWE_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(LWE_OS_LINUX)
Str_8 result;
Str_8 input(bufferSize);
ssize_t read = 0;
do
{
read = ::read(hdlIn, input, bufferSize);
if (read == -1)
{
LWE_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(LWE_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(LWE_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)
{
LWE_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(LWE_OS_WINDOWS)
if (!SetConsoleTitleW(UTF::To_16(title)))
LWE_LOG_INT("Error", 0, "Failed to set console title with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(LWE_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)
{
LWE_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(LWE_OS_WINDOWS)
if (!SetConsoleTitleW(title))
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(LWE_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)
{
LWE_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(LWE_OS_WINDOWS)
if (!SetConsoleTitleW(UTF::To_16(title)))
LWE_LOG_INT("Error", 0, "Failed with error #" + Str_8::FromNum(GetLastError()) + ".");
#elif defined(LWE_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)
{
LWE_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(LWE_OS_WINDOWS)
Str_16 title(LWE_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], LWE_MAX_PATH);
title.Resize(size);
return UTF::To_32(title);
#else
return {};
#endif
}
Str_16 Console::GetTitle_16()
{
#if defined(LWE_OS_WINDOWS)
Str_16 title(LWE_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], LWE_MAX_PATH);
title.Resize(size);
return title;
#else
return {};
#endif
}
Str_8 Console::GetTitle_8()
{
#if defined(LWE_OS_WINDOWS)
Str_16 title(LWE_MAX_PATH);
DWORD size = GetConsoleTitleW(&title[0], LWE_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(LWE_OS_WINDOWS)
return UTF::To_32(GetCommandLineW()).Split(U" ");
#elif defined(LWE_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(LWE_OS_WINDOWS)
return Str_16(GetCommandLineW()).Split(L" ");
#elif defined(LWE_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(LWE_OS_WINDOWS)
return UTF::To_8(GetCommandLineW()).Split(" ");
#elif defined(LWE_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(LWE_OS_WINDOWS)
void* hdl = FindWindowW(nullptr, GetTitle_16());
if (hdl == nullptr)
LWE_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 "../../include/IO/FileMonitor_UNX.h"
#include "../../include/Log.h"
#include <sys/inotify.h>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>
#define BUF_LEN (1024 * (sizeof(inotify_event) + 16))
namespace lwe
{
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)
{
LWE_LOG_INT("Error", 0, "Failed to initialize inotify.");
return;
}
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
LWE_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)
{
LWE_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)
{
LWE_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 = LWE_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)
LWE_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 |= LWE_FE_MODIFIED;
if (event->mask & IN_DELETE_SELF)
mask |= LWE_FE_DELETED;
if (event->mask & IN_MOVE_SELF)
mask |= LWE_FE_MOVED;
if (event->mask & IN_ACCESS)
mask |= LWE_FE_OPENED;
i += sizeof(inotify_event) + event->len;
}
if (mask & LWE_FE_DELETED || mask & LWE_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 "../../include/IO/FileMonitor_W32.h"
#include "../../include/Log.h"
#include "../../include/UTF.h"
#include <chrono>
namespace lwe
{
FileMonitor::~FileMonitor()
{
if (!IsInitialized())
return;
if (!CloseHandle(hdl))
LWE_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)
LWE_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))
LWE_LOG_INT("Error", 0, "Failed to close file at file path, \"" + filePath + "\", with error #" + GetLastError() + ".");
hdl = nullptr;
}
UInt_8 FileMonitor::Poll()
{
UInt_8 mask = LWE_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 = LWE_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 "../../include/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 lwe
{
File::~File()
{
if (map != MAP_FAILED && munmap(map, mapSize) == -1)
LWE_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
if (hdl >= 0 && close(hdl) == -1)
LWE_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)
LWE_LOG_INT("Error", 0, strerror(errno));
}
else
{
if (code == ENOENT)
LWE_LOG_INT("Error", 0, "File at filepath, \"" + filePath + "\" not found.");
else
LWE_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)
LWE_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(errno) + ".");
map = MAP_FAILED;
mapSize = 0;
if (IsValid() && close(hdl) == -1)
LWE_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)
{
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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)
LWE_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 "../../include/IO/File_W32.h"
namespace lwe
{
File::~File()
{
if (view && !UnmapViewOfFile(view))
LWE_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
if (map != INVALID_HANDLE_VALUE && !CloseHandle(map))
LWE_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
if (hdl != INVALID_HANDLE_VALUE && !CloseHandle(hdl))
LWE_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)
LWE_LOG_INT("Error", 1, "File not found at path, \"" + path + "\".");
else if (code != ERROR_SUCCESS)
LWE_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))
LWE_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
view = nullptr;
viewSize = 0;
if (IsMapped() && !CloseHandle(map))
LWE_LOG_INT("Error", 0, "Failed to unmap with error #" + Str_8::FromNum(GetLastError()) + ".");
map = INVALID_HANDLE_VALUE;
if (IsValid() && !CloseHandle(hdl))
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "Failed to map view with error #" + Str_8::FromNum(GetLastError()) + ".");
if (!CloseHandle(map))
LWE_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))
LWE_LOG_INT("Error", 0, "Failed to unmap view with error #" + Str_8::FromNum(GetLastError()) + ".");
view = nullptr;
viewSize = 0;
if (!CloseHandle(map))
LWE_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))
LWE_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))
LWE_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))
LWE_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)
LWE_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)
LWE_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)
LWE_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))
LWE_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))
LWE_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))
LWE_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));
}
}

239
src/IO/FontAtlas.cpp Normal file
View File

@@ -0,0 +1,239 @@
#include "../../include/IO/FontAtlas.h"
#include "../../include/IO/File.h"
#include "../../include/Serializer.h"
namespace lwe
{
FontAtlas::FontAtlas()
: glyphScale(0)
{
AddType("FontAtlas");
}
FontAtlas::FontAtlas(const Str_8& filePath)
: glyphScale(0)
{
AddType("FontAtlas");
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))
{
LWE_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);
bitDepth = 8;
channels = 1;
width = fData.Read<UInt_64>();
height = fData.Read<UInt_64>();
data = new Byte[width * height * (bitDepth / 8) * channels];
fData.ReadArray(data, &size);
aspect = IMG_ASPECT_COLOR;
}
FontAtlas::FontAtlas(FontAtlas&& fa) noexcept
: Img(std::move(fa)), glyphScale(fa.glyphScale), glyphs(std::move(fa.glyphs))
{
fa.glyphScale = 0;
}
FontAtlas::FontAtlas(const FontAtlas& fa)
: Img(fa), glyphScale(0)
{
}
FontAtlas& FontAtlas::operator=(FontAtlas&& fa) noexcept
{
if (this == &fa)
return *this;
Img::operator=(std::move(fa));
glyphScale = fa.glyphScale;
glyphs = std::move(fa.glyphs);
fa.glyphScale = 0;
return *this;
}
FontAtlas& FontAtlas::operator=(const FontAtlas& fa)
{
if (this == &fa)
return *this;
Img::operator=(fa);
glyphScale = 0;
glyphs = Array<Glyph>();
return *this;
}
UInt_64 FontAtlas::GetGlyphScale() const
{
return glyphScale;
}
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_f FontAtlas::CalculateSize(const Str_8& text) const
{
Vec2_f size;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
size.x += (float)glyph.GetAdvance().x;
if ((float)glyph.GetScale().y > size.y)
size.y = (float)glyph.GetScale().y;
}
return size;
}
float FontAtlas::CalculateWidth(const Str_8 &text) const
{
float width = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
width += (float)glyph.GetAdvance().x;
}
return width;
}
float FontAtlas::CalculateHeight(const Str_8& text) const
{
float height = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
if ((float)glyph.GetScale().y > height)
height = (float)glyph.GetScale().y;
}
return height;
}
UInt_64 FontAtlas::CalculateIndexAtPoint(const Str_8& text, const Vec2_f& point) const
{
float width = 0.0f;
for (UInt_64 i = 0; i < text.Size(); ++i)
{
Glyph glyph = GetGlyph(text[i]);
float temp = width + (float)glyph.GetAdvance().x;
if (point.x > temp)
width += (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 {"Label", std::move(verts), std::move(indices)};
}
FontAtlas* FontAtlas::Clone() const
{
return new FontAtlas(*this);
}
}

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

@@ -0,0 +1,115 @@
#include "../../include/IO/Glyph.h"
namespace lwe
{
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);
}
}

50
src/IO/HID/Button.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "../../../include/IO/HID/Button.h"
namespace lwe
{
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 "../../../include/IO/HID/ButtonState.h"
namespace lwe
{
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 "../../../include/IO/HID/HID.h"
namespace lwe
{
HID::HID()
: type(LWE_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 = LWE_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 = LWE_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 "../../../include/IO/HID/Input.h"
namespace lwe
{
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 "../../../include/IO/HID/InputHandler.h"
namespace lwe
{
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 "../../../include/IO/HID/Keyboard.h"
namespace lwe
{
Keyboard::Keyboard()
{
}
Keyboard::Keyboard(Str_8 name, const UInt_64 id)
: HID(LWE_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 "../../../include/IO/HID/Mouse.h"
namespace lwe
{
Mouse::Mouse()
{
}
Mouse::Mouse(Str_8 name, const UInt_64 id)
: HID(LWE_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;
}
}
}

1482
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 "../../../include/IO/Img/ImgCodec.h"
#include "../../../include/IO/Img/Img.h"
namespace lwe
{
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)
{
LWE_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)
{
LWE_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 "../../../include/IO/Img/PNG.h"
namespace lwe
{
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::ProcessName_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)
{
LWE_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 "../../../include/IO/Img/PNG_Chunk.h"
namespace lwe
{
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 "../../../include/IO/Model/AnimBone.h"
#include <algorithm>
namespace lwe
{
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 "../../../include/IO/Model/Animation.h"
namespace lwe
{
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 "../../../include/IO/Model/Bone.h"
namespace lwe
{
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 "../../../include/IO/Model/KeyFrame.h"
#include <algorithm>
namespace lwe
{
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;
}
}

369
src/IO/Model/Mesh.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include "../../../include/IO/Model/Mesh.h"
namespace lwe
{
Mesh::Mesh()
{
AddType("Mesh");
}
Mesh::Mesh(Str_8 id, Array<Vertex_f> vertices, Array<UInt_32> indices)
: Resource(std::move(id)), vertices(std::move(vertices)), indices(std::move(indices))
{
AddType("Mesh");
}
Mesh::Mesh(Str_8 id, Array<Vertex_f> vertices)
: Resource(std::move(id)), vertices(std::move(vertices))
{
AddType("Mesh");
}
Mesh::Mesh(Str_8 id)
: Resource(std::move(id))
{
AddType("Mesh");
}
Mesh::Mesh(Mesh&& mesh) noexcept
: Resource(std::move(mesh)), vertices(std::move(mesh.vertices)),
indices(std::move(mesh.indices))
{
}
Mesh::Mesh(const Mesh& mesh)
: Resource(mesh), vertices(mesh.vertices), indices(mesh.indices), srcVertBuffer(mesh.srcVertBuffer),
dstVertBuffer(mesh.dstVertBuffer), srcIndBuffer(mesh.srcIndBuffer), dstIndBuffer(mesh.dstIndBuffer)
{
}
Mesh& Mesh::operator=(Mesh&& mesh) noexcept
{
if (this == &mesh)
return *this;
vertices = std::move(mesh.vertices);
indices = std::move(mesh.indices);
srcVertBuffer = std::move(mesh.srcVertBuffer);
dstVertBuffer = std::move(mesh.dstVertBuffer);
srcIndBuffer = std::move(mesh.srcIndBuffer);
dstIndBuffer = std::move(mesh.dstIndBuffer);
Resource::operator=(std::move(mesh));
return *this;
}
Mesh& Mesh::operator=(const Mesh& mesh)
{
if (this == &mesh)
return *this;
vertices = mesh.vertices;
indices = mesh.indices;
srcVertBuffer = mesh.srcVertBuffer;
dstVertBuffer = mesh.dstVertBuffer;
srcIndBuffer = mesh.srcIndBuffer;
dstIndBuffer = mesh.dstIndBuffer;
Resource::operator=(mesh);
return *this;
}
bool Mesh::UploadToGpu(GpuCmdBuffer* cmdBuffer)
{
GameLoop* gl = (GameLoop*)GetParent("GameLoop");
if (!gl)
return false;
RenderWindow* win = gl->GetWindow();
if (!win)
return false;
GpuInterface* inf = win->GetInterface();
if (readOnly)
{
srcVertBuffer = {
inf,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
sizeof(Vertex_f) * vertices.Size()
};
Byte* data = (Byte*)srcVertBuffer.MapMemory();
for (UInt_64 i = 0; i < vertices.Size(); ++i)
for (UInt_64 v = 0; v < sizeof(Vertex_f); ++v)
data[sizeof(Vertex_f) * i + v] = ((Byte*) &vertices[i])[v];
srcVertBuffer.UnMapMemory();
dstVertBuffer = {
inf,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
srcVertBuffer.Size(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
};
VK_MEMORY_PROPERTY_HOST
VkBufferMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = dstVertBuffer;
barrier.offset = 0;
barrier.size = VK_WHOLE_SIZE;
cmdBuffer->BufferBarrier(
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
1,
&barrier
);
GpuBuffer::Copy(cmdBuffer, &srcVertBuffer, &dstVertBuffer);
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = dstVertBuffer;
barrier.offset = 0;
barrier.size = VK_WHOLE_SIZE;
cmdBuffer->BufferBarrier(
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
0,
1,
&barrier
);
if (indices.Size())
{
srcIndBuffer = {
inf,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
sizeof(UInt_32) * indices.Size()
};
UInt_32* indMem = (UInt_32*)srcIndBuffer.MapMemory();
for (UInt_64 i = 0; i < indices.Size(); ++i)
indMem[i] = indices[i];
srcIndBuffer.UnMapMemory();
dstIndBuffer = {
inf,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
srcIndBuffer.Size(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
};
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = dstIndBuffer;
barrier.offset = 0;
barrier.size = VK_WHOLE_SIZE;
cmdBuffer->BufferBarrier(
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
1,
&barrier
);
GpuBuffer::Copy(cmdBuffer, &srcIndBuffer, &dstIndBuffer);
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.buffer = dstIndBuffer;
barrier.offset = 0;
barrier.size = VK_WHOLE_SIZE;
cmdBuffer->BufferBarrier(
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
0,
1,
&barrier
);
}
cmdBuffer->AddDependency(this);
}
else
{
dstVertBuffer = {
inf,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
sizeof(Vertex_f) * vertices.Size()
};
void* data = dstVertBuffer.MapMemory();
Util::Copy(data, &vertices[0], dstVertBuffer.Size());
dstVertBuffer.UnMapMemory();
if (indices.Size())
{
dstIndBuffer = {
inf,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
sizeof(UInt_32) * indices.Size()
};
data = dstIndBuffer.MapMemory();
Util::Copy(data, &indices[0], dstIndBuffer.Size());
dstIndBuffer.UnMapMemory();
}
}
return true;
}
bool Mesh::PostGpuUpload()
{
srcVertBuffer.Release();
srcIndBuffer.Release();
return true;
}
bool Mesh::HasPostGpuUploaded() const
{
return !srcVertBuffer.IsValid() && !srcIndBuffer.IsValid();
}
bool Mesh::ReleaseFromGpu()
{
srcVertBuffer.Release();
srcIndBuffer.Release();
dstVertBuffer.Release();
dstIndBuffer.Release();
return true;
}
bool Mesh::IsUploaded() const
{
return dstVertBuffer.IsValid();
}
void Mesh::Bind(GpuCmdBuffer* cmdBuffer)
{
cmdBuffer->AddDependency(this);
if (dstIndBuffer.IsValid())
{
cmdBuffer->AddDependency(&dstIndBuffer);
vkCmdBindIndexBuffer(*cmdBuffer, dstIndBuffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
}
cmdBuffer->AddDependency(&dstVertBuffer);
VkDeviceSize offset = 0;
VkBuffer vertB = dstVertBuffer.GetBuffer();
vkCmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertB, &offset);
}
void Mesh::Draw(GpuCmdBuffer* cmdBuffer, const UInt_32 instances)
{
if (dstIndBuffer.IsValid())
vkCmdDrawIndexed(*cmdBuffer, indices.Size(), instances, 0, 0, 0);
else
vkCmdDraw(*cmdBuffer, vertices.Size(), instances, 0, 0);
}
void Mesh::SetVertices(const Array<Vertex_f>& newVertices)
{
vertices = newVertices;
}
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();
}
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;
}
}

295
src/IO/Model/Model.cpp Normal file
View File

@@ -0,0 +1,295 @@
#include "../../../include/IO/Model/Model.h"
namespace lwe
{
Model::Model()
{
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)
: Resource(std::move(id)), meshes(std::move(meshes)), skeleton(std::move(skeleton)),
animations(std::move(animations))
{
AddType("Model");
}
Model::Model(Str_8 id, Array<Mesh> meshes, Bone skeleton)
: Resource(std::move(id)), meshes(std::move(meshes)), skeleton(std::move(skeleton))
{
AddType("Model");
}
Model::Model(Str_8 id, Array<Mesh> meshes)
: Resource(std::move(id)), meshes(std::move(meshes))
{
AddType("Model");
}
Model::Model(Model&& model) noexcept
: Resource(std::move(model)), meshes(std::move(model.meshes)),
skeleton(std::move(model.skeleton)), animations(std::move(model.animations))
{
}
Model& Model::operator=(Model&& model) noexcept
{
if (this == &model)
return *this;
hashId = model.hashId;
id = std::move(model.id);
meshes = std::move(model.meshes);
skeleton = std::move(model.skeleton);
animations = std::move(model.animations);
model.hashId = 0;
return *this;
}
bool Model::UploadToGpu(GpuCmdBuffer* cmdBuffer)
{
for (UInt_64 i = 0; i < meshes.Size(); ++i)
if (!meshes[i].UploadToGpu(cmdBuffer))
return false;
return true;
}
bool Model::PostGpuUpload()
{
bool result = true;
for (UInt_64 i = 0; i < meshes.Size(); ++i)
if (!meshes[i].PostGpuUpload())
result = false;
return result;
}
bool Model::ReleaseFromGpu()
{
bool result = true;
for (UInt_64 i = 0; i < meshes.Size(); ++i)
if (!meshes[i].ReleaseFromGpu())
result = false;
return result;
}
bool Model::IsUploaded() const
{
return meshes[0].IsUploaded();
}
void Model::Draw(GpuCmdBuffer* cmdBuffer, const UInt_32 instances)
{
for (UInt_64 i = 0; i < meshes.Size(); ++i)
{
meshes[i].Bind(cmdBuffer);
meshes[i].Draw(cmdBuffer, instances);
}
}
Array<Mesh> Model::GetMeshes() const
{
return meshes;
}
Array<Mesh>& Model::GetMeshes()
{
return meshes;
}
Mesh* Model::GetMesh(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < meshes.Size(); ++i)
if (meshes[i].GetHashId() == hashId)
return &meshes[i];
return nullptr;
}
Mesh* Model::GetMesh(const Str_8& id)
{
return GetMesh(id.Hash_64());
}
Bone Model::GetSkeleton() const
{
return skeleton;
}
Bone& Model::GetSkeleton()
{
return skeleton;
}
Animation* Model::GetAnimation(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < animations.Size(); ++i)
if (animations[i].GetHashId() == hashId)
return &animations[i];
return nullptr;
}
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))
{
LWE_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>());
meshes[i].SetParent(this);
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)
{
LWE_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 "../../../include/IO/Model/PropertyChange.h"
namespace lwe
{
PropertyChange::PropertyChange()
: type(ChangeType::INVALID), value(0.0f)
{
}
PropertyChange::PropertyChange(const ChangeType type, const float value)
: type(type), value(value)
{
}
}

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

@@ -0,0 +1,95 @@
#include "../../include/IO/RIFF.h"
#include "../../include/IO/File.h"
namespace lwe
{
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")
{
LWE_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")
{
LWE_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 "../../include/IO/RIFF_Chunk.h"
namespace lwe
{
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;
}
}

336
src/IO/Socket/BaseTCP.cpp Normal file
View File

@@ -0,0 +1,336 @@
#include "../../../include/IO/Socket/BaseTCP.h"
#include "../../../include/Log.h"
namespace lwe
{
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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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 "../../../include/IO/Socket/BaseUDP.h"
namespace lwe
{
BaseUDP::BaseUDP()
: addrType(AddrType::IPV6), port(0), bound(false)
{
}
BaseUDP::BaseUDP(const AddrType addrType)
: addrType(addrType), port(0), bound(false)
{
}
BaseUDP::BaseUDP(BaseUDP&& udp) noexcept
: addrType(udp.addrType), address(std::move(udp.address)), port(udp.port), bound(true)
{
udp.addrType = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
}
BaseUDP::BaseUDP(const BaseUDP& udp)
: addrType(udp.addrType), address(udp.address), port(udp.port), bound(false)
{
}
BaseUDP& BaseUDP::operator=(BaseUDP&& udp) noexcept
{
if (this == &udp)
return *this;
addrType = udp.addrType;
address = std::move(udp.address);
port = udp.port;
bound = udp.bound;
udp.addrType = AddrType::IPV6;
udp.port = 0;
udp.bound = false;
return *this;
}
BaseUDP& BaseUDP::operator=(const BaseUDP& udp)
{
if (this == &udp)
return *this;
addrType = udp.addrType;
address = udp.address;
port = udp.port;
bound = false;
return *this;
}
bool BaseUDP::IsBound() const
{
return bound;
}
AddrType BaseUDP::GetAddressType() const
{
return addrType;
}
Str_8 BaseUDP::GetLocalAddress() const
{
return address;
}
UInt_16 BaseUDP::GetLocalPort() const
{
return port;
}
}

1316
src/IO/Socket/Comms.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
#include "../../../include/IO/Socket/CommsSystem.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/IO/Socket/Endpoint.h"
#include "../../../include/IO/Socket/Operation.h"
namespace lwe
{
CommsSystem::~CommsSystem()
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
delete ops[i];
ops.Clear();
}
CommsSystem::CommsSystem()
: hashId(0)
{
}
CommsSystem::CommsSystem(const Str_8& id)
: id(id), hashId(id.Hash_64())
{
}
CommsSystem::CommsSystem(const CommsSystem& sys)
: id(sys.id), hashId(sys.hashId)
{
}
CommsSystem& CommsSystem::operator=(const CommsSystem& sys)
{
if (this == &sys)
return *this;
id = sys.id;
hashId = sys.hashId;
ops = Array<Operation*>();
return *this;
}
Str_8 CommsSystem::GetId() const
{
return id;
}
UInt_64 CommsSystem::GetHashId() const
{
return hashId;
}
bool CommsSystem::HasOperation(const UInt_64 hashId)
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
if (ops[i]->GetHashId() == hashId)
return true;
return false;
}
bool CommsSystem::AddOperation(Operation* op)
{
if (HasOperation(op->GetHashId()))
return false;
ops.Push(op);
return true;
}
void CommsSystem::Execute(Comms* comms, Endpoint* endpoint, const UInt_64 hashId, Serializer<>& payload)
{
for (UInt_64 i = 0; i < ops.Size(); ++i)
{
if (ops[i]->GetHashId() == hashId)
{
ops[i]->Process(comms, endpoint, this, payload);
return;
}
}
LWE_LOG_INT("Info", 0, "System not found.");
}
}

75
src/IO/Socket/DNS.cpp Normal file
View File

@@ -0,0 +1,75 @@
#include "../../../include/IO/Socket/DNS.h"
#include "../../../include/Log.h"
#if defined(LWE_OS_WINDOWS)
#include <WinSock2.h>
#include <WS2tcpip.h>
#elif defined(LWE_OS_LINUX)
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
namespace lwe
{
Str_8 DNS::Resolve(const AddrType addrType, const Str_8& hostName)
{
#if defined(LWE_OS_WINDOWS)
WSADATA data = {};
Int_32 wsaCode = WSAStartup(MAKEWORD(2, 2), &data);
if (wsaCode)
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "Failed to resolve host with error #" + Str_8::FromNum(code) + ".");
return {};
}
#if defined(LWE_OS_WINDOWS)
if (WSACleanup() == SOCKET_ERROR)
{
LWE_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 {};
}
}

650
src/IO/Socket/Endpoint.cpp Normal file
View File

@@ -0,0 +1,650 @@
#include "../../../include/IO/Socket/Endpoint.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/Encryption.h"
#include "../../../include/System/CPU.h"
#if defined(LWE_OS_WINDOWS)
#include <WinSock2.h>
#include <WS2tcpip.h>
#elif defined(LWE_OS_LINUX)
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
#endif
namespace lwe
{
Endpoint::Endpoint()
: hdl(LWE_INVALID_SOCKET), disposition(EndDisp::UNKNOWN), status(Status::PENDING), arch(Architecture::UNKNOWN),
hashId(0), nextSendId(0), nextRecvId(0), port(0), deltaDuration(0.0f), deltaRate(1.0f / 60.0f),
timeout(0.0f), lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(Socket hdl, const EndDisp disposition, const Architecture arch, const Str_8& id,
const AddrType& type, const Str_8& address, const UInt_16 port)
: hdl(hdl), disposition(disposition), status(Status::ACTIVE), arch(arch), id(id), hashId(id.Hash_32()), nextSendId(0),
nextRecvId(0), address(address), port(port), deltaDuration(0.0f), deltaRate(1.0f / 60.0f), timeout(0.0f),
lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(Socket hdl, const AddrType& type, const Str_8& address, const UInt_16 port)
: hdl(hdl), disposition(EndDisp::UNKNOWN), status(Status::PENDING), arch(Architecture::UNKNOWN), hashId(0),
nextSendId(0), nextRecvId(0), address(address), port(port), deltaDuration(0.0f), deltaRate(1.0f / 60.0f),
timeout(0.0f), lastPing(0.0f), oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
AddType("Endpoint");
}
Endpoint::Endpoint(const Endpoint& end)
: BaseObj(end), hdl(LWE_INVALID_SOCKET), disposition(end.disposition), status(Status::PENDING), arch(end.arch),
id(end.id), hashId(end.hashId), nextSendId(0), nextRecvId(0), address(end.address), port(end.port),
deltaDuration(0.0f), deltaRate(1.0f / 60.0f), timeout(0.0f), lastPing(0.0f),
oldLatency(0.0f), latency(0.0f), queueSlot(0)
{
}
Endpoint& Endpoint::operator=(const Endpoint& end)
{
if (this == &end)
return *this;
BaseObj::operator=(end);
if (status == Status::PENDING)
{
disposition = end.disposition;
status = end.status;
arch = end.arch;
id = end.id;
hashId = end.hashId;
nextSendId = end.nextSendId;
sent = end.sent;
nextRecvId = end.nextRecvId;
received = end.received;
address = end.address;
port = end.port;
deltaDuration = end.deltaDuration;
deltaRate = end.deltaRate;
timeout = end.timeout;
lastPing = end.lastPing;
oldLatency = end.oldLatency;
latency = end.latency;
queueSlot = end.queueSlot;
}
else
{
hdl = LWE_INVALID_SOCKET;
disposition = end.disposition;
status = Status::PENDING;
arch = end.arch;
id = end.id;
hashId = end.hashId;
nextSendId = 0;
sent = Vector<Insurance>();
nextRecvId = 0;
received = Vector<Fragments>();
address = end.address;
port = end.port;
deltaDuration = 0.0f;
deltaRate = 1.0f / 60.0f;
timeout = 0.0f;
lastPing = 0.0f;
oldLatency = 0.0f;
latency = 0.0f;
queueSlot = 0;
}
return *this;
}
void Endpoint::Poll(const float delta)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
SortReceived();
if (deltaDuration >= deltaRate)
deltaDuration = Math::Mod(deltaDuration, deltaRate);
deltaDuration += delta;
timeout += delta;
latency += delta;
if (sent.Size())
{
for (UInt_64 i = 0; i < sent.Size(); ++i)
{
sent[i].lastResend += delta;
if (sent[i].lastResend >= comms->GetResendRate())
{
Serializer result(Endianness::LE);
result.Write(sent[i].header);
result.WriteSer(sent[i].payload);
if (sent[i].header.encrypted)
Encryption::Encrypt_64(result.Size() - sizeof(bool), &result[sizeof(bool)]);
if (comms->GetAddressType() == AddrType::IPV6)
Send_v6(result);
else if (comms->GetAddressType() == AddrType::IPV4)
Send_v4(result);
sent[i].lastResend = Math::Mod(sent[i].lastResend, comms->GetResendRate());
}
}
}
if (comms->GetDisposition() == EndDisp::SERVICE)
{
lastPing += delta;
if (lastPing >= 1.0f)
Ping(delta);
}
}
EndDisp Endpoint::GetDisposition() const
{
return disposition;
}
void Endpoint::SetStatus(const Status newStatus)
{
status = newStatus;
}
Status Endpoint::GetStatus() const
{
return status;
}
Architecture Endpoint::GetArchitecture() const
{
return arch;
}
Str_8 Endpoint::GetId() const
{
return id;
}
UInt_64 Endpoint::GetHashId() const
{
return hashId;
}
UInt_64 Endpoint::GetNextSendId() const
{
return nextSendId;
}
void Endpoint::Send(const bool deltaLocked, const bool encrypted, const bool ensure, const UInt_64 sys,
const UInt_64 op, const Serializer<>& payload)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
if (deltaLocked && deltaDuration < deltaRate)
return;
Header header = {
encrypted,
nextSendId++,
1,
0,
ensure,
comms->GetDisposition(),
comms->GetHashId(),
sys,
op
};
if ((comms->GetAddressType() == AddrType::IPV6 && payload.Size() > COMMS_IPV6_PAYLOAD) || (comms->GetAddressType() == AddrType::IPV4 && payload.Size() > COMMS_IPV4_PAYLOAD))
{
Fragments frags = FragmentData(header, payload);
for (UInt_64 i = 0; i < frags.Size(); ++i)
{
Header newHeader = frags.GetHeader();
newHeader.fragment = i;
Send(newHeader, frags[i]);
}
}
else
{
Send(header, payload);
}
}
void Endpoint::Send(const bool deltaLocked, const bool encrypted, const bool ensure, const Str_8& sys,
const Str_8& op, const Serializer<>& payload)
{
Send(deltaLocked, encrypted, ensure, sys.Hash_64(), op.Hash_64(), payload);
}
void Endpoint::RemoveInsurance(const UInt_64 msgId, const UInt_64 fragment)
{
for (UInt_64 i = 0; i < sent.Size(); ++i)
{
if (sent[i].header.id == msgId && sent[i].header.fragment == fragment)
{
sent.Remove(i);
break;
}
}
timeout = 0.0f;
}
UInt_64 Endpoint::GetNextRecvId() const
{
return nextRecvId;
}
void Endpoint::AddReceived(const Header& header, const Serializer<>& payload)
{
Fragments* frags = nullptr;
for (UInt_64 i = 0; i < received.Size(); ++i)
{
if (received[i].GetHeader().id == header.id)
{
if (received[i][header.fragment].Size())
return;
frags = &received[i];
break;
}
}
if (header.id > nextRecvId)
nextRecvId = header.id + 1;
if (frags)
(*frags)[header.fragment] = payload;
else
received.Push({header, payload});
timeout = 0.0f;
}
Vector<Fragments> Endpoint::GetReceived() const
{
return received;
}
Vector<Fragments>* Endpoint::GetReceived()
{
return &received;
}
Str_8 Endpoint::GetAddress() const
{
return address;
}
UInt_16 Endpoint::GetPort() const
{
return port;
}
void Endpoint::SetDeltaRate(const float newDeltaRate)
{
deltaRate = newDeltaRate;
}
float Endpoint::GetDeltaRate() const
{
return deltaRate;
}
float Endpoint::GetTimeout() const
{
return timeout;
}
float Endpoint::GetLastPing() const
{
return lastPing;
}
void Endpoint::Ping(const float delta)
{
Serializer payload(Endianness::LE);
payload.Write(delta);
Send(false, true, false, "Internal", "Ping", payload);
lastPing = 0.0f;
latency = 0.0f;
}
void Endpoint::Pong(const float delta)
{
Serializer payload(Endianness::LE);
payload.Write(delta);
Send(false, true, false, "Internal", "Pong", payload);
timeout = 0.0f;
}
void Endpoint::SendLatency()
{
oldLatency = latency * 1000;
Serializer sPayload(Endianness::LE);
sPayload.Write(oldLatency);
Send(false, true, false, "Internal", "Latency", sPayload);
latency = 0.0f;
timeout = 0.0f;
}
void Endpoint::SetLatency(const float newLatency)
{
oldLatency = newLatency;
}
float Endpoint::GetLatency() const
{
return oldLatency;
}
void Endpoint::SetQueueSlot(const UInt_64 slot)
{
queueSlot = slot;
}
UInt_64 Endpoint::GetQueueSlot() const
{
return queueSlot;
}
Fragments Endpoint::FragmentData(const Header& header, const Serializer<>& data)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return {};
}
Fragments result;
if (comms->GetAddressType() == AddrType::IPV6)
{
UInt_64 frags = data.Size() / COMMS_IPV6_PAYLOAD;
if (data.Size() % COMMS_IPV6_PAYLOAD)
++frags;
result = Fragments(header, frags);
UInt_64 size = COMMS_IPV6_PAYLOAD;
for (UInt_64 i = 0; i < result.Size(); ++i)
{
size = COMMS_IPV6_PAYLOAD;
if (i == result.Size() - 1)
size = data.Size() % COMMS_IPV6_PAYLOAD;
result[i] = {data.GetEndianness(), &data[i * COMMS_IPV6_PAYLOAD], size};
}
}
else if (comms->GetAddressType() == AddrType::IPV4)
{
UInt_64 frags = data.Size() / COMMS_IPV4_PAYLOAD;
if (data.Size() % COMMS_IPV4_PAYLOAD)
++frags;
result = Fragments(header, frags);
UInt_64 size = COMMS_IPV4_PAYLOAD;
for (UInt_64 i = 0; i < result.Size(); ++i)
{
size = COMMS_IPV4_PAYLOAD;
if (i == result.Size() - 1)
size = data.Size() % COMMS_IPV4_PAYLOAD;
result[i] = {data.GetEndianness(), &data[i * COMMS_IPV4_PAYLOAD], size};
}
}
return result;
}
void Endpoint::Send(const Header& header, const Serializer<>& payload)
{
Comms* comms = (Comms*)GetParent();
if (!comms)
{
LWE_LOG_INT("Error", 0, "Endpoint must be a child of a Socket object.");
return;
}
Serializer result(Endianness::LE);
result.Write(header);
result.WriteSer(payload);
if (header.encrypted)
Encryption::Encrypt_64(result.Size() - sizeof(bool), &result[sizeof(bool)]);
if (header.ensure)
sent.Push({header, payload});
if (comms->GetAddressType() == AddrType::IPV6)
Send_v6(result);
else if (comms->GetAddressType() == AddrType::IPV4)
Send_v4(result);
}
bool Endpoint::SortingNeeded() const
{
UInt_64 lastPacket = 0;
for (UInt_64 i = 0; i < received.Size(); ++i)
{
if (received[i].GetHeader().id < lastPacket)
return true;
else
lastPacket = received[i].GetHeader().id;
}
return false;
}
void Endpoint::SortReceived()
{
if (!SortingNeeded())
return;
Vector<Fragments> sorted(0, received.Stride());
for (UInt_64 a = 0; a < received.Size(); ++a)
{
if (sorted.Size())
{
for (UInt_64 b = sorted.Size(); b; --b)
{
if (received[a].GetHeader().id > sorted[b - 1].GetHeader().id)
{
if (b == sorted.Size())
sorted.Push(received[a]);
else
sorted.Insert(b, received[a]);
break;
}
else
{
sorted.Insert(b - 1, received[a]);
break;
}
}
}
else
{
sorted.Push(received[a]);
}
}
received = sorted;
}
UInt_16 Endpoint::Send_v6(const Serializer<>& payload)
{
if (hdl == LWE_INVALID_SOCKET)
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if (payload.Size() > LWE_IPV6_UDP_PAYLOAD)
{
LWE_LOG_INT("Info", 1, "Attempted to send a packet with the size, \"" + Str_8::FromNum(payload.Size())
+ "\", that exceeds the max payload of, \"" + Str_8::FromNum(LWE_IPV6_UDP_PAYLOAD) + "\".");
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)
{
LWE_LOG_INT("Error", 2, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = 0;
#if defined(LWE_OS_WINDOWS)
dCode = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
dCode = errno;
#endif
LWE_LOG_INT("Error", 3, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
Int_32 sent = sendto(hdl, (char*)&payload[0], (int)payload.Size(), 0, (sockaddr*)&result, sizeof(sockaddr_in6));
#if defined(LWE_OS_WINDOWS)
if (sent == SOCKET_ERROR)
#elif defined(LWE_OS_LINUX)
if (sent == -1)
#endif
{
Int_32 dCode = 0;
#if defined(LWE_OS_WINDOWS)
code = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
code = errno;
#endif
LWE_LOG_INT("Error", 4, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
return 0;
}
return (UInt_16)sent;
}
UInt_16 Endpoint::Send_v4(const Serializer<>& payload)
{
if (hdl == LWE_INVALID_SOCKET)
{
LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if (payload.Size() > LWE_IPV4_UDP_PAYLOAD)
{
LWE_LOG_INT("Info", 1, "Attempted to send a packet with the size, \"" + Str_8::FromNum(payload.Size())
+ "\", that exceeds the max payload of, \"" + Str_8::FromNum(LWE_IPV4_UDP_PAYLOAD) + "\".");
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)
{
LWE_LOG_INT("Error", 2, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
#if defined(LWE_OS_WINDOWS)
Int_32 dCode = WSAGetLastError();
#elif defined(LWE_OS_LINUX)
Int_32 dCode = errno;
#else
Int_32 dCode = 0;
#endif
LWE_LOG_INT("Error", 2, "Failed to convert address with error #" + Str_8::FromNum(dCode) + ".");
return 0;
}
SInt_64 sent = sendto(hdl, (char*)&payload[0], (int)payload.Size(), 0, (sockaddr*)&result, sizeof(sockaddr_in));
#if defined(LWE_OS_WINDOWS)
if (sent == SOCKET_ERROR)
#elif defined(LWE_OS_LINUX)
if (sent == -1)
#endif
{
#if defined(LWE_OS_WINDOWS)
Int_32 dCode = WSAGetLastError();
if (dCode != WSAEWOULDBLOCK)
{
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
}
#elif defined(LWE_OS_LINUX)
Int_32 dCode = errno;
if (dCode != EWOULDBLOCK)
{
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
((Comms*)GetParent())->UnInitialize();
}
#else
Int_32 dCode = 0;
#endif
return 0;
}
return (UInt_16)sent;
}
}

100
src/IO/Socket/Fragments.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "../../../include/IO/Socket/Fragments.h"
namespace lwe
{
Fragments::~Fragments()
{
delete[] data;
}
Fragments::Fragments()
: header{}, data(nullptr), size(0)
{
}
Fragments::Fragments(const Header& header, const Serializer<>& payload)
: header(header), data(new Serializer<>[header.fragments]), size(header.fragments)
{
this->header.fragment = 0;
data[header.fragment] = payload;
}
Fragments::Fragments(const Header& header, const UInt_64 size)
: header(header), data(new Serializer<>[size]), size(size)
{
this->header.fragments = size;
this->header.fragment = 0;
}
Fragments::Fragments(const Fragments& frags)
: header(frags.header), data(new Serializer<>[frags.size]), size(frags.size)
{
for (UInt_64 i = 0; i < size; ++i)
data[i] = frags.data[i];
}
Fragments& Fragments::operator=(const Fragments& frags)
{
if (this == &frags)
return *this;
header = frags.header;
delete[] data;
data = new Serializer<>[frags.size];
for (UInt_64 i = 0; i < frags.size; ++i)
data[i] = frags.data[i];
size = frags.size;
return *this;
}
Fragments::operator const Serializer<>* () const
{
return data;
}
Fragments::operator Serializer<>* ()
{
return data;
}
Header Fragments::GetHeader() const
{
return header;
}
UInt_64 Fragments::Size() const
{
return size;
}
bool Fragments::IsComplete() const
{
for (UInt_64 i = 0; i < size; ++i)
if (!data[i].Size())
return false;
return true;
}
Packet Fragments::Combine() const
{
UInt_64 rSize = 0;
for (UInt_64 i = 0; i < size; ++i)
rSize += data[i].Size();
Packet result =
{
header,
{Endianness::LE, rSize}
};
result.header.fragments = 0;
for (UInt_64 i = 0; i < size; ++i)
result.payload.WriteSer(data[i]);
result.payload.SetOffset(0);
return result;
}
}

View File

@@ -0,0 +1,47 @@
#include "../../../include/IO/Socket/Operation.h"
#include "../../../include/IO/Socket/CommsSystem.h"
#include "../../../include/IO/Socket/Comms.h"
#include "../../../include/IO/Socket/Endpoint.h"
namespace lwe
{
Operation::Operation()
: hashId(0)
{
}
Operation::Operation(const Str_8& id)
: id(id), hashId(id.Hash_64())
{
}
Operation::Operation(const Operation& cmd)
: id(cmd.id), hashId(cmd.hashId)
{
}
Operation& Operation::operator=(const Operation& cmd)
{
if (this == &cmd)
return *this;
id = cmd.id;
hashId = cmd.hashId;
return *this;
}
void Operation::Process(Comms* comms, Endpoint* endpoint, CommsSystem* sys, Serializer<>& payload)
{
}
Str_8 Operation::GetId() const
{
return id;
}
UInt_64 Operation::GetHashId() const
{
return hashId;
}
}

337
src/IO/Socket/Request.cpp Normal file
View File

@@ -0,0 +1,337 @@
#include "../../../include/IO/Socket/Request.h"
#include "../../../include/Base64.h"
namespace lwe
{
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 "../../../include/IO/Socket/Response.h"
namespace lwe
{
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]);
}
}
}

View File

@@ -0,0 +1,653 @@
#include "../../../../include/IO/Socket/RestAPIs/Spotify.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/System/System.h"
#include "../../../../include/URI.h"
namespace lwe
{
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)
{
LWE_LOG_INT("Error", 0, "Could not authorize with Spotify because the client id was invalid.");
return false;
}
else if (authRes.GetCode() == 403)
{
LWE_LOG_INT("Error", 1, "Could not authorize with Spotify because the secret was invalid.");
return false;
}
else if (authRes.GetCode() != 200)
{
LWE_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)
{
LWE_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 "../../../../include/IO/Socket/RestAPIs/Twitch.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/System/System.h"
#include "../../../../include/URI.h"
namespace lwe
{
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();
LWE_LOG_INT("Error", 0, "Could not authorize with Twitch because the client id was invalid.");
return false;
} else if (authRes.GetCode() == 403)
{
client.Release();
LWE_LOG_INT("Error", 1, "Could not authorize with Twitch because the secret was invalid.");
return false;
} else if (authRes.GetCode() != 200)
{
client.Release();
LWE_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 "../../../../include/IO/Socket/RestAPIs/TwitchChat.h"
#include "../../../../include/IO/Socket/DNS.h"
#include "../../../../include/IO/Console.h"
namespace lwe
{
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(lwe::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;
}
}

236
src/IO/Socket/SSL.cpp Normal file
View File

@@ -0,0 +1,236 @@
#include "../../../include/IO/Socket/SSL.h"
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
namespace lwe
{
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)
{
LWE_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);
LWE_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);
LWE_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)
{
LWE_LOG_INT("Error", 0, "Invalid certificate.");
return;
}
if (SSL_CTX_use_certificate(ctx, cert) != 1)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "Invalid private key.");
return;
}
if (SSL_CTX_use_PrivateKey(ctx, key) != 1)
{
LWE_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 "../../../include/IO/Socket/TCP_BSD.h"
#include "../../../include/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 lwe
{
TCP::~TCP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
if (connection)
{
if (shutdown(hdl, SHUT_RDWR) == -1)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
TCP::TCP()
: hdl(LWE_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = LWE_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(LWE_INVALID_SOCKET)
{
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(std::move(tcp));
hdl = tcp.hdl;
tcp.hdl = LWE_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = LWE_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 == LWE_INVALID_SOCKET)
{
UInt_32 code = errno;
LWE_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)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(errno) + ".");
}
if (close(hdl) == -1)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
connection = false;
bound = false;
listening = false;
connected = false;
hdl = LWE_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)
{
LWE_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 == LWE_INVALID_SOCKET)
{
if (errno != EWOULDBLOCK)
LWE_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))
{
LWE_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))
{
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_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();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_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();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err != EWOULDBLOCK)
{
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
int flags = fcntl(hdl, F_GETFL, 0);
if (flags == -1)
{
LWE_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)
LWE_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)
{
LWE_LOG_INT("Error", 0, "Failed to retrieve flags.");
return true;
}
return !(flags & O_NONBLOCK);
}
bool TCP::IsValid() const
{
return hdl != LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_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 "../../../include/IO/Socket/TCP_W32.h"
#include "../../../include/IO/Socket/DNS.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace lwe
{
TCP::~TCP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code;
if (connection)
{
code = shutdown(hdl, SD_SEND);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (!connection && WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 2, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
TCP::TCP()
: hdl(LWE_INVALID_SOCKET)
{
}
TCP::TCP(const AddrType addrType)
: BaseTCP(addrType), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP::TCP(TCP&& tcp) noexcept
: BaseTCP(std::move(tcp)), hdl(tcp.hdl)
{
tcp.hdl = LWE_INVALID_SOCKET;
}
TCP::TCP(const TCP& tcp)
: BaseTCP(tcp), hdl(LWE_INVALID_SOCKET)
{
TCP::Initialize();
}
TCP& TCP::operator=(TCP&& tcp) noexcept
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = tcp.hdl;
tcp.hdl = LWE_INVALID_SOCKET;
return *this;
}
TCP& TCP::operator=(const TCP& tcp)
{
if (this == &tcp)
return *this;
BaseTCP::operator=(tcp);
hdl = LWE_INVALID_SOCKET;
TCP::Initialize();
return *this;
}
void TCP::Initialize()
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
LWE_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 == LWE_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_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)
LWE_LOG_INT("Error", 0, "Failed to shutdown socket with error #" + Str_8::FromNum(GetLastError()) + ".");
}
code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = LWE_INVALID_SOCKET;
if (!connection && WSACleanup() == SOCKET_ERROR)
LWE_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)
{
LWE_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 == LWE_INVALID_SOCKET)
{
Int_32 code = WSAGetLastError();
if (code != WSAEWOULDBLOCK)
LWE_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();
LWE_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();
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to send while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_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();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized.");
return 0;
}
if ((!connection && !connected))
{
LWE_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();
LWE_LOG_INT("Information", 0, "Connection dropped.");
}
else if (err == WSAECONNABORTED)
{
LWE_LOG_INT("Information", 1, "Receiving timed-out.");
}
else if (err != WSAEWOULDBLOCK)
{
LWE_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())
{
LWE_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)
LWE_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)
LWE_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool TCP::IsValid() const
{
return hdl != LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_LOG_INT("Information", 2, "Connection attempt timed-out.");
}
else
{
LWE_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 "../../../include/IO/Socket/UDP_BSD.h"
#include "../../../include/Log.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <cerrno>
namespace lwe
{
UDP::~UDP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code = close(hdl);
if (code == -1)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
}
UDP::UDP()
: hdl(LWE_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(LWE_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 == LWE_INVALID_SOCKET)
{
UInt_32 code = errno;
LWE_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 = LWE_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(LWE_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = LWE_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = LWE_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = close(hdl);
if (code == -1)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + ".");
hdl = LWE_INVALID_SOCKET;
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())
{
LWE_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 = 0;
received = recvfrom(hdl, data, size, 0, (sockaddr*)&remote, &addrLen);
if (received == -1)
{
int code = errno;
if (code != ECONNRESET && code != EWOULDBLOCK)
{
Release();
LWE_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;
LWE_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 = errno;
LWE_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())
{
LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized.");
return;
}
if (fcntl(hdl, F_SETFL, O_NONBLOCK, blocking) == -1)
LWE_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 != LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_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)
{
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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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)
{
LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + ".");
return;
}
}
UInt_64 UDP::Send_v6(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size)
{
if (!IsValid())
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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 == -1)
{
Int_32 dCode = errno;
LWE_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())
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = errno;
LWE_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 == -1)
{
Int_32 dCode = errno;
LWE_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 "../../../include/IO/Socket/UDP_W32.h"
#include "../../../include/Log.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
namespace lwe
{
UDP::~UDP()
{
if (hdl == LWE_INVALID_SOCKET)
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_LOG_INT("Error", 1, "Failed to shutdown WSA with error #" + Str_8::FromNum(WSAGetLastError()) + ".");
}
UDP::UDP()
: hdl(LWE_INVALID_SOCKET)
{
}
UDP::UDP(const AddrType addrType)
: BaseUDP(addrType), hdl(LWE_INVALID_SOCKET)
{
WSADATA data = {};
int code = WSAStartup(MAKEWORD(2, 2), &data);
if (code)
{
LWE_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 == LWE_INVALID_SOCKET)
{
UInt_32 code = WSAGetLastError();
LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + ".");
if (WSACleanup() == SOCKET_ERROR)
LWE_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 = LWE_INVALID_SOCKET;
}
UDP::UDP(const UDP& udp)
: BaseUDP(udp), hdl(LWE_INVALID_SOCKET)
{
}
UDP& UDP::operator=(UDP&& udp) noexcept
{
if (this == &udp)
return *this;
BaseUDP::operator=(std::move(udp));
hdl = udp.hdl;
udp.hdl = LWE_INVALID_SOCKET;
return *this;
}
UDP& UDP::operator=(const UDP& udp)
{
if (this == &udp)
return *this;
BaseUDP::operator=(udp);
hdl = LWE_INVALID_SOCKET;
return *this;
}
void UDP::Release()
{
if (!IsValid())
return;
Int_32 code = closesocket(hdl);
if (code == SOCKET_ERROR)
LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(GetLastError()) + ".");
hdl = LWE_INVALID_SOCKET;
if (WSACleanup() == SOCKET_ERROR)
LWE_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())
{
LWE_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();
LWE_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();
LWE_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();
LWE_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())
{
LWE_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)
LWE_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)
LWE_LOG_INT("Error", 0, "Failed to retrieve socket info.");
return (bool)r;
}
bool UDP::IsValid() const
{
return hdl != LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_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)
{
LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid.");
return;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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)
{
LWE_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())
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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();
LWE_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())
{
LWE_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)
{
LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid.");
return 0;
}
else if (code == -1)
{
Int_32 dCode = WSAGetLastError();
LWE_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();
LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + ".");
Release();
return 0;
}
return sent;
}
}

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

@@ -0,0 +1,720 @@
#include "../../include/IO/Window_W32.h"
#include "../../include/IO/HID/Keyboard.h"
#include "../../include/IO/HID/Mouse.h"
#include "../../include/System/Thread.h"
#include <hidusage.h>
namespace lwe
{
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)
{
LWE_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)
{
LWE_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)
{
LWE_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))
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
{
LWE_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))
LWE_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)
{
LWE_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)
{
LWE_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)))
LWE_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)
{
LWE_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)
{
LWE_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))
LWE_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)
{
LWE_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)
{
LWE_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)))
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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))
LWE_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))
{
LWE_LOG_INT("Error", 0, "Failed to retrieve client scale with error #" + Str_8::FromNum(GetLastError()) + ".");
return;
}
POINT pos = {};
if (!ClientToScreen(GetHdl(), &pos))
{
LWE_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))
{
LWE_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))
{
LWE_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 "../../include/IO/Window_Way.h"
namespace lwe
{
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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
}
}

656
src/IO/Window_XCB.cpp Normal file
View File

@@ -0,0 +1,656 @@
#include "../../include/IO/Window_XCB.h"
#include "../../include/UTF.h"
#include "../../include/IO/HID/Keyboard.h"
#include "../../include/IO/HID/Mouse.h"
#include "../../include/IO/Console.h"
#include <cstdlib>
#include <xcb/xfixes.h>
#include <xcb/xcb_cursor.h>
namespace lwe
{
Window::Window()
: server(nullptr), screen(nullptr), hdl(0), events{XCB_ATOM_NONE, XCB_ATOM_NONE}, extOpCode(0)
{
}
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))
{
LWE_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);
LWE_LOG_INT("Warning", 1, "Failed to query for XCB XInput extension.");
return;
}
if (!extension->present)
{
xcb_disconnect(server);
LWE_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);
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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)
{
LWE_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;
}
}

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,
};