1use crate::{
2 platform::{EncodingError, EncodingId, PlatformId},
3 tables::{Table, TableDirectory, TableError},
4 types::{Offset16, Tag, tags, uint16},
5 util::custom_iterator,
6};
7use std::{borrow::Cow, bstr::ByteStr};
8
9#[repr(C)]
10pub struct NameV0 {
11 pub version: uint16,
13 pub count: uint16,
14 pub storage_offset: Offset16,
15 name_records: [NameRecordRaw; 0],
16}
17#[repr(C)]
18pub struct NameV1 {
19 v0: NameV0,
20 }
24
25const impl std::ops::Deref for NameV1 {
26 type Target = NameV0;
27 fn deref(&self) -> &Self::Target {
28 &self.v0
29 }
30}
31
32#[repr(C)]
33pub struct NameRecordRaw {
34 pub platform_id: uint16,
35 pub encoding_id: uint16,
36 pub language_id: uint16,
37 pub name_id: uint16,
38 pub length: uint16,
39 pub string_offset: Offset16,
40}
41#[repr(C)]
42pub struct LangTagRecordRaw {
43 pub length: uint16,
44 pub lang_tag_offset: Offset16,
45}
46
47impl<'a> Table<'a> for Name<'a> {
48 const TAG: Tag = tags::name;
49 fn new_in(dir: &'a TableDirectory) -> Result<Self, TableError> {
50 let rec = dir.table_record(Self::TAG).ok_or(TableError::NotFound)?;
51 let v0 = rec.raw_as::<NameV0>().ok_or(TableError::InvalidLen)?;
52
53 let mut required_len =
54 size_of::<NameV0>() + v0.count.get() as usize * size_of::<NameRecordRaw>();
55 if (rec.length.get() as usize) < required_len {
57 return Err(TableError::InvalidLen);
58 }
59
60 let storage_offset = v0.storage_offset.get() as u32;
61
62 for name in v0.name_records() {
64 let offset = (name.string_offset.get() as u32) + (name.length.get() as u32);
65 if rec.length.get() < storage_offset + offset {
66 return Err(TableError::InvalidLen);
67 }
68 }
69
70 if v0.version.get() >= 1 {
71 required_len += size_of::<uint16>(); if (rec.length.get() as usize) < required_len {
74 return Err(TableError::InvalidLen);
75 }
76
77 let v1 = rec.raw_as::<NameV1>().unwrap();
78 required_len += v1.lang_tag_count().get() as usize * size_of::<LangTagRecordRaw>();
79
80 if (rec.length.get() as usize) < required_len {
82 return Err(TableError::InvalidLen);
83 }
84
85 for tag in v1.lang_tag_records() {
87 let offset = (tag.lang_tag_offset.get() as u32) + (tag.length.get() as u32);
88 if rec.length.get() < storage_offset + offset {
89 return Err(TableError::InvalidLen);
90 }
91 }
92 }
93
94 Ok(Self { name: v0 })
95 }
96}
97
98#[derive(Copy)]
99#[derive_const(Clone)]
100pub struct Name<'a> {
101 name: &'a NameV0,
102}
103
104const impl<'a> std::ops::Deref for Name<'a> {
105 type Target = &'a NameV0;
106 fn deref(&self) -> &Self::Target {
107 &self.name
108 }
109}
110
111impl<'a> Name<'a> {
112 pub const fn version(&self) -> u16 {
113 self.version.get()
114 }
115
116 pub const fn v1(&self) -> Option<&'a NameV1> {
117 if self.version() >= 1 {
118 Some(unsafe { std::mem::transmute::<&NameV0, &NameV1>(self.name) })
119 } else {
120 None
121 }
122 }
123
124 pub const fn names(&self) -> NameRecordsIter<'a> {
125 NameRecordsIter::new(*self)
126 }
127 pub const fn lang_tags(&self) -> LangTagRecordsIter<'a> {
128 LangTagRecordsIter::new(*self)
129 }
130
131 pub const fn lang_tag_count(&self) -> Option<uint16> {
133 Some(self.v1()?.lang_tag_count())
134 }
135 pub const fn lang_tag_records(&self) -> Option<&'a [LangTagRecordRaw]> {
136 Some(self.v1()?.lang_tag_records())
137 }
138}
139
140impl NameV0 {
141 pub const fn name_records(&self) -> &[NameRecordRaw] {
142 unsafe { std::slice::from_raw_parts(self.name_records.as_ptr(), self.count.get() as _) }
143 }
144 pub const fn string_storage(&self) -> &StringStorage {
145 let offset = self.storage_offset.get() as usize;
146 unsafe { &*std::ptr::from_ref(self).byte_add(offset).cast() }
147 }
148}
149
150impl NameV1 {
151 pub const fn lang_tag_count(&self) -> uint16 {
152 unsafe { *self.name_records().as_ptr_range().end.cast::<uint16>() }
153 }
154 pub const fn lang_tag_records(&self) -> &[LangTagRecordRaw] {
155 let len_ptr = self.name_records().as_ptr_range().end.cast::<uint16>();
156 unsafe { std::slice::from_raw_parts(len_ptr.add(1).cast(), (*len_ptr).get() as _) }
157 }
158}
159
160pub struct StringStorage {
161 _dont_instantiate: (),
162}
163
164impl StringStorage {
165 pub const fn as_ptr(&self) -> *const u8 {
166 std::ptr::from_ref(self).cast()
167 }
168 pub(crate) const unsafe fn get(&self, offset: u16, length: u16) -> &[u8] {
169 unsafe { std::slice::from_raw_parts(self.as_ptr().add(offset as _), length as _) }
170 }
171}
172
173#[derive(Copy)]
174#[derive_const(Clone)]
175pub struct NameRecord<'a>(Name<'a>, &'a NameRecordRaw);
176
177#[derive(Copy)]
178#[derive_const(Clone)]
179pub struct LangTagRecord<'a>(Name<'a>, &'a LangTagRecordRaw);
180
181const impl<'a> std::ops::Deref for NameRecord<'a> {
182 type Target = &'a NameRecordRaw;
183 fn deref(&self) -> &Self::Target {
184 &self.1
185 }
186}
187const impl<'a> std::ops::Deref for LangTagRecord<'a> {
188 type Target = &'a LangTagRecordRaw;
189 fn deref(&self) -> &Self::Target {
190 &self.1
191 }
192}
193
194impl<'a> NameRecord<'a> {
195 pub const fn bytes(&self) -> &'a [u8] {
196 unsafe { self.0.string_storage().get(self.1.string_offset.get(), self.1.length.get()) }
197 }
198 pub fn string(&self) -> Result<String, EncodingError> {
199 let encoding = EncodingId::new(self.1.platform_id.get(), self.1.encoding_id.get())?;
200 encoding.decode_utf16be(self.bytes())
201 }
202}
203
204impl<'a> LangTagRecord<'a> {
205 pub const fn bytes(&self) -> &'a [u8] {
206 unsafe { self.0.string_storage().get(self.1.lang_tag_offset.get(), self.1.length.get()) }
207 }
208 pub fn string(&self) -> String {
209 String::from_utf16be_lossy(self.bytes())
211 }
212}
213
214#[derive(Clone)]
216pub struct NameRecordsIter<'a> {
217 table: Name<'a>,
218 inner: std::slice::Iter<'a, NameRecordRaw>,
219}
220impl<'a> NameRecordsIter<'a> {
221 pub const fn new(table: Name<'a>) -> Self {
222 Self { table, inner: table.name_records().iter() }
223 }
224 pub fn as_records(&self) -> &'a [NameRecordRaw] {
226 self.inner.as_slice()
227 }
228}
229custom_iterator!(NameRecordsIter<'a> as this {
230 type Item = NameRecord<'a>;
231 map: |x| NameRecord(this.table, x);
232});
233
234#[derive(Clone)]
236pub struct LangTagRecordsIter<'a> {
237 table: Name<'a>,
238 inner: std::slice::Iter<'a, LangTagRecordRaw>,
239}
240impl<'a> LangTagRecordsIter<'a> {
241 pub const fn new(table: Name<'a>) -> Self {
242 Self { table, inner: table.lang_tag_records().unwrap_or(&[]).iter() }
243 }
244 pub fn as_records(&self) -> &'a [LangTagRecordRaw] {
246 self.inner.as_slice()
247 }
248}
249custom_iterator!(LangTagRecordsIter<'a> as this {
250 type Item = LangTagRecord<'a>;
251 map: |x| LangTagRecord(this.table, x);
252});
253
254impl std::fmt::Debug for Name<'_> {
255 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
256 let mut f = f.debug_struct("NameTable");
257
258 f.field("version", &self.version.get())
259 .field("count", &self.count.get())
260 .field_with("storage_offset", |f| write!(f, "{:#06X}", self.storage_offset))
261 .field_with("name_records", |f| f.debug_list().entries(self.names()).finish());
262
263 if let Some(v1) = self.v1() {
264 f.field("lang_tag_count", &v1.lang_tag_records().len());
265 f.field_with("lang_tag_records", |f| f.debug_list().entries(self.lang_tags()).finish());
266 }
267
268 f.finish()
269 }
270}
271
272impl std::fmt::Debug for NameV0 {
274 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
275 Name { name: self }.fmt(f)
276 }
277}
278impl std::fmt::Debug for NameV1 {
279 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
280 Name { name: self }.fmt(f)
281 }
282}
283
284impl std::fmt::Debug for NameRecord<'_> {
285 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
286 let Self(name, rec) = *self;
287
288 let value = self.string().map_err(|err| (err, ByteStr::new(self.bytes())));
289
290 let plat_id = PlatformId::new(rec.platform_id.get());
291 let plat_name = plat_id.map_or("Unknown", |x| x.name());
292
293 let enc_id = plat_id.and_then(|x| x.encoding(rec.encoding_id.get()));
294 let enc_name = enc_id.map_or(Cow::Borrowed("Unknown"), |x| x.name());
295
296 let lang_id = plat_id.and_then(|x| x.language(rec.language_id.get()));
297 let lang_name = format!(
298 "{}: {}",
299 lang_id.and_then(|x| x.tag(Some(name))).unwrap_or(Cow::Borrowed("und")),
300 lang_id.and_then(|x| x.english_name(Some(name))).unwrap_or(Cow::Borrowed("Unknown")),
301 );
302
303 f.debug_struct("NameRecord")
304 .field_with("platform_id", |f| write!(f, "{} ({})", rec.platform_id, plat_name))
305 .field_with("encoding_id", |f| write!(f, "{} ({})", rec.encoding_id, enc_name))
306 .field_with("language_id", |f| write!(f, "{:#06X} ({})", rec.language_id, lang_name))
307 .field("name_id", &rec.name_id.get())
309 .field("length", &rec.length.get())
310 .field_with("string_offset", |f| write!(f, "{:#06X}", rec.string_offset))
311 .field_with("value", |f| {
312 let mut f = f.with_options(*f.options().alternate(false));
313 value.fmt(&mut f)
314 })
315 .finish()
316 }
317}
318
319impl std::fmt::Debug for LangTagRecord<'_> {
320 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
321 let Self(_, rec) = *self;
322
323 f.debug_struct("LangTagRecord")
324 .field("length", &rec.length.get())
325 .field_with("lang_tag_offset", |f| write!(f, "{:#06X}", rec.lang_tag_offset))
326 .field_with("value", |f| {
327 let mut f = f.with_options(*f.options().alternate(false));
328 self.string().fmt(&mut f)
329 })
330 .finish()
331 }
332}