@@ -4,51 +4,100 @@ use crate::mem::MaybeUninit;
4
4
use crate :: os:: uefi;
5
5
use crate :: ptr:: NonNull ;
6
6
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
+ }
8
39
9
- pub struct Stdin ;
10
40
pub struct Stdout ;
11
41
pub struct Stderr ;
12
42
13
43
impl Stdin {
14
44
pub const fn new ( ) -> Stdin {
15
- Stdin
45
+ Stdin { surrogate : None , incomplete_utf8 : IncompleteUtf8 :: new ( ) }
16
46
}
17
47
}
18
48
19
49
impl io:: Read for Stdin {
20
50
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
35
58
} ;
36
59
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) ;
40
62
}
41
63
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" ) ) ;
47
75
}
48
76
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
+ }
50
99
51
- Ok ( ch . len_utf8 ( ) )
100
+ Ok ( bytes_copied )
52
101
}
53
102
}
54
103
@@ -90,11 +139,11 @@ impl io::Write for Stderr {
90
139
}
91
140
}
92
141
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 ;
95
144
96
145
pub fn is_ebadf ( _err : & io:: Error ) -> bool {
97
- true
146
+ false
98
147
}
99
148
100
149
pub fn panic_output ( ) -> Option < impl io:: Write > {
@@ -105,19 +154,15 @@ fn write(
105
154
protocol : * mut r_efi:: protocols:: simple_text_output:: Protocol ,
106
155
buf : & [ u8 ] ,
107
156
) -> io:: Result < usize > {
108
- let mut utf16 = [ 0 ; MAX_BUFFER_SIZE / 2 ] ;
109
-
110
157
// Get valid UTF-8 buffer
111
158
let utf8 = match crate :: str:: from_utf8 ( buf) {
112
159
Ok ( x) => x,
113
160
Err ( e) => unsafe { crate :: str:: from_utf8_unchecked ( & buf[ ..e. valid_up_to ( ) ] ) } ,
114
161
} ;
115
- // Clip UTF-8 buffer to max UTF-16 buffer we support
116
- let utf8 = & utf8[ ..utf8. floor_char_boundary ( utf16. len ( ) - 1 ) ] ;
117
162
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 ) ;
121
166
122
167
unsafe { simple_text_output ( protocol, & mut utf16) } ?;
123
168
@@ -132,6 +177,18 @@ unsafe fn simple_text_output(
132
177
if res. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( res. as_usize ( ) ) ) } else { Ok ( ( ) ) }
133
178
}
134
179
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
+
135
192
fn wait_stdin ( stdin : * mut r_efi:: protocols:: simple_text_input:: Protocol ) -> io:: Result < ( ) > {
136
193
let boot_services: NonNull < r_efi:: efi:: BootServices > =
137
194
uefi:: env:: boot_services ( ) . unwrap ( ) . cast ( ) ;
0 commit comments