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