@@ -4,51 +4,100 @@ use crate::mem::MaybeUninit;
44use crate :: os:: uefi;
55use crate :: ptr:: NonNull ;
66
7- const MAX_BUFFER_SIZE : usize = 8192 ;
7+ pub struct Stdin {
8+ surrogate : Option < u16 > ,
9+ incomplete_utf8 : IncompleteUtf8 ,
10+ }
11+
12+ struct IncompleteUtf8 {
13+ bytes : [ u8 ; 4 ] ,
14+ len : u8 ,
15+ }
16+
17+ impl IncompleteUtf8 {
18+ pub const fn new ( ) -> IncompleteUtf8 {
19+ IncompleteUtf8 { bytes : [ 0 ; 4 ] , len : 0 }
20+ }
21+
22+ // Implemented for use in Stdin::read.
23+ fn read ( & mut self , buf : & mut [ u8 ] ) -> usize {
24+ // Write to buffer until the buffer is full or we run out of bytes.
25+ let to_write = crate :: cmp:: min ( buf. len ( ) , self . len as usize ) ;
26+ buf[ ..to_write] . copy_from_slice ( & self . bytes [ ..to_write] ) ;
27+
28+ // Rotate the remaining bytes if not enough remaining space in buffer.
29+ if usize:: from ( self . len ) > buf. len ( ) {
30+ self . bytes . copy_within ( to_write.., 0 ) ;
31+ self . len -= to_write as u8 ;
32+ } else {
33+ self . len = 0 ;
34+ }
35+
36+ to_write
37+ }
38+ }
839
9- pub struct Stdin ;
1040pub struct Stdout ;
1141pub struct Stderr ;
1242
1343impl Stdin {
1444 pub const fn new ( ) -> Stdin {
15- Stdin
45+ Stdin { surrogate : None , incomplete_utf8 : IncompleteUtf8 :: new ( ) }
1646 }
1747}
1848
1949impl io:: Read for Stdin {
2050 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
21- let st: NonNull < r_efi:: efi:: SystemTable > = uefi:: env:: system_table ( ) . cast ( ) ;
22- let stdin = unsafe { ( * st. as_ptr ( ) ) . con_in } ;
23-
24- // Try reading any pending data
25- let inp = match read_key_stroke ( stdin) {
26- Ok ( x) => x,
27- Err ( e) if e == r_efi:: efi:: Status :: NOT_READY => {
28- // Wait for keypress for new data
29- wait_stdin ( stdin) ?;
30- read_key_stroke ( stdin) . map_err ( |x| io:: Error :: from_raw_os_error ( x. as_usize ( ) ) ) ?
31- }
32- Err ( e) => {
33- return Err ( io:: Error :: from_raw_os_error ( e. as_usize ( ) ) ) ;
34- }
51+ // If there are bytes in the incomplete utf-8, start with those.
52+ // (No-op if there is nothing in the buffer.)
53+ let mut bytes_copied = self . incomplete_utf8 . read ( buf) ;
54+
55+ let stdin: * mut r_efi:: protocols:: simple_text_input:: Protocol = unsafe {
56+ let st: NonNull < r_efi:: efi:: SystemTable > = uefi:: env:: system_table ( ) . cast ( ) ;
57+ ( * st. as_ptr ( ) ) . con_in
3558 } ;
3659
37- // Check if the key is printiable character
38- if inp. scan_code != 0x00 {
39- return Err ( io:: const_io_error!( io:: ErrorKind :: Interrupted , "Special Key Press" ) ) ;
60+ if bytes_copied == buf. len ( ) {
61+ return Ok ( bytes_copied) ;
4062 }
4163
42- // SAFETY: Iterator will have only 1 character since we are reading only 1 Key
43- // SAFETY: This character will always be UCS-2 and thus no surrogates.
44- let ch: char = char:: decode_utf16 ( [ inp. unicode_char ] ) . next ( ) . unwrap ( ) . unwrap ( ) ;
45- if ch. len_utf8 ( ) > buf. len ( ) {
46- return Ok ( 0 ) ;
64+ let ch = simple_text_input_read ( stdin) ?;
65+ // Only 1 character should be returned.
66+ let mut ch: Vec < Result < char , crate :: char:: DecodeUtf16Error > > =
67+ if let Some ( x) = self . surrogate . take ( ) {
68+ char:: decode_utf16 ( [ x, ch] ) . collect ( )
69+ } else {
70+ char:: decode_utf16 ( [ ch] ) . collect ( )
71+ } ;
72+
73+ if ch. len ( ) > 1 {
74+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidData , "invalid utf-16 sequence" ) ) ;
4775 }
4876
49- ch. encode_utf8 ( buf) ;
77+ match ch. pop ( ) . unwrap ( ) {
78+ Err ( e) => {
79+ self . surrogate = Some ( e. unpaired_surrogate ( ) ) ;
80+ }
81+ Ok ( x) => {
82+ // This will always be > 0
83+ let buf_free_count = buf. len ( ) - bytes_copied;
84+ assert ! ( buf_free_count > 0 ) ;
85+
86+ if buf_free_count >= x. len_utf8 ( ) {
87+ // There is enough space in the buffer for the character.
88+ bytes_copied += x. encode_utf8 ( & mut buf[ bytes_copied..] ) . len ( ) ;
89+ } else {
90+ // There is not enough space in the buffer for the character.
91+ // Store the character in the incomplete buffer.
92+ self . incomplete_utf8 . len =
93+ x. encode_utf8 ( & mut self . incomplete_utf8 . bytes ) . len ( ) as u8 ;
94+ // write partial character to buffer.
95+ bytes_copied += self . incomplete_utf8 . read ( buf) ;
96+ }
97+ }
98+ }
5099
51- Ok ( ch . len_utf8 ( ) )
100+ Ok ( bytes_copied )
52101 }
53102}
54103
@@ -90,11 +139,11 @@ impl io::Write for Stderr {
90139 }
91140}
92141
93- // UCS-2 character should occupy 3 bytes at most in UTF-8
94- pub const STDIN_BUF_SIZE : usize = 3 ;
142+ // UTF-16 character should occupy 4 bytes at most in UTF-8
143+ pub const STDIN_BUF_SIZE : usize = 4 ;
95144
96145pub fn is_ebadf ( _err : & io:: Error ) -> bool {
97- true
146+ false
98147}
99148
100149pub fn panic_output ( ) -> Option < impl io:: Write > {
@@ -105,19 +154,15 @@ fn write(
105154 protocol : * mut r_efi:: protocols:: simple_text_output:: Protocol ,
106155 buf : & [ u8 ] ,
107156) -> io:: Result < usize > {
108- let mut utf16 = [ 0 ; MAX_BUFFER_SIZE / 2 ] ;
109-
110157 // Get valid UTF-8 buffer
111158 let utf8 = match crate :: str:: from_utf8 ( buf) {
112159 Ok ( x) => x,
113160 Err ( e) => unsafe { crate :: str:: from_utf8_unchecked ( & buf[ ..e. valid_up_to ( ) ] ) } ,
114161 } ;
115- // Clip UTF-8 buffer to max UTF-16 buffer we support
116- let utf8 = & utf8[ ..utf8. floor_char_boundary ( utf16. len ( ) - 1 ) ] ;
117162
118- for ( i , ch ) in utf8. encode_utf16 ( ) . enumerate ( ) {
119- utf16 [ i ] = ch ;
120- }
163+ let mut utf16 : Vec < u16 > = utf8. encode_utf16 ( ) . collect ( ) ;
164+ // NULL terminate the string
165+ utf16 . push ( 0 ) ;
121166
122167 unsafe { simple_text_output ( protocol, & mut utf16) } ?;
123168
@@ -132,6 +177,18 @@ unsafe fn simple_text_output(
132177 if res. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( res. as_usize ( ) ) ) } else { Ok ( ( ) ) }
133178}
134179
180+ fn simple_text_input_read (
181+ stdin : * mut r_efi:: protocols:: simple_text_input:: Protocol ,
182+ ) -> io:: Result < u16 > {
183+ loop {
184+ match read_key_stroke ( stdin) {
185+ Ok ( x) => return Ok ( x. unicode_char ) ,
186+ Err ( e) if e == r_efi:: efi:: Status :: NOT_READY => wait_stdin ( stdin) ?,
187+ Err ( e) => return Err ( io:: Error :: from_raw_os_error ( e. as_usize ( ) ) ) ,
188+ }
189+ }
190+ }
191+
135192fn wait_stdin ( stdin : * mut r_efi:: protocols:: simple_text_input:: Protocol ) -> io:: Result < ( ) > {
136193 let boot_services: NonNull < r_efi:: efi:: BootServices > =
137194 uefi:: env:: boot_services ( ) . unwrap ( ) . cast ( ) ;
0 commit comments