Skip to content

Commit 299b085

Browse files
XAMPPRockypepyakin
authored andcommitted
Document and slightly refactor BinaryReader (#152)
* Document and slightly refactor BinaryReader * Update src/binary_reader.rs Co-Authored-By: Sergei Pepyakin <[email protected]>
1 parent 17022cf commit 299b085

File tree

1 file changed

+115
-16
lines changed

1 file changed

+115
-16
lines changed

src/binary_reader.rs

Lines changed: 115 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
use std::boxed::Box;
17+
use std::convert::TryInto;
1718
use std::str;
1819
use std::vec::Vec;
1920

@@ -38,36 +39,43 @@ fn is_name_prefix(name: &str, prefix: &'static str) -> bool {
3839
name.starts_with(prefix)
3940
}
4041

41-
const WASM_MAGIC_NUMBER: u32 = 0x6d736100;
42+
const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm";
4243
const WASM_EXPERIMENTAL_VERSION: u32 = 0xd;
4344
const WASM_SUPPORTED_VERSION: u32 = 0x1;
4445

45-
pub struct SectionHeader<'a> {
46+
pub(crate) struct SectionHeader<'a> {
4647
pub code: SectionCode<'a>,
4748
pub payload_start: usize,
4849
pub payload_len: usize,
4950
}
5051

5152
/// Bytecode range in the WebAssembly module.
52-
#[derive(Debug, Copy, Clone)]
53+
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
5354
pub struct Range {
55+
/// The start bound of the range.
5456
pub start: usize,
57+
/// The end bound of the range.
5558
pub end: usize,
5659
}
5760

5861
impl Range {
62+
/// Constructs a new instance of `Range`.
63+
///
64+
/// # Panics
65+
/// If `start` is greater than `end`.
5966
pub fn new(start: usize, end: usize) -> Range {
6067
assert!(start <= end);
6168
Range { start, end }
6269
}
6370

71+
/// Returns a new slice between `start` and `end - 1` from `data`.
6472
pub fn slice<'a>(&self, data: &'a [u8]) -> &'a [u8] {
6573
&data[self.start..self.end]
6674
}
6775
}
6876

6977
/// A binary reader of the WebAssembly structures and types.
70-
#[derive(Clone)]
78+
#[derive(Clone, Debug)]
7179
pub struct BinaryReader<'a> {
7280
pub(crate) buffer: &'a [u8],
7381
pub(crate) position: usize,
@@ -94,6 +102,7 @@ impl<'a> BinaryReader<'a> {
94102
}
95103
}
96104

105+
/// Constructs a `BinaryReader` with an explicit starting offset.
97106
pub fn new_with_offset(data: &[u8], original_offset: usize) -> BinaryReader {
98107
BinaryReader {
99108
buffer: data,
@@ -106,6 +115,7 @@ impl<'a> BinaryReader<'a> {
106115
self.original_offset + self.position
107116
}
108117

118+
/// Returns a range from the starting offset to the end of the buffer.
109119
pub fn range(&self) -> Range {
110120
Range {
111121
start: self.original_offset,
@@ -374,48 +384,77 @@ impl<'a> BinaryReader<'a> {
374384
})
375385
}
376386

387+
/// Returns whether the `BinaryReader` has reached the end of the file.
377388
pub fn eof(&self) -> bool {
378389
self.position >= self.buffer.len()
379390
}
380391

392+
/// Returns the `BinaryReader`'s current position.
381393
pub fn current_position(&self) -> usize {
382394
self.position
383395
}
384396

397+
/// Returns the number of bytes remaining in the `BinaryReader`.
385398
pub fn bytes_remaining(&self) -> usize {
386399
self.buffer.len() - self.position
387400
}
388401

402+
/// Advances the `BinaryReader` `size` bytes, and returns a slice from the
403+
/// current position of `size` length.
404+
///
405+
/// # Errors
406+
/// If `size` exceeds the remaining length in `BinaryReader`.
389407
pub fn read_bytes(&mut self, size: usize) -> Result<&'a [u8]> {
390408
self.ensure_has_bytes(size)?;
391409
let start = self.position;
392410
self.position += size;
393411
Ok(&self.buffer[start..self.position])
394412
}
395413

414+
/// Advances the `BinaryReader` four bytes and returns a `u32`.
415+
/// # Errors
416+
/// If `BinaryReader` has less than four bytes remaining.
396417
pub fn read_u32(&mut self) -> Result<u32> {
397418
self.ensure_has_bytes(4)?;
398-
let b1 = u32::from(self.buffer[self.position]);
399-
let b2 = u32::from(self.buffer[self.position + 1]);
400-
let b3 = u32::from(self.buffer[self.position + 2]);
401-
let b4 = u32::from(self.buffer[self.position + 3]);
419+
let word = u32::from_le_bytes(
420+
self.buffer[self.position..self.position + 4]
421+
.try_into()
422+
.unwrap(),
423+
);
402424
self.position += 4;
403-
Ok(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24))
425+
Ok(word)
404426
}
405427

