initial commit

This commit is contained in:
Blue 2018-08-05 00:46:25 +03:00 committed by Юрий Губич
commit 4b60ece582
327 changed files with 28286 additions and 0 deletions

View file

@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.6)
project(fontparser)
set(SOURCES
font.cpp
)
add_subdirectory(tables)
add_library(font STATIC ${SOURCES})
target_link_libraries(font tables)
add_executable(fontparser main.cpp)
target_link_libraries(fontparser font)
install(TARGETS fontparser RUNTIME DESTINATION bin)

223
lib/fontParser/font.cpp Normal file
View file

@ -0,0 +1,223 @@
#include "font.h"
#include <arpa/inet.h>
Font::Font(const std::string& p_path):
path(p_path),
tables(),
cmap(0),
hhea(0),
hmtx(0),
head(0),
name(0)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
char * buffer;
buffer = new char[4];
file.read(buffer, 4);
uint32_t sfntVersion = ntohl(*((uint32_t*) buffer));
if (sfntVersion == 0x00010000) {
version = TrueTypeOutlines;
} else if (sfntVersion == 0x4f54544f) {
version = WithCFFData;
} else {
std::cout << "unsupported sfntVersion" << std::endl;
throw 1;
}
delete[] buffer;
buffer = new char[2];
file.read(buffer, 2);
numberTables = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
searchRange = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
entrySelector = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
rangeShift = ntohs(*((uint16_t*) buffer));
for (int i = 0; i < numberTables; ++i) {
Table* t = Table::fromIfStream(file);
tables.insert(std::make_pair(t->tag, t));
}
file.close();
}
Font::~Font()
{
std::map<std::string, Table*>::const_iterator beg = tables.begin();
std::map<std::string, Table*>::const_iterator end = tables.end();
for (; beg != end; ++beg) {
delete beg->second;
}
}
bool Font::hasTable(const std::string& tag) const
{
std::map<std::string, Table*>::const_iterator itr = tables.find(tag);
return itr != tables.end();
}
std::list<std::string> Font::availableTables() const
{
std::list<std::string> res;
std::map<std::string, Table*>::const_iterator beg = tables.begin();
std::map<std::string, Table*>::const_iterator end = tables.end();
for (; beg != end; ++beg) {
res.push_back(beg->first);
}
return res;
}
std::map<uint32_t, uint32_t> Font::getCharCodeToCIDTable(uint32_t start, uint32_t end)
{
if (cmap == NULL) {
cmap = static_cast<Cmap*>(tables.at("cmap"));
cmap->read(path);
}
std::map<uint32_t, uint32_t> res;
for (uint32_t i = start; i <= end; ++i) {
res.insert(std::make_pair(i, cmap->getCID(i)));
}
return res;
}
std::map<uint32_t, Hmtx::HMetric> Font::getCharCodeMetrics(uint32_t start, uint32_t end)
{
std::map<uint32_t, uint32_t> CCtoCID = getCharCodeToCIDTable(start, end);
std::map<uint32_t, Hmtx::HMetric> res;
if (hmtx == NULL) {
hmtx = static_cast<Hmtx*>(tables.at("hmtx"));
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
hmtx->numOfLongHorMetrics = hhea->numOfLongHorMetrics;
hmtx->read(path);
}
std::map<uint32_t, uint32_t>::const_iterator itr = CCtoCID.begin();
std::map<uint32_t, uint32_t>::const_iterator mend = CCtoCID.end();
for (; itr != mend; ++itr) {
res.insert(std::make_pair(itr->first, hmtx->getMetric(itr->second)));
}
return res;
}
Table * Font::getTable(const std::string& tag)
{
std::map<std::string, Table*>::iterator itr = tables.find(tag);
return itr->second;
}
uint16_t Font::getUnitsPerEm()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->unitsPerEm;
}
int16_t Font::getAscent()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->ascent;
}
int16_t Font::getDescent()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->descent;
}
int16_t Font::getLineGap()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->lineGap;
}
std::string Font::getNameField(std::string key)
{
if (name == NULL) {
name = static_cast<Name*>(tables.at("name"));
name->read(path);
}
return name->getRecord(key);
}
int16_t Font::getCaretSlopeRise()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->caretSlopeRise;
}
int16_t Font::getCaretSlopeRun()
{
if (hhea == NULL) {
hhea = static_cast<Hhea*>(tables.at("hhea"));
hhea->read(path);
}
return hhea->caretSlopeRun;
}
int16_t Font::getXMax()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->xMax;
}
int16_t Font::getXMin()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->xMin;
}
int16_t Font::getYMax()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->yMax;
}
int16_t Font::getYMin()
{
if (head == NULL) {
head = static_cast<Head*>(tables.at("head"));
head->read(path);
}
return head->yMin;
}

