160 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef TTF_HEADER_INCLUDED
 | 
						|
#define TTF_HEADER_INCLUDED
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <fstream>
 | 
						|
#include <nana/charset.hpp>
 | 
						|
#include <nana/filesystem/filesystem.hpp>
 | 
						|
 | 
						|
namespace nana
 | 
						|
{
 | 
						|
	namespace spec
 | 
						|
	{
 | 
						|
		class truetype
 | 
						|
		{
 | 
						|
			struct tt_offset_table
 | 
						|
			{
 | 
						|
				std::uint16_t major_version;
 | 
						|
				std::uint16_t minor_version;
 | 
						|
				std::uint16_t num_of_tables;
 | 
						|
				std::uint16_t search_range;
 | 
						|
				std::uint16_t entry_selector;
 | 
						|
				std::uint16_t range_shift;
 | 
						|
			};
 | 
						|
 | 
						|
			struct tt_table_directory
 | 
						|
			{
 | 
						|
				char	name[4];		//table name
 | 
						|
				std::uint32_t checksum;	//Check sum
 | 
						|
				std::uint32_t offset;	//Offset from beginning of file
 | 
						|
				std::uint32_t length;	//length of the table in bytes
 | 
						|
			};
 | 
						|
 | 
						|
			struct tt_name_table_header
 | 
						|
			{
 | 
						|
				std::uint16_t format_selector;		//format selector. Always 0
 | 
						|
				std::uint16_t name_records_count;	//Name Records count
 | 
						|
				std::uint16_t storage_offset;		//Offset for strings storage, from start of the table
 | 
						|
			};
 | 
						|
 | 
						|
			struct tt_name_record
 | 
						|
			{
 | 
						|
				std::uint16_t platform_id;
 | 
						|
				std::uint16_t encoding_id;
 | 
						|
				std::uint16_t language_id;
 | 
						|
				std::uint16_t name_id;
 | 
						|
				std::uint16_t string_length;
 | 
						|
				std::uint16_t string_offset; //from start of storage area
 | 
						|
			};
 | 
						|
		public:
 | 
						|
			using path_type = ::std::experimental::filesystem::path;
 | 
						|
 | 
						|
			truetype(const path_type& filename)
 | 
						|
			{
 | 
						|
				std::ifstream ifs(filename.string(), std::ios::binary);
 | 
						|
				if (!ifs.is_open())
 | 
						|
					return;
 | 
						|
 | 
						|
				tt_offset_table offset_table;
 | 
						|
				if (ifs.read(reinterpret_cast<char*>(&offset_table), sizeof offset_table).gcount() != sizeof offset_table)
 | 
						|
					return;
 | 
						|
 | 
						|
				const std::size_t num_of_tables = _m_swap(offset_table.num_of_tables);
 | 
						|
				for (std::size_t i = 0; i < num_of_tables; ++i)
 | 
						|
				{
 | 
						|
					tt_table_directory table_directory;
 | 
						|
					if (ifs.read(reinterpret_cast<char*>(&table_directory), sizeof table_directory).gcount() != sizeof table_directory)
 | 
						|
						return;
 | 
						|
 | 
						|
					if (*reinterpret_cast<const std::uint32_t*>("name") == reinterpret_cast<std::uint32_t&>(table_directory.name))
 | 
						|
					{
 | 
						|
						//const std::size_t length = _m_swap(table_directory.length);
 | 
						|
						const std::size_t directory_offset = _m_swap(table_directory.offset);
 | 
						|
 | 
						|
						ifs.seekg(directory_offset, std::ios::beg);
 | 
						|
 | 
						|
						tt_name_table_header name_table;
 | 
						|
						if (ifs.read(reinterpret_cast<char*>(&name_table), sizeof name_table).gcount() != sizeof name_table)
 | 
						|
							return;
 | 
						|
 | 
						|
						const std::size_t name_records_count = _m_swap(name_table.name_records_count);
 | 
						|
						const std::size_t storage_offset = _m_swap(name_table.storage_offset);
 | 
						|
 | 
						|
						for (std::size_t u = 0; u < name_records_count; ++u)
 | 
						|
						{
 | 
						|
							tt_name_record record;
 | 
						|
							if (ifs.read(reinterpret_cast<char*>(&record), sizeof record).gcount() != sizeof record)
 | 
						|
								return;
 | 
						|
 | 
						|
							if ((0 == record.string_length) || (0x100 != record.name_id))
 | 
						|
								continue;
 | 
						|
 | 
						|
							std::size_t string_length = _m_swap(record.string_length);
 | 
						|
 | 
						|
							auto const filepos = ifs.tellg();
 | 
						|
							ifs.seekg(directory_offset + _m_swap(record.string_offset) + storage_offset, std::ios::beg);
 | 
						|
 | 
						|
							std::string text;
 | 
						|
 | 
						|
							//Check if it is unicode
 | 
						|
							if ((0 == record.platform_id) || (record.platform_id == 0x300 && record.encoding_id == 0x100))
 | 
						|
							{
 | 
						|
								if (0 == (string_length & 1)) //the string_length must be
 | 
						|
								{
 | 
						|
									//This is unicode
 | 
						|
									text.resize(string_length);
 | 
						|
									ifs.read(&text.front(), string_length);
 | 
						|
 | 
						|
									for (std::size_t i = 0; i < string_length; i += 2)
 | 
						|
										std::swap(text[i], text[i + 1]);
 | 
						|
									
 | 
						|
									text = ::nana::charset(text, nana::unicode::utf16).to_bytes(nana::unicode::utf8);
 | 
						|
								}
 | 
						|
							}
 | 
						|
							else
 | 
						|
							{
 | 
						|
								text.resize(string_length);
 | 
						|
								ifs.read(&text.front(), string_length);
 | 
						|
							}
 | 
						|
 | 
						|
							if (!text.empty())
 | 
						|
							{
 | 
						|
								switch (record.name_id)
 | 
						|
								{
 | 
						|
								case 0x100:
 | 
						|
									font_family_.swap(text);
 | 
						|
									break;
 | 
						|
								case 0x400:
 | 
						|
									text.clear();
 | 
						|
								}
 | 
						|
							}
 | 
						|
							ifs.seekg(filepos, std::ios::beg);
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
 | 
						|
				}
 | 
						|
 | 
						|
			}
 | 
						|
 | 
						|
			const std::string& font_family() const
 | 
						|
			{
 | 
						|
				return font_family_;
 | 
						|
			}
 | 
						|
		private:
 | 
						|
			static std::uint16_t _m_swap(std::uint16_t val)
 | 
						|
			{
 | 
						|
				return (val << 8) | (val >> 8);
 | 
						|
			}
 | 
						|
 | 
						|
			static std::uint32_t _m_swap(std::uint32_t val)
 | 
						|
			{
 | 
						|
				return (static_cast<std::uint32_t>(_m_swap(std::uint16_t(val & 0xFFFF))) << 16) | _m_swap(std::uint16_t(val >> 16));
 | 
						|
			}
 | 
						|
		private:
 | 
						|
			std::string font_family_;
 | 
						|
		};
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#endif |