1use crate::{
2 platform::{EncodingError, EncodingId, PlatformId},
3 types::{Offset16, Tag, tags, uint16},
4 util::iterator_map,
5};
6use std::{borrow::Cow, bstr::ByteStr};
7
8#[repr(C)]
9#[non_exhaustive]
10pub struct NameTableRepr {
11 pub version: uint16,
13 pub count: uint16,
14 pub storage_offset: Offset16,
15 name_records: [NameRecordRepr; 0],
16 }
20#[repr(C)]
21pub struct NameRecordRepr {
22 pub platform_id: uint16,
23 pub encoding_id: uint16,
24 pub language_id: uint16,
25 pub name_id: uint16,
26 pub length: uint16,
27 pub string_offset: Offset16,
28}
29#[repr(C)]
30pub struct LangTagRecordRepr {
31 pub length: uint16,
32 pub lang_tag_offset: Offset16,
33}
34
35impl super::Table for NameTableRepr {
36 const TAG: Tag = tags::name;
37 type Handle<'a> = &'a Self;
38}
39
40impl NameTableRepr {
41 pub const fn name_records(&self) -> &[NameRecordRepr] {
42 unsafe { std::slice::from_raw_parts(self.name_records.as_ptr(), self.count.get() as _) }
43 }
44 pub const fn names(&self) -> NamesIter<'_> {
45 NamesIter::new(self)
46 }
47
48 pub const fn lang_tag_records(&self) -> &[LangTagRecordRepr] {
52 if self.version.get() == 0 {
53 return &[];
54 }
55 let len_ptr = self.name_records().as_ptr_range().end.cast::<uint16>();
56 unsafe { std::slice::from_raw_parts(len_ptr.add(1).cast(), (*len_ptr).get() as _) }
57 }
58 pub const fn lang_tags(&self) -> LangTagsIter<'_> {
59 LangTagsIter::new(self)
60 }
61
62 pub const fn string_storage(&self) -> &StringStorage {
63 let offset = self.storage_offset.get() as usize;
64 unsafe { &*std::ptr::from_ref(self).byte_add(offset).cast() }
65 }
66}
67
68#[non_exhaustive]
69pub struct StringStorage {}
70
71impl StringStorage {
72 pub const fn as_ptr(&self) -> *const u8 {
73 std::ptr::from_ref(self).cast()
74 }
75 pub(crate) const unsafe fn get(&self, offset: u16, length: u16) -> &[u8] {
76 unsafe { std::slice::from_raw_parts(self.as_ptr().add(offset as _), length as _) }
77 }
78}
79
80#[derive(Copy)]
81#[derive_const(Clone)]
82pub struct NameHandle<'a>(&'a NameTableRepr, &'a NameRecordRepr);
83
84#[derive(Copy)]
85#[derive_const(Clone)]
86pub struct LangTagHandle<'a>(&'a NameTableRepr, &'a LangTagRecordRepr);
87
88const impl std::ops::Deref for NameHandle<'_> {
89 type Target = NameRecordRepr;
90 fn deref(&self) -> &Self::Target {
91 self.1
92 }
93}
94const impl std::ops::Deref for LangTagHandle<'_> {
95 type Target = LangTagRecordRepr;
96 fn deref(&self) -> &Self::Target {
97 self.1
98 }
99}
100
101impl<'a> NameHandle<'a> {
102 pub const fn bytes(&self) -> &'a [u8] {
103 unsafe { self.0.string_storage().get(self.1.string_offset.get(), self.1.length.get()) }
104 }
105 pub fn string(&self) -> Result<String, EncodingError> {
106 let encoding = EncodingId::new(self.1.platform_id.get(), self.1.encoding_id.get())?;
107 encoding.decode_utf16be(self.bytes())
108 }
109}
110
111impl<'a> LangTagHandle<'a> {
112 pub const fn bytes(&self) -> &'a [u8] {
113 unsafe { self.0.string_storage().get(self.1.lang_tag_offset.get(), self.1.length.get()) }
114 }
115 pub fn string(&self) -> String {
116 String::from_utf16be_lossy(self.bytes())
118 }
119}
120
121#[derive(Clone)]
123pub struct NamesIter<'a> {
124 table: &'a NameTableRepr,
125 inner: std::slice::Iter<'a, NameRecordRepr>,
126}
127impl<'a> NamesIter<'a> {
128 pub const fn new(table: &'a NameTableRepr) -> Self {
129 Self { table, inner: table.name_records().iter() }
130 }
131 pub fn as_records(&self) -> &'a [NameRecordRepr] {
133 self.inner.as_slice()
134 }
135}
136iterator_map!(NamesIter<'a> {
137 type Item = NameHandle<'a>;
138 |this, x| NameHandle(this.table, x)
139});
140
141#[derive(Clone)]
143pub struct LangTagsIter<'a> {
144 table: &'a NameTableRepr,
145 inner: std::slice::Iter<'a, LangTagRecordRepr>,
146}
147impl<'a> LangTagsIter<'a> {
148 pub const fn new(table: &'a NameTableRepr) -> Self {
149 Self { table, inner: table.lang_tag_records().iter() }
150 }
151 pub fn as_records(&self) -> &'a [LangTagRecordRepr] {
153 self.inner.as_slice()
154 }
155}
156iterator_map!(LangTagsIter<'a> {
157 type Item = LangTagHandle<'a>;
158 |this, x| LangTagHandle(this.table, x)
159});
160
161impl std::fmt::Debug for NameTableRepr {
162 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
163 let mut builder = f.debug_struct("NameTable");
164
165 builder
166 .field("version", &self.version.get())
167 .field("count", &self.count.get())
168 .field_with("storage_offset", |f| write!(f, "{:#06X}", self.storage_offset))
169 .field_with("name_records", |f| f.debug_list().entries(self.names()).finish());
170
171 if self.version.get() != 0 {
172 builder
173 .field("lang_tag_count", &self.lang_tag_records().len())
174 .field_with("lang_tag_records", |f| {
175 f.debug_list().entries(self.lang_tags()).finish()
176 });
177 }
178
179 builder.finish()
180 }
181}
182
183impl std::fmt::Debug for NameHandle<'_> {
184 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
185 let Self(name, rec) = *self;
186
187 let value = self.string().map_err(|err| (err, ByteStr::new(self.bytes())));
188
189 let plat_id = PlatformId::new(rec.platform_id.get());
190 let plat_name = plat_id.map_or("Unknown", |x| x.name());
191
192 let enc_id = plat_id.and_then(|x| x.encoding(rec.encoding_id.get()));
193 let enc_name = enc_id.map_or(Cow::Borrowed("Unknown"), |x| x.name());
194
195 let lang_id = plat_id.and_then(|x| x.language(rec.language_id.get()));
196 let lang_name = format!(
197 "{}: {}",
198 lang_id.and_then(|x| x.tag(Some(name))).unwrap_or(Cow::Borrowed("und")),
199 lang_id.and_then(|x| x.english_name(Some(name))).unwrap_or(Cow::Borrowed("Unknown")),
200 );
201
202 f.debug_struct("NameRecord")
203 .field_with("platform_id", |f| write!(f, "{} ({})", rec.platform_id, plat_name))
204 .field_with("encoding_id", |f| write!(f, "{} ({})", rec.encoding_id, enc_name))
205 .field_with("language_id", |f| write!(f, "{:#06X} ({})", rec.language_id, lang_name))
206 .field("name_id", &rec.name_id.get())
208 .field("length", &rec.length.get())
209 .field_with("string_offset", |f| write!(f, "{:#06X}", rec.string_offset))
210 .field_with("value", |f| {
211 let mut f = f.with_options(*f.options().alternate(false));
212 value.fmt(&mut f)
213 })
214 .finish()
215 }
216}
217
218impl std::fmt::Debug for LangTagHandle<'_> {
219 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
220 let Self(_, rec) = *self;
221
222 f.debug_struct("LangTagRecord")
223 .field("length", &rec.length.get())
224 .field_with("lang_tag_offset", |f| write!(f, "{:#06X}", rec.lang_tag_offset))
225 .field_with("value", |f| {
226 let mut f = f.with_options(*f.options().alternate(false));
227 self.string().fmt(&mut f)
228 })
229 .finish()
230 }
231}