use util::{Error, Result};
#[inline]
pub fn pop_bool(stack: &mut Vec<Vec<u8>>) -> Result<bool> {
if stack.len() == 0 {
let msg = "Cannot pop bool, empty stack".to_string();
return Err(Error::ScriptError(msg));
}
let top = stack.pop().unwrap();
if top.len() > 4 {
let msg = format!("Cannot pop bool, len too long {}", top.len());
return Err(Error::ScriptError(msg));
}
Ok(decode_bool(&top))
}
#[inline]
pub fn pop_num(stack: &mut Vec<Vec<u8>>) -> Result<i32> {
if stack.len() == 0 {
let msg = "Cannot pop num, empty stack".to_string();
return Err(Error::ScriptError(msg));
}
let top = stack.pop().unwrap();
if top.len() > 4 {
let msg = format!("Cannot pop num, len too long {}", top.len());
return Err(Error::ScriptError(msg));
}
Ok(decode_num(&top)? as i32)
}
#[inline]
pub fn decode_bool(s: &[u8]) -> bool {
if s.len() == 0 {
return false;
}
for i in 0..s.len() - 1 {
if s[i] != 0 {
return true;
}
}
s[s.len() - 1] & 127 != 0
}
#[inline]
pub fn decode_num(s: &[u8]) -> Result<i64> {
let mut val = match s.len() {
0 => return Ok(0),
1 => (s[0] & 127) as i64,
2 => (((s[1] & 127) as i64) << 8) + ((s[0] as i64) << 0),
3 => (((s[2] & 127) as i64) << 16) + ((s[1] as i64) << 8) + ((s[0] as i64) << 0),
4 => {
(((s[3] & 127) as i64) << 24)
+ ((s[2] as i64) << 16)
+ ((s[1] as i64) << 8)
+ ((s[0] as i64) << 0)
}
_ => {
for i in 4..s.len() - 1 {
if s[i] != 0 {
return Err(Error::ScriptError("Number too big".to_string()));
}
}
if s[s.len() - 1] & 127 != 0 {
return Err(Error::ScriptError("Number too big".to_string()));
}
((s[3] as i64) << 24)
+ ((s[2] as i64) << 16)
+ ((s[1] as i64) << 8)
+ ((s[0] as i64) << 0)
}
};
if s[s.len() - 1] & 128 != 0 {
val = 0 - val;
}
Ok(val)
}
#[inline]
pub fn encode_num(val: i64) -> Result<Vec<u8>> {
if val > 2147483647 || val < -2147483647 {
return Err(Error::ScriptError("Number out of range".to_string()));
}
let (posval, negmask) = if val < 0 { (-val, 128) } else { (val, 0) };
if posval == 0 {
Ok(vec![])
} else if posval < 128 {
Ok(vec![(posval as u8) | negmask])
} else if posval < 32768 {
Ok(vec![(posval >> 0) as u8, ((posval >> 8) as u8) | negmask])
} else if posval < 8388608 {
Ok(vec![
(posval >> 0) as u8,
(posval >> 8) as u8,
((posval >> 16) as u8) | negmask,
])
} else {
Ok(vec![
(posval >> 0) as u8,
(posval >> 8) as u8,
(posval >> 16) as u8,
((posval >> 24) as u8) | negmask,
])
}
}
#[inline]
pub fn encode_num_overflow(val: i64) -> Result<Vec<u8>> {
if val > 4294967294 || val < -4294967294 {
return Err(Error::ScriptError("Number out of range".to_string()));
}
let (posval, negmask) = if val < 0 { (-val, 128) } else { (val, 0) };
if posval <= 2147483647 {
encode_num(val)
} else {
Ok(vec![
(posval >> 0) as u8,
(posval >> 8) as u8,
(posval >> 16) as u8,
(posval >> 24) as u8,
((posval >> 32) as u8) | negmask,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode_bool_tests() {
assert!(decode_bool(&[1]) == true);
assert!(decode_bool(&[255, 0, 0, 0]) == true);
assert!(decode_bool(&[0, 0, 0, 129]) == true);
assert!(decode_bool(&[0]) == false);
assert!(decode_bool(&[0, 0, 0, 0]) == false);
assert!(decode_bool(&[0, 0, 0, 128]) == false);
assert!(decode_bool(&[]) == false);
}
#[test]
fn pop_bool_tests() {
assert!(pop_bool(&mut vec![vec![1]]).unwrap() == true);
assert!(pop_bool(&mut vec![vec![0, 0, 0, 127]]).unwrap() == true);
assert!(pop_bool(&mut vec![vec![0, 0, 0, 127]]).unwrap() == true);
assert!(pop_bool(&mut vec![]).is_err());
assert!(pop_bool(&mut vec![vec![0, 0, 0, 0, 0]]).is_err());
assert!(pop_bool(&mut vec![vec![]]).unwrap() == false);
assert!(pop_bool(&mut vec![vec![0]]).unwrap() == false);
assert!(pop_bool(&mut vec![vec![0, 0, 0, 0]]).unwrap() == false);
assert!(pop_bool(&mut vec![vec![0, 0, 0, 128]]).unwrap() == false);
}
#[test]
fn encode_decode_num_tests() {
assert!(encode_num(2147483647).is_ok());
assert!(encode_num(-2147483647).is_ok());
assert!(encode_num(2147483648).is_err());
assert!(encode_num(-2147483648).is_err());
assert!(encode_num_overflow(4294967294).is_ok());
assert!(encode_num_overflow(-4294967294).is_ok());
assert!(encode_num_overflow(4294967295).is_err());
assert!(encode_num_overflow(-4294967295).is_err());
assert!(decode_num(&encode_num(0).unwrap()).unwrap() == 0);
assert!(decode_num(&encode_num(1).unwrap()).unwrap() == 1);
assert!(decode_num(&encode_num(-1).unwrap()).unwrap() == -1);
assert!(decode_num(&encode_num(1111).unwrap()).unwrap() == 1111);
assert!(decode_num(&encode_num(-1111).unwrap()).unwrap() == -1111);
assert!(decode_num(&encode_num(111111).unwrap()).unwrap() == 111111);
assert!(decode_num(&encode_num(-111111).unwrap()).unwrap() == -111111);
assert!(decode_num(&encode_num(2147483647).unwrap()).unwrap() == 2147483647);
assert!(decode_num(&encode_num(-2147483647).unwrap()).unwrap() == -2147483647);
assert!(decode_num(&encode_num_overflow(0).unwrap()).unwrap() == 0);
assert!(decode_num(&encode_num_overflow(1).unwrap()).unwrap() == 1);
assert!(decode_num(&encode_num_overflow(-1).unwrap()).unwrap() == -1);
assert!(decode_num(&encode_num_overflow(1111).unwrap()).unwrap() == 1111);
assert!(decode_num(&encode_num_overflow(-1111).unwrap()).unwrap() == -1111);
assert!(decode_num(&encode_num_overflow(111111).unwrap()).unwrap() == 111111);
assert!(decode_num(&encode_num_overflow(-111111).unwrap()).unwrap() == -111111);
assert!(decode_num(&encode_num_overflow(2147483647).unwrap()).unwrap() == 2147483647);
assert!(decode_num(&encode_num_overflow(-2147483647).unwrap()).unwrap() == -2147483647);
assert!(decode_num(&encode_num_overflow(4294967294).unwrap()).unwrap() == 4294967294);
assert!(decode_num(&encode_num_overflow(-4294967294).unwrap()).unwrap() == -4294967294);
assert!(encode_num_overflow(0).unwrap().len() == 0);
assert!(encode_num_overflow(1).unwrap().len() == 1);
assert!(encode_num_overflow(-1).unwrap().len() == 1);
assert!(encode_num_overflow(127).unwrap().len() == 1);
assert!(encode_num_overflow(-127).unwrap().len() == 1);
assert!(encode_num_overflow(128).unwrap().len() == 2);
assert!(encode_num_overflow(-128).unwrap().len() == 2);
assert!(encode_num_overflow(32767).unwrap().len() == 2);
assert!(encode_num_overflow(-32767).unwrap().len() == 2);
assert!(encode_num_overflow(32768).unwrap().len() == 3);
assert!(encode_num_overflow(-32768).unwrap().len() == 3);
assert!(encode_num_overflow(8388607).unwrap().len() == 3);
assert!(encode_num_overflow(-8388607).unwrap().len() == 3);
assert!(encode_num_overflow(8388608).unwrap().len() == 4);
assert!(encode_num_overflow(-8388608).unwrap().len() == 4);
assert!(encode_num_overflow(2147483647).unwrap().len() == 4);
assert!(encode_num_overflow(-2147483647).unwrap().len() == 4);
assert!(encode_num_overflow(2147483648).unwrap().len() == 5);
assert!(encode_num_overflow(-2147483648).unwrap().len() == 5);
}
#[test]
fn pop_num_tests() {
assert!(pop_num(&mut vec![vec![]]).unwrap() == 0);
assert!(pop_num(&mut vec![vec![1]]).unwrap() == 1);
assert!(pop_num(&mut vec![vec![129]]).unwrap() == -1);
assert!(pop_num(&mut vec![vec![0, 0, 0, 0]]).unwrap() == 0);
assert!(pop_num(&mut vec![vec![0, 0, 0, 0, 0]]).is_err());
}
}