diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6e0469..e936aea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(database) add_subdirectory(network) add_subdirectory(geometry) add_subdirectory(audio) +add_subdirectory(fonts) add_subdirectory(image) add_subdirectory(console) add_subdirectory(client) diff --git a/src/audio/AudioWriter.cpp b/src/audio/AudioWriter.cpp index 5c29258..da8d46c 100644 --- a/src/audio/AudioWriter.cpp +++ b/src/audio/AudioWriter.cpp @@ -1,7 +1,7 @@ #include "AudioWriter.h" #include "File.h" -#include "BinaryFile.h" +#include "BinaryStream.h" #include "AudioSample.h" AudioWriter::AudioWriter() @@ -36,22 +36,22 @@ void AudioWriter::Write(const AudioSamplePtr& sample) const auto num_samples = data.size(); unsigned content_size = 36 + bytes_per_sample* num_samples*num_channels; - BinaryFile::Write(handle, content_size); + BinaryStream::write(handle, content_size); handle->write("WAVE", 4); /* write fmt subchunk */ handle->write("fmt ", 4); - BinaryFile::Write(handle, 16); // SubChunk1Size - BinaryFile::Write(handle, 1); // PCM Format - BinaryFile::Write(handle, num_channels); - BinaryFile::Write(handle, sample_rate); - BinaryFile::Write(handle, byte_rate); - BinaryFile::Write(handle, num_channels*bytes_per_sample); // block align - BinaryFile::Write(handle, 8*bytes_per_sample); // bits/sample + BinaryStream::write(handle, 16); // SubChunk1Size + BinaryStream::write(handle, 1); // PCM Format + BinaryStream::write(handle, num_channels); + BinaryStream::write(handle, sample_rate); + BinaryStream::write(handle, byte_rate); + BinaryStream::write(handle, num_channels*bytes_per_sample); // block align + BinaryStream::write(handle, 8*bytes_per_sample); // bits/sample /* write data subchunk */ handle->write("data", 4); - BinaryFile::Write(handle, bytes_per_sample* num_samples*num_channels); // bits/sample + BinaryStream::write(handle, bytes_per_sample* num_samples*num_channels); // bits/sample handle->write(reinterpret_cast(&data[0]), data.size()*sizeof(short)); outfile.Close(); diff --git a/src/audio/midi/reader/MidiChannelEventAdapter.cpp b/src/audio/midi/reader/MidiChannelEventAdapter.cpp index 1c176fe..f06d540 100644 --- a/src/audio/midi/reader/MidiChannelEventAdapter.cpp +++ b/src/audio/midi/reader/MidiChannelEventAdapter.cpp @@ -1,6 +1,6 @@ #include "MidiChannelEventAdapter.h" -#include "BinaryFile.h" +#include "BinaryStream.h" #include "ByteUtils.h" #include @@ -15,7 +15,7 @@ int MidiChannelEventAdapter::ReadEvent(std::ifstream* file, char firstByte, Midi unsigned byteCount = 0; std::cout << "Channel: " << midi_channel << std::endl; - const bool isStatusByte = ByteUtils::MSBIsOne(firstByte); + const bool isStatusByte = ByteUtils::MostSignificantBitIsOne(firstByte); if(isStatusByte) { event->SetTypeAndChannel(firstByte); @@ -44,8 +44,7 @@ int MidiChannelEventAdapter::ReadEvent(std::ifstream* file, char firstByte, Midi } case MidiChannelEvent::Type::PROGRAM: { - int value0 = 0; - BinaryFile::GetNextByteAsInt(file, value0); + int value0 = *BinaryStream::getNextByteAsInt(file); byteCount ++; break; } @@ -59,19 +58,15 @@ int MidiChannelEventAdapter::ReadEvent(std::ifstream* file, char firstByte, Midi int MidiChannelEventAdapter::ReadEventData(std::ifstream* file, MidiChannelEvent* event, char c) { int value0 = int(c); - int value1 = 0; - BinaryFile::GetNextByteAsInt(file, value1); + int value1 = *BinaryStream::getNextByteAsInt(file); event->SetValues(value0, value1); return 1; } int MidiChannelEventAdapter::ReadEventData(std::ifstream* file, MidiChannelEvent* event) { - int value0 = 0; - BinaryFile::GetNextByteAsInt(file, value0); - - int value1 = 0; - BinaryFile::GetNextByteAsInt(file, value1); + int value0 = *BinaryStream::getNextByteAsInt(file); + int value1 = *BinaryStream::getNextByteAsInt(file); event->SetValues(value0, value1); return 2; } diff --git a/src/audio/midi/reader/MidiMetaEventAdapter.cpp b/src/audio/midi/reader/MidiMetaEventAdapter.cpp index 7437c47..18f1b1f 100644 --- a/src/audio/midi/reader/MidiMetaEventAdapter.cpp +++ b/src/audio/midi/reader/MidiMetaEventAdapter.cpp @@ -1,6 +1,6 @@ #include "MidiMetaEventAdapter.h" -#include "BinaryFile.h" +#include "BinaryStream.h" #include "ByteUtils.h" #include @@ -35,8 +35,7 @@ int MidiMetaEventAdapter::ReadEvent(std::ifstream* file, MetaMidiEvent* event, i break; case MetaMidiEvent::Type::END_TRACK: { - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); byteCount ++; break; } @@ -66,8 +65,7 @@ int MidiMetaEventAdapter::ReadEvent(std::ifstream* file, MetaMidiEvent* event, i int MidiMetaEventAdapter::ReadUnknownEvent(std::ifstream* file) { - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); char c; for(unsigned idx=0; idxSetLabel(name); return byteCount; @@ -102,15 +99,15 @@ int MidiMetaEventAdapter::ReadIntEvent(std::ifstream* file, MetaMidiEvent* event } else { - BinaryFile::GetNextByteAsInt(file, length); + length = *BinaryStream::getNextByteAsInt(file); byteCount ++; } std::string buffer; - BinaryFile::GetNextNBytes(file, buffer.data(), length); + BinaryStream::getNextNBytes(file, buffer.data(), length); byteCount += length; - const int value = ByteUtils::ToInt(buffer.data(), length); + const int value = ByteUtils::ToType(buffer.data(), length); event->SetValue(value); return byteCount; } @@ -118,15 +115,14 @@ int MidiMetaEventAdapter::ReadIntEvent(std::ifstream* file, MetaMidiEvent* event int MidiMetaEventAdapter::ReadChannelPrefixEvent(std::ifstream* file, MetaMidiEvent* event, int& lastMidiChannel) { unsigned byteCount = 0; - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); byteCount ++; std::string buffer; - BinaryFile::GetNextNBytes(file, buffer.data(), length); + BinaryStream::getNextNBytes(file, buffer.data(), length); byteCount += length; - const int value = ByteUtils::ToInt(buffer.data(), length); + const int value = ByteUtils::ToType(buffer.data(), length); event->SetValue(value); lastMidiChannel = value; return byteCount; @@ -135,15 +131,14 @@ int MidiMetaEventAdapter::ReadChannelPrefixEvent(std::ifstream* file, MetaMidiEv int MidiMetaEventAdapter::ReadTimeSignatureEvent(std::ifstream* file, MetaMidiEvent* event) { unsigned byteCount = 0; - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); byteCount++; MidiTimeSignature timeSig; - BinaryFile::GetNextByteAsInt(file, timeSig.mNumer); - BinaryFile::GetNextByteAsInt(file, timeSig.mDenom); - BinaryFile::GetNextByteAsInt(file, timeSig.mMetro); - BinaryFile::GetNextByteAsInt(file, timeSig.mF32); + timeSig.mNumer = *BinaryStream::getNextByteAsInt(file); + timeSig.mDenom = *BinaryStream::getNextByteAsInt(file); + timeSig.mMetro = *BinaryStream::getNextByteAsInt(file); + timeSig.mF32 = *BinaryStream::getNextByteAsInt(file); byteCount +=4; if (length > 4) @@ -161,13 +156,12 @@ int MidiMetaEventAdapter::ReadTimeSignatureEvent(std::ifstream* file, MetaMidiEv int MidiMetaEventAdapter::ReadKeySignatureEvent(std::ifstream* file, MetaMidiEvent* event) { unsigned byteCount = 0; - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); byteCount++; MidiKeySignature keySig; - BinaryFile::GetNextByteAsInt(file, keySig.mSharpsFlats); - BinaryFile::GetNextByteAsInt(file, keySig.mMinor); + keySig.mSharpsFlats = *BinaryStream::getNextByteAsInt(file); + keySig.mMinor = *BinaryStream::getNextByteAsInt(file); byteCount +=2; return byteCount; } @@ -175,16 +169,15 @@ int MidiMetaEventAdapter::ReadKeySignatureEvent(std::ifstream* file, MetaMidiEve int MidiMetaEventAdapter::ReadTimeCodeEvent(std::ifstream* file, MetaMidiEvent* event) { unsigned byteCount = 0; - int length = 0; - BinaryFile::GetNextByteAsInt(file, length); + int length = *BinaryStream::getNextByteAsInt(file); byteCount++; MidiSmtpeTimecode timeCode; - BinaryFile::GetNextByteAsInt(file, timeCode.mHr); - BinaryFile::GetNextByteAsInt(file, timeCode.mMin); - BinaryFile::GetNextByteAsInt(file, timeCode.mSec); - BinaryFile::GetNextByteAsInt(file, timeCode.mFrame); - BinaryFile::GetNextByteAsInt(file, timeCode.mFrameFrac); + timeCode.mHr = *BinaryStream::getNextByteAsInt(file); + timeCode.mMin = *BinaryStream::getNextByteAsInt(file); + timeCode.mSec = *BinaryStream::getNextByteAsInt(file); + timeCode.mFrame = *BinaryStream::getNextByteAsInt(file); + timeCode.mFrameFrac = *BinaryStream::getNextByteAsInt(file); byteCount +=5; return byteCount; } diff --git a/src/audio/midi/reader/MidiReader.cpp b/src/audio/midi/reader/MidiReader.cpp index 124eb19..f6e8160 100644 --- a/src/audio/midi/reader/MidiReader.cpp +++ b/src/audio/midi/reader/MidiReader.cpp @@ -3,7 +3,7 @@ #include "MidiDocument.h" #include "ByteUtils.h" #include "MidiTrack.h" -#include "BinaryFile.h" +#include "BinaryStream.h" #include "FileLogger.h" #include "MidiElements.h" #include "MidiTimeAdapter.h" @@ -29,30 +29,30 @@ MidiDocument* MidiReader::GetDocument() const bool MidiReader::ProcessHeader() { - if(!BinaryFile::CheckNextDWord(mFile->GetInHandle(), HeaderLabel)) + if(!BinaryStream::checkNextDWord(mFile->GetInHandle(), HeaderLabel)) { return false; } - int length = 0; - if(!BinaryFile::GetNextDWord(mFile->GetInHandle(), length)) + const auto length = BinaryStream::getNextDWord(mFile->GetInHandle()); + if(!length) { return false; } - int formatType { 0 }; - if(!BinaryFile::GetNextWord(mFile->GetInHandle(), formatType)) + const auto formatType = BinaryStream::getNextWord(mFile->GetInHandle()); + if(!formatType) { return false; } - mDocument->SetFormatType(formatType); + mDocument->SetFormatType(*formatType); - int expectedTracks { 0 }; - if(!BinaryFile::GetNextWord(mFile->GetInHandle(), expectedTracks)) + const auto expectedTracks = BinaryStream::getNextWord(mFile->GetInHandle()); + if(!expectedTracks) { return false; } - mDocument->SetExpectedTracks(expectedTracks); + mDocument->SetExpectedTracks(*expectedTracks); MidiTimeDivision timeDivision; MidiTimeAdapter::ReadTimeDivision(mFile->GetInHandle(), timeDivision); @@ -95,13 +95,13 @@ int MidiReader::ProcessEvent(MidiTrack* track) bool MidiReader::ProcessTrackChunk(bool debug) { - if(!BinaryFile::CheckNextDWord(mFile->GetInHandle(), TrackChunkLabel)) + if(!BinaryStream::checkNextDWord(mFile->GetInHandle(), TrackChunkLabel)) { return false; } - int chunkSize = 0; - if(!BinaryFile::GetNextDWord(mFile->GetInHandle(), chunkSize)) + const auto chunkSize = BinaryStream::getNextDWord(mFile->GetInHandle()); + if(!chunkSize) { return false; } @@ -109,11 +109,11 @@ bool MidiReader::ProcessTrackChunk(bool debug) unsigned byteCount = 0; auto track = std::make_unique(); unsigned iter_count = 0; - while(byteCount < unsigned(chunkSize)) + while(byteCount < static_cast(*chunkSize)) { std::cout << "-------------" << std::endl; byteCount += ProcessEvent(track.get()); - std::cout << "Track byte count: " << byteCount << " of " << chunkSize << std::endl; + std::cout << "Track byte count: " << byteCount << " of " << *chunkSize << std::endl; if(debug && iter_count == 40) { return true; diff --git a/src/audio/midi/reader/MidiTimeAdapter.cpp b/src/audio/midi/reader/MidiTimeAdapter.cpp index e4bee2f..3ce2978 100644 --- a/src/audio/midi/reader/MidiTimeAdapter.cpp +++ b/src/audio/midi/reader/MidiTimeAdapter.cpp @@ -1,6 +1,6 @@ #include "MidiTimeAdapter.h" -#include "BinaryFile.h" +#include "BinaryStream.h" #include "ByteUtils.h" #include @@ -13,7 +13,7 @@ int MidiTimeAdapter::ReadEventTimeDelta(std::ifstream* file, int& delta) file->get(c); byteCount++; - if(!ByteUtils::MSBIsOne(c)) + if(!ByteUtils::MostSignificantBitIsOne(c)) { delta = int(c); std::cout << "Time delta final: " << delta << std::endl; @@ -48,19 +48,19 @@ int MidiTimeAdapter::ReadEventTimeDelta(std::ifstream* file, int& delta) int MidiTimeAdapter::ReadTimeDivision(std::ifstream* file, MidiTimeDivision& division) { - int time_division; - if(!BinaryFile::GetNextWord(file, time_division, false)) + const auto time_division = BinaryStream::getNextWord(file, false); + if(!time_division) { return -1; } - division.mUseFps = ByteUtils::GetWordFirstBit(time_division); + division.mUseFps = ByteUtils::GetWordFirstBit(*time_division); if (division.mUseFps) { const int TOP_7_BITS = 0x7F00; // 0111 1111 - 0000 0000 - division.mFps = ((~time_division & TOP_7_BITS) >> 8) - 1; // Reverse 2complement of next 7 bits + division.mFps = ((~(*time_division) & TOP_7_BITS) >> 8) - 1; // Reverse 2complement of next 7 bits } - division.mTicks = ByteUtils::GetWordLastByte(time_division); + division.mTicks = ByteUtils::GetWordLastByte(*time_division); return 2; // Bytes advanced } diff --git a/src/client/GuiApplication.cpp b/src/client/GuiApplication.cpp index 39cc9d6..34d7f55 100644 --- a/src/client/GuiApplication.cpp +++ b/src/client/GuiApplication.cpp @@ -84,7 +84,7 @@ void GuiApplication::Run() #ifdef __linux__ mDesktopManager->SetKeyboard(XcbKeyboard::Create()); - bool useOpenGl = true; + bool useOpenGl = false; XcbInterface window_interface; window_interface.SetUseOpenGl(useOpenGl); window_interface.Initialize(mDesktopManager.get()); diff --git a/src/core/ByteUtils.h b/src/core/ByteUtils.h index 6de6a22..7780b7a 100644 --- a/src/core/ByteUtils.h +++ b/src/core/ByteUtils.h @@ -1,24 +1,26 @@ #pragma once + #include -#include +#include class ByteUtils { public: - using Word = int; - using DWord = int; + using Word = int16_t; + using DWord = int32_t; + using QWord = int64_t; - static bool MSBIsOne(char c) + static bool MostSignificantBitIsOne(char c) { return c & (1 << 7); } - static int GetWordFirstBit(const Word word) + static Word GetWordFirstBit(const Word word) { return word & ByteUtils::WORD_FIRST_BIT; }; - static int GetWordLastByte(const Word word) + static Word GetWordLastByte(const Word word) { return word & ByteUtils::WORD_LAST_BYTE; } @@ -38,30 +40,36 @@ public: } } - static int ToInt(char* buffer, const unsigned size, bool reverse = true) + template + static T ToType(char* buffer, bool reverse = true) { - int result {0}; + T result {0}; if(reverse) { - char reversed[sizeof(int)]; - ReverseBuffer(buffer, reversed, size, sizeof(int)); - std::memcpy(&result, reversed, sizeof(int)); + char reversed[sizeof(T)]; + ReverseBuffer(buffer, reversed, sizeof(T), sizeof(T)); + std::memcpy(&result, reversed, sizeof(T)); } else { - std::memcpy(&result, buffer, sizeof(int)); + std::memcpy(&result, buffer, sizeof(T)); } return result; } static Word ToWord(char* buffer, bool reverse = true) { - return ToInt(buffer, BYTES_PER_WORD, reverse); + return ToType(buffer, reverse); } static DWord ToDWord(char* buffer, bool reverse = true) { - return ToInt(buffer, BYTES_PER_DWORD, reverse); + return ToType(buffer, reverse); + } + + static QWord ToQWord(char* buffer, bool reverse = true) + { + return ToType(buffer, reverse); } static bool Compare(char* buffer, const char* tag, unsigned size) @@ -78,17 +86,15 @@ public: static bool CompareDWords(char* buffer, const char* tag) { - return Compare(buffer, tag, BYTES_PER_DWORD); + return Compare(buffer, tag, sizeof(DWord)); } static bool CompareWords(char* buffer, const char* tag) { - return Compare(buffer, tag, BYTES_PER_WORD); + return Compare(buffer, tag, sizeof(Word)); } - static const int BYTES_PER_WORD = 2; - static const int BYTES_PER_DWORD = 4; static const int BYTE_FIRST_BIT = 0x40; // 1000 0000 - static const int WORD_FIRST_BIT = 0x8000; // 1000 0000 - 0000 0000 - static const int WORD_LAST_BYTE = 0x00FF; // 0000 0000 - 1111 1111 + static const Word WORD_FIRST_BIT = 0x8000; // 1000 0000 - 0000 0000 + static const Word WORD_LAST_BYTE = 0x00FF; // 0000 0000 - 1111 1111 }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 398f9a3..130e9de 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -5,7 +5,6 @@ list(APPEND core_HEADERS Color.h CommandLineArgs.h loggers/FileLogger.h - file_utilities/BinaryFile.h file_utilities/File.h file_utilities/FileFormats.h StringUtils.h @@ -17,12 +16,12 @@ list(APPEND core_LIB_INCLUDES Color.cpp CommandLineArgs.cpp loggers/FileLogger.cpp - file_utilities/BinaryFile.cpp file_utilities/File.cpp file_utilities/FileFormats.cpp memory/SharedMemory.cpp RandomUtils.cpp StringUtils.cpp + streams/BinaryStream.cpp http/HttpResponse.cpp http/HttpHeader.cpp http/HttpRequest.cpp) @@ -35,6 +34,7 @@ target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/file_utilities" "${CMAKE_CURRENT_SOURCE_DIR}/loggers" "${CMAKE_CURRENT_SOURCE_DIR}/memory" + "${CMAKE_CURRENT_SOURCE_DIR}/streams" ) set_target_properties( core PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) set_property(TARGET core PROPERTY FOLDER src) \ No newline at end of file diff --git a/src/core/file_utilities/BinaryFile.cpp b/src/core/file_utilities/BinaryFile.cpp deleted file mode 100644 index 819eee6..0000000 --- a/src/core/file_utilities/BinaryFile.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "BinaryFile.h" -#include "ByteUtils.h" - -bool BinaryFile::GetNextByteAsInt(std::ifstream* file, int& target) -{ - char c; - file->get(c); - target = int(c); - return true; -} - -bool BinaryFile::GetNextNBytes(std::ifstream* file, char* buffer, unsigned number) -{ - char c; - for(unsigned idx=0; idxget(c)) - { - buffer[idx] = c; - } - else - { - return false; - } - } - return true; -} - -bool BinaryFile::GetNextWord(std::ifstream* file, char* buffer) -{ - return GetNextNBytes(file, buffer, ByteUtils::BYTES_PER_WORD); -} - -bool BinaryFile::GetNextDWord(std::ifstream* file, char* buffer) -{ - return GetNextNBytes(file, buffer, ByteUtils::BYTES_PER_DWORD); -} - -bool BinaryFile::GetNextWord(std::ifstream* file, int& target, bool reverse) -{ - char buffer[ByteUtils::BYTES_PER_WORD]; - if(!BinaryFile::GetNextWord(file, buffer)) - { - return false; - } - target = ByteUtils::ToWord(buffer, reverse); - return true; -} - -bool BinaryFile::GetNextDWord(std::ifstream* file, int& target) -{ - char buffer[ByteUtils::BYTES_PER_DWORD]; - if(!BinaryFile::GetNextDWord(file, buffer)) - { - return false; - } - target = ByteUtils::ToDWord(buffer); - return true; -} - -bool BinaryFile::CheckNextDWord(std::ifstream* file, const char* target) -{ - char buffer[ByteUtils::BYTES_PER_DWORD]; - if(!BinaryFile::GetNextDWord(file, buffer)) - { - return false; - } - - if(!ByteUtils::CompareDWords(buffer, target)) - { - return false; - } - return true; -} - -bool BinaryFile::GetNextString(std::ifstream* file, std::string& target, unsigned numBytes) -{ - char c; - for(unsigned idx=0; idxget(c)) - { - return false; - } - target += c; - } - return true; -} diff --git a/src/core/file_utilities/BinaryFile.h b/src/core/file_utilities/BinaryFile.h deleted file mode 100644 index 50ac0f2..0000000 --- a/src/core/file_utilities/BinaryFile.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -class BinaryFile -{ -public: - - template - static bool Write(std::ofstream* file, T data) - { - file->write(reinterpret_cast(&data), sizeof(data)); - return true; - } - - static bool GetNextByteAsInt(std::ifstream* file, int& target); - - static bool GetNextNBytes(std::ifstream* file, char* buffer, unsigned numBytes); - - static bool GetNextWord(std::ifstream* file, char* buffer); - - static bool GetNextDWord(std::ifstream* file, char* buffer); - - static bool GetNextWord(std::ifstream* file, int& target, bool reverse = true); - - static bool GetNextDWord(std::ifstream* file, int& target); - - static bool CheckNextDWord(std::ifstream* file, const char* target); - - static bool GetNextString(std::ifstream* file, std::string& target, unsigned numBytes); -}; diff --git a/src/core/streams/BinaryStream.cpp b/src/core/streams/BinaryStream.cpp new file mode 100644 index 0000000..aee7ac2 --- /dev/null +++ b/src/core/streams/BinaryStream.cpp @@ -0,0 +1,97 @@ +#include "BinaryStream.h" + +std::optional BinaryStream::getNextByteAsInt(std::basic_istream* stream) +{ + return stream->get(); +} + +bool BinaryStream::getNextNBytes(std::basic_istream* stream, char* buffer, unsigned number) +{ + char c; + for(unsigned idx=0; idxget(c)) + { + buffer[idx] = c; + } + else + { + return false; + } + } + return true; +} + +bool BinaryStream::getNextWord(std::basic_istream* stream, char* buffer) +{ + return getNextNBytes(stream, buffer, sizeof(ByteUtils::Word)); +} + +bool BinaryStream::getNextDWord(std::basic_istream* stream, char* buffer) +{ + return getNextNBytes(stream, buffer, sizeof(ByteUtils::DWord)); +} + +bool BinaryStream::getNextQWord(std::basic_istream* stream, char* buffer) +{ + return getNextNBytes(stream, buffer, sizeof(ByteUtils::QWord)); +} + +std::optional BinaryStream::getNextWord(std::basic_istream* stream, bool reverse) +{ + char buffer[sizeof(ByteUtils::Word)]; + if(!BinaryStream::getNextWord(stream, buffer)) + { + return false; + } + return ByteUtils::ToWord(buffer, reverse); +} + +std::optional BinaryStream::getNextDWord(std::basic_istream* stream) +{ + char buffer[sizeof(ByteUtils::DWord)]; + if(!BinaryStream::getNextDWord(stream, buffer)) + { + return false; + } + return ByteUtils::ToDWord(buffer);; +} + +std::optional BinaryStream::getNextQWord(std::basic_istream* stream) +{ + char buffer[sizeof(ByteUtils::QWord)]; + if(!BinaryStream::getNextQWord(stream, buffer)) + { + return false; + } + return ByteUtils::ToQWord(buffer);; +} + +bool BinaryStream::checkNextDWord(std::basic_istream* stream, const char* target) +{ + char buffer[sizeof(ByteUtils::DWord)]; + if(!BinaryStream::getNextDWord(stream, buffer)) + { + return false; + } + + if(!ByteUtils::CompareDWords(buffer, target)) + { + return false; + } + return true; +} + +bool BinaryStream::getNextString(std::basic_istream* stream, std::string& target, unsigned numBytes) +{ + char c; + for(unsigned idx=0; idxget(c)) + { + return false; + } + target += c; + } + return true; +} diff --git a/src/core/streams/BinaryStream.h b/src/core/streams/BinaryStream.h new file mode 100644 index 0000000..33df8fe --- /dev/null +++ b/src/core/streams/BinaryStream.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +#include "ByteUtils.h" + +class BinaryStream +{ +public: + + template + static bool write(std::basic_ostream* stream, T data) + { + stream->write(reinterpret_cast(&data), sizeof(data)); + return true; + } + + static std::optional getNextByteAsInt(std::basic_istream* stream); + + static bool getNextNBytes(std::basic_istream* stream, char* buffer, unsigned numBytes); + + static bool getNextWord(std::basic_istream* stream, char* buffer); + + static bool getNextDWord(std::basic_istream* stream, char* buffer); + + static bool getNextQWord(std::basic_istream* stream, char* buffer); + + static std::optional getNextWord(std::basic_istream* stream, bool reverse = true); + + static std::optional getNextDWord(std::basic_istream* stream); + + static std::optional getNextQWord(std::basic_istream* stream); + + static bool checkNextDWord(std::basic_istream* stream, const char* target); + + static bool getNextString(std::basic_istream* stream, std::string& target, unsigned numBytes); +}; diff --git a/src/fonts/CMakeLists.txt b/src/fonts/CMakeLists.txt new file mode 100644 index 0000000..42d3aec --- /dev/null +++ b/src/fonts/CMakeLists.txt @@ -0,0 +1,15 @@ + +list(APPEND fonts_LIB_INCLUDES + FontReader.cpp + TrueTypeFont.cpp + ) + +add_library(fonts SHARED ${fonts_LIB_INCLUDES}) + +target_include_directories(fonts PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" + ) + +target_link_libraries(fonts PUBLIC core) +set_property(TARGET fonts PROPERTY FOLDER src) +set_target_properties( fonts PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) \ No newline at end of file diff --git a/src/fonts/FontReader.cpp b/src/fonts/FontReader.cpp new file mode 100644 index 0000000..fe37ea1 --- /dev/null +++ b/src/fonts/FontReader.cpp @@ -0,0 +1,181 @@ +#include "FontReader.h" +#include "TrueTypeFont.h" + +#include "File.h" +#include "BinaryStream.h" + +#include +#include + +FontReader::~FontReader() +{ + +} + +void FontReader::setPath(const std::string& path) +{ + mPath = path; +} + +bool FontReader::readOffsetSubtable() +{ + mOffsetSubtable.scaler_type = *BinaryStream::getNextDWord(mFile->GetInHandle()); + mCurrentOffset += 4; + + mOffsetSubtable.num_tables = *BinaryStream::getNextWord(mFile->GetInHandle()); + mCurrentOffset += 2; + + mOffsetSubtable.search_range = *BinaryStream::getNextWord(mFile->GetInHandle()); + mCurrentOffset += 2; + + mOffsetSubtable.entry_selector = *BinaryStream::getNextWord(mFile->GetInHandle()); + mCurrentOffset += 2; + + mOffsetSubtable.range_shift = *BinaryStream::getNextWord(mFile->GetInHandle()); + mCurrentOffset += 2; + + return true; +} + +void FontReader::logOffsetSubtable() +{ + std::stringstream sstr; + sstr << "Offset Subtable\n"; + sstr << "scaler_type: " << mOffsetSubtable.scaler_type << "\n"; + + sstr << "num_tables: " << mOffsetSubtable.num_tables << "\n"; + + sstr << "search_range: " << mOffsetSubtable.search_range << "\n"; + + sstr << "entry_selector: " << mOffsetSubtable.entry_selector << "\n"; + + sstr << "range_shift: " << mOffsetSubtable.range_shift << "\n"; + sstr << "************\n"; + std::cout << sstr.str() << std::endl; +} + +void FontReader::readTableDirectory() +{ + mTables.clear(); + for (unsigned idx=0; idxGetInHandle(), table.name, 4); + mCurrentOffset += 4; + + table.checksum = *BinaryStream::getNextDWord(mFile->GetInHandle()); + mCurrentOffset += 4; + + table.offset = *BinaryStream::getNextDWord(mFile->GetInHandle()); + mCurrentOffset += 4; + + table.length = *BinaryStream::getNextDWord(mFile->GetInHandle()); + mCurrentOffset += 4; + + logTable(table); + mTables.push_back(table); + } +} + +void FontReader::logTable(const Table& table) +{ + std::stringstream sstr; + sstr << "Table\n"; + sstr << "name: " << table.name << "\n"; + + sstr << "checksum: " << table.checksum << "\n"; + + sstr << "offset: " << table.offset << "\n"; + + sstr << "length: " << table.length << "\n"; + sstr << "************\n"; + std::cout << sstr.str() << std::endl; +} + +void FontReader::readTable() +{ + std::string working_table_name; + for (const auto& table : mTables) + { + if (mCurrentOffset == table.offset) + { + working_table_name = table.name; + break; + } + } + + if (working_table_name == "head") + { + readHeadTable(); + } + +} + +void FontReader::readHeadTable() +{ + std::cout << "Reading head table" << std::endl; + + TrueTypeFont::HeadTable table; + + table.version = *BinaryStream::getNextDWord(mFile->GetInHandle()); + table.fontRevision = *BinaryStream::getNextDWord(mFile->GetInHandle()); + table.checksumAdjustment = *BinaryStream::getNextDWord(mFile->GetInHandle()); + table.magicNumber = *BinaryStream::getNextDWord(mFile->GetInHandle()); + mCurrentOffset += 16; + + table.flags = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.unitsPerEm = *BinaryStream::getNextWord(mFile->GetInHandle()); + mCurrentOffset += 4; + + table.created = *BinaryStream::getNextQWord(mFile->GetInHandle()); + table.modified = *BinaryStream::getNextQWord(mFile->GetInHandle()); + mCurrentOffset += 16; + + table.xMin = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.yMin = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.xMax = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.yMax = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.macStyle = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.lowestRecPPEM = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.fontDirectionHint = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.indexToLocFormat = *BinaryStream::getNextWord(mFile->GetInHandle()); + table.glyphDataFormat = *BinaryStream::getNextWord(mFile->GetInHandle()); + + mCurrentOffset += 18; + + auto working_ttf_font = dynamic_cast(mWorkingFont.get()); + working_ttf_font->setHeadTable(table); + std::cout << working_ttf_font->logHeadTable() << std::endl; +} + + +std::unique_ptr FontReader::read() +{ + mWorkingFont = std::make_unique(); + + mFile = std::make_unique(mPath); + mFile->Open(true); + + readOffsetSubtable(); + std::cout << "Current offset: " << mCurrentOffset << std::endl; + + logOffsetSubtable(); + + readTableDirectory(); + std::cout << "Current offset: " << mCurrentOffset << std::endl; + + for (unsigned idx=0; idxClose(); + + + + + return std::move(mWorkingFont); +} + diff --git a/src/fonts/FontReader.h b/src/fonts/FontReader.h new file mode 100644 index 0000000..02cd07b --- /dev/null +++ b/src/fonts/FontReader.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include +#include "IFont.h" +#include "File.h" + +class File; + +class FontReader +{ +public: + ~FontReader(); + void setPath(const std::string& path); + + std::unique_ptr read(); + +private: + + struct OffsetSubtable + { + uint32_t scaler_type{0}; + uint16_t num_tables{0}; + uint16_t search_range{0}; + uint16_t entry_selector{0}; + uint16_t range_shift{0}; + }; + + struct Table + { + std::string name; + unsigned checksum{0}; + unsigned offset{0}; + unsigned length{0}; + }; + + bool readOffsetSubtable(); + void logOffsetSubtable(); + void logTable(const Table& table); + + void readTableDirectory(); + + void readTable(); + void readHeadTable(); + + unsigned mCurrentOffset{0}; + OffsetSubtable mOffsetSubtable; + std::vector mTables; + + std::unique_ptr mWorkingFont; + std::unique_ptr mFile; + std::string mPath; +}; diff --git a/src/fonts/IFont.h b/src/fonts/IFont.h new file mode 100644 index 0000000..2554052 --- /dev/null +++ b/src/fonts/IFont.h @@ -0,0 +1,8 @@ +#pragma once + +class IFont +{ +public: + virtual ~IFont() = default; + virtual void dumpInfo() = 0; +}; diff --git a/src/fonts/TrueTypeFont.cpp b/src/fonts/TrueTypeFont.cpp new file mode 100644 index 0000000..843fe1b --- /dev/null +++ b/src/fonts/TrueTypeFont.cpp @@ -0,0 +1,31 @@ +#include "TrueTypeFont.h" + +#include + +std::string TrueTypeFont::logHeadTable() const +{ + std::stringstream sstr; + sstr << "Head Table\n"; + sstr << "version: " << mHeadTable.version << "\n"; + sstr << "fontRevision: " << mHeadTable.fontRevision << "\n"; + sstr << "checksumAdjustment: " << mHeadTable.checksumAdjustment << "\n"; + sstr << "magicNumber: " << mHeadTable.magicNumber << "\n"; + sstr << "flags: " << mHeadTable.flags << "\n"; + sstr << "unitsPerEm: " << mHeadTable.unitsPerEm << "\n"; + sstr << "created: " << mHeadTable.created << "\n"; + sstr << "modified: " << mHeadTable.modified << "\n"; + sstr << "xMin: " << mHeadTable.xMin << "\n"; + sstr << "yMin: " << mHeadTable.yMin << "\n"; + sstr << "xMax: " << mHeadTable.xMax << "\n"; + sstr << "yMax: " << mHeadTable.yMax << "\n"; + sstr << "macStyle: " << mHeadTable.macStyle << "\n"; + sstr << "lowestRecPPEM: " << mHeadTable.lowestRecPPEM << "\n"; + sstr << "fontDirectionHint: " << mHeadTable.fontDirectionHint << "\n"; + sstr << "indexToLocFormat: " << mHeadTable.indexToLocFormat << "\n"; + sstr << "glyphDataFormat: " << mHeadTable.glyphDataFormat << "\n"; + return sstr.str(); + + + +} + diff --git a/src/fonts/TrueTypeFont.h b/src/fonts/TrueTypeFont.h new file mode 100644 index 0000000..5749dec --- /dev/null +++ b/src/fonts/TrueTypeFont.h @@ -0,0 +1,53 @@ +#pragma once + +#include "IFont.h" + +#include +#include + +class TrueTypeFont : public IFont +{ +public: + + using Fixed = int32_t; + using LongDateTime = int64_t; + using FWord = int16_t; + + // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6head.html + struct HeadTable + { + Fixed version{0}; + Fixed fontRevision{0}; + uint32_t checksumAdjustment{0}; + uint32_t magicNumber{0}; + uint16_t flags{0}; + uint16_t unitsPerEm{0}; + LongDateTime created{0}; + LongDateTime modified{0}; + FWord xMin{0}; + FWord yMin{0}; + FWord xMax{0}; + FWord yMax{0}; + uint16_t macStyle{0}; + uint16_t lowestRecPPEM{0}; + int16_t fontDirectionHint{0}; + int16_t indexToLocFormat{0}; + int16_t glyphDataFormat{0}; + }; + + std::string logHeadTable() const; + + void setHeadTable(const HeadTable& table) + { + mHeadTable = table; + } + + void dumpInfo() override + { + std::cout << "Got ttf" << std::endl; + } + +private: + + HeadTable mHeadTable; +}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bb9657b..edc4187 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,7 +10,9 @@ target_include_directories(test_utils PUBLIC list(APPEND TestFiles audio/TestAudioWriter.cpp audio/TestMidiReader.cpp + core/TestBinaryStream.cpp database/TestDatabase.cpp + fonts/TestFontReader.cpp graphics/TestOpenGlRendering.cpp graphics/TestRasterizer.cpp ipc/TestDbus.cpp @@ -26,7 +28,9 @@ list(APPEND TestFiles list(APPEND TestNames TestAudioWriter TestMidiReader + TestBinaryStream TestDatabase + TestFontReader TestOpenGlRendering TestRasterizer TestDbus @@ -46,9 +50,9 @@ link_directories(${DBUS_LIBRARY_DIRS}) foreach(TestFile TestName IN ZIP_LISTS TestFiles TestNames) add_executable(${TestName} ${TestFile}) - target_link_libraries(${TestName} PUBLIC core network image publishing video database geometry audio graphics web client test_utils ${DBUS_LIBRARIES}) + target_link_libraries(${TestName} PUBLIC core fonts network image publishing video database geometry audio graphics web client test_utils ${DBUS_LIBRARIES}) endforeach() add_executable(test_runner test_runner.cpp) -target_link_libraries(test_runner PUBLIC core network database geometry audio graphics web client) \ No newline at end of file +target_link_libraries(test_runner PUBLIC core fonts network database geometry audio graphics web client) \ No newline at end of file diff --git a/test/core/TestBinaryStream.cpp b/test/core/TestBinaryStream.cpp new file mode 100644 index 0000000..905869d --- /dev/null +++ b/test/core/TestBinaryStream.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/test/fonts/TestFontReader.cpp b/test/fonts/TestFontReader.cpp new file mode 100644 index 0000000..33b612a --- /dev/null +++ b/test/fonts/TestFontReader.cpp @@ -0,0 +1,17 @@ +#include "TrueTypeFont.h" +#include "FontReader.h" + +#include + +int main() +{ + const auto font_path = "/usr/share/fonts/truetype/tlwg/TlwgTypo-Bold.ttf"; + + FontReader reader; + reader.setPath(font_path); + auto font = reader.read(); + + font->dumpInfo(); + + return 0; +}