Skip to main content

bitcoin_cash/
encoding_utils.rs

1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use std::io;
3
4pub fn read_var_int<R: io::Read>(read: &mut R) -> io::Result<u64> {
5    let first_byte = read.read_u8()?;
6    match first_byte {
7        0..=0xfc => Ok(first_byte as u64),
8        0xfd => Ok(read.read_u16::<LittleEndian>()? as u64),
9        0xfe => Ok(read.read_u32::<LittleEndian>()? as u64),
10        0xff => Ok(read.read_u64::<LittleEndian>()? as u64),
11    }
12}
13
14pub fn write_var_int<W: io::Write>(write: &mut W, number: u64) -> io::Result<()> {
15    match number {
16        0..=0xfc => write.write_u8(number as u8)?,
17        0xfd..=0xffff => {
18            write.write_all(b"\xfd")?;
19            write.write_u16::<LittleEndian>(number as u16)?
20        }
21        0x10000..=0xffff_ffff => {
22            write.write_all(b"\xfe")?;
23            write.write_u32::<LittleEndian>(number as u32)?
24        }
25        _ => {
26            write.write_all(b"\xff")?;
27            write.write_u64::<LittleEndian>(number as u64)?
28        }
29    }
30    Ok(())
31}
32
33pub fn encode_minimally(vec: &mut Vec<u8>) {
34    // If the last byte is not 0x00 or 0x80, we are minimally encoded.
35    if let Some(&last) = vec.last() {
36        if last & 0x7f != 0 {
37            return;
38        }
39        // If the script is one byte long, then we have a zero, which encodes as an
40        // empty array.
41        if vec.len() == 1 {
42            vec.clear();
43            return;
44        }
45        // If the next byte has it sign bit set, then we are minimally encoded.
46        if vec[vec.len() - 2] & 0x80 != 0 {
47            return;
48        }
49        // We are not minimally encoded, we need to figure out how much to trim.
50        let mut i = vec.len() - 1;
51        while i > 0 {
52            // We found a non zero byte, time to encode.
53            if vec[i - 1] != 0 {
54                if vec[i - 1] & 0x80 != 0 {
55                    // We found a byte with it sign bit set so we need one more byte.
56                    vec[i] = last;
57                    i += 1;
58                } else {
59                    // the sign bit is clear, we can use it.
60                    vec[i - 1] |= last;
61                }
62                vec.resize(i, 0u8);
63                return;
64            }
65            i -= 1;
66        }
67        vec.resize(i, 0u8);
68    }
69}
70
71pub fn encode_int(int: i32) -> Vec<u8> {
72    let mut vec = Vec::new();
73    vec.write_i32::<LittleEndian>(int.abs()).unwrap();
74    if int < 0 {
75        vec.write_u8(0x80).unwrap();
76    }
77    encode_minimally(&mut vec);
78    vec
79}
80
81pub fn encode_bool(b: bool) -> Vec<u8> {
82    if b {
83        vec![0x01]
84    } else {
85        vec![]
86    }
87}
88
89pub fn vec_to_int(vec: &[u8]) -> i32 {
90    if vec.is_empty() {
91        return 0;
92    }
93    let mut shift = 0;
94    let mut int = 0;
95    let sign_bit = vec[vec.len() - 1] & 0x80;
96    for (i, value) in vec.iter().enumerate() {
97        if i == vec.len() - 1 && sign_bit != 0 {
98            int += ((*value ^ sign_bit) as i32) << (shift);
99            int *= -1;
100        } else {
101            int += (*value as i32) << (shift);
102            shift += 8;
103        }
104    }
105    int
106}