62
lib/fontParser/font.h Normal file
View file

@ -0,0 +1,62 @@
#ifndef FILE_H
#define FILE_H
#include <fstream>
#include <iostream>
#include <string>
#include <stdint.h>
#include <map>
#include <list>
#include "tables/table.h"
#include "tables/cmap.h"
#include "tables/hhea.h"
#include "tables/hmtx.h"
#include "tables/head.h"
#include "tables/name.h"
class Font
{
public:
enum SfntVersion {
TrueTypeOutlines,
WithCFFData
};
Font(const std::string& p_path);
~Font();
bool hasTable(const std::string& tag) const;
Table* getTable(const std::string& tag);
std::list<std::string> availableTables() const;
std::map<uint32_t, uint32_t> getCharCodeToCIDTable(uint32_t start = 0, uint32_t end = 0xffff);
std::map<uint32_t, Hmtx::HMetric> getCharCodeMetrics(uint32_t start = 0, uint32_t end = 0xffff);
uint16_t getUnitsPerEm();
int16_t getAscent();
int16_t getDescent();
int16_t getLineGap();
int16_t getCaretSlopeRise();
int16_t getCaretSlopeRun();
int16_t getXMin();
int16_t getXMax();
int16_t getYMin();
int16_t getYMax();
std::string getNameField(std::string key);
SfntVersion version;
uint16_t numberTables;
uint16_t searchRange;
uint16_t entrySelector;
uint16_t rangeShift;
private:
const std::string path;
std::map<std::string, Table*> tables;
Cmap* cmap;
Hhea* hhea;
Hmtx* hmtx;
Head* head;
Name* name;
};
#endif // FILE_H

50
lib/fontParser/main.cpp Normal file
View file

@ -0,0 +1,50 @@
#include "font.h"
#include <iostream>
#include <list>
#include <string>
#include "tables/hmtx.h"
int main(int argc, char **argv) {
Font file(argv[1]);
std::map<uint32_t, Hmtx::HMetric> cidMap = file.getCharCodeMetrics(0, 0x4ff);
std::map<uint32_t, Hmtx::HMetric>::const_iterator itr = cidMap.begin();
std::map<uint32_t, Hmtx::HMetric>::const_iterator end = cidMap.end();
std::cout << "{\n";
std::cout << " \"ascent\": " << file.getAscent() << ",\n";
std::cout << " \"descent\": " << file.getDescent() << ",\n";
std::cout << " \"lineGap\": " << file.getLineGap() << ",\n";
std::cout << " \"caretSlopeRise\": " << file.getCaretSlopeRise() << ",\n";
std::cout << " \"caretSlopeRun\": " << file.getCaretSlopeRun() << ",\n";
std::cout << " \"unitsPerEm\": " << file.getUnitsPerEm() << ",\n";
std::cout << " \"fontFamily\": \"" << file.getNameField("fontFamily") << "\",\n";
std::cout << " \"postScriptName\": \"" << file.getNameField("postScriptName") << "\",\n";
std::cout << " \"boundingBox\": {\n";
std::cout << " \"xMin\": " << file.getXMin() << ",\n";
std::cout << " \"xMax\": " << file.getXMax() << ",\n";
std::cout << " \"yMin\": " << file.getYMin() << ",\n";
std::cout << " \"yMax\": " << file.getYMax() << "\n";
std::cout << " },\n";
std::cout << " \"advanceWidthArray\": [\n ";
int i = 0;
for (; itr != end; ++itr) {
if (i != 0) {
if (i == 16) {
std::cout << ",\n ";
i = 0;
} else {
std::cout << ", ";
}
}
std::cout << itr->second.advanceWidth;
++i;
}
std::cout << "\n ]\n";
std::cout << "}" << std::endl;
return 0;
}

