Skip to content

Commit bd03ea7

Browse files
d-sonuganicholasbishop
authored andcommitted
Added tests for the unicode collation protocol
1 parent af715af commit bd03ea7

File tree

6 files changed

+171
-89
lines changed

6 files changed

+171
-89
lines changed

src/proto/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ pub mod pi;
7474
pub mod rng;
7575
pub mod security;
7676
pub mod shim;
77-
pub mod string;
77+
pub mod string;

src/proto/string/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//! String protocols
1+
//! String protocols.
22
//!
33
//! The protocols provide some string operations like
44
//! lexical comparison.
55
6-
pub mod unicode_collation;
6+
pub mod unicode_collation;

src/proto/string/unicode_collation.rs

Lines changed: 58 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,43 @@
1-
//! The Unicode Collation Protocol
1+
//! The Unicode Collation Protocol.
22
//!
3-
//! Used in the boot services environment to perform
4-
//! lexical comparison functions on Unicode strings for given languages
3+
//! This protocol is used in the boot services environment to perform
4+
//! lexical comparison functions on Unicode strings for given languages.
55
66
use core::cmp::Ordering;
7+
use uefi::data_types::{CStr16, CStr8, Char16, Char8};
78
use uefi_macros::{unsafe_guid, Protocol};
8-
use uefi::data_types::{Char16, CStr16, Char8, CStr8};
99

10-
/// The Unicode Collation Protocol
10+
/// The Unicode Collation Protocol.
1111
///
12-
/// Used to perform case-insensitive comaprisons of strings
12+
/// Used to perform case-insensitive comaprisons of strings.
1313
#[repr(C)]
1414
#[unsafe_guid("a4c751fc-23ae-4c3e-92e9-4964cf63f349")]
1515
#[derive(Protocol)]
1616
pub struct UnicodeCollation {
17-
stri_coll: extern "efiapi" fn(
18-
this: &Self,
19-
s1: *const Char16,
20-
s2: *const Char16
21-
) -> isize,
22-
metai_match: extern "efiapi" fn(
23-
this: &Self,
24-
string: *const Char16,
25-
pattern: *const Char16
26-
) -> bool,
27-
str_lwr: extern "efiapi" fn(
28-
this: &Self,
29-
s: *mut Char16
30-
),
31-
str_upr: extern "efiapi" fn(
32-
this: &Self,
33-
s: *mut Char16
34-
),
35-
fat_to_str: extern "efiapi" fn(
36-
this: &Self,
37-
fat_size: usize,
38-
fat: *const Char8,
39-
s: *mut Char16
40-
),
41-
str_to_fat: extern "efiapi" fn(
42-
this: &Self,
43-
s: *const Char16,
44-
fat_size: usize,
45-
fat: *mut Char8
46-
) -> bool
17+
stri_coll: extern "efiapi" fn(this: &Self, s1: *const Char16, s2: *const Char16) -> isize,
18+
metai_match:
19+
extern "efiapi" fn(this: &Self, string: *const Char16, pattern: *const Char16) -> bool,
20+
str_lwr: extern "efiapi" fn(this: &Self, s: *mut Char16),
21+
str_upr: extern "efiapi" fn(this: &Self, s: *mut Char16),
22+
fat_to_str: extern "efiapi" fn(this: &Self, fat_size: usize, fat: *const Char8, s: *mut Char16),
23+
str_to_fat:
24+
extern "efiapi" fn(this: &Self, s: *const Char16, fat_size: usize, fat: *mut Char8) -> bool,
4725
}
4826

4927
impl UnicodeCollation {
5028
/// Performs a case insensitive comparison of two
51-
/// null-terminated strings
29+
/// null-terminated strings.
5230
pub fn stri_coll(&self, s1: &CStr16, s2: &CStr16) -> Ordering {
53-
let order = (self.stri_coll)(
54-
self,
55-
s1.as_ptr(),
56-
s2.as_ptr()
57-
);
58-
if order == 0 {
59-
Ordering::Equal
60-
} else if order < 0 {
61-
Ordering::Less
62-
} else {
63-
Ordering::Greater
64-
}
31+
let order = (self.stri_coll)(self, s1.as_ptr(), s2.as_ptr());
32+
order.cmp(&0)
6533
}
6634

6735
/// Performs a case insensitive comparison between a null terminated
68-
/// pattern string and a null terminated string
36+
/// pattern string and a null terminated string.
6937
///
7038
/// This function checks if character pattern described in `pattern`
7139
/// is found in `string`. If the pattern match succeeds, true is returned.
72-
/// Otherwise, false is returned
40+
/// Otherwise, false is returned.
7341
///
7442
/// The following syntax can be used to build the string `pattern`:
7543
///
@@ -85,77 +53,81 @@ impl UnicodeCollation {
8553
/// in ".FW", ".fw", ".Fw" or ".fW". The pattern "[a-z]" will match any
8654
/// letter in the alphabet. The pattern "z" will match the letter "z".
8755
/// The pattern "d?.*" will match the character "D" or "d" followed by
88-
/// any single character followed by a "." followed by any string
56+
/// any single character followed by a "." followed by any string.
8957
pub fn metai_match(&self, s: &CStr16, pattern: &CStr16) -> bool {
90-
(self.metai_match)(
91-
self,
92-
s.as_ptr(),
93-
pattern.as_ptr()
94-
)
58+
(self.metai_match)(self, s.as_ptr(), pattern.as_ptr())
9559
}
9660

97-
/// Converts the characters in `s` to lower case characters
98-
pub fn str_lwr<'a>(&self, s: &CStr16, buf: &'a mut [u16]) -> Result<&'a CStr16, StrConversionError> {
61+
/// Converts the characters in `s` to lower case characters.
62+
pub fn str_lwr<'a>(
63+
&self,
64+
s: &CStr16,
65+
buf: &'a mut [u16],
66+
) -> Result<&'a CStr16, StrConversionError> {
9967
let mut last_index = 0;
10068
for (i, c) in s.iter().enumerate() {
101-
*buf.get_mut(i)
102-
.ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
69+
*buf.get_mut(i).ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
10370
last_index = i;
10471
}
10572
*buf.get_mut(last_index + 1)
10673
.ok_or(StrConversionError::BufferTooSmall)? = 0;
107-
108-
(self.str_lwr)(
109-
self,
110-
buf.as_ptr() as *mut _
111-
);
74+
75+
(self.str_lwr)(self, buf.as_ptr() as *mut _);
11276

