use std::io;
use crate::decode;
use crate::mode::Mode;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Length {
Definite(usize),
Indefinite
}
impl Length {
pub fn take_from<S: decode::Source>(
source: &mut S,
mode: Mode
) -> Result<Self, S::Err> {
match source.take_u8()? {
n if (n & 0x80) == 0 => Ok(Length::Definite(n as usize)),
0x80 => Ok(Length::Indefinite),
0x81 => {
let len = source.take_u8()? as usize;
if mode.is_ber() || len > 127 {
Ok(Length::Definite(len))
}
else {
Err(decode::Error::Malformed.into())
}
}
0x82 => {
let len =
(source.take_u8()? as usize) << 8 |
(source.take_u8()? as usize);
if mode.is_ber() || len > 255 {
Ok(Length::Definite(len))
}
else {
Err(decode::Error::Malformed.into())
}
}
0x83 => {
let len =
(source.take_u8()? as usize) << 16 |
(source.take_u8()? as usize) << 8 |
(source.take_u8()? as usize);
if mode.is_ber() || len > 0xFFFF {
Ok(Length::Definite(len))
}
else {
Err(decode::Error::Malformed.into())
}
}
0x84 => {
let len =
(source.take_u8()? as usize) << 24 |
(source.take_u8()? as usize) << 16 |
(source.take_u8()? as usize) << 8 |
(source.take_u8()? as usize);
if mode.is_ber() || len > 0x00FF_FFFF {
Ok(Length::Definite(len))
}
else {
Err(decode::Error::Malformed.into())
}
}
_ => {
Err(decode::Error::Unimplemented.into())
}
}
}
pub fn is_zero(&self) -> bool {
if let Length::Definite(0) = *self { true }
else { false }
}
#[cfg(not(target_pointer_width = "64"))]
pub fn encoded_len(&self) -> usize {
match *self {
Length::Indefinite => 1,
Length::Definite(len) => {
if len < 0x80 { 1 }
else if len < 0x1_00 { 2 }
else if len < 0x1_0000 { 3 }
else if len < 0x100_0000 { 4 }
else {
panic!("excessive length")
}
}
}
}
#[cfg(target_pointer_width = "64")]
pub fn encoded_len(&self) -> usize {
match *self {
Length::Indefinite => 1,
Length::Definite(len) => {
if len < 0x80 { 1 }
else if len < 0x1_00 { 2 }
else if len < 0x1_0000 { 3 }
else if len < 0x100_0000 { 4 }
else if len < 0x1_0000_0000 { 5 }
else {
panic!("excessive length")
}
}
}
}
#[cfg(target_pointer_len = "64")]
pub fn write_encoded<W: io::Write>(
&self,
target: &mut W
) -> Result<(), io::Error> {
match *self {
Length::Indefinite => {
let buf = [0x80];
target.write_all(&buf)
}
Length::Definite(len) => {
if len < 0x80 {
let buf = [len as u8];
target.write_all(&buf)
}
else if len < 0x1_00 {
let buf = [0x81, len as u8];
target.write_all(&buf)
}
else if len < 0x1_0000 {
let buf = [
0x82, (len >> 8) as u8, len as u8
];
target.write_all(&buf)
}
else if len < 0x100_0000 {
let buf = [
0x83, (len >> 16) as u8, (len >> 8) as u8, len as u8
];
target.write_all(&buf)
}
else if len < 0x1_0000_0000 {
let buf = [
0x84,
(len >> 24) as u8, (len >> 16) as u8,
(len >> 8) as u8, len as u8
];
target.write_all(&buf)
}
else {
panic!("excessive length")
}
}
}
}
#[cfg(not(target_pointer_len = "64"))]
pub fn write_encoded<W: io::Write>(
&self,
target: &mut W
) -> Result<(), io::Error> {
match *self {
Length::Indefinite => {
let buf = [0x80];
target.write_all(&buf)
}
Length::Definite(len) => {
if len < 0x80 {
let buf = [len as u8];
target.write_all(&buf)
}
else if len < 0x1_00 {
let buf = [0x81, len as u8];
target.write_all(&buf)
}
else if len < 0x1_0000 {
let buf = [
0x82, (len >> 8) as u8, len as u8
];
target.write_all(&buf)
}
else if len < 0x100_0000 {
let buf = [
0x83, (len >> 16) as u8, (len >> 8) as u8, len as u8
];
target.write_all(&buf)
}
else {
panic!("excessive length")
}
}
}
}
}