v/vlib/os/file_le_be.c.v
2025-03-25 15:34:57 +02:00

149 lines
4.5 KiB
V

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
}
// write_u8 writes a single byte value to the file `f`.
// Note: if possible, use some of the other APIs, that write larger chunks of data, before using write_u8/1.
pub fn (mut f File) write_u8(b u8) ! {
C.errno = 0 // needed for tcc
check_fwrite(C.fwrite(voidptr(&b), 1, 1, f.cfile))!
}
// read_u8 reads a single byte value from the file `f`.
// Note: if possible, use some of the other APIs, that read larger chunks of data, before using read_u8/1.
pub fn (mut f File) read_u8() !u8 {
mut res := u8(0)
C.errno = 0 // needed for tcc
check_fread(C.fread(voidptr(&res), 1, 1, f.cfile))!
return res
}
// private helpers
@[inline]
fn swap_bytes_u16(x u16) u16 {
// vfmt off
return ((x >> 8) & 0x00FF) |
((x << 8) & 0xFF00)
// vfmt on
}
@[inline]
fn swap_bytes_u32(x u32) u32 {
// vfmt off
return ((x >> 24) & 0x0000_00FF) |
((x >> 8) & 0x0000_FF00) |
((x << 8) & 0x00FF_0000) |
((x << 24) & 0xFF00_0000)
// vfmt on
}
@[inline]
fn swap_bytes_u64(x u64) u64 {
// vfmt off
return ((x >> 56) & 0x00000000_000000FF) |
((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)
// vfmt on
}
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]().str())
}
}
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')!
}