Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit af715af

Browse files
d-sonuganicholasbishop
authored andcommitted
Added the unicode collation protocol
1 parent 89f6d6f commit af715af

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

‎src/proto/mod.rs

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

‎src/proto/string/mod.rs

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

‎src/proto/string/unicode_collation.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//! The Unicode Collation Protocol
2+
//!
3+
//! Used in the boot services environment to perform
4+
//! lexical comparison functions on Unicode strings for given languages
5+
6+
use core::cmp::Ordering;
7+
use uefi_macros::{unsafe_guid, Protocol};
8+
use uefi::data_types::{Char16, CStr16, Char8, CStr8};
9+
10+
/// The Unicode Collation Protocol
11+
///
12+
/// Used to perform case-insensitive comaprisons of strings
13+
#[repr(C)]
14+
#[unsafe_guid("a4c751fc-23ae-4c3e-92e9-4964cf63f349")]
15+
#[derive(Protocol)]
16+
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
47+
}
48+
49+
impl UnicodeCollation {
50+
/// Performs a case insensitive comparison of two
51+
/// null-terminated strings
52+
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+
}
65+
}
66+
67+
/// Performs a case insensitive comparison between a null terminated
68+
/// pattern string and a null terminated string
69+
///
70+
/// This function checks if character pattern described in `pattern`
71+
/// is found in `string`. If the pattern match succeeds, true is returned.
72+
/// Otherwise, false is returned
73+
///
74+
/// The following syntax can be used to build the string `pattern`:
75+
///
76+
/// |Pattern Character |Meaning |
77+
/// |-----------------------------|--------------------------------------------------|
78+
/// |* | Match 0 or more characters |
79+
/// |? | Match any one character |
80+
/// |[`char1` `char2`...`charN`]| Match any character in the set |
81+
/// |[`char1`-`char2`] | Match any character between `char1` and `char2`|
82+
/// |`char` | Match the character `char` |
83+
///
84+
/// For example, the pattern "*.Fw" will match all strings that end
85+
/// in ".FW", ".fw", ".Fw" or ".fW". The pattern "[a-z]" will match any
86+
/// letter in the alphabet. The pattern "z" will match the letter "z".
87+
/// The pattern "d?.*" will match the character "D" or "d" followed by
88+
/// any single character followed by a "." followed by any string
89+
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+
)
95+
}
96+
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> {
99+
let mut last_index = 0;
100+
for (i, c) in s.iter().enumerate() {
101+
*buf.get_mut(i)
102+
.ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
103+
last_index = i;
104+
}
105+
*buf.get_mut(last_index + 1)
106+
.ok_or(StrConversionError::BufferTooSmall)? = 0;
107+
108+
(self.str_lwr)(
109+
self,
110+
buf.as_ptr() as *mut _
111+
);
112+
113+
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
114+
}
115+
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> {
118+
let mut last_index = 0;
119+
for (i, c) in s.iter().enumerate() {
120+
*buf.get_mut(i)
121+
.ok_or(StrConversionError::BufferTooSmall)? = (*c).into();
122+
last_index = i;
123+
}
124+
*buf.get_mut(last_index + 1)
125+
.ok_or(StrConversionError::BufferTooSmall)? = 0;
126+
127+
(self.str_upr)(
128+
self,
129+
buf.as_ptr() as *mut _
130+
);
131+
132+
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
133+
}
134+
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> {
137+
if buf.len() < fat.to_bytes_with_nul().len() {
138+
return Err(StrConversionError::BufferTooSmall);
139+
}
140+
(self.fat_to_str)(
141+
self,
142+
fat.to_bytes_with_nul().len(),
143+
fat.as_ptr(),
144+
buf.as_ptr() as *mut _
145+
);
146+
Ok(unsafe { CStr16::from_u16_with_nul_unchecked(buf) })
147+
}
148+
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> {
151+
if s.as_slice_with_nul().len() > buf.len() {
152+
return Err(StrConversionError::BufferTooSmall);
153+
}
154+
let failed = (self.str_to_fat)(
155+
self,
156+
s.as_ptr(),
157+
s.as_slice_with_nul().len(),
158+
buf.as_ptr() as *mut _
159+
);
160+
if failed {
161+
Err(StrConversionError::ConversionFailed)
162+
} else {
163+
// After the conversion, there is a possibility that the converted string
164+
// is smaller than the original `s` string.
165+
// When the converted string is smaller, there will be a bunch of trailing
166+
// nulls.
167+
// To remove all those trailing nulls:
168+
let mut last_null_index = buf.len() - 1;
169+
for i in (0..buf.len()).rev() {
170+
if buf[i] != 0 {
171+
last_null_index = i + 1;
172+
break;
173+
}
174+
}
175+
let buf = unsafe { core::slice::from_raw_parts(buf.as_ptr(), last_null_index + 1) };
176+
Ok(unsafe { CStr8::from_bytes_with_nul_unchecked(buf) })
177+
}
178+
}
179+
}
180+
181+
/// Errors returned by [`UnicodeCollation::str_lwr`] and [`UnicodeCollation::str_upr`]
182+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183+
pub enum StrConversionError {
184+
/// The conversion failed
185+
ConversionFailed,
186+
/// The buffer given is too small to hold the string
187+
BufferTooSmall
188+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /