Start font reading support.

This commit is contained in:
jmsgrogan 2022-07-31 20:01:13 +01:00
parent 92e7a78710
commit ed925afabf
22 changed files with 599 additions and 220 deletions

View file

@ -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)

View file

@ -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<int>(handle, content_size);
BinaryStream::write<int>(handle, content_size);
handle->write("WAVE", 4);
/* write fmt subchunk */
handle->write("fmt ", 4);
BinaryFile::Write<int>(handle, 16); // SubChunk1Size
BinaryFile::Write<short>(handle, 1); // PCM Format
BinaryFile::Write<short>(handle, num_channels);
BinaryFile::Write<int>(handle, sample_rate);
BinaryFile::Write<int>(handle, byte_rate);
BinaryFile::Write<short>(handle, num_channels*bytes_per_sample); // block align
BinaryFile::Write<short>(handle, 8*bytes_per_sample); // bits/sample
BinaryStream::write<int>(handle, 16); // SubChunk1Size
BinaryStream::write<short>(handle, 1); // PCM Format
BinaryStream::write<short>(handle, num_channels);
BinaryStream::write<int>(handle, sample_rate);
BinaryStream::write<int>(handle, byte_rate);
BinaryStream::write<short>(handle, num_channels*bytes_per_sample); // block align
BinaryStream::write<short>(handle, 8*bytes_per_sample); // bits/sample
/* write data subchunk */
handle->write("data", 4);
BinaryFile::Write<int>(handle, bytes_per_sample* num_samples*num_channels); // bits/sample
BinaryStream::write<int>(handle, bytes_per_sample* num_samples*num_channels); // bits/sample
handle->write(reinterpret_cast<const char*>(&data[0]), data.size()*sizeof(short));
outfile.Close();

View file

@ -1,6 +1,6 @@
#include "MidiChannelEventAdapter.h"
#include "BinaryFile.h"
#include "BinaryStream.h"
#include "ByteUtils.h"
#include <iostream>
@ -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;
}

View file

