1 // This module defines the `ComponentName1` type and marks it deprecated. That
2 // causes warnings for uses within this module (e.g. the `impl ComponentName1`
3 // block), so turn off deprecated warnings. It's not yet possible to make this
4 // allow more fine-grained, see https://github.com/rust-lang/rust/issues/62398.
5 #![allow(deprecated)]
6
7 use crate::boot::{self, ScopedProtocol};
8 use crate::proto::unsafe_protocol;
9 use crate::{CStr16, Error, Handle, Result, Status, StatusExt};
10 use core::fmt::{self, Debug, Display, Formatter};
11 use core::{ptr, slice};
12 use uefi_raw::protocol::driver::ComponentName2Protocol;
13
14 /// Protocol that provides human-readable names for a driver and for each of the
15 /// controllers that the driver is managing.
16 ///
17 /// This protocol was deprecated in UEFI 2.1 in favor of the new
18 /// [`ComponentName2`] protocol. The two protocols are identical except the
19 /// encoding of supported languages changed from [ISO 639-2] to [RFC 4646]. The
20 /// [`ComponentName`] wrapper can be used to automatically select
21 /// [`ComponentName2`] if available, and otherwise fall back to
22 /// [`ComponentName1`].
23 ///
24 /// The corresponding C type is `EFI_COMPONENT_NAME_PROTOCOL`.
25 ///
26 /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
27 /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646
28 #[deprecated = "deprecated in UEFI 2.1; use ComponentName2 where possible"]
29 #[unsafe_protocol(ComponentName2Protocol::DEPRECATED_COMPONENT_NAME_GUID)]
30 #[derive(Debug)]
31 #[repr(transparent)]
32 pub struct ComponentName1(
33 // The layout of the protocol is the same as ComponentName2, only the format
34 // of the language string changed.
35 ComponentName2Protocol,
36 );
37
38 impl ComponentName1 {
39 /// Get an iterator over supported languages. Each language is identified by
40 /// a three-letter ASCII string specified in [ISO 639-2]. For example,
41 /// English is encoded as "eng".
42 ///
43 /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError>44 pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
45 LanguageIter::new(self.0.supported_languages, LanguageIterKind::V1)
46 }
47
48 /// Get the human-readable name of the driver in the given language.
49 ///
50 /// `language` must be one of the languages returned by [`supported_languages`].
51 ///
52 /// [`supported_languages`]: Self::supported_languages
driver_name(&self, language: &str) -> Result<&CStr16>53 pub fn driver_name(&self, language: &str) -> Result<&CStr16> {
54 let language = language_to_cstr(language)?;
55 let mut driver_name = ptr::null();
56 unsafe { (self.0.get_driver_name)(&self.0, language.as_ptr(), &mut driver_name) }
57 .to_result_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) })
58 }
59
60 /// Get the human-readable name of a controller in the given language.
61 ///
62 /// `language` must be one of the languages returned by [`supported_languages`].
63 ///
64 /// [`supported_languages`]: Self::supported_languages
controller_name( &self, controller_handle: Handle, child_handle: Option<Handle>, language: &str, ) -> Result<&CStr16>65 pub fn controller_name(
66 &self,
67 controller_handle: Handle,
68 child_handle: Option<Handle>,
69 language: &str,
70 ) -> Result<&CStr16> {
71 let language = language_to_cstr(language)?;
72 let mut driver_name = ptr::null();
73 unsafe {
74 (self.0.get_controller_name)(
75 &self.0,
76 controller_handle.as_ptr(),
77 Handle::opt_to_ptr(child_handle),
78 language.as_ptr(),
79 &mut driver_name,
80 )
81 }
82 .to_result_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) })
83 }
84 }
85
86 /// Protocol that provides human-readable names for a driver and for each of the
87 /// controllers that the driver is managing.
88 ///
89 /// This protocol was introduced in UEFI 2.1 to replace the now-deprecated
90 /// [`ComponentName1`] protocol. The two protocols are identical except the
91 /// encoding of supported languages changed from [ISO 639-2] to [RFC 4646]. The
92 /// [`ComponentName`] wrapper can be used to automatically select
93 /// [`ComponentName2`] if available, and otherwise fall back to
94 /// [`ComponentName1`].
95 ///
96 /// The corresponding C type is `EFI_COMPONENT_NAME2_PROTOCOL`.
97 ///
98 /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
99 /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646
100 #[unsafe_protocol(ComponentName2Protocol::GUID)]
101 #[derive(Debug)]
102 #[repr(transparent)]
103 pub struct ComponentName2(ComponentName2Protocol);
104
105 impl ComponentName2 {
106 /// Get an iterator over supported languages. Each language is identified by
107 /// an ASCII string specified in [RFC 4646]. For example, English is encoded
108 /// as "en".
109 ///
110 /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646
supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError>111 pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
112 LanguageIter::new(self.0.supported_languages, LanguageIterKind::V2)
113 }
114
115 /// Get the human-readable name of the driver in the given language.
116 ///
117 /// `language` must be one of the languages returned by [`supported_languages`].
118 ///
119 /// [`supported_languages`]: Self::supported_languages
driver_name(&self, language: &str) -> Result<&CStr16>120 pub fn driver_name(&self, language: &str) -> Result<&CStr16> {
121 let language = language_to_cstr(language)?;
122 let mut driver_name = ptr::null();
123 unsafe { (self.0.get_driver_name)(&self.0, language.as_ptr(), &mut driver_name) }
124 .to_result_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) })
125 }
126
127 /// Get the human-readable name of a controller in the given language.
128 ///
129 /// `language` must be one of the languages returned by [`supported_languages`].
130 ///
131 /// [`supported_languages`]: Self::supported_languages
controller_name( &self, controller_handle: Handle, child_handle: Option<Handle>, language: &str, ) -> Result<&CStr16>132 pub fn controller_name(
133 &self,
134 controller_handle: Handle,
135 child_handle: Option<Handle>,
136 language: &str,
137 ) -> Result<&CStr16> {
138 let language = language_to_cstr(language)?;
139 let mut driver_name = ptr::null();
140 unsafe {
141 (self.0.get_controller_name)(
142 &self.0,
143 controller_handle.as_ptr(),
144 Handle::opt_to_ptr(child_handle),
145 language.as_ptr(),
146 &mut driver_name,
147 )
148 }
149 .to_result_with_val(|| unsafe { CStr16::from_ptr(driver_name.cast()) })
150 }
151 }
152
153 /// Wrapper around [`ComponentName1`] and [`ComponentName2`]. This will use
154 /// [`ComponentName2`] if available, otherwise it will back to
155 /// [`ComponentName1`].
156 pub enum ComponentName {
157 /// Opened [`ComponentName1`] protocol.
158 V1(ScopedProtocol<ComponentName1>),
159
160 /// Opened [`ComponentName2`] protocol.
161 V2(ScopedProtocol<ComponentName2>),
162 }
163
164 impl ComponentName {
165 /// Open the [`ComponentName2`] protocol if available, otherwise fall back to
166 /// [`ComponentName1`].
open(handle: Handle) -> Result<Self>167 pub fn open(handle: Handle) -> Result<Self> {
168 if let Ok(cn2) = boot::open_protocol_exclusive::<ComponentName2>(handle) {
169 Ok(Self::V2(cn2))
170 } else {
171 Ok(Self::V1(boot::open_protocol_exclusive::<ComponentName1>(
172 handle,
173 )?))
174 }
175 }
176
177 /// Get an iterator over supported languages. Each language is identified by
178 /// an ASCII string. If the opened protocol is [`ComponentName1`] this will
179 /// be an [ISO 639-2] string. If the opened protocol is [`ComponentName2`]
180 /// it will be an [RFC 4646] string. For example, English is encoded as
181 /// "eng" in ISO 639-2, and "en" in RFC 4646.
182 ///
183 /// [ISO 639-2]: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
184 /// [RFC 4646]: https://www.rfc-editor.org/rfc/rfc4646
supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError>185 pub fn supported_languages(&self) -> core::result::Result<LanguageIter, LanguageError> {
186 match self {
187 Self::V1(cn1) => cn1.supported_languages(),
188 Self::V2(cn2) => cn2.supported_languages(),
189 }
190 }
191
192 /// Get the human-readable name of the driver in the given language.
193 ///
194 /// `language` must be one of the languages returned by [`supported_languages`].
195 ///
196 /// [`supported_languages`]: Self::supported_languages
driver_name(&self, language: &str) -> Result<&CStr16>197 pub fn driver_name(&self, language: &str) -> Result<&CStr16> {
198 match self {
199 Self::V1(cn1) => cn1.driver_name(language),
200 Self::V2(cn2) => cn2.driver_name(language),
201 }
202 }
203
204 /// Get the human-readable name of a controller in the given language.
205 ///
206 /// `language` must be one of the languages returned by [`supported_languages`].
207 ///
208 /// [`supported_languages`]: Self::supported_languages
controller_name( &self, controller_handle: Handle, child_handle: Option<Handle>, language: &str, ) -> Result<&CStr16>209 pub fn controller_name(
210 &self,
211 controller_handle: Handle,
212 child_handle: Option<Handle>,
213 language: &str,
214 ) -> Result<&CStr16> {
215 match self {
216 Self::V1(cn1) => cn1.controller_name(controller_handle, child_handle, language),
217 Self::V2(cn2) => cn2.controller_name(controller_handle, child_handle, language),
218 }
219 }
220 }
221
222 impl Debug for ComponentName {
fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result223 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
224 match self {
225 Self::V1(_) => f.debug_tuple("V1").finish(),
226 Self::V2(_) => f.debug_tuple("V2").finish(),
227 }
228 }
229 }
230
231 /// Error returned by [`ComponentName1::supported_languages`] and
232 /// [`ComponentName2::supported_languages`].
233 #[derive(Debug, Eq, PartialEq)]
234 pub enum LanguageError {
235 /// The supported languages list contains a non-ASCII character at the
236 /// specified index.
237 Ascii {
238 /// Index of the invalid character.
239 index: usize,
240 },
241 }
242
243 impl Display for LanguageError {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result244 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
245 match self {
246 Self::Ascii { index } => write!(f, "invalid character at index: {}", index),
247 }
248 }
249 }
250
251 #[cfg(feature = "unstable")]
252 impl core::error::Error for LanguageError {}
253
254 #[derive(Debug, PartialEq)]
255 enum LanguageIterKind {
256 V1,
257 V2,
258 }
259
260 /// Iterator returned by [`ComponentName1::supported_languages`] and
261 /// [`ComponentName2::supported_languages`].
262 #[derive(Debug)]
263 pub struct LanguageIter<'a> {
264 languages: &'a [u8],
265 kind: LanguageIterKind,
266 }
267
268 impl<'a> LanguageIter<'a> {
new( languages: *const u8, kind: LanguageIterKind, ) -> core::result::Result<Self, LanguageError>269 fn new(
270 languages: *const u8,
271 kind: LanguageIterKind,
272 ) -> core::result::Result<Self, LanguageError> {
273 let mut index = 0;
274 loop {
275 let c = unsafe { languages.add(index).read() };
276 if c == 0 {
277 break;
278 } else if !c.is_ascii() {
279 return Err(LanguageError::Ascii { index });
280 } else {
281 index += 1;
282 }
283 }
284
285 Ok(Self {
286 languages: unsafe { slice::from_raw_parts(languages, index) },
287 kind,
288 })
289 }
290 }
291
292 impl<'a> Iterator for LanguageIter<'a> {
293 type Item = &'a str;
294
next(&mut self) -> Option<Self::Item>295 fn next(&mut self) -> Option<Self::Item> {
296 if self.languages.is_empty() {
297 return None;
298 }
299
300 let lang;
301 match self.kind {
302 LanguageIterKind::V1 => {
303 if self.languages.len() <= 3 {
304 lang = self.languages;
305 self.languages = &[];
306 } else {
307 lang = &self.languages[..3];
308 self.languages = &self.languages[3..];
309 }
310 }
311 LanguageIterKind::V2 => {
312 if let Some(index) = self.languages.iter().position(|c| *c == b';') {
313 lang = &self.languages[..index];
314 self.languages = &self.languages[index + 1..];
315 } else {
316 lang = self.languages;
317 self.languages = &[];
318 }
319 }
320 }
321
322 // OK to unwrap because we already checked the string is ASCII.
323 Some(core::str::from_utf8(lang).unwrap())
324 }
325 }
326
327 /// Statically-sized buffer used to convert a `str` to a null-terminated C
328 /// string. The buffer should be at least 42 characters per
329 /// <https://www.rfc-editor.org/rfc/rfc4646#section-4.3.1>, plus one for the
330 /// null terminator. Round up to 64 bytes just for aesthetics.
331 type LanguageCStr = [u8; 64];
332
language_to_cstr(language: &str) -> Result<LanguageCStr>333 fn language_to_cstr(language: &str) -> Result<LanguageCStr> {
334 let mut lang_cstr: LanguageCStr = [0; 64];
335 // Ensure there's room for a null-terminator.
336 if language.len() >= lang_cstr.len() - 1 {
337 return Err(Error::from(Status::BUFFER_TOO_SMALL));
338 }
339 lang_cstr[..language.len()].copy_from_slice(language.as_bytes());
340 // Assert that it's null-terminated.
341 assert_eq!(*lang_cstr.last().unwrap(), 0);
342 Ok(lang_cstr)
343 }
344
345 #[cfg(test)]
346 mod tests {
347 use super::*;
348 use alloc::vec::Vec;
349 use LanguageIterKind::{V1, V2};
350
351 #[test]
test_language_iter_v1()352 fn test_language_iter_v1() {
353 // Empty string.
354 let data = "\0";
355 assert!(LanguageIter::new(data.as_ptr(), V1)
356 .unwrap()
357 .next()
358 .is_none());
359
360 // Two languages.
361 let data = "engfra\0";
362 assert_eq!(
363 LanguageIter::new(data.as_ptr(), V1)
364 .unwrap()
365 .collect::<Vec<_>>(),
366 ["eng", "fra"]
367 );
368
369 // Truncated data.
370 let data = "en\0";
371 assert_eq!(
372 LanguageIter::new(data.as_ptr(), V1)
373 .unwrap()
374 .collect::<Vec<_>>(),
375 ["en"]
376 );
377
378 // Non-ASCII.
379 let data = "engæ\0";
380 assert_eq!(
381 LanguageIter::new(data.as_ptr(), V1).err().unwrap(),
382 LanguageError::Ascii { index: 3 },
383 );
384 }
385
386 #[test]
test_language_iter_v2()387 fn test_language_iter_v2() {
388 // Empty string.
389 let data = "\0";
390 assert!(LanguageIter::new(data.as_ptr(), V2)
391 .unwrap()
392 .next()
393 .is_none());
394
395 // Two languages.
396 let data = "en;fr\0";
397 assert_eq!(
398 LanguageIter::new(data.as_ptr(), V2)
399 .unwrap()
400 .collect::<Vec<_>>(),
401 ["en", "fr"]
402 );
403
404 // Non-ASCII.
405 let data = "engæ\0";
406 assert_eq!(
407 LanguageIter::new(data.as_ptr(), V2).err().unwrap(),
408 LanguageError::Ascii { index: 3 },
409 );
410 }
411
412 #[test]
test_language_to_cstr()413 fn test_language_to_cstr() {
414 let mut expected = [0; 64];
415 expected[0] = b'e';
416 expected[1] = b'n';
417 assert_eq!(language_to_cstr("en"), Ok(expected));
418
419 assert_eq!(
420 language_to_cstr(
421 "0123456789012345678901234567890123456789012345678901234567890123456789"
422 )
423 .err()
424 .unwrap()
425 .status(),
426 Status::BUFFER_TOO_SMALL
427 );
428 }
429 }
430