View file

@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 2.6)
project(tables)
set(SOURCES
table.cpp
cmap.cpp
hhea.cpp
hmtx.cpp
head.cpp
name.cpp
)
add_library(tables STATIC ${SOURCES})

View file

@ -0,0 +1,218 @@
#include "cmap.h"
#include <arpa/inet.h>
Cmap::Cmap(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
initialized(false),
mt(0)
{
}
Cmap::~Cmap()
{
if (initialized) {
delete mt;
}
}
void Cmap::read(const std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
file.read(buffer, 2);
version = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
numberOfTables = ntohs(*((uint16_t*) buffer));
delete[] buffer;
buffer = new char[8];
std::list<Enc> encodings;
for (int i = 0; i < numberOfTables; ++i) {
file.read(buffer, 8);
char pb[2] = {buffer[0], buffer[1]};
char eb[2] = {buffer[2], buffer[3]};
char ob[4] = {buffer[4], buffer[5], buffer[6], buffer[7]};
uint16_t pid = ntohs(*((uint16_t*) pb));
uint16_t eid = ntohs(*((uint16_t*) eb));
uint16_t offset = ntohl(*((uint32_t*) ob));
//std::cout << "Found encoding platformId " << pid << ", encodingId " << eid << std::endl;
if (pid == 0 || (pid == 3 && eid == 1)) {
encodings.emplace_back(pid, eid, offset);
}
}
delete[] buffer;
std::list<Enc>::const_iterator itr = encodings.begin();
std::list<Enc>::const_iterator end = encodings.end();
for (; itr != end; ++itr) {
//std::cout << "Trying platformId " << itr->platformId << ", encodingId " << itr->encodingId << std::endl;
file.seekg(offset + itr->offset);
bool success = true;
MappingTable* table;
try {
table = MappingTable::fromIfStream(file);
} catch (int e) {
success = false;
}
if (success) {
initialized = true;
mt = table;
break;
}
}
file.close();
if (!initialized) {
//std::cout << "Error reading cmap: no supported encoding format" << std::endl;
throw 3;
}
}
uint32_t Cmap::getCID(uint32_t charCode) const
{
return this->mt->getCID(charCode);
}
MappingTable * MappingTable::fromIfStream(std::ifstream& file)
{
uint64_t position = file.tellg();
char * buffer;
buffer = new char[2];
file.read(buffer, 2);
uint16_t format = ntohs(*((uint16_t*) buffer));
MappingTable* table = NULL;
if (format >= 8) {
if (format != 14) {
file.read(buffer, 2); //padded .0 in stupid formats
}
delete[] buffer;
buffer = new char[4];
file.read(buffer, 4);
uint32_t length = ntohl(*((uint32_t*) buffer));
file.seekg(position);
buffer = new char[length];
file.read(buffer, length);
} else {
file.read(buffer, 2);
uint16_t length = ntohs(*((uint16_t*) buffer));
file.seekg(position);
buffer = new char[length];
file.read(buffer, length);
if (format == 4) {
table = new Format4(buffer, length);
}
}
delete[] buffer;
if (table == NULL) {
std::cout << "Unrecognized format " << format << std::endl;
throw 3;
}
return table;
}
MappingTable::MappingTable(uint16_t p_f):
format(p_f)
{
}
MappingTable::~MappingTable()
{
}
Format4::Format4(char * data, uint16_t length):
MappingTable(4),
charCodesEndCode(),
segments(0),
glyphIndexArray(0)
{
char sc[2] = {data[6], data[7]};
uint16_t segCount = ntohs(*((uint16_t*) sc)) / 2;
segments = new std::vector<SegParams>(segCount);
int endCodeShift = 14;
int startCodeShift = endCodeShift + segCount * 2 + 2;
int deltaShift = startCodeShift + segCount * 2;
int rangeShift = deltaShift + segCount * 2;
int giaShift = rangeShift + segCount * 2;
int giaLength = (length - giaShift) / 2;
glyphIndexArray = new std::vector<uint16_t>(giaLength);
// std::cout << "Segments: " << segCount << ", ";
// std::cout << "Glyphs: " << giaLength << "\n";
// std::cout << "******************************************" << "\n";
for (int i = 0; i < segCount; ++i) {
char cc[2] = {data[2 * i + endCodeShift], data[2 * i + endCodeShift + 1]};
char sc[2] = {data[2 * i + startCodeShift], data[2 * i + startCodeShift + 1]};
char dc[2] = {data[2 * i + deltaShift], data[2 * i + deltaShift + 1]};
char rc[2] = {data[2 * i + rangeShift], data[2 * i + rangeShift + 1]};
uint16_t endCharCode = ntohs(*((uint16_t*) cc));
uint16_t startCharCode = ntohs(*((uint16_t*) sc));
int16_t delta = ntohs(*((int16_t*) dc));
uint16_t range = ntohs(*((uint16_t*) rc));
SegParams& sp = segments->at(i);
sp.endCode = endCharCode;
sp.startCode = startCharCode;
sp.idDelta = delta;
sp.idRangeOffset = range;
charCodesEndCode.insert(std::make_pair(endCharCode, i));
// std::cout << "Segment " << i << ",\t";
// std::cout << "Start " << startCharCode << ",\t";
// std::cout << "End " << endCharCode << ",\t";
// std::cout << "Delta " << delta << ",\t";
// std::cout << "Range " << range << "\n";
}
// std::cout << "******************************************" << std::endl;;
for (int i = 0; i < giaLength; ++i) {
char cc[2] = {data[2 * i + giaShift], data[2 * i + giaShift + 1]};
uint16_t glyphIndex = ntohs(*((uint16_t*) cc));
glyphIndexArray->at(i) = glyphIndex;
}
}
Format4::~Format4()
{
delete segments;
delete glyphIndexArray;
}
uint32_t Format4::getCID(uint32_t charCode) const
{
uint16_t cid;
uint16_t c = charCode & 0xffff;
std::map<uint16_t, uint16_t>::const_iterator itr = charCodesEndCode.lower_bound(c);
uint16_t i = itr->second;
SegParams& seg = segments->at(i);
if (seg.startCode > c) {
return 0;
}
if (seg.idRangeOffset == 0) {
cid = c + seg.idDelta;
} else {
cid = i + seg.idRangeOffset - segments->size() + c - seg.startCode;
}
return cid;
}

View file

@ -0,0 +1,66 @@
#ifndef CMAP_H
#define CMAP_H
#include "table.h"
#include <list>
#include <map>
#include <vector>
struct Enc {
Enc(uint16_t pid, uint16_t eid, uint32_t off): platformId(pid), encodingId(eid), offset(off) {}
uint16_t platformId;
uint16_t encodingId;
uint32_t offset;
};
class MappingTable {
protected:
MappingTable(uint16_t p_f);
uint16_t format;
public:
static MappingTable* fromIfStream(std::ifstream& file);
virtual ~MappingTable();
virtual uint32_t getCID(uint32_t charCode) const = 0;
};
class Format4 : public MappingTable {
public:
Format4(char* data, uint16_t length);
~Format4();
uint32_t getCID(uint32_t charCode) const override;
private:
struct SegParams {
uint16_t endCode;
uint16_t startCode;
int16_t idDelta;
uint16_t idRangeOffset;
};
std::map<uint16_t, uint16_t> charCodesEndCode;
std::vector<SegParams>* segments;
std::vector<uint16_t>* glyphIndexArray;
};
class Cmap : public Table
{
public:
Cmap(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Cmap();
void read(const std::string & path) override;
uint32_t getCID(uint32_t charCode) const;
uint16_t version;
uint16_t numberOfTables;
private:
bool initialized;
MappingTable* mt;
};
#endif // CMAP_H

View file

@ -0,0 +1,93 @@
#include "head.h"
#include <arpa/inet.h>
Head::Head(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
fontRevisionMajor(0),
fontRevisionMinor(0),
flags(0),
unitsPerEm(0),
xMin(0),
yMin(0),
xMax(0),
yMax(0),
macStyle(0),
lowestRecPPEM(0),
fontDirectionHint(0),
indexToLocFormat(0)
{
}
Head::~Head()
{
}
void Head::read(const std::string& path)
{
char * buffer;
buffer = new char[2];
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2);
fontRevisionMajor = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
fontRevisionMinor = ntohs(*((uint16_t*) buffer));
delete[] buffer;
buffer = new char[4];
file.read(buffer, 4); //checkSumAdjustment - it's something fishy, no idea what to use it for;
file.read(buffer, 4); //magicNumber, always set to 0x5f0f3cf5;
delete[] buffer;
buffer = new char[2];
file.read(buffer, 2);
flags = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
unitsPerEm = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2); //creation date is a signed int64
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2); //last modification date is a signed int64
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
file.read(buffer, 2);
xMin = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
yMin = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
xMax = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
yMax = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
macStyle = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
lowestRecPPEM = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
fontDirectionHint = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
indexToLocFormat = ntohs(*((int16_t*) buffer));
//and there is stil uint16 glyph data format, but its always 0;
file.close();
delete[] buffer;
}