@ -1,6 +1,6 @@
#include "MidiMetaEventAdapter.h"
#include "BinaryFile.h"
#include "BinaryStream.h"
#include "ByteUtils.h"
#include <iostream>
@ -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; idx<length; idx++)
@ -81,12 +79,11 @@ int MidiMetaEventAdapter::ReadStringEvent(std::ifstream* file, MetaMidiEvent* ev
{
unsigned byteCount = 0;
int length = 0;
BinaryFile::GetNextByteAsInt(file, length);
int length = *BinaryStream::getNextByteAsInt(file);
byteCount++;
std::string name;
BinaryFile::GetNextString(file, name, length);
BinaryStream::getNextString(file, name, length);
byteCount += length;
event->SetLabel(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<ByteUtils::DWord>(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<ByteUtils::DWord>(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;
}

View file

@ -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<MidiTrack>();
unsigned iter_count = 0;
while(byteCount < unsigned(chunkSize))
while(byteCount < static_cast<unsigned>(*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;

View file

@ -1,6 +1,6 @@
#include "MidiTimeAdapter.h"
#include "BinaryFile.h"
#include "BinaryStream.h"
#include "ByteUtils.h"
#include <iostream>
@ -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
}

View file

@ -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());

View file

@ -1,24 +1,26 @@
#pragma once
#include <cstring>
#include <iostream>
#include <stdint.h>
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<typename T>
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<Word>(buffer, reverse);
}
static DWord ToDWord(char* buffer, bool reverse = true)
{
return ToInt(buffer, BYTES_PER_DWORD, reverse);
return ToType<DWord>(buffer, reverse);
}
static QWord ToQWord(char* buffer, bool reverse = true)
{
return ToType<QWord>(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
};

View file

@ -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)

View file

@ -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; idx<number; idx++)
{
if(file->get(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; idx<numBytes; idx++)
{
if(!file->get(c))
{
return false;
}
target += c;
}
return true;
}

View file

@ -1,32 +0,0 @@
#pragma once
#include <fstream>
#include <string>
class BinaryFile
{
public:
template<typename T>
static bool Write(std::ofstream* file, T data)
{
file->write(reinterpret_cast<char*>(&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);
};

View file

@ -0,0 +1,97 @@
#include "BinaryStream.h"
std::optional<int> BinaryStream::getNextByteAsInt(std::basic_istream<char>* stream)
{
return stream->get();
}
bool BinaryStream::getNextNBytes(std::basic_istream<char>* stream, char* buffer, unsigned number)
{
char c;
for(unsigned idx=0; idx<number; idx++)
{
if(stream->get(c))
{
buffer[idx] = c;
}
else
{
return false;
}
}
return true;
}
bool BinaryStream::getNextWord(std::basic_istream<char>* stream, char* buffer)
{
return getNextNBytes(stream, buffer, sizeof(ByteUtils::Word));
}
bool BinaryStream::getNextDWord(std::basic_istream<char>* stream, char* buffer)
{
return getNextNBytes(stream, buffer, sizeof(ByteUtils::DWord));
}
bool BinaryStream::getNextQWord(std::basic_istream<char>* stream, char* buffer)
{
return getNextNBytes(stream, buffer, sizeof(ByteUtils::QWord));
}
std::optional<ByteUtils::Word> BinaryStream::getNextWord(std::basic_istream<char>* stream, bool reverse)
{
char buffer[sizeof(ByteUtils::Word)];
if(!BinaryStream::getNextWord(stream, buffer))
{
return false;
}
return ByteUtils::ToWord(buffer, reverse);
}
std::optional<ByteUtils::DWord> BinaryStream::getNextDWord(std::basic_istream<char>* stream)
{
char buffer[sizeof(ByteUtils::DWord)];
if(!BinaryStream::getNextDWord(stream, buffer))
{
return false;
}
return ByteUtils::ToDWord(buffer);;
}
std::optional<ByteUtils::QWord> BinaryStream::getNextQWord(std::basic_istream<char>* stream)
{
char buffer[sizeof(ByteUtils::QWord)];
if(!BinaryStream::getNextQWord(stream, buffer))
{
return false;
}
return ByteUtils::ToQWord(buffer);;
}
bool BinaryStream::checkNextDWord(std::basic_istream<char>* 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<char>* stream, std::string& target, unsigned numBytes)
{
char c;
for(unsigned idx=0; idx<numBytes; idx++)
{
if(!stream->get(c))
{
return false;
}
target += c;
}
return true;
}

View file

@ -0,0 +1,40 @@
#pragma once
#include <istream>
#include <ostream>
#include <string>
#include <optional>
#include "ByteUtils.h"
class BinaryStream
{
public:
template<typename T>
static bool write(std::basic_ostream<char>* stream, T data)
{
stream->write(reinterpret_cast<char*>(&data), sizeof(data));
return true;
}
static std::optional<int> getNextByteAsInt(std::basic_istream<char>* stream);
static bool getNextNBytes(std::basic_istream<char>* stream, char* buffer, unsigned numBytes);
static bool getNextWord(std::basic_istream<char>* stream, char* buffer);
static bool getNextDWord(std::basic_istream<char>* stream, char* buffer);
static bool getNextQWord(std::basic_istream<char>* stream, char* buffer);
static std::optional<ByteUtils::Word> getNextWord(std::basic_istream<char>* stream, bool reverse = true);
static std::optional<ByteUtils::DWord> getNextDWord(std::basic_istream<char>* stream);
static std::optional<ByteUtils::QWord> getNextQWord(std::basic_istream<char>* stream);
static bool checkNextDWord(std::basic_istream<char>* stream, const char* target);
static bool getNextString(std::basic_istream<char>* stream, std::string& target, unsigned numBytes);
};

15
src/fonts/CMakeLists.txt Normal file
View file

@ -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 )

181
src/fonts/FontReader.cpp Normal file
View file

@ -0,0 +1,181 @@
#include "FontReader.h"
#include "TrueTypeFont.h"
#include "File.h"
#include "BinaryStream.h"
#include <iostream>
#include <sstream>
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; idx<mOffsetSubtable.num_tables; idx++)
{
Table table;
BinaryStream::getNextString(mFile->GetInHandle(), 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<TrueTypeFont*>(mWorkingFont.get());
working_ttf_font->setHeadTable(table);
std::cout << working_ttf_font->logHeadTable() << std::endl;
}
std::unique_ptr<IFont> FontReader::read()
{
mWorkingFont = std::make_unique<TrueTypeFont>();
mFile = std::make_unique<File>(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; idx<mOffsetSubtable.num_tables; idx++)
{
readTable();
std::cout << "Current offset: " << mCurrentOffset << std::endl;
break;
}
mFile->Close();
return std::move(mWorkingFont);
}

54
src/fonts/FontReader.h Normal file
View file

@ -0,0 +1,54 @@
#pragma once
#include <string>
#include <memory>
#include <vector>
#include "IFont.h"
#include "File.h"
class File;
class FontReader
{
public:
~FontReader();
void setPath(const std::string& path);
std::unique_ptr<IFont> 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<Table> mTables;
std::unique_ptr<IFont> mWorkingFont;
std::unique_ptr<File> mFile;
std::string mPath;
};

8
src/fonts/IFont.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
class IFont
{
public:
virtual ~IFont() = default;
virtual void dumpInfo() = 0;
};

View file

@ -0,0 +1,31 @@
#include "TrueTypeFont.h"
#include <sstream>
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();
}

53
src/fonts/TrueTypeFont.h Normal file
View file

@ -0,0 +1,53 @@
#pragma once
#include "IFont.h"
#include <iostream>
#include <stdint.h>
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;
};

View file

@ -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)
target_link_libraries(test_runner PUBLIC core fonts network database geometry audio graphics web client)

View file

@ -0,0 +1,4 @@
int main()
{
return 0;
}

View file

@ -0,0 +1,17 @@
#include "TrueTypeFont.h"
#include "FontReader.h"
#include <iostream>
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;
}