|
1 |
| -import { HEADER_SIZE } from "./internal/arraybuffer"; |
| 1 | +import { |
| 2 | + HEADER_SIZE, |
| 3 | + MAX_BLENGTH |
| 4 | +} from "./internal/arraybuffer"; |
2 | 5 |
|
3 | 6 | export class DataView {
|
| 7 | + |
4 | 8 | constructor(
|
5 | 9 | readonly buffer: ArrayBuffer,
|
6 | 10 | readonly byteOffset: i32 = 0,
|
7 |
| - readonly byteLength: i32 = i32.MIN_VALUE, |
| 11 | + readonly byteLength: i32 = i32.MIN_VALUE // FIXME |
8 | 12 | ) {
|
9 |
| - if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; |
10 |
| - |
11 |
| - if (byteOffset < 0) throw new RangeError("byteOffset cannot be negative"); |
12 |
| - if (byteLength < 0) throw new RangeError("byteLength cannot be negative"); |
13 |
| - if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Length out of range of buffer"); |
| 13 | + if (byteLength === i32.MIN_VALUE) byteLength = buffer.byteLength - byteOffset; // FIXME |
| 14 | + if (<u32>byteOffset > <u32>MAX_BLENGTH) throw new RangeError("Invalid byteOffset"); |
| 15 | + if (<u32>byteLength > <u32>MAX_BLENGTH) throw new RangeError("Invalid byteLength"); |
| 16 | + if (byteOffset + byteLength > buffer.byteLength) throw new RangeError("Invalid length"); |
14 | 17 | }
|
15 | 18 |
|
16 |
| - @inline |
17 | 19 | getFloat32(byteOffset: i32, littleEndian: boolean = false): f32 {
|
18 |
| - var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
19 |
| - return reinterpret<f32>(littleEndian ? result : bswap<u32>(result)); |
| 20 | + checkOffset(byteOffset, 4, this.byteLength); |
| 21 | + return littleEndian |
| 22 | + ? load<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE) |
| 23 | + : reinterpret<f32>( |
| 24 | + bswap<u32>( |
| 25 | + load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE) |
| 26 | + ) |
| 27 | + ); |
20 | 28 | }
|
21 | 29 |
|
22 |
| - @inline |
23 | 30 | getFloat64(byteOffset: i32, littleEndian: boolean = false): f64 {
|
24 |
| - var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
25 |
| - return reinterpret<f64>(littleEndian ? result : bswap<u64>(result)); |
| 31 | + checkOffset(byteOffset, 8, this.byteLength); |
| 32 | + return littleEndian |
| 33 | + ? load<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE) |
| 34 | + : reinterpret<f64>( |
| 35 | + bswap( |
| 36 | + load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE) |
| 37 | + ) |
| 38 | + ); |
26 | 39 | }
|
27 | 40 |
|
28 |
| - @inline |
29 | 41 | getInt8(byteOffset: i32): i8 {
|
| 42 | + checkOffset(byteOffset, 1, this.byteLength); |
30 | 43 | return load<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
|
31 | 44 | }
|
32 | 45 |
|
33 |
| - @inline |
34 | 46 | getInt16(byteOffset: i32, littleEndian: boolean = false): i16 {
|
| 47 | + checkOffset(byteOffset, 2, this.byteLength); |
35 | 48 | var result: i16 = load<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
|
36 | 49 | return littleEndian ? result : bswap<i16>(result);
|
37 | 50 | }
|
38 | 51 |
|
39 |
| - @inline |
40 | 52 | getInt32(byteOffset: i32, littleEndian: boolean = false): i32 {
|
41 |
| - var result: i32 = load<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
| 53 | + checkOffset(byteOffset, 4, this.byteLength); |
| 54 | + var result = load<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
42 | 55 | return littleEndian ? result : bswap<i32>(result);
|
43 | 56 | }
|
44 | 57 |
|
45 |
| - @inline |
46 | 58 | getUint8(byteOffset: i32): u8 {
|
| 59 | + checkOffset(byteOffset, 1, this.byteLength); |
47 | 60 | return load<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
|
48 | 61 | }
|
49 | 62 |
|
50 |
| - @inline |
51 | 63 | getUint16(byteOffset: i32, littleEndian: boolean = false): u16 {
|
| 64 | + checkOffset(byteOffset, 2, this.byteLength); |
52 | 65 | var result: u16 = load<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE);
|
53 | 66 | return littleEndian ? result : bswap<u16>(result);
|
54 | 67 | }
|
55 | 68 |
|
56 |
| - @inline |
57 | 69 | getUint32(byteOffset: i32, littleEndian: boolean = false): u32 {
|
58 |
| - var result: u32 = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
| 70 | + checkOffset(byteOffset, 4, this.byteLength); |
| 71 | + var result = load<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
59 | 72 | return littleEndian ? result : bswap<u32>(result);
|
60 | 73 | }
|
61 | 74 |
|
62 |
| - @inline |
63 | 75 | setFloat32(byteOffset: i32, value: f32, littleEndian: boolean = false): void {
|
64 |
| - var input: f32 = littleEndian ? value : reinterpret<f32>(bswap<u32>(reinterpret<u32>(value))); |
65 |
| - store<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE); |
| 76 | + checkOffset(byteOffset, 4, this.byteLength); |
| 77 | + if (littleEndian) { |
| 78 | + store<f32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE); |
| 79 | + } else { |
| 80 | + store<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 81 | + bswap( |
| 82 | + reinterpret<u32>(value) |
| 83 | + ), |
| 84 | + HEADER_SIZE |
| 85 | + ); |
| 86 | + } |
66 | 87 | }
|
67 | 88 |
|
68 |
| - @inline |
69 | 89 | setFloat64(byteOffset: i32, value: f64, littleEndian: boolean = false): void {
|
70 |
| - var input: f64 = littleEndian ? value : reinterpret<f64>(bswap<u64>(reinterpret<u64>(value))); |
71 |
| - store<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, input, HEADER_SIZE); |
| 90 | + checkOffset(byteOffset, 8, this.byteLength); |
| 91 | + if (littleEndian) { |
| 92 | + store<f64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE); |
| 93 | + } else { |
| 94 | + store<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 95 | + bswap( |
| 96 | + reinterpret<u64>(value) |
| 97 | + ), |
| 98 | + HEADER_SIZE |
| 99 | + ); |
| 100 | + } |
72 | 101 | }
|
73 | 102 |
|
74 |
| - @inline |
75 | 103 | setInt8(byteOffset: i32, value: i8): void {
|
| 104 | + checkOffset(byteOffset, 1, this.byteLength); |
76 | 105 | store<i8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
|
77 | 106 | }
|
78 | 107 |
|
79 |
| - @inline |
80 | 108 | setInt16(byteOffset: i32, value: i16, littleEndian: boolean = false): void {
|
81 |
| - store<i16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i16>(value), HEADER_SIZE); |
| 109 | + checkOffset(byteOffset, 2, this.byteLength); |
| 110 | + store<i16>( |
| 111 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 112 | + littleEndian ? value : bswap(value), |
| 113 | + HEADER_SIZE |
| 114 | + ); |
82 | 115 | }
|
83 | 116 |
|
84 |
| - @inline |
85 | 117 | setInt32(byteOffset: i32, value: i32, littleEndian: boolean = false): void {
|
86 |
| - store<i32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i32>(value), HEADER_SIZE); |
| 118 | + checkOffset(byteOffset, 4, this.byteLength); |
| 119 | + store<i32>( |
| 120 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 121 | + littleEndian ? value : bswap(value), |
| 122 | + HEADER_SIZE |
| 123 | + ); |
87 | 124 | }
|
88 | 125 |
|
89 |
| - @inline |
90 | 126 | setUint8(byteOffset: i32, value: u8): void {
|
| 127 | + checkOffset(byteOffset, 1, this.byteLength); |
91 | 128 | store<u8>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, value, HEADER_SIZE);
|
92 | 129 | }
|
93 | 130 |
|
94 |
| - @inline |
95 | 131 | setUint16(byteOffset: i32, value: u16, littleEndian: boolean = false): void {
|
96 |
| - store<u16>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u16>(value), HEADER_SIZE); |
| 132 | + checkOffset(byteOffset, 2, this.byteLength); |
| 133 | + store<u16>( |
| 134 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 135 | + littleEndian ? value : bswap(value), |
| 136 | + HEADER_SIZE |
| 137 | + ); |
97 | 138 | }
|
98 | 139 |
|
99 |
| - @inline |
100 | 140 | setUint32(byteOffset: i32, value: u32, littleEndian: boolean = false): void {
|
101 |
| - store<u32>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u32>(value), HEADER_SIZE); |
| 141 | + checkOffset(byteOffset, 4, this.byteLength); |
| 142 | + store<u32>( |
| 143 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 144 | + littleEndian ? value : bswap(value), |
| 145 | + HEADER_SIZE |
| 146 | + ); |
102 | 147 | }
|
103 | 148 |
|
104 |
| - /** |
105 |
| - * Non-standard additions that makes sense in WebAssembly, but won't work in JS |
106 |
| - */ |
| 149 | + // Non-standard additions that make sense in WebAssembly, but won't work in JS: |
107 | 150 |
|
108 |
| - @inline |
109 | 151 | getInt64(byteOffset: i32, littleEndian: boolean = false): i64 {
|
110 |
| - var result: i64 = load<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
111 |
| - return littleEndian ? result : bswap<i64>(result); |
| 152 | + checkOffset(byteOffset, 8, this.byteLength); |
| 153 | + var result = load<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
| 154 | + return littleEndian ? result : bswap(result); |
112 | 155 | }
|
113 | 156 |
|
114 |
| - @inline |
115 | 157 | getUint64(byteOffset: i32, littleEndian: boolean = false): u64 {
|
116 |
| - var result: u64 = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
117 |
| - return littleEndian ? result : bswap<u64>(result); |
| 158 | + checkOffset(byteOffset, 8, this.byteLength); |
| 159 | + var result = load<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, HEADER_SIZE); |
| 160 | + return littleEndian ? result : bswap(result); |
118 | 161 | }
|
119 | 162 |
|
120 |
| - @inline |
121 | 163 | setInt64(byteOffset: i32, value: i64, littleEndian: boolean = false): void {
|
122 |
| - store<i64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<i64>(value), HEADER_SIZE); |
| 164 | + checkOffset(byteOffset, 8, this.byteLength); |
| 165 | + store<i64>( |
| 166 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 167 | + littleEndian ? value : bswap(value), |
| 168 | + HEADER_SIZE |
| 169 | + ); |
123 | 170 | }
|
124 | 171 |
|
125 |
| - @inline |
126 | 172 | setUint64(byteOffset: i32, value: u64, littleEndian: boolean = false): void {
|
127 |
| - store<u64>(changetype<usize>(this.buffer) + this.byteOffset + byteOffset, littleEndian ? value : bswap<u64>(value), HEADER_SIZE); |
| 173 | + checkOffset(byteOffset, 8, this.byteLength); |
| 174 | + store<u64>( |
| 175 | + changetype<usize>(this.buffer) + this.byteOffset + byteOffset, |
| 176 | + littleEndian ? value : bswap(value), |
| 177 | + HEADER_SIZE |
| 178 | + ); |
128 | 179 | }
|
129 | 180 | }
|
| 181 | + |
| 182 | +@inline function checkOffset(byteOffset: i32, n: i32, byteLength: i32): void { |
| 183 | + // n and byteLength must be known to be in bounds |
| 184 | + if (<u32>byteOffset > <u32>MAX_BLENGTH || byteOffset + n > byteLength) throw new Error("Offset out of bounds"); |
| 185 | +} |
0 commit comments