428+
/// Advances the `BinaryReader` eight bytes and returns a `u64`.
429+
/// # Errors
430+
/// If `BinaryReader` has less than eight bytes remaining.
406431
pub fn read_u64(&mut self) -> Result<u64> {
407-
let w1 = u64::from(self.read_u32()?);
408-
let w2 = u64::from(self.read_u32()?);
409-
Ok(w1 | (w2 << 32))
432+
self.ensure_has_bytes(8)?;
433+
let word = u64::from_le_bytes(
434+
self.buffer[self.position..self.position + 8]
435+
.try_into()
436+
.unwrap(),
437+
);
438+
self.position += 8;
439+
Ok(word)
410440
}
411441

442+
/// Advances the `BinaryReader` a single byte, and returns the data as
443+
/// a `u32`.
444+
/// # Errors
445+
/// If `BinaryReader` has no bytes remaining.
412446
pub fn read_u8(&mut self) -> Result<u32> {
413447
self.ensure_has_byte()?;
414448
let b = u32::from(self.buffer[self.position]);
415449
self.position += 1;
416450
Ok(b)
417451
}
418452

453+
/// Advances the `BinaryReader` up to two bytes to parse a variable
454+
/// length integer as a `u8`.
455+
/// # Errors
456+
/// If `BinaryReader` has less than one or two bytes remaining, or the
457+
/// integer is larger than eight bits.
419458
pub fn read_var_u8(&mut self) -> Result<u32> {
420459
// Optimization for single byte i32.
421460
let byte = self.read_u8()?;
@@ -433,6 +472,11 @@ impl<'a> BinaryReader<'a> {
433472
Ok(result)
434473
}
435474

475+
/// Advances the `BinaryReader` up to four bytes to parse a variable
476+
/// length integer as a `u32`.
477+
/// # Errors
478+
/// If `BinaryReader` has less than one or up to four bytes remaining, or
479+
/// the integer is larger than 32 bits.
436480
pub fn read_var_u32(&mut self) -> Result<u32> {
437481
// Optimization for single byte i32.
438482
let byte = self.read_u8()?;
@@ -460,6 +504,11 @@ impl<'a> BinaryReader<'a> {
460504
Ok(result)
461505
}
462506

507+
/// Advances the `BinaryReader` up to four bytes over a variable length 32
508+
/// bit integer, discarding the result.
509+
/// # Errors
510+
/// If `BinaryReader` has less than one or up to four bytes remaining, or
511+
/// the integer is larger than 32 bits.
463512
pub fn skip_var_32(&mut self) -> Result<()> {
464513
for _ in 0..5 {
465514
let byte = self.read_u8()?;
@@ -473,16 +522,26 @@ impl<'a> BinaryReader<'a> {
473522
})
474523
}
475524

525+
/// Alias method for `BinaryReader::skip_var_u32`.
476526
pub fn skip_type(&mut self) -> Result<()> {
477527
self.skip_var_32()
478528
}
479529

530+
/// Advances the `BinaryReader` `len` bytes, skipping the result.
531+
/// # Errors
532+
/// If `BinaryReader` has less than `len` bytes remaining.
480533
pub fn skip_bytes(&mut self, len: usize) -> Result<()> {
481534
self.ensure_has_bytes(len)?;
482535
self.position += len;
483536
Ok(())
484537
}
485538

539+
/// Advances the `BinaryReader` past a WebAssembly string. This method does
540+
/// not perform any utf-8 validation.
541+
/// # Errors
542+
/// If `BinaryReader` has less than four bytes, the string's length exceeds
543+
/// the remaining bytes, or the string length
544+
/// exceeds `limits::MAX_WASM_STRING_SIZE`.
486545
pub fn skip_string(&mut self) -> Result<()> {
487546
let len = self.read_var_u32()? as usize;
488547
if len > MAX_WASM_STRING_SIZE {
@@ -502,6 +561,11 @@ impl<'a> BinaryReader<'a> {
502561
self.position = position;
503562
}
504563

564+
/// Advances the `BinaryReader` up to four bytes to parse a variable
565+
/// length integer as a `i32`.
566+
/// # Errors
567+
/// If `BinaryReader` has less than one or up to four bytes remaining, or
568+
/// the integer is larger than 32 bits.
505569
pub fn read_var_i32(&mut self) -> Result<i32> {
506570
// Optimization for single byte i32.
507571
let byte = self.read_u8()?;
@@ -534,6 +598,11 @@ impl<'a> BinaryReader<'a> {
534598
Ok((result << ashift) >> ashift)
535599
}
536600

601+
/// Advances the `BinaryReader` up to four bytes to parse a variable
602+
/// length integer as a signed 33 bit integer, returned as a `i64`.
603+
/// # Errors
604+
/// If `BinaryReader` has less than one or up to five bytes remaining, or
605+
/// the integer is larger than 33 bits.
537606
pub fn read_var_s33(&mut self) -> Result<i64> {
538607
// Optimization for single byte.
539608
let byte = self.read_u8()?;
@@ -551,7 +620,7 @@ impl<'a> BinaryReader<'a> {
551620
let sign_and_unused_bit = (byte << 1) as i8 >> (33 - shift);
552621
if continuation_bit || (sign_and_unused_bit != 0 && sign_and_unused_bit != -1) {
553622
return Err(BinaryReaderError {
554-
message: "Invalid var_i33",
623+
message: "Invalid var_s33",
555624
offset: self.original_position() - 1,
556625
});
557626
}
@@ -566,6 +635,11 @@ impl<'a> BinaryReader<'a> {
566635
Ok((result << ashift) >> ashift)
567636
}
568637

638+
/// Advances the `BinaryReader` up to eight bytes to parse a variable
639+
/// length integer as a 64 bit integer, returned as a `i64`.
640+
/// # Errors
641+
/// If `BinaryReader` has less than one or up to eight bytes remaining, or
642+
/// the integer is larger than 64 bits.
569643
pub fn read_var_i64(&mut self) -> Result<i64> {
570644
let mut result: i64 = 0;
571645
let mut shift = 0;
@@ -592,16 +666,31 @@ impl<'a> BinaryReader<'a> {
592666
Ok((result << ashift) >> ashift)
593667
}
594668

669+
/// Advances the `BinaryReader` up to four bytes to parse a variable
670+
/// length integer as a 32 bit floating point integer, returned as `Ieee32`.
671+
/// # Errors
672+
/// If `BinaryReader` has less than one or up to four bytes remaining, or
673+
/// the integer is larger than 32 bits.
595674
pub fn read_f32(&mut self) -> Result<Ieee32> {
596675
let value = self.read_u32()?;
597676
Ok(Ieee32(value))
598677
}
599678

679+
/// Advances the `BinaryReader` up to four bytes to parse a variable
680+
/// length integer as a 32 bit floating point integer, returned as `Ieee32`.
681+
/// # Errors
682+
/// If `BinaryReader` has less than one or up to four bytes remaining, or
683+
/// the integer is larger than 32 bits.
600684
pub fn read_f64(&mut self) -> Result<Ieee64> {
601685
let value = self.read_u64()?;
602686
Ok(Ieee64(value))
603687
}
604688

689+
/// Reads a WebAssembly string from the module.
690+
/// # Errors
691+
/// If `BinaryReader` has less than up to four bytes remaining, the string's
692+
/// length exceeds the remaining bytes, the string's length exceeds
693+
/// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8.
605694
pub fn read_string(&mut self) -> Result<&'a str> {
606695
let len = self.read_var_u32()? as usize;
607696
if len > MAX_WASM_STRING_SIZE {
@@ -859,6 +948,10 @@ impl<'a> BinaryReader<'a> {
859948
}
860949
}
861950

951+
/// Reads the next available `Operator`.
952+
/// # Errors
953+
/// If `BinaryReader` has less bytes remaining than required to parse
954+
/// the `Operator`.
862955
pub fn read_operator(&mut self) -> Result<Operator<'a>> {
863956
let code = self.read_u8()? as u8;
864957
Ok(match code {
@@ -1442,8 +1535,8 @@ impl<'a> BinaryReader<'a> {
14421535
0xc0 => Operator::V8x16Swizzle,
14431536
0x03 | 0xc1 => {
14441537
let mut lanes = [0 as SIMDLaneIndex; 16];
1445-
for i in 0..16 {
1446-
lanes[i] = self.read_lane_index(32)?
1538+
for lane in &mut lanes {
1539+
*lane = self.read_lane_index(32)?
14471540
}
14481541
Operator::V8x16Shuffle { lanes }
14491542
}
@@ -1469,7 +1562,7 @@ impl<'a> BinaryReader<'a> {
14691562
}
14701563

14711564
pub(crate) fn read_file_header(&mut self) -> Result<u32> {
1472-
let magic_number = self.read_u32()?;
1565+
let magic_number = self.read_bytes(4)?;
14731566
if magic_number != WASM_MAGIC_NUMBER {
14741567
return Err(BinaryReaderError {
14751568
message: "Bad magic number",
@@ -1560,6 +1653,11 @@ impl<'a> BrTable<'a> {
15601653
self.cnt
15611654
}
15621655

1656+
/// Returns whether `BrTable` doesn't have any labels apart from the default one.
1657+
pub fn is_empty(&self) -> bool {
1658+
self.len() == 0
1659+
}
1660+
15631661
/// Reads br_table entries.
15641662
///
15651663
/// # Examples
@@ -1602,6 +1700,7 @@ impl<'a> BrTable<'a> {
16021700
/// }
16031701
/// }
16041702
/// ```
1703+
#[derive(Clone, Debug)]
16051704
pub struct BrTableIterator<'a> {
16061705
reader: BinaryReader<'a>,
16071706
}

0 commit comments

Comments
 (0)