11377
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
11478
}
11579

116-
/// Coverts the characters in `s` to upper case characters
117-
pub fn str_upr<'a>(&self, s: &CStr16, buf: &'a mut [u16]) -> Result<&'a CStr16, StrConversionError> {
80+
/// Converts the characters in `s` to upper case characters.
81+
pub fn str_upr<'a>(
82+
&self,
83+
s: &CStr16,
84+
buf: &'a mut [u16],
85+
) -> Result<&'a CStr16, StrConversionError> {
11886
let mut last_index = 0;
11987
for (i, c) in s.iter().enumerate() {
120-
*buf.get_mut(i)
121-
.ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
88+
*buf.get_mut(i).ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
12289
last_index = i;
12390
}
12491
*buf.get_mut(last_index + 1)
12592
.ok_or(StrConversionError::BufferTooSmall)? = 0;
126-
127-
(self.str_upr)(
128-
self,
129-
buf.as_ptr() as *mut _
130-
);
93+
94+
(self.str_upr)(self, buf.as_ptr() as *mut _);
13195

13296
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
13397
}
13498

135-
/// Converts the 8.3 FAT file name `fat` to a null terminated string
136-
pub fn fat_to_str<'a>(&self, fat: &CStr8, buf: &'a mut [u16]) -> Result<&'a CStr16, StrConversionError> {
99+
/// Converts the 8.3 FAT file name `fat` to a null terminated string.
100+
pub fn fat_to_str<'a>(
101+
&self,
102+
fat: &CStr8,
103+
buf: &'a mut [u16],
104+
) -> Result<&'a CStr16, StrConversionError> {
137105
if buf.len() < fat.to_bytes_with_nul().len() {
138106
return Err(StrConversionError::BufferTooSmall);
139107
}
140108
(self.fat_to_str)(
141109
self,
142110
fat.to_bytes_with_nul().len(),
143111
fat.as_ptr(),
144-
buf.as_ptr() as *mut _
112+
buf.as_ptr() as *mut _,
145113
);
146114
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
147115
}
148116

149-
/// Converts the null terminated string `s` to legal characters in a FAT file name
150-
pub fn str_to_fat<'a>(&self, s: &CStr16, buf: &'a mut [u8]) -> Result<&'a CStr8, StrConversionError> {
117+
/// Converts the null terminated string `s` to legal characters in a FAT file name.
118+
pub fn str_to_fat<'a>(
119+
&self,
120+
s: &CStr16,
121+
buf: &'a mut [u8],
122+
) -> Result<&'a CStr8, StrConversionError> {
151123
if s.as_slice_with_nul().len() > buf.len() {
152124
return Err(StrConversionError::BufferTooSmall);
153125
}
154126
let failed = (self.str_to_fat)(
155127
self,
156128
s.as_ptr(),
157129
s.as_slice_with_nul().len(),
158-
buf.as_ptr() as *mut _
130+
buf.as_ptr() as *mut _,
159131
);
160132
if failed {
161133
Err(StrConversionError::ConversionFailed)
@@ -178,11 +150,11 @@ impl UnicodeCollation {
178150
}
179151
}
180152

181-
/// Errors returned by [`UnicodeCollation::str_lwr`] and [`UnicodeCollation::str_upr`]
153+
/// Errors returned by [`UnicodeCollation::str_lwr`] and [`UnicodeCollation::str_upr`].
182154
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183155
pub enum StrConversionError {
184-
/// The conversion failed
156+
/// The conversion failed.
185157
ConversionFailed,
186-
/// The buffer given is too small to hold the string
187-
BufferTooSmall
188-
}
158+
/// The buffer given is too small to hold the string.
159+
BufferTooSmall,
160+
}

