font_map_core/raw/ttf/
name.rs1use crate::error::ParseResult;
2use crate::reader::{BinaryReader, Parse};
3
4use super::PlatformType;
5
6#[derive(Debug)]
8pub struct NameRecord {
9 pub platform_id: PlatformType,
10 pub encoding_id: u16,
11 pub language_id: u16,
12
13 pub name_id: NameKind,
14 pub name: String,
15}
16
17#[derive(Debug, Default)]
19pub struct NameTable {
20 pub records: Vec<NameRecord>,
22}
23
24impl Parse for NameTable {
25 fn parse(reader: &mut BinaryReader) -> ParseResult<Self> {
26 let mut table = Self::default();
27
28 reader.skip_u16()?; let num_records = reader.read_u16()?;
32
33 let string_offset = reader.read_u16()?;
36
37 table.records.reserve(num_records as usize);
40 for _ in 0..num_records {
41 let platform_id = reader.read_u16()?.into();
42 let encoding_id = reader.read_u16()?;
43 let language_id = reader.read_u16()?;
44 let name_id = reader.read_u16()?.into();
45 let length = reader.read_u16()?;
46 let offset = reader.read_u16()?;
47
48 let mut name_reader = reader.clone();
50 name_reader.advance_to(string_offset as usize + offset as usize)?;
51 let name = name_reader.read(length as usize)?;
52 let name = name.decode(platform_id, encoding_id);
53
54 debug_msg!(
55 " Name record: {platform_id:?}::{encoding_id}::{language_id}::{name_id:?} = {name}"
56 );
57
58 table.records.push(NameRecord {
59 platform_id,
60 encoding_id,
61 language_id,
62 name_id,
63 name,
64 });
65 }
66
67 Ok(table)
68 }
69}
70
71#[allow(missing_docs)]
73#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
74#[repr(u16)]
75pub enum NameKind {
76 CopyrightNotice = 0,
77 FontFamily = 1,
78 FontSubfamily = 2,
79 UniqueIdentifier = 3,
80 FullFontName = 4,
81 NameTableVersion = 5,
82 PostscriptName = 6,
83 Trademark = 7,
84 Manufacturer = 8,
85 Designer = 9,
86 Description = 10,
87 VendorUrl = 11,
88 DesignerUrl = 12,
89 LicenseDescription = 13,
90 LicenseInfoUrl = 14,
91
92 PreferredFamily = 16,
93 PreferredSubfamily = 17,
94 CompatibleFull = 18,
95
96 SampleText = 19,
97
98 PostscriptCid = 20,
99 WwsFamily = 21,
100 WwsSubfamily = 22,
101 LightBackgroundPalette = 23,
102 DarkBackgroundPalette = 24,
103 VariationsPostscriptNamePrefix = 25,
104
105 Other = 0xFFFF,
106}
107impl From<u16> for NameKind {
108 fn from(value: u16) -> Self {
109 match value {
110 0 => Self::CopyrightNotice,
111 1 => Self::FontFamily,
112 2 => Self::FontSubfamily,
113 3 => Self::UniqueIdentifier,
114 4 => Self::FullFontName,
115 5 => Self::NameTableVersion,
116 6 => Self::PostscriptName,
117 7 => Self::Trademark,
118 8 => Self::Manufacturer,
119 9 => Self::Designer,
120 10 => Self::Description,
121 11 => Self::VendorUrl,
122 12 => Self::DesignerUrl,
123 13 => Self::LicenseDescription,
124 14 => Self::LicenseInfoUrl,
125 16 => Self::PreferredFamily,
126 17 => Self::PreferredSubfamily,
127 18 => Self::CompatibleFull,
128 19 => Self::SampleText,
129 20 => Self::PostscriptCid,
130 21 => Self::WwsFamily,
131 22 => Self::WwsSubfamily,
132 23 => Self::LightBackgroundPalette,
133 24 => Self::DarkBackgroundPalette,
134 25 => Self::VariationsPostscriptNamePrefix,
135 _ => Self::Other,
136 }
137 }
138}
139
140pub trait StringDecoderExt {
142 fn decode(&self, platform_id: PlatformType, encoding_id: u16) -> String;
144}
145impl StringDecoderExt for [u8] {
146 fn decode(&self, platform_id: PlatformType, encoding_id: u16) -> String {
147 match (platform_id, encoding_id) {
148 (PlatformType::Unicode, _) | (PlatformType::Microsoft, 1 | 10) => {
151 let words = self
152 .chunks_exact(2)
153 .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]));
154 String::from_utf16_lossy(&words.collect::<Vec<u16>>())
155 }
156
157 (PlatformType::Macintosh, 0) => {
158 let (s, _, _) = encoding_rs::MACINTOSH.decode(self);
159 s.to_string()
160 }
161
162 _ => format!("UNSUPPORTED_STRING::{platform_id:?}::{encoding_id}"),
163 }
164 }
165}