-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
os: add
pub (mut f File) write_le[T](x T) !
, `pub (mut f File) writ…
…e_be[T](x T) !` + read equivalents, add tests
- Loading branch information
Showing
2 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
module os | ||
|
||
// write_le writes an unsigned number value to the file. | ||
// It assumes that the value should be stored in a *little endian order*. | ||
// If the machine is a big endian one, it will first convert the big endian value to a little endian one. | ||
// It is safe to use as a cross platform way to write data, for which you have to use a predefined order (defined in a file format spec). | ||
pub fn (mut f File) write_le[T](data T) ! { | ||
mut serialized := data | ||
$if big_endian { | ||
serialized = swap_bytes(serialized) | ||
} | ||
C.errno = 0 // needed for tcc | ||
check_fwrite(C.fwrite(voidptr(&serialized), sizeof(T), 1, f.cfile))! | ||
} | ||
|
||
// write_be writes an unsigned number value to the file. | ||
// It assumes that the value should be stored in a *big endian order*. | ||
// If the machine is a little endian one, it will first convert the little endian value to a big endian one. | ||
// It is safe to use as a cross platform way to write data, for which you have to use a predefined order (defined in a file format spec). | ||
pub fn (mut f File) write_be[T](data T) ! { | ||
mut serialized := data | ||
$if little_endian { | ||
serialized = swap_bytes(serialized) | ||
} | ||
C.errno = 0 // needed for tcc | ||
check_fwrite(C.fwrite(voidptr(&serialized), sizeof(T), 1, f.cfile))! | ||
} | ||
|
||
// read_le reads an unsigned number value from the file. | ||
// It assumes that the value was stored in a *little endian order*. | ||
// If the machine is a big endian one, it will convert the value to a big endian one. | ||
// It is intended to use as a cross platform way to read data, for which the order is known (from the file format spec). | ||
pub fn (mut f File) read_le[T]() !T { | ||
mut serialized := T(0) | ||
C.errno = 0 // needed for tcc | ||
check_fread(C.fread(voidptr(&serialized), sizeof(T), 1, f.cfile))! | ||
$if big_endian { | ||
return swap_bytes(serialized) | ||
} | ||
return serialized | ||
} | ||
|
||
// read_be reads an unsigned number value from the file. | ||
// It assumes that the value was stored in a *big endian order*. | ||
// If the machine is a little endian one, it will convert the value to a little endian one. | ||
// It is intended to use as a cross platform way to read data, for which the order is known (from the file format spec). | ||
pub fn (mut f File) read_be[T]() !T { | ||
mut serialized := T(0) | ||
C.errno = 0 // needed for tcc | ||
check_fread(C.fread(voidptr(&serialized), sizeof(T), 1, f.cfile))! | ||
$if little_endian { | ||
return swap_bytes(serialized) | ||
} | ||
return serialized | ||
} | ||
|
||
// private helpers | ||
|
||
@[inline] | ||
fn swap_bytes_u16(x u16) u16 { | ||
return ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00) | ||
} | ||
|
||
@[inline] | ||
fn swap_bytes_u32(x u32) u32 { | ||
return ((x >> 24) & 0x0000_00FF) | ((x >> 8) & 0x0000_FF00) | ((x << 8) & 0x00FF_0000) | ((x << 24) & 0xFF00_0000) | ||
} | ||
|
||
@[inline] | ||
fn swap_bytes_u64(x u64) u64 { | ||
return ((x >> 40) & 0x00000000_0000FF00) | ((x >> 24) & 0x00000000_00FF0000) | ((x >> 8) & 0x00000000_FF000000) | ((x << 8) & 0x000000FF_00000000) | ((x << 24) & 0x0000FF00_00000000) | ((x << 40) & 0x00FF0000_00000000) | ((x << 56) & 0xFF000000_00000000) | ||
} | ||
|
||
fn swap_bytes[T](input T) T { | ||
$if T is u8 { | ||
return input | ||
} $else $if T is i8 { | ||
return input | ||
} $else $if T is byte { | ||
return input | ||
} $else $if T is u16 { | ||
return swap_bytes_u16(input) | ||
} $else $if T is u32 { | ||
return swap_bytes_u32(input) | ||
} $else $if T is u64 { | ||
return swap_bytes_u64(input) | ||
} $else $if T is i16 { | ||
return i16(swap_bytes_u16(u16(input))) | ||
} $else $if T is i32 { | ||
return i32(swap_bytes_u32(u32(input))) | ||
} $else $if T is int { | ||
return i32(swap_bytes_u32(u32(input))) | ||
} $else $if T is i64 { | ||
return i64(swap_bytes_u64(u64(input))) | ||
} $else { | ||
panic('type is not supported: ${typeof[T]()}') | ||
} | ||
} | ||
|
||
fn check_cf(x usize, label string) ! { | ||
if C.errno != 0 { | ||
return error(posix_get_error_msg(C.errno)) | ||
} | ||
if x == 0 { | ||
return error(label) | ||
} | ||
} | ||
|
||
fn check_fwrite(x usize) ! { | ||
check_cf(x, 'fwrite')! | ||
} | ||
|
||
fn check_fread(x usize) ! { | ||
check_cf(x, 'fread')! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import os | ||
|
||
const tfolder = os.join_path(os.vtmp_dir(), 'os_file_le_be') | ||
|
||
fn testsuite_begin() { | ||
os.mkdir_all(tfolder) or {} | ||
os.chdir(tfolder)! | ||
dump(tfolder) | ||
assert os.is_dir(tfolder) | ||
} | ||
|
||
fn testsuite_end() { | ||
os.rmdir_all(tfolder) or {} | ||
} | ||
|
||
fn test_write_be_read_be() { | ||
fname := os.join_path(tfolder, 'f_be') | ||
os.write_file(os.join_path(tfolder, 'abc'), 'hello')! | ||
mut f := os.open_file(fname, 'wb')! | ||
f.write_be[u8](0x08)! | ||
f.write_be[u16](0x1617)! | ||
f.write_be[u32](0x3233)! | ||
f.write_be[u64](0x6465)! | ||
f.close() | ||
// vfmt off | ||
assert os.read_bytes(fname)! == [ | ||
u8(0x08), | ||
0x16, 0x17, | ||
0x00, 0x00, 0x32, 0x33, | ||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, | ||
] | ||
// vfmt on | ||
} | ||
|
||
fn test_write_le_read_le() { | ||
fname := os.join_path(tfolder, 'f_le') | ||
mut f := os.open_file(fname, 'wb')! | ||
f.write_le[u8](0x08)! | ||
f.write_le[u16](0x1617)! | ||
f.write_le[u32](0x3233)! | ||
f.write_le[u64](0x6465)! | ||
f.close() | ||
// vfmt off | ||
assert os.read_bytes('f_le')! == [ | ||
u8(0x08), | ||
0x17, 0x16, | ||
0x33, 0x32, 0x00, 0x00, | ||
0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
] | ||
// vfmt on | ||
mut r := os.open_file(fname, 'rb')! | ||
assert r.read_le[u8]()! == 0x08 | ||
assert r.read_le[u16]()! == 0x1617 | ||
assert r.read_le[u32]()! == 0x3233 | ||
assert r.read_le[u64]()! == 0x6465 | ||
r.close() | ||
} |