dmidecode/structures/
013_bios_language.rs

1//! BIOS Language Information (Type 13)
2//!
3//! The information in this structure defines the installable language attributes of the BIOS.
4
5use crate::bitfield::{BitField, FlagType, Layout};
6use crate::{MalformedStructureError, RawStructure};
7
8/// The `BIOS Language Information` table defined in the SMBIOS specification.
9#[derive(Clone, Debug, Eq, Hash, PartialEq)]
10pub struct BiosLanguage<'a> {
11    /// Specifies the structure’s handle
12    pub handle: u16,
13    /// Available languages
14    pub installable_languages: InstallableLanguages<'a>,
15    /// Flags
16    pub flags: Option<LanguageFlags>,
17    /// String number (one-based) of the currently installed language
18    pub current_language: u8,
19}
20
21/// An iterator through available languages. Each available language has a description string.
22#[derive(Clone, Debug, Eq, Hash, PartialEq)]
23pub struct InstallableLanguages<'a> {
24    structure: RawStructure<'a>,
25    index: u8,
26}
27
28/// BIOS Language flags
29#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
30pub struct LanguageFlags(u8);
31
32impl<'a> BiosLanguage<'a> {
33    pub(crate) fn try_from(structure: RawStructure<'a>) -> Result<BiosLanguage<'a>, MalformedStructureError> {
34        #[repr(C)]
35        #[repr(packed)]
36        struct BiosLanguagePacked2_1 {
37            installable_languages: u8,
38            flags: u8,
39            reserved: [u8; 15],
40            current_language: u8,
41        }
42
43        #[repr(C)]
44        #[repr(packed)]
45        struct BiosLanguagePacked2_0 {
46            installable_languages: u8,
47            reserved: [u8; 15],
48            current_language: u8,
49        }
50
51        match structure.version {
52            v if v >= (2, 1).into() => {
53                let_as_struct!(packed, BiosLanguagePacked2_1, structure.data);
54                Ok(BiosLanguage {
55                    handle: structure.handle,
56                    installable_languages: InstallableLanguages::new(structure),
57                    flags: Some(LanguageFlags(packed.flags)),
58                    current_language: packed.current_language,
59                })
60            }
61            _ => {
62                let_as_struct!(packed, BiosLanguagePacked2_0, structure.data);
63                Ok(BiosLanguage {
64                    handle: structure.handle,
65                    installable_languages: InstallableLanguages::new(structure),
66                    flags: None,
67                    current_language: packed.current_language,
68                })
69            }
70        }
71    }
72}
73
74impl<'a> InstallableLanguages<'a> {
75    fn new(structure: RawStructure<'a>) -> Self {
76        // String number is one-based
77        Self { structure, index: 1 }
78    }
79}
80impl<'a> Iterator for InstallableLanguages<'a> {
81    type Item = &'a str;
82    fn next(&mut self) -> Option<Self::Item> {
83        let index = self.index;
84        self.index += 1;
85        self.structure.find_string(index).ok()
86    }
87}
88
89impl BitField<'_> for LanguageFlags {
90    type Size = u8;
91    fn value(&self) -> Self::Size {
92        self.0
93    }
94    layout!(
95        length = 8;
96        "Current Language strings use the abbreviated format"
97            "If the bit is 0, each language string is in the form “ISO 639-1 Language Name | ISO \
98            3166-1-alpha-2 Territory Name | Encoding Method”.\nIf the bit is 1, each language \
99            string consists of the two-character “ISO 639-1 Language Name” directly followed by the \
100            two-character “ISO 3166-1-alpha-2 Territory Name”.",
101        "Reserved": 7,
102    );
103}
104
105#[cfg(test)]
106mod tests {
107    use std::{prelude::v1::*, sync::OnceLock};
108
109    use pretty_assertions::assert_eq;
110
111    use super::*;
112
113    const DMIDECODE_BIN: &[u8] = include_bytes!("../../tests/data/dmi.0.bin");
114
115    fn entrypoint() -> &'static crate::EntryPoint {
116        static ENTRYPOINT: OnceLock<crate::EntryPoint> = OnceLock::new();
117        ENTRYPOINT.get_or_init(|| crate::EntryPoint::search(DMIDECODE_BIN).unwrap())
118    }
119
120    #[test]
121    fn installable_languages() {
122        use crate::InfoType;
123        let sample = vec![
124            "en|US|iso8859-1",
125            "fr|FR|iso8859-1",
126            "es|ES|iso8859-1",
127            "de|DE|iso8859-1",
128            "it|IT|iso8859-1",
129            "da|DK|iso8859-1",
130            "fi|FI|iso8859-1",
131            "nl|NL|iso8859-1",
132            "no|NO|iso8859-1",
133            "pt|PT|iso8859-1",
134            "sv|SE|iso8859-1",
135            "ja|JP|unicode",
136            "zh|CN|unicode",
137        ];
138        let structure = RawStructure {
139            version: (0, 0).into(),
140            info: InfoType::BiosLanguage,
141            length: 0x1A,
142            handle: 0,
143            data: &[],
144            strings: &[
145                // "en|US|iso8859-1"
146                0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
147                0x00, // "fr|FR|iso8859-1"
148                0x66, 0x72, 0x7C, 0x46, 0x52, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
149                0x00, // "es|ES|iso8859-1"
150                0x65, 0x73, 0x7C, 0x45, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
151                0x00, // "de|DE|iso8859-1"
152                0x64, 0x65, 0x7C, 0x44, 0x45, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
153                0x00, // "it|IT|iso8859-1"
154                0x69, 0x74, 0x7C, 0x49, 0x54, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
155                0x00, // "da|DK|iso8859-1"
156                0x64, 0x61, 0x7C, 0x44, 0x4B, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
157                0x00, // "fi|FI|iso8859-1"
158                0x66, 0x69, 0x7C, 0x46, 0x49, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
159                0x00, // "nl|NL|iso8859-1"
160                0x6E, 0x6C, 0x7C, 0x4E, 0x4C, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
161                0x00, // "no|NO|iso8859-1"
162                0x6E, 0x6F, 0x7C, 0x4E, 0x4F, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
163                0x00, // "pt|PT|iso8859-1"
164                0x70, 0x74, 0x7C, 0x50, 0x54, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
165                0x00, // "sv|SE|iso8859-1"
166                0x73, 0x76, 0x7C, 0x53, 0x45, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
167                0x00, // "ja|JP|unicode"
168                0x6A, 0x61, 0x7C, 0x4A, 0x50, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00,
169                // "zh|CN|unicode"
170                0x7A, 0x68, 0x7C, 0x43, 0x4E, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00,
171            ],
172        };
173        let result = InstallableLanguages::new(structure);
174        assert_eq!(sample, result.collect::<Vec<_>>(), "Installable language list");
175    }
176
177    #[test]
178    fn dmi_bin() {
179        use crate::InfoType;
180        let bios_language_result = entrypoint()
181            .structures(&DMIDECODE_BIN[(entrypoint().smbios_address() as usize)..])
182            .find_map(|s| {
183                if let Ok(crate::Structure::BiosLanguage(bl)) = s {
184                    Some(bl)
185                } else {
186                    None
187                }
188            })
189            .unwrap();
190        let bios_language_sample = BiosLanguage {
191            handle: 0x0D00,
192            installable_languages: InstallableLanguages::new(RawStructure {
193                version: (3, 2).into(),
194                info: InfoType::BiosLanguage,
195                length: 0x16,
196                handle: 0x0D00,
197                data: &[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
198                strings: &[
199                    0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31, 0x00,
200                    0x00,
201                ],
202            }),
203            flags: Some(LanguageFlags([].iter().collect())),
204            current_language: 1,
205        };
206        assert_eq!(bios_language_sample, bios_language_result, "BIOS language structure");
207    }
208}