From c1e345a47b182e49cd49df659ddae366ef3ceac3 Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Tue, 25 Sep 2018 09:09:32 +0200 Subject: [PATCH 1/9] Add Unicode character types and faillible conversion from Rust characters --- src/data_types/chars.rs | 36 ++++++++++++++++++++++++++++++++++++ src/data_types/mod.rs | 3 +++ src/lib.rs | 1 + 3 files changed, 40 insertions(+) create mode 100644 src/data_types/chars.rs diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs new file mode 100644 index 000000000..951139717 --- /dev/null +++ b/src/data_types/chars.rs @@ -0,0 +1,36 @@ +use core::convert::TryFrom; + +/// Character conversion error +pub struct CharConversionError; + +/// A Latin-1 character +pub struct Char8(u8); +// +impl TryFrom for Char8 { + type Error = CharConversionError; + + fn try_from(value: char) -> Result { + let code_point = value as u32; + if code_point <= 0xff { + Ok(Char8(code_point as u8)) + } else { + Err(CharConversionError) + } + } +} + +/// An UCS-2 code point +pub struct Char16(u16); +// +impl TryFrom for Char16 { + type Error = CharConversionError; + + fn try_from(value: char) -> Result { + let code_point = value as u32; + if code_point <= 0xffff { + Ok(Char16(code_point as u16)) + } else { + Err(CharConversionError) + } + } +} \ No newline at end of file diff --git a/src/data_types/mod.rs b/src/data_types/mod.rs index 8f979a90f..d5f019453 100644 --- a/src/data_types/mod.rs +++ b/src/data_types/mod.rs @@ -13,5 +13,8 @@ pub struct Event(*mut c_void); mod guid; pub use self::guid::Guid; +mod chars; +pub use self::chars::{Char8, Char16}; + #[macro_use] mod enums; diff --git a/src/lib.rs b/src/lib.rs index 6d1987982..e2ebedbc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ //! therefore all the network protocols will be unavailable. #![feature(optin_builtin_traits)] +#![feature(try_from)] #![feature(try_trait)] #![no_std] // Enable some additional warnings and lints. From 81e5c632466e5b46528fcd77b04c9532fd00ec66 Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Tue, 25 Sep 2018 09:16:20 +0200 Subject: [PATCH 2/9] Add conversion back into integer --- src/data_types/chars.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index 951139717..f945310c1 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -18,6 +18,12 @@ impl TryFrom for Char8 { } } } +// +impl Into for Char8 { + fn into(self) -> u8 { + self.0 as u8 + } +} /// An UCS-2 code point pub struct Char16(u16); @@ -33,4 +39,10 @@ impl TryFrom for Char16 { Err(CharConversionError) } } +} +// +impl Into for Char16 { + fn into(self) -> u16 { + self.0 as u16 + } } \ No newline at end of file From 865786bf5970ad5c021d2cf2bb4a232c5531f95b Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Tue, 25 Sep 2018 22:03:06 +0200 Subject: [PATCH 3/9] Use a transparent repr for C compatibility --- src/data_types/chars.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index f945310c1..d99a9b9e8 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -4,6 +4,7 @@ use core::convert::TryFrom; pub struct CharConversionError; /// A Latin-1 character +#[repr(transparent)] pub struct Char8(u8); // impl TryFrom for Char8 { @@ -26,6 +27,7 @@ impl Into for Char8 { } /// An UCS-2 code point +#[repr(transparent)] pub struct Char16(u16); // impl TryFrom for Char16 { From 86decf136eefaac10efbdf4b190135e480482e0e Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 16:04:20 +0200 Subject: [PATCH 4/9] Extend Char types, start using them for text input --- src/data_types/chars.rs | 43 ++++++++++++++++++++++++++++++--- src/proto/console/text/input.rs | 3 ++- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index d99a9b9e8..c48303e8b 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -1,12 +1,14 @@ use core::convert::TryFrom; +use core::fmt; /// Character conversion error pub struct CharConversionError; /// A Latin-1 character +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] #[repr(transparent)] pub struct Char8(u8); -// + impl TryFrom for Char8 { type Error = CharConversionError; @@ -19,17 +21,30 @@ impl TryFrom for Char8 { } } } -// + impl Into for Char8 { fn into(self) -> u8 { self.0 as u8 } } +impl fmt::Debug for Char8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(&From::from(self.0), f) + } +} + +impl fmt::Display for Char8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::fmt(&From::from(self.0), f) + } +} + /// An UCS-2 code point +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] #[repr(transparent)] pub struct Char16(u16); -// + impl TryFrom for Char16 { type Error = CharConversionError; @@ -42,9 +57,29 @@ impl TryFrom for Char16 { } } } -// + impl Into for Char16 { fn into(self) -> u16 { self.0 as u16 } +} + +impl fmt::Debug for Char16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(c) = TryFrom::try_from(self.0 as u32) { + ::fmt(&c, f) + } else { + write!(f, "Char16({:?})", self.0) + } + } +} + +impl fmt::Display for Char16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(c) = TryFrom::try_from(self.0 as u32) { + ::fmt(&c, f) + } else { + write!(f, "{}", core::char::REPLACEMENT_CHARACTER) + } + } } \ No newline at end of file diff --git a/src/proto/console/text/input.rs b/src/proto/console/text/input.rs index df41e4a8d..0d8c92f7b 100644 --- a/src/proto/console/text/input.rs +++ b/src/proto/console/text/input.rs @@ -1,5 +1,6 @@ use core::mem; use crate::{Event, Result, Status}; +use crate::data_types::Char16; /// Interface for text-based input devices. #[repr(C)] @@ -54,7 +55,7 @@ pub struct Key { pub scan_code: ScanCode, /// Associated Unicode character, /// or 0 if not printable. - pub unicode_char: u16, + pub unicode_char: Char16, } newtype_enum! { From d78ae6a481440b70e1af7770a76fe87865a31e4b Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 19:04:39 +0200 Subject: [PATCH 5/9] Add CStr-like types for UEFI strings, use them for text output --- src/data_types/chars.rs | 39 +++++++++- src/data_types/mod.rs | 9 ++- src/data_types/strs.rs | 128 +++++++++++++++++++++++++++++++ src/lib.rs | 2 +- src/proto/console/text/output.rs | 20 +++-- 5 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 src/data_types/strs.rs diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index c48303e8b..af9f74419 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -1,4 +1,9 @@ -use core::convert::TryFrom; +//! UEFI character handling +//! +//! UEFI uses both Latin-1 and UCS-2 character encoding, this module implements +//! support for the associated character types. + +use core::convert::{TryFrom, TryInto}; use core::fmt; /// Character conversion error @@ -22,6 +27,12 @@ impl TryFrom for Char8 { } } +impl From for Char8 { + fn from(value: u8) -> Self { + Char8(value) + } +} + impl Into for Char8 { fn into(self) -> u8 { self.0 as u8 @@ -40,6 +51,9 @@ impl fmt::Display for Char8 { } } +/// Latin-1 version of the NUL character +pub const NULL_8: Char8 = Char8(0); + /// An UCS-2 code point #[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] #[repr(transparent)] @@ -58,6 +72,20 @@ impl TryFrom for Char16 { } } +impl TryFrom for Char16 { + type Error = CharConversionError; + + fn try_from(value: u16) -> Result { + // We leverage char's TryFrom impl for Unicode validity checking + let res: Result = (value as u32).try_into(); + if let Ok(ch) = res { + ch.try_into() + } else { + Err(CharConversionError) + } + } +} + impl Into for Char16 { fn into(self) -> u16 { self.0 as u16 @@ -66,7 +94,7 @@ impl Into for Char16 { impl fmt::Debug for Char16 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(c) = TryFrom::try_from(self.0 as u32) { + if let Ok(c) = (self.0 as u32).try_into() { ::fmt(&c, f) } else { write!(f, "Char16({:?})", self.0) @@ -76,10 +104,13 @@ impl fmt::Debug for Char16 { impl fmt::Display for Char16 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(c) = TryFrom::try_from(self.0 as u32) { + if let Ok(c) = (self.0 as u32).try_into() { ::fmt(&c, f) } else { write!(f, "{}", core::char::REPLACEMENT_CHARACTER) } } -} \ No newline at end of file +} + +/// UCS-2 version of the NUL character +pub const NULL_16: Char16 = Char16(0); \ No newline at end of file diff --git a/src/data_types/mod.rs b/src/data_types/mod.rs index d5f019453..d4b90b5d0 100644 --- a/src/data_types/mod.rs +++ b/src/data_types/mod.rs @@ -1,3 +1,7 @@ +//! Data type definitions +//! +//! This module defines the basic data types that are used throughout uefi-rs + use core::ffi::c_void; /// Opaque handle to an UEFI entity (protocol, image...) @@ -13,8 +17,11 @@ pub struct Event(*mut c_void); mod guid; pub use self::guid::Guid; -mod chars; +pub mod chars; pub use self::chars::{Char8, Char16}; #[macro_use] mod enums; + +mod strs; +pub use self::strs::{CStr8, CStr16}; \ No newline at end of file diff --git a/src/data_types/strs.rs b/src/data_types/strs.rs new file mode 100644 index 000000000..c4f15cf57 --- /dev/null +++ b/src/data_types/strs.rs @@ -0,0 +1,128 @@ +use core::convert::TryInto; +use core::slice; +use core::result::Result; +use super::chars::{Char8, Char16, NULL_8, NULL_16}; + +/// Errors which can occur during checked [uN] -> CStrN conversions +pub enum FromSliceWithNulError { + /// An invalid character was encountered before the end of the slice + InvalidChar(usize), + + /// A null character was encountered before the end of the slice + InteriorNul(usize), + + /// The slice was not null-terminated + NotNulTerminated, +} + +/// A Latin-1 null-terminated string +/// +/// This type is largely inspired by std::ffi::CStr, see documentation of CStr +/// for more details on its semantics. +/// +#[repr(transparent)] +pub struct CStr8([Char8]); + +impl CStr8 { + /// Wraps a raw UEFI string with a safe C string wrapper + pub unsafe fn from_ptr<'a>(ptr: *const Char8) -> &'a Self { + let mut len = 0; + while *ptr.add(len) != NULL_8 { len += 1 } + let ptr = ptr as *const u8; + Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) + } + + /// Creates a C string wrapper from a Char8 slice + pub fn from_bytes_with_nul(chars: &[u8]) -> Result<&Self, FromSliceWithNulError> { + let nul_pos = chars.iter().position(|&c| c == 0); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != chars.len() { + return Err(FromSliceWithNulError::InteriorNul(nul_pos)); + } + Ok(unsafe { Self::from_bytes_with_nul_unchecked(chars) }) + } else { + Err(FromSliceWithNulError::NotNulTerminated) + } + } + + /// Unsafely creates a C string wrapper from a Char8 slice. + pub unsafe fn from_bytes_with_nul_unchecked(chars: &[u8]) -> &Self { + &*(chars as *const [u8] as *const Self) + } + + /// Returns the inner pointer to this C string + pub fn as_ptr(&self) -> *const Char8 { + self.0.as_ptr() + } + + /// Converts this C string to a Char8 slice + pub fn to_bytes(&self) -> &[u8] { + let chars = self.to_bytes_with_nul(); + &chars[..chars.len() - 1] + } + + /// Converts this C string to a Char8 slice containing the trailing 0 char + pub fn to_bytes_with_nul(&self) -> &[u8] { + unsafe { &*(&self.0 as *const [Char8] as *const [u8]) } + } +} + +/// An UCS-2 null-terminated string +/// +/// This type is largely inspired by std::ffi::CStr, see documentation of CStr +/// for more details on its semantics. +/// +#[repr(transparent)] +pub struct CStr16([Char16]); + +impl CStr16 { + /// Wraps a raw UEFI string with a safe C string wrapper + pub unsafe fn from_ptr<'a>(ptr: *const Char16) -> &'a Self { + let mut len = 0; + while *ptr.add(len) != NULL_16 { len += 1 } + let ptr = ptr as *const u16; + Self::from_u16_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) + } + + /// Creates a C string wrapper from a u16 slice + /// + /// Since not every u16 value is a valid UCS-2 code point, this function + /// must do a bit more validity checking than CStr::from_bytes_with_nul + pub fn from_u16_with_nul(codes: &[u16]) -> Result<&Self, FromSliceWithNulError> { + for (pos, &code) in codes.iter().enumerate() { + match code.try_into() { + Ok(NULL_16) => { + if pos != codes.len() - 1 { + return Err(FromSliceWithNulError::InteriorNul(pos)); + } else { + return Ok(unsafe { Self::from_u16_with_nul_unchecked(codes) }); + } + } + Err(_) => { return Err(FromSliceWithNulError::InvalidChar(pos)); } + _ => {} + } + } + Err(FromSliceWithNulError::NotNulTerminated) + } + + /// Unsafely creates a C string wrapper from a u16 slice. + pub unsafe fn from_u16_with_nul_unchecked(codes: &[u16]) -> &Self { + &*(codes as *const [u16] as *const Self) + } + + /// Returns the inner pointer to this C string + pub fn as_ptr(&self) -> *const Char16 { + self.0.as_ptr() + } + + /// Converts this C string to a u16 slice + pub fn to_u16_slice(&self) -> &[u16] { + let chars = self.to_u16_slice_with_nul(); + &chars[..chars.len() - 1] + } + + /// Converts this C string to a u16 slice containing the trailing 0 char + pub fn to_u16_slice_with_nul(&self) -> &[u16] { + unsafe { &*(&self.0 as *const [Char16] as *const [u16]) } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e2ebedbc5..199b64ea1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ #![deny(clippy::all)] #[macro_use] -mod data_types; +pub mod data_types; pub use self::data_types::{Event, Guid, Handle}; mod error; diff --git a/src/proto/console/text/output.rs b/src/proto/console/text/output.rs index 977c3558d..206835378 100644 --- a/src/proto/console/text/output.rs +++ b/src/proto/console/text/output.rs @@ -1,6 +1,7 @@ use core::fmt; -use crate::prelude::*; use crate::{Completion, Result, Status}; +use crate::data_types::{Char16, CStr16}; +use crate::prelude::*; /// Interface for text-based output devices. /// @@ -9,8 +10,8 @@ use crate::{Completion, Result, Status}; #[repr(C)] pub struct Output { reset: extern "win64" fn(this: &Output, extended: bool) -> Status, - output_string: extern "win64" fn(this: &Output, string: *const u16) -> Status, - test_string: extern "win64" fn(this: &Output, string: *const u16) -> Status, + output_string: extern "win64" fn(this: &Output, string: *const Char16) -> Status, + test_string: extern "win64" fn(this: &Output, string: *const Char16) -> Status, query_mode: extern "win64" fn(this: &Output, mode: i32, columns: &mut usize, rows: &mut usize) -> Status, set_mode: extern "win64" fn(this: &mut Output, mode: i32) -> Status, @@ -36,8 +37,8 @@ impl Output { } /// Writes a string to the output device. - pub fn output_string(&mut self, string: *const u16) -> Result<()> { - (self.output_string)(self, string).into() + pub fn output_string(&mut self, string: &CStr16) -> Result<()> { + (self.output_string)(self, string.as_ptr()).into() } /// Checks if a string contains only supported characters. @@ -45,8 +46,8 @@ impl Output { /// /// UEFI applications are encouraged to try to print a string even if it contains /// some unsupported characters. - pub fn test_string(&mut self, string: *const u16) -> bool { - match (self.test_string)(self, string) { + pub fn test_string(&mut self, string: &CStr16) -> bool { + match (self.test_string)(self, string.as_ptr()) { Status::SUCCESS => true, _ => false, } @@ -146,9 +147,12 @@ impl fmt::Write for Output { // This closure writes the local buffer to the output and resets the buffer. let mut flush_buffer = |buf: &mut [u16], i: &mut usize| { buf[*i] = 0; + let codes = &buf[..=*i]; *i = 0; - self.output_string(buf.as_ptr()) + let text = CStr16::from_u16_with_nul(codes).map_err(|_| fmt::Error)?; + + self.output_string(text) .warning_as_error() .map_err(|_| fmt::Error) }; From b6b7282accd984e97a74edeb1dac2395178f67e7 Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 19:56:01 +0200 Subject: [PATCH 6/9] Interface cleanup --- src/data_types/chars.rs | 16 ++++++++++++++-- src/data_types/strs.rs | 16 ++++++++-------- src/lib.rs | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index af9f74419..d996dbc55 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -27,6 +27,12 @@ impl TryFrom for Char8 { } } +impl Into for Char8 { + fn into(self) -> char { + self.0 as char + } +} + impl From for Char8 { fn from(value: u8) -> Self { Char8(value) @@ -52,7 +58,7 @@ impl fmt::Display for Char8 { } /// Latin-1 version of the NUL character -pub const NULL_8: Char8 = Char8(0); +pub const NUL_8: Char8 = Char8(0); /// An UCS-2 code point #[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] @@ -72,6 +78,12 @@ impl TryFrom for Char16 { } } +impl Into for Char16 { + fn into(self) -> char { + (self.0 as u32).try_into().unwrap() + } +} + impl TryFrom for Char16 { type Error = CharConversionError; @@ -113,4 +125,4 @@ impl fmt::Display for Char16 { } /// UCS-2 version of the NUL character -pub const NULL_16: Char16 = Char16(0); \ No newline at end of file +pub const NUL_16: Char16 = Char16(0); \ No newline at end of file diff --git a/src/data_types/strs.rs b/src/data_types/strs.rs index c4f15cf57..38361f378 100644 --- a/src/data_types/strs.rs +++ b/src/data_types/strs.rs @@ -1,7 +1,7 @@ use core::convert::TryInto; use core::slice; use core::result::Result; -use super::chars::{Char8, Char16, NULL_8, NULL_16}; +use super::chars::{Char8, Char16, NUL_8, NUL_16}; /// Errors which can occur during checked [uN] -> CStrN conversions pub enum FromSliceWithNulError { @@ -27,12 +27,12 @@ impl CStr8 { /// Wraps a raw UEFI string with a safe C string wrapper pub unsafe fn from_ptr<'a>(ptr: *const Char8) -> &'a Self { let mut len = 0; - while *ptr.add(len) != NULL_8 { len += 1 } + while *ptr.add(len) != NUL_8 { len += 1 } let ptr = ptr as *const u8; Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) } - /// Creates a C string wrapper from a Char8 slice + /// Creates a C string wrapper from bytes pub fn from_bytes_with_nul(chars: &[u8]) -> Result<&Self, FromSliceWithNulError> { let nul_pos = chars.iter().position(|&c| c == 0); if let Some(nul_pos) = nul_pos { @@ -45,7 +45,7 @@ impl CStr8 { } } - /// Unsafely creates a C string wrapper from a Char8 slice. + /// Unsafely creates a C string wrapper from bytes pub unsafe fn from_bytes_with_nul_unchecked(chars: &[u8]) -> &Self { &*(chars as *const [u8] as *const Self) } @@ -55,13 +55,13 @@ impl CStr8 { self.0.as_ptr() } - /// Converts this C string to a Char8 slice + /// Converts this C string to a slice of bytes pub fn to_bytes(&self) -> &[u8] { let chars = self.to_bytes_with_nul(); &chars[..chars.len() - 1] } - /// Converts this C string to a Char8 slice containing the trailing 0 char + /// Converts this C string to a slice of bytes containing the trailing 0 char pub fn to_bytes_with_nul(&self) -> &[u8] { unsafe { &*(&self.0 as *const [Char8] as *const [u8]) } } @@ -79,7 +79,7 @@ impl CStr16 { /// Wraps a raw UEFI string with a safe C string wrapper pub unsafe fn from_ptr<'a>(ptr: *const Char16) -> &'a Self { let mut len = 0; - while *ptr.add(len) != NULL_16 { len += 1 } + while *ptr.add(len) != NUL_16 { len += 1 } let ptr = ptr as *const u16; Self::from_u16_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) } @@ -91,7 +91,7 @@ impl CStr16 { pub fn from_u16_with_nul(codes: &[u16]) -> Result<&Self, FromSliceWithNulError> { for (pos, &code) in codes.iter().enumerate() { match code.try_into() { - Ok(NULL_16) => { + Ok(NUL_16) => { if pos != codes.len() - 1 { return Err(FromSliceWithNulError::InteriorNul(pos)); } else { diff --git a/src/lib.rs b/src/lib.rs index 199b64ea1..a725524f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ #[macro_use] pub mod data_types; -pub use self::data_types::{Event, Guid, Handle}; +pub use self::data_types::{Char8, Char16, CStr8, CStr16, Event, Guid, Handle}; mod error; pub use self::error::{Completion, Result, ResultExt, Status}; From 51cf6abab1440f73e568dcfa797b08f249101d3d Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 20:14:24 +0200 Subject: [PATCH 7/9] More cleanup + spread usage of Char16 / CStr16 --- src/proto/console/text/input.rs | 3 +-- src/proto/console/text/output.rs | 3 +-- src/proto/media/file.rs | 16 ++++++++-------- src/proto/media/fs.rs | 2 +- src/table/system.rs | 9 +++++++-- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/proto/console/text/input.rs b/src/proto/console/text/input.rs index 0d8c92f7b..8ef388881 100644 --- a/src/proto/console/text/input.rs +++ b/src/proto/console/text/input.rs @@ -1,6 +1,5 @@ use core::mem; -use crate::{Event, Result, Status}; -use crate::data_types::Char16; +use crate::{Char16, Event, Result, Status}; /// Interface for text-based input devices. #[repr(C)] diff --git a/src/proto/console/text/output.rs b/src/proto/console/text/output.rs index 206835378..fbab7e903 100644 --- a/src/proto/console/text/output.rs +++ b/src/proto/console/text/output.rs @@ -1,6 +1,5 @@ use core::fmt; -use crate::{Completion, Result, Status}; -use crate::data_types::{Char16, CStr16}; +use crate::{Char16, CStr16, Completion, Result, Status}; use crate::prelude::*; /// Interface for text-based output devices. diff --git a/src/proto/media/file.rs b/src/proto/media/file.rs index 99e749ef9..956864f14 100644 --- a/src/proto/media/file.rs +++ b/src/proto/media/file.rs @@ -8,7 +8,7 @@ use bitflags::bitflags; use core::mem; use crate::prelude::*; -use crate::{Result, Status}; +use crate::{Char16, CStr16, Result, Status}; use ucs2; /// A file represents an abstraction of some contiguous block of data residing @@ -22,11 +22,9 @@ pub struct File<'a> { } impl<'a> File<'a> { - pub(super) fn new(ptr: usize) -> Self { + pub(super) unsafe fn new(ptr: usize) -> Self { let ptr = ptr as *mut FileImpl; - - let inner = unsafe { &mut *ptr }; - + let inner = &mut *ptr; File { inner } } @@ -62,8 +60,10 @@ impl<'a> File<'a> { let mut buf = [0u16; BUF_SIZE + 1]; let mut ptr = 0usize; - ucs2::encode(filename, &mut buf)?; - (self.inner.open)(self.inner, &mut ptr, buf.as_ptr(), open_mode, attributes).into_with( + let len = ucs2::encode(filename, &mut buf)?; + let filename = unsafe { CStr16::from_u16_with_nul_unchecked(&buf[..=len]) }; + + (self.inner.open)(self.inner, &mut ptr, filename.as_ptr(), open_mode, attributes).into_with( || File { inner: unsafe { &mut *(ptr as *mut FileImpl) }, }, @@ -175,7 +175,7 @@ struct FileImpl { open: extern "win64" fn( this: &mut FileImpl, new_handle: &mut usize, - filename: *const u16, + filename: *const Char16, open_mode: FileMode, attributes: FileAttribute, ) -> Status, diff --git a/src/proto/media/fs.rs b/src/proto/media/fs.rs index c86b01688..7aa0a8727 100644 --- a/src/proto/media/fs.rs +++ b/src/proto/media/fs.rs @@ -27,7 +27,7 @@ impl SimpleFileSystem { /// * `uefi::Status::MEDIA_CHANGED` - The device has a different medium in it pub fn open_volume(&mut self) -> Result { let mut ptr = 0usize; - (self.open_volume)(self, &mut ptr).into_with(|| File::new(ptr)) + (self.open_volume)(self, &mut ptr).into_with(|| unsafe { File::new(ptr) }) } } diff --git a/src/table/system.rs b/src/table/system.rs index 494a37672..53f185993 100644 --- a/src/table/system.rs +++ b/src/table/system.rs @@ -1,14 +1,14 @@ use super::{cfg, Header, Revision}; use core::slice; use crate::proto::console::text; -use crate::Handle; +use crate::{Char16, CStr16, Handle}; /// The system table entry points for accessing the core UEFI system functionality. #[repr(C)] pub struct SystemTable { header: Header, /// Null-terminated string representing the firmware's vendor. - pub fw_vendor: *const u16, + fw_vendor: *const Char16, /// Revision of the UEFI specification the firmware conforms to. pub fw_revision: Revision, stdin_handle: Handle, @@ -30,6 +30,11 @@ pub struct SystemTable { // This is unsafe, but it's the best solution we have from now. #[allow(clippy::mut_from_ref)] impl SystemTable { + /// Return the firmware vendor string + pub fn firmware_vendor(&self) -> &CStr16 { + unsafe { CStr16::from_ptr(self.fw_vendor) } + } + /// Returns the revision of this table, which is defined to be /// the revision of the UEFI specification implemented by the firmware. pub fn uefi_revision(&self) -> Revision { From 80b4a591181f7ec70a0c12ac5741743b2e0ec040 Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 20:17:45 +0200 Subject: [PATCH 8/9] Run a cargo fmt pass --- src/data_types/chars.rs | 2 +- src/data_types/mod.rs | 4 ++-- src/data_types/strs.rs | 18 ++++++++++++------ src/lib.rs | 2 +- src/proto/console/text/output.rs | 2 +- src/proto/media/file.rs | 15 ++++++++++----- src/table/system.rs | 2 +- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index d996dbc55..b255f460c 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -125,4 +125,4 @@ impl fmt::Display for Char16 { } /// UCS-2 version of the NUL character -pub const NUL_16: Char16 = Char16(0); \ No newline at end of file +pub const NUL_16: Char16 = Char16(0); diff --git a/src/data_types/mod.rs b/src/data_types/mod.rs index d4b90b5d0..d567fa33d 100644 --- a/src/data_types/mod.rs +++ b/src/data_types/mod.rs @@ -18,10 +18,10 @@ mod guid; pub use self::guid::Guid; pub mod chars; -pub use self::chars::{Char8, Char16}; +pub use self::chars::{Char16, Char8}; #[macro_use] mod enums; mod strs; -pub use self::strs::{CStr8, CStr16}; \ No newline at end of file +pub use self::strs::{CStr16, CStr8}; diff --git a/src/data_types/strs.rs b/src/data_types/strs.rs index 38361f378..d27bd4fa2 100644 --- a/src/data_types/strs.rs +++ b/src/data_types/strs.rs @@ -1,7 +1,7 @@ +use super::chars::{Char16, Char8, NUL_16, NUL_8}; use core::convert::TryInto; -use core::slice; use core::result::Result; -use super::chars::{Char8, Char16, NUL_8, NUL_16}; +use core::slice; /// Errors which can occur during checked [uN] -> CStrN conversions pub enum FromSliceWithNulError { @@ -27,7 +27,9 @@ impl CStr8 { /// Wraps a raw UEFI string with a safe C string wrapper pub unsafe fn from_ptr<'a>(ptr: *const Char8) -> &'a Self { let mut len = 0; - while *ptr.add(len) != NUL_8 { len += 1 } + while *ptr.add(len) != NUL_8 { + len += 1 + } let ptr = ptr as *const u8; Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) } @@ -79,7 +81,9 @@ impl CStr16 { /// Wraps a raw UEFI string with a safe C string wrapper pub unsafe fn from_ptr<'a>(ptr: *const Char16) -> &'a Self { let mut len = 0; - while *ptr.add(len) != NUL_16 { len += 1 } + while *ptr.add(len) != NUL_16 { + len += 1 + } let ptr = ptr as *const u16; Self::from_u16_with_nul_unchecked(slice::from_raw_parts(ptr, len + 1)) } @@ -98,7 +102,9 @@ impl CStr16 { return Ok(unsafe { Self::from_u16_with_nul_unchecked(codes) }); } } - Err(_) => { return Err(FromSliceWithNulError::InvalidChar(pos)); } + Err(_) => { + return Err(FromSliceWithNulError::InvalidChar(pos)); + } _ => {} } } @@ -125,4 +131,4 @@ impl CStr16 { pub fn to_u16_slice_with_nul(&self) -> &[u16] { unsafe { &*(&self.0 as *const [Char16] as *const [u16]) } } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index a725524f1..6e82987e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ #[macro_use] pub mod data_types; -pub use self::data_types::{Char8, Char16, CStr8, CStr16, Event, Guid, Handle}; +pub use self::data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle}; mod error; pub use self::error::{Completion, Result, ResultExt, Status}; diff --git a/src/proto/console/text/output.rs b/src/proto/console/text/output.rs index fbab7e903..bf1936cff 100644 --- a/src/proto/console/text/output.rs +++ b/src/proto/console/text/output.rs @@ -1,6 +1,6 @@ use core::fmt; -use crate::{Char16, CStr16, Completion, Result, Status}; use crate::prelude::*; +use crate::{CStr16, Char16, Completion, Result, Status}; /// Interface for text-based output devices. /// diff --git a/src/proto/media/file.rs b/src/proto/media/file.rs index 956864f14..fdf2b3072 100644 --- a/src/proto/media/file.rs +++ b/src/proto/media/file.rs @@ -8,7 +8,7 @@ use bitflags::bitflags; use core::mem; use crate::prelude::*; -use crate::{Char16, CStr16, Result, Status}; +use crate::{CStr16, Char16, Result, Status}; use ucs2; /// A file represents an abstraction of some contiguous block of data residing @@ -63,11 +63,16 @@ impl<'a> File<'a> { let len = ucs2::encode(filename, &mut buf)?; let filename = unsafe { CStr16::from_u16_with_nul_unchecked(&buf[..=len]) }; - (self.inner.open)(self.inner, &mut ptr, filename.as_ptr(), open_mode, attributes).into_with( - || File { - inner: unsafe { &mut *(ptr as *mut FileImpl) }, - }, + (self.inner.open)( + self.inner, + &mut ptr, + filename.as_ptr(), + open_mode, + attributes, ) + .into_with(|| File { + inner: unsafe { &mut *(ptr as *mut FileImpl) }, + }) } } diff --git a/src/table/system.rs b/src/table/system.rs index 53f185993..efd72a36f 100644 --- a/src/table/system.rs +++ b/src/table/system.rs @@ -1,7 +1,7 @@ use super::{cfg, Header, Revision}; use core::slice; use crate::proto::console::text; -use crate::{Char16, CStr16, Handle}; +use crate::{CStr16, Char16, Handle}; /// The system table entry points for accessing the core UEFI system functionality. #[repr(C)] From ae4ee8505eaf502f773b63cf4532e321cec45db5 Mon Sep 17 00:00:00 2001 From: Hadrien G Date: Sat, 13 Oct 2018 20:30:09 +0200 Subject: [PATCH 9/9] Use clippy-friendly casts --- src/data_types/chars.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data_types/chars.rs b/src/data_types/chars.rs index b255f460c..08728cf31 100644 --- a/src/data_types/chars.rs +++ b/src/data_types/chars.rs @@ -80,7 +80,7 @@ impl TryFrom for Char16 { impl Into for Char16 { fn into(self) -> char { - (self.0 as u32).try_into().unwrap() + u32::from(self.0).try_into().unwrap() } } @@ -89,7 +89,7 @@ impl TryFrom for Char16 { fn try_from(value: u16) -> Result { // We leverage char's TryFrom impl for Unicode validity checking - let res: Result = (value as u32).try_into(); + let res: Result = u32::from(value).try_into(); if let Ok(ch) = res { ch.try_into() } else { @@ -106,7 +106,7 @@ impl Into for Char16 { impl fmt::Debug for Char16 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(c) = (self.0 as u32).try_into() { + if let Ok(c) = u32::from(self.0).try_into() { ::fmt(&c, f) } else { write!(f, "Char16({:?})", self.0) @@ -116,7 +116,7 @@ impl fmt::Debug for Char16 { impl fmt::Display for Char16 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(c) = (self.0 as u32).try_into() { + if let Ok(c) = u32::from(self.0).try_into() { ::fmt(&c, f) } else { write!(f, "{}", core::char::REPLACEMENT_CHARACTER)