v2 / vlib / os / file_le_be.c.v
146 lines · 132 sloc · 4.5 KB · 7e1a0e77ab2c2aa06c06f361126affb2de3880a7
Raw
1module os
2
3// write_le writes an unsigned number value to the file.
4// It assumes that the value should be stored in a *little endian order*.
5// If the machine is a big endian one, it will first convert the big endian value to a little endian one.
6// 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).
7pub fn (mut f File) write_le[T](data T) ! {
8 mut serialized := data
9 $if big_endian {
10 serialized = swap_bytes(serialized)
11 }
12 C.errno = 0 // needed for tcc
13 check_fwrite(C.fwrite(voidptr(&serialized), sizeof(T), 1, f.cfile))!
14}
15
16// write_be writes an unsigned number value to the file.
17// It assumes that the value should be stored in a *big endian order*.
18// If the machine is a little endian one, it will first convert the little endian value to a big endian one.
19// 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).
20pub fn (mut f File) write_be[T](data T) ! {
21 mut serialized := data
22 $if little_endian {
23 serialized = swap_bytes(serialized)
24 }
25 C.errno = 0 // needed for tcc
26 check_fwrite(C.fwrite(voidptr(&serialized), sizeof(T), 1, f.cfile))!
27}
28
29// read_le reads an unsigned number value from the file.
30// It assumes that the value was stored in a *little endian order*.
31// If the machine is a big endian one, it will convert the value to a big endian one.
32// It is intended to use as a cross platform way to read data, for which the order is known (from the file format spec).
33pub fn (mut f File) read_le[T]() !T {
34 mut serialized := T(0)
35 C.errno = 0 // needed for tcc
36 check_fread(C.fread(voidptr(&serialized), sizeof(T), 1, f.cfile))!
37 $if big_endian {
38 return swap_bytes(serialized)
39 }
40 return serialized
41}
42
43// read_be reads an unsigned number value from the file.
44// It assumes that the value was stored in a *big endian order*.
45// If the machine is a little endian one, it will convert the value to a little endian one.
46// It is intended to use as a cross platform way to read data, for which the order is known (from the file format spec).
47pub fn (mut f File) read_be[T]() !T {
48 mut serialized := T(0)
49 C.errno = 0 // needed for tcc
50 check_fread(C.fread(voidptr(&serialized), sizeof(T), 1, f.cfile))!
51 $if little_endian {
52 return swap_bytes(serialized)
53 }
54 return serialized
55}
56
57// write_u8 writes a single byte value to the file `f`.
58// Note: if possible, use some of the other APIs, that write larger chunks of data, before using write_u8/1.
59pub fn (mut f File) write_u8(b u8) ! {
60 C.errno = 0 // needed for tcc
61 check_fwrite(C.fwrite(voidptr(&b), 1, 1, f.cfile))!
62}
63
64// read_u8 reads a single byte value from the file `f`.
65// Note: if possible, use some of the other APIs, that read larger chunks of data, before using read_u8/1.
66pub fn (mut f File) read_u8() !u8 {
67 mut res := u8(0)
68 C.errno = 0 // needed for tcc
69 check_fread(C.fread(voidptr(&res), 1, 1, f.cfile))!
70 return res
71}
72
73// private helpers
74
75@[inline]
76fn swap_bytes_u16(x u16) u16 {
77 // vfmt off
78 return ((x >> 8) & 0x00FF) |
79 ((x << 8) & 0xFF00)
80 // vfmt on
81}
82
83@[inline]
84fn swap_bytes_u32(x u32) u32 {
85 // vfmt off
86 return ((x >> 24) & 0x0000_00FF) |
87 ((x >> 8) & 0x0000_FF00) |
88 ((x << 8) & 0x00FF_0000) |
89 ((x << 24) & 0xFF00_0000)
90 // vfmt on
91}
92
93@[inline]
94fn swap_bytes_u64(x u64) u64 {
95 // vfmt off
96 return ((x >> 56) & 0x00000000_000000FF) |
97 ((x >> 40) & 0x00000000_0000FF00) |
98 ((x >> 24) & 0x00000000_00FF0000) |
99 ((x >> 8) & 0x00000000_FF000000) |
100 ((x << 8) & 0x000000FF_00000000) |
101 ((x << 24) & 0x0000FF00_00000000) |
102 ((x << 40) & 0x00FF0000_00000000) |
103 ((x << 56) & 0xFF000000_00000000)
104 // vfmt on
105}
106
107fn swap_bytes[T](input T) T {
108 $if T is u8 {
109 return input
110 } $else $if T is i8 {
111 return input
112 } $else $if T is u16 {
113 return swap_bytes_u16(input)
114 } $else $if T is u32 {
115 return swap_bytes_u32(input)
116 } $else $if T is u64 {
117 return swap_bytes_u64(input)
118 } $else $if T is i16 {
119 return i16(swap_bytes_u16(u16(input)))
120 } $else $if T is i32 {
121 return i32(swap_bytes_u32(u32(input)))
122 } $else $if T is int {
123 return i32(swap_bytes_u32(u32(input)))
124 } $else $if T is i64 {
125 return i64(swap_bytes_u64(u64(input)))
126 } $else {
127 panic('type is not supported: ' + typeof[T]().str())
128 }
129}
130
131fn check_cf(x usize, label string) ! {
132 if C.errno != 0 {
133 return error(posix_get_error_msg(C.errno))
134 }
135 if x == 0 {
136 return error(label)
137 }
138}
139
140fn check_fwrite(x usize) ! {
141 check_cf(x, 'fwrite')!
142}
143
144fn check_fread(x usize) ! {
145 check_cf(x, 'fread')!
146}
147