uefi-test-runner/src/proto/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
1919
network::test(bt);
2020
pi::test(bt);
2121
rng::test(bt);
22+
string::test(bt);
2223

2324
#[cfg(any(
2425
target_arch = "i386",
@@ -71,3 +72,4 @@ mod rng;
7172
target_arch = "aarch64"
7273
))]
7374
mod shim;
75+
mod string;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use uefi::prelude::*;
2+
3+
pub fn test(bt: &BootServices) {
4+
info!("Testing String protocols");
5+
6+
unicode_collation::test(bt);
7+
}
8+
9+
mod unicode_collation;
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use core::cmp::Ordering;
2+
use uefi::prelude::*;
3+
use uefi::proto::string::unicode_collation::{StrConversionError, UnicodeCollation};
4+
use uefi::{CStr16, CStr8};
5+
6+
pub fn test(bt: &BootServices) {
7+
info!("Testing the Unicode Collation protocol");
8+
9+
if let Ok(handles) = bt.find_handles::<UnicodeCollation>() {
10+
for handle in handles {
11+
let uc = bt
12+
.open_protocol_exclusive::<UnicodeCollation>(handle)
13+
.unwrap();
14+
15+
let mut buf1 = [0; 30];
16+
let mut buf2 = [0; 30];
17+
18+
macro_rules! strings {
19+
($s1:expr, $s2:expr) => {{
20+
let s1 = CStr16::from_str_with_buf($s1, &mut buf1).unwrap();
21+
let s2 = CStr16::from_str_with_buf($s2, &mut buf2).unwrap();
22+
(s1, s2)
23+
}};
24+
}
25+
26+
let (s1, s2) = strings!("aab", "aaa");
27+
// "aab" is lexically greater than "aaa"
28+
assert_eq!(uc.stri_coll(s1, s2), Ordering::Greater);
29+
30+
let (s1, s2) = strings!("{}", "{}");
31+
assert_eq!(uc.stri_coll(s1, s2), Ordering::Equal);
32+
33+
let (s1, s2) = strings!("\t", "-");
34+
// Tab comes before dash in the unicode table
35+
assert_eq!(uc.stri_coll(s1, s2), Ordering::Less);
36+
37+
let (s, pattern) = strings!("haaaaaaaaarderr", "h*a*r*derr");
38+
assert!(uc.metai_match(s, pattern));
39+
40+
let (s, pattern) = strings!("haaaaaaaaarder0r", "h*a*r*derr");
41+
assert!(!uc.metai_match(s, pattern));
42+
43+
let mut buf1 = [0; 13];
44+
let s = CStr16::from_str_with_buf("HeLlO World!", &mut buf1).unwrap();
45+
46+
let mut buf2 = [0; 12];
47+
assert_eq!(
48+
uc.str_lwr(s, &mut buf2),
49+
Err(StrConversionError::BufferTooSmall)
50+
);
51+
52+
let mut buf2 = [0; 13];
53+
let lower_s = uc.str_lwr(s, &mut buf2).unwrap();
54+
assert_eq!(
55+
lower_s,
56+
CStr16::from_str_with_buf("hello world!", &mut [0; 13]).unwrap()
57+
);
58+
59+
let mut buf = [0; 12];
60+
assert_eq!(
61+
uc.str_upr(s, &mut buf),
62+
Err(StrConversionError::BufferTooSmall)
63+
);
64+
65+
let mut buf = [0; 13];
66+
let upper_s = uc.str_upr(s, &mut buf).unwrap();
67+
assert_eq!(
68+
upper_s,
69+
CStr16::from_str_with_buf("HELLO WORLD!", &mut [0; 13]).unwrap()
70+
);
71+
72+
let s = CStr8::from_bytes_with_nul(b"Hello World!\0").unwrap();
73+
assert_eq!(
74+
uc.fat_to_str(s, &mut [0; 12]),
75+
Err(StrConversionError::BufferTooSmall)
76+
);
77+
78+
assert_eq!(
79+
uc.fat_to_str(s, &mut [0; 13]).unwrap(),
80+
CStr16::from_str_with_buf("Hello World!", &mut [0; 13]).unwrap()
81+
);
82+
83+
let mut buf = [0; 13];
84+
let s = CStr16::from_str_with_buf("Hello World!", &mut buf).unwrap();
85+
let mut buf = [0; 12];
86+
assert_eq!(
87+
uc.str_to_fat(s, &mut buf),
88+
Err(StrConversionError::BufferTooSmall)
89+
);
90+
let mut buf = [0; 13];
91+
assert_eq!(
92+
uc.str_to_fat(s, &mut buf).unwrap(),
93+
CStr8::from_bytes_with_nul(b"HELLOWORLD!\0").unwrap()
94+
);
95+
}
96+
} else {
97+
warn!("The Unicode Collation protocol is not supported");
98+
}
99+
}

0 commit comments

Comments
 (0)