1
1
use core:: arch:: asm;
2
2
use core:: cmp:: min;
3
+ use crate :: dos:: error_code:: ErrorCode ;
3
4
4
5
extern crate rlibc;
5
6
6
7
#[ allow( dead_code) ]
7
8
pub struct File {
8
9
handle : u16 ,
9
10
}
11
+ #[ allow( dead_code) ]
12
+ pub enum SeekFrom {
13
+ Start ( u32 ) ,
14
+ End ( u32 ) ,
15
+ Current ( u32 ) ,
16
+ }
17
+
18
+ impl SeekFrom {
19
+ fn to_dos_seek_code ( & self ) -> u8 {
20
+ match self {
21
+ SeekFrom :: Start ( _) => 0 ,
22
+ SeekFrom :: End ( _) => 2 ,
23
+ SeekFrom :: Current ( _) => 1 ,
24
+ }
25
+ }
26
+
27
+ fn to_seek_offset ( & self ) -> u32 {
28
+ match self {
29
+ SeekFrom :: Start ( offset) => * offset,
30
+ SeekFrom :: End ( offset) => * offset,
31
+ SeekFrom :: Current ( offset) => * offset,
32
+ }
33
+ }
34
+ }
10
35
11
- // TODO: return Err(error_code) instead of Err()
12
36
#[ allow( dead_code) ]
13
37
#[ allow( unused_assignments) ]
14
38
impl File {
15
- pub fn open ( filename : & str ) -> Result < Self , ( ) > {
39
+ pub fn open ( filename : & str ) -> Result < Self , ErrorCode > {
16
40
let mut is_open_success: u16 = 1 ; // 0: success, 1: fail
17
41
let mut error_code_or_handle: u16 = 0 ;
18
42
// DOS PATH length limit is 66 bytes.
@@ -25,35 +49,34 @@ impl File {
25
49
asm ! ( "mov al, 0x40" , "mov ah, 0x3d" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "dx" ) filename_ptr as u16 , lateout( "cx" ) is_open_success, lateout( "ax" ) error_code_or_handle) ;
26
50
}
27
51
if is_open_success == 1 {
28
- return Err ( ( ) ) ;
52
+ return Err ( ErrorCode :: from_u8 ( error_code_or_handle as u8 ) . unwrap_or ( ErrorCode :: UnknownError ) ) ;
29
53
}
30
54
Ok ( Self {
31
55
handle : error_code_or_handle,
32
56
} )
33
57
}
34
58
35
- pub fn read ( & self , buffer : & mut [ u8 ] ) -> Result < usize , ( ) > {
59
+ pub fn read ( & self , buffer : & mut [ u8 ] ) -> Result < usize , ErrorCode > {
36
60
let mut total_bytes_read: usize = 0 ;
37
61
for buffer_write_pos in 0 ..buffer. len ( ) {
38
62
let mut is_read_success: u16 = 1 ; // 0: success, 1: fail
39
63
let mut error_code_or_bytes_read: u16 = 0 ;
40
64
let mut tmp_stack_buffer: [ u8 ; 1 ] = [ 0 ; 1 ] ; // To be sure of the segment
41
65
let tmp_buffer_ptr = tmp_stack_buffer. as_mut_ptr ( ) ;
42
66
unsafe {
43
- let mut registers: [ u16 ; 4 ] = [ 0 ; 4 ] ; // Save registers content on the stack
44
- asm ! ( "nop" , out( "ax" ) registers[ 0 ] , out( "bx" ) registers[ 1 ] , out( "cx" ) registers[ 2 ] , out( "dx" ) registers[ 3 ] ) ;
67
+ asm ! ( "push ax" , "push bx" , "push cx" , "push dx" ) ;
45
68
asm ! ( "mov cx, 1" , "mov ah, 0x3f" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "bx" ) self . handle, in( "dx" ) tmp_buffer_ptr, lateout( "cx" ) is_read_success, lateout( "ax" ) error_code_or_bytes_read) ;
46
- asm ! ( "nop " , in ( "ax" ) registers [ 0 ] , in ( " bx") registers [ 1 ] , in ( "cx" ) registers [ 2 ] , in ( "dx" ) registers [ 3 ] ) ;
69
+ asm ! ( "pop dx " , "pop cx" , "pop bx", "pop ax" ) ;
47
70
}
48
71
if is_read_success == 1 {
49
- return Err ( ( ) ) ;
72
+ return Err ( ErrorCode :: from_u8 ( error_code_or_bytes_read as u8 ) . unwrap_or ( ErrorCode :: UnknownError ) ) ;
50
73
}
51
74
if error_code_or_bytes_read == 0 {
52
75
// End of file
53
76
break ;
54
77
}
55
-
56
- total_bytes_read += error_code_or_bytes_read as usize ; // = 1
78
+ //total_bytes_read += error_code_or_bytes_read as usize; // = 1
79
+ total_bytes_read += 1 as usize ;
57
80
buffer[ buffer_write_pos] = tmp_stack_buffer[ 0 ] ;
58
81
}
59
82
@@ -64,18 +87,71 @@ impl File {
64
87
Ok ( total_bytes_read)
65
88
}
66
89
67
- pub fn close ( self ) -> Result < ( ) , ( ) > {
90
+ // TODO check
91
+ pub fn write ( & self , buffer : & [ u8 ] ) -> Result < usize , ErrorCode > {
92
+ let mut total_bytes_written: usize = 0 ;
93
+ for buffer_read_pos in 0 ..buffer. len ( ) {
94
+ let mut is_write_success: u16 = 1 ; // 0: success, 1: fail
95
+ let mut error_code_or_bytes_written: u16 = 0 ;
96
+ let mut tmp_stack_buffer: [ u8 ; 1 ] = [ 0 ; 1 ] ; // To be sure of the segment
97
+ tmp_stack_buffer[ 0 ] = buffer[ buffer_read_pos] ;
98
+ let tmp_buffer_ptr = tmp_stack_buffer. as_ptr ( ) ;
99
+ unsafe {
100
+ asm ! ( "push ax" , "push bx" , "push cx" , "push dx" ) ;
101
+ asm ! ( "mov cx, 1" , "mov ah, 0x40" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "bx" ) self . handle, in( "dx" ) tmp_buffer_ptr, lateout( "cx" ) is_write_success, lateout( "ax" ) error_code_or_bytes_written) ;
102
+ asm ! ( "pop dx" , "pop cx" , "pop bx" , "pop ax" ) ;
103
+ }
104
+ if is_write_success == 1 {
105
+ return Err ( ErrorCode :: from_u8 ( error_code_or_bytes_written as u8 ) . unwrap_or ( ErrorCode :: UnknownError ) ) ;
106
+ }
107
+ //total_bytes_written += error_code_or_bytes_written as usize; // = 1
108
+ total_bytes_written += 1 as usize ;
109
+ }
110
+ Ok ( total_bytes_written)
111
+ }
112
+
113
+ pub fn close ( self ) -> Result < ( ) , ErrorCode > {
114
+ self . close_with_ref ( )
115
+ }
116
+
117
+ fn close_with_ref ( & self ) -> Result < ( ) , ErrorCode > {
68
118
let mut is_close_success: u16 = 1 ; // 0: success, 1: fail
69
- let mut _error_code : u16 = 0 ; // 6 = unknown handle
119
+ let mut error_code : u16 = 0 ; // 6 = unknown handle
70
120
unsafe {
71
- let mut registers: [ u16 ; 4 ] = [ 0 ; 4 ] ; // Save registers content on the stack
72
- asm ! ( "nop" , out( "ax" ) registers[ 0 ] , out( "bx" ) registers[ 1 ] , out( "cx" ) registers[ 2 ] , out( "dx" ) registers[ 3 ] ) ;
73
- asm ! ( "mov ah, 0x3e" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "bx" ) self . handle, lateout( "cx" ) is_close_success, lateout( "ax" ) _error_code) ;
74
- asm ! ( "nop" , in( "ax" ) registers[ 0 ] , in( "bx" ) registers[ 1 ] , in( "cx" ) registers[ 2 ] , in( "dx" ) registers[ 3 ] ) ;
121
+ asm ! ( "push ax" , "push bx" , "push cx" , "push dx" ) ;
122
+ asm ! ( "mov ah, 0x3e" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "bx" ) self . handle, lateout( "cx" ) is_close_success, lateout( "ax" ) error_code) ;
123
+ asm ! ( "pop dx" , "pop cx" , "pop bx" , "pop ax" ) ;
75
124
}
76
125
if is_close_success == 1 {
77
- return Err ( ( ) ) ;
126
+ return Err ( ErrorCode :: from_u8 ( error_code as u8 ) . unwrap_or ( ErrorCode :: UnknownError ) ) ;
78
127
}
79
128
Ok ( ( ) )
80
129
}
130
+
131
+ /// Seek to an offset, in bytes, in a stream.
132
+ /// Returns number of bytes from the start of the stream if success, or an error code otherwise.
133
+ pub fn seek ( & self , pos : SeekFrom ) -> Result < u32 , ErrorCode > {
134
+ let mut is_seek_success: u16 = 1 ; // 0: success, 1: fail
135
+ let mut error_code_or_new_pos_low_from_start: u16 = 0 ;
136
+ let mut new_pos_high_from_start: u16 = 0 ;
137
+ let requested_relative_new_pos: u32 = pos. to_seek_offset ( ) ;
138
+ let requested_relative_new_pos_low = ( requested_relative_new_pos & 0xffff ) as u16 ;
139
+ let requested_relative_new_pos_high = ( ( requested_relative_new_pos >> 16 ) & 0xffff ) as u16 ;
140
+ let seek_from: u8 = pos. to_dos_seek_code ( ) ;
141
+ unsafe {
142
+ asm ! ( "push ax" , "push bx" , "push cx" , "push dx" ) ;
143
+ asm ! ( "mov ah, 0x42" , "int 0x21" , "setc dl" , "movzx cx, dl" , in( "bx" ) self . handle, in( "cx" ) requested_relative_new_pos_high as u16 , in( "dx" ) requested_relative_new_pos_low, in( "al" ) seek_from, lateout( "cx" ) is_seek_success, lateout( "ax" ) error_code_or_new_pos_low_from_start, lateout( "dx" ) new_pos_high_from_start) ;
144
+ asm ! ( "pop dx" , "pop cx" , "pop bx" , "pop ax" ) ;
145
+ }
146
+ if is_seek_success == 1 {
147
+ return Err ( ErrorCode :: from_u8 ( error_code_or_new_pos_low_from_start as u8 ) . unwrap_or ( ErrorCode :: UnknownError ) ) ;
148
+ }
149
+ Ok ( ( new_pos_high_from_start as u32 ) << 16 | ( error_code_or_new_pos_low_from_start as u32 ) )
150
+ }
81
151
}
152
+
153
+ impl Drop for File {
154
+ fn drop ( & mut self ) {
155
+ let _ = self . close_with_ref ( ) ;
156
+ }
157
+ }
0 commit comments