1use crate::bitfield::{BitField, FlagType, Layout};
6use crate::{MalformedStructureError, RawStructure};
7
8#[derive(Clone, Debug, Eq, Hash, PartialEq)]
10pub struct BiosLanguage<'a> {
11 pub handle: u16,
13 pub installable_languages: InstallableLanguages<'a>,
15 pub flags: Option<LanguageFlags>,
17 pub current_language: u8,
19}
20
21#[derive(Clone, Debug, Eq, Hash, PartialEq)]
23pub struct InstallableLanguages<'a> {
24 structure: RawStructure<'a>,
25 index: u8,
26}
27
28#[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 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 0x65, 0x6E, 0x7C, 0x55, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
147 0x00, 0x66, 0x72, 0x7C, 0x46, 0x52, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
149 0x00, 0x65, 0x73, 0x7C, 0x45, 0x53, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
151 0x00, 0x64, 0x65, 0x7C, 0x44, 0x45, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
153 0x00, 0x69, 0x74, 0x7C, 0x49, 0x54, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
155 0x00, 0x64, 0x61, 0x7C, 0x44, 0x4B, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
157 0x00, 0x66, 0x69, 0x7C, 0x46, 0x49, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
159 0x00, 0x6E, 0x6C, 0x7C, 0x4E, 0x4C, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
161 0x00, 0x6E, 0x6F, 0x7C, 0x4E, 0x4F, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
163 0x00, 0x70, 0x74, 0x7C, 0x50, 0x54, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
165 0x00, 0x73, 0x76, 0x7C, 0x53, 0x45, 0x7C, 0x69, 0x73, 0x6F, 0x38, 0x38, 0x35, 0x39, 0x2D, 0x31,
167 0x00, 0x6A, 0x61, 0x7C, 0x4A, 0x50, 0x7C, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00,
169 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}