View file

@ -0,0 +1,28 @@
#ifndef HEAD_H
#define HEAD_H
#include "table.h"
class Head : public Table
{
public:
Head(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Head();
void read(const std::string & path) override;
uint16_t fontRevisionMajor;
uint16_t fontRevisionMinor;
uint16_t flags;
uint16_t unitsPerEm;
int16_t xMin;
int16_t yMin;
int16_t xMax;
int16_t yMax;
uint16_t macStyle;
uint16_t lowestRecPPEM;
int16_t fontDirectionHint;
int16_t indexToLocFormat;
};
#endif // HEAD_H

View file

@ -0,0 +1,76 @@
#include "hhea.h"
#include <arpa/inet.h>
Hhea::Hhea(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
ascent(0),
descent(0),
lineGap(0),
advanceWidthMax(0),
minLeftSideBearing(0),
minRightSideBearing(0),
xMaxExtent(0),
caretSlopeRise(0),
caretSlopeRun(0),
caretOffset(0),
numOfLongHorMetrics(0)
{
}
Hhea::~Hhea()
{
}
void Hhea::read(const std::string& path)
{
char * buffer;
buffer = new char[2];
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2); //version is not interesting, it is always 16.16 fixed point number equals to "1.0";
file.read(buffer, 2);
ascent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
descent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
lineGap = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
advanceWidthMax = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
minLeftSideBearing = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
minRightSideBearing = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
xMaxExtent = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretSlopeRise = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretSlopeRun = ntohs(*((int16_t*) buffer));
file.read(buffer, 2);
caretOffset = ntohs(*((int16_t*) buffer));
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //reserved empty field, supposed to be 0;
file.read(buffer, 2); //metricDataFormat, it's supposed to be 0;
file.read(buffer, 2);
numOfLongHorMetrics = ntohs(*((uint16_t*) buffer));
delete[] buffer;
file.close();
}

View file

@ -0,0 +1,27 @@
#ifndef HHEA_H
#define HHEA_H
#include "table.h"
class Hhea : public Table
{
public:
Hhea(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Hhea();
void read(const std::string & path) override;
int16_t ascent;
int16_t descent;
int16_t lineGap;
uint16_t advanceWidthMax;
int16_t minLeftSideBearing;
int16_t minRightSideBearing;
int16_t xMaxExtent;
int16_t caretSlopeRise;
int16_t caretSlopeRun;
int16_t caretOffset;
uint16_t numOfLongHorMetrics;
};
#endif // HHEA_H

View file

@ -0,0 +1,59 @@
#include "hmtx.h"
#include <arpa/inet.h>
Hmtx::Hmtx(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
numOfLongHorMetrics(0),
longHorMetric(0)
{
}
Hmtx::~Hmtx()
{
delete longHorMetric;
}
void Hmtx::read(const std::string& path)
{
if (numOfLongHorMetrics == 0) {
throw 1;
}
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
longHorMetric = new std::vector<HMetric>(numOfLongHorMetrics);
for (int i = 0; i < numOfLongHorMetrics; ++i) {
HMetric& met = longHorMetric->at(i);
file.read(buffer, 2);
uint16_t aw = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
int16_t lsb = ntohs(*((int16_t*) buffer));
met.advanceWidth = aw;
met.leftSideBearing = lsb;
}
file.close();
delete[] buffer;
}
Hmtx::HMetric::HMetric():
advanceWidth(0),
leftSideBearing(0)
{
}
Hmtx::HMetric Hmtx::getMetric(uint16_t cid) const
{
if (cid >= longHorMetric->size()) {
cid = longHorMetric->size() - 1;
}
return longHorMetric->at(cid);
}

View file

@ -0,0 +1,29 @@
#ifndef HMTX_H
#define HMTX_H
#include "table.h"
#include <vector>
class Hmtx : public Table
{
public:
Hmtx(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Hmtx();
uint16_t numOfLongHorMetrics;
struct HMetric {
HMetric();
uint16_t advanceWidth;
int16_t leftSideBearing;
};
void read(const std::string & path) override;
HMetric getMetric(uint16_t cid) const;
private:
std::vector<HMetric>* longHorMetric;
};
#endif // HMTX_H

View file

@ -0,0 +1,136 @@
#include "name.h"
#include <arpa/inet.h>
#include <list>
#include <set>
#include <codecvt>
#include <locale>
const std::map<std::string, uint16_t> Name::nameIds({
{ "copyright", 0 },
{ "fontFamily", 1 },
{ "fontSubfamily", 2 },
{ "uniqueSubfamilyId", 3 },
{ "fullFontName", 4 },
{ "nameTableVersion", 5 },
{ "postScriptName", 6 },
{ "trademarkNotice", 7 },
{ "manufacturerName", 8 },
{ "designerName", 9 },
{ "description", 10 },
{ "vendorURL", 11 },
{ "designerURL", 12 },
{ "licenseDescription", 13 },
{ "licenseURL", 14 },
{ "preferredFamily", 16 },
{ "preferredSubfamily", 17 },
{ "compatibleFull", 18 },
{ "sampleText", 19 },
{ "postScriptCID", 20 }
});
Name::Name(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
Table(p_tag, p_checkSum, p_offset, p_length),
names()
{
}
Name::~Name()
{
}
void Name::read(const std::string& path)
{
std::ifstream file(path, std::ios::in | std::ios::binary);
file.seekg(offset);
char * buffer;
buffer = new char[2];
file.read(buffer, 2); //format. it is always 0 or 1 for stupid microsoft langTags, but I don't cate, gonna use offset;
file.read(buffer, 2);
uint16_t count = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint32_t storageOffset = offset + ntohs(*((uint16_t*) buffer));
std::list<NameRecord> list;
std::set<uint16_t> ids;
for (int i = 0; i < count; ++i) {
file.read(buffer, 2);
uint16_t pid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t eid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t lid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t nid = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t length = ntohs(*((uint16_t*) buffer));
file.read(buffer, 2);
uint16_t nameOffset = ntohs(*((uint16_t*) buffer));
//std::cout << "Found pid " << pid << ", eid " << eid << ", nid " << nid << std::endl;
if (ids.find(nid) == ids.end()) {
if ((pid == 0 && (eid == 3 || eid == 4)) || (pid == 3 && eid == 1)) { //screw microsoft, screw apple;
list.emplace_back(pid, eid, lid, nid, length, nameOffset);
ids.insert(nid);
}
}
}
std::list<NameRecord>::const_iterator itr;
for (itr = list.begin(); itr != list.end(); ++itr) {
const NameRecord& nr = *itr;
file.seekg(storageOffset + nr.offset);
if ((nr.platformId == 0 && (nr.encodingId == 3 || nr.encodingId == 4)) || (nr.platformId == 3 && nr.encodingId == 1)) {
char16_t buf[nr.length / 2];
for (int i = 0; i < nr.length / 2; ++i) {
file.read(buffer, 2);
buf[i] = ntohs(*((char16_t*) buffer));
}
std::u16string string(buf, nr.length / 2);
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
names.insert(std::make_pair(nr.nameId, convert.to_bytes(string)));
}
}
delete[] buffer;
file.close();
}
std::string Name::getRecord(uint16_t id) const
{
std::string res("");
std::map<uint16_t, std::string>::const_iterator itr = names.find(id);
if (itr != names.end()) {
res = itr->second;
}
return res;
}
std::string Name::getRecord(const std::string& name) const
{
std::map<std::string, uint16_t>::const_iterator itr = nameIds.find(name);
if (itr == nameIds.end()) {
return "";
} else {
return getRecord(itr->second);
}
}
NameRecord::NameRecord(uint16_t pid, uint16_t eid, uint16_t lid, uint16_t nid, uint16_t p_l, uint16_t p_o):
platformId(pid),
encodingId(eid),
languageId(lid),
nameId(nid),
length(p_l),
offset(p_o)
{
}

View file

@ -0,0 +1,35 @@
#ifndef NAME_H
#define NAME_H
#include <map>
#include <string>
#include "table.h"
class Name : public Table
{
public:
Name(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
~Name();
void read(const std::string & path) override;
std::string getRecord(uint16_t id) const;
std::string getRecord(const std::string& name) const;
private:
std::map<uint16_t, std::string> names;
static const std::map<std::string, uint16_t> nameIds;
};
struct NameRecord {
NameRecord(uint16_t pid, uint16_t eid, uint16_t lid, uint16_t nid, uint16_t p_l, uint16_t p_o);
uint16_t platformId;
uint16_t encodingId;
uint16_t languageId;
uint16_t nameId;
uint16_t length;
uint16_t offset;
};
#endif // NAME_H

View file

@ -0,0 +1,56 @@
#include "table.h"
#include <arpa/inet.h>
#include "cmap.h"
#include "hhea.h"
#include "hmtx.h"
#include "head.h"
#include "name.h"
Table::Table(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length):
tag(p_tag),
checkSum(p_checkSum),
offset(p_offset),
length(p_length)
{
}
Table::~Table()
{
}
Table* Table::fromIfStream(std::ifstream& stream)
{
char * buffer;
buffer = new char[4];
stream.read(buffer, 4);
std::string tag(buffer, 4);
stream.read(buffer, 4);
uint32_t cs = ntohl(*((uint32_t*) buffer));
stream.read(buffer, 4);
uint32_t offset = ntohl(*((uint32_t*) buffer));
stream.read(buffer, 4);
uint32_t l = ntohl(*((uint32_t*) buffer));
if (tag == "cmap") {
return new Cmap(tag, cs, offset, l);
} else if (tag == "hhea") {
return new Hhea(tag, cs, offset, l);
} else if (tag == "hmtx") {
return new Hmtx(tag, cs, offset, l);
} else if (tag == "head") {
return new Head(tag, cs, offset, l);
} else if (tag == "name") {
return new Name(tag, cs, offset, l);
} else {
return new Table(tag, cs, offset, l);
}
}
void Table::read(const std::string& path)
{
std::cout << "table with type " << tag << " is not supported yet" << std::endl;
}

View file

@ -0,0 +1,26 @@
#ifndef TABLE_H
#define TABLE_H
#include <fstream>
#include <iostream>
#include <string>
#include <stdint.h>
class Table
{
public:
Table(const std::string& p_tag, uint32_t p_checkSum, uint32_t p_offset, uint32_t p_length);
virtual ~Table();
const std::string tag;
const uint32_t checkSum;
const uint32_t offset;
const uint32_t length;
static Table* fromIfStream(std::ifstream& stream);
virtual void read(const std::string& path);
};
#endif // TABLE_H