use std::{fmt, io};
use super::decode;
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Tag(u8);
impl Tag {
const CLASS_MASK: u8 = 0xc0;
const UNIVERSAL: u8 = 0x00;
const APPLICATION: u8 = 0x40;
const CONTEXT_SPECIFIC: u8 = 0x80;
const PRIVATE: u8 = 0xc0;
pub const END_OF_VALUE: Self = Tag(0);
pub const BOOLEAN: Self = Tag(1);
pub const INTEGER: Self = Tag(2);
pub const BIT_STRING: Self = Tag(3);
pub const OCTET_STRING: Self = Tag(4);
pub const NULL: Self = Tag(5);
pub const OID: Self = Tag(6);
pub const OBJECT_DESCRIPTOR: Self = Tag(7);
pub const EXTERNAL: Self = Tag(8);
pub const REAL: Self = Tag(9);
pub const ENUMERATED: Self = Tag(10);
pub const EMBEDDED_PDV: Self = Tag(11);
pub const UTF8_STRING: Self = Tag(12);
pub const RELATIVE_OID: Self = Tag(13);
pub const SEQUENCE: Self = Tag(16);
pub const SET: Self = Tag(17);
pub const NUMERIC_STRING: Self = Tag(18);
pub const PRINTABLE_STRING: Self = Tag(19);
pub const TELETEX_STRING: Self = Tag(20);
pub const VIDEOTEX_STRING: Self = Tag(21);
pub const IA5_STRING: Self = Tag(22);
pub const UTC_TIME: Self = Tag(23);
pub const GENERALIZED_TIME: Self = Tag(24);
pub const GRAPHIC_STRING: Self = Tag(25);
pub const VISIBLE_STRING: Self = Tag(26);
pub const GENERAL_STRING: Self = Tag(27);
pub const UNIVERSAL_STRING: Self = Tag(28);
pub const BMP_STRING: Self = Tag(29);
pub const CTX_0: Self = Tag(Tag::CONTEXT_SPECIFIC);
pub const CTX_1: Self = Tag(Tag::CONTEXT_SPECIFIC | 1);
pub const CTX_2: Self = Tag(Tag::CONTEXT_SPECIFIC | 2);
pub const CTX_3: Self = Tag(Tag::CONTEXT_SPECIFIC | 3);
pub const CTX_4: Self = Tag(Tag::CONTEXT_SPECIFIC | 4);
pub const CTX_5: Self = Tag(Tag::CONTEXT_SPECIFIC | 5);
pub const CTX_6: Self = Tag(Tag::CONTEXT_SPECIFIC | 6);
}
impl Tag {
pub fn universal(number: u8) -> Self {
assert!(number < 31);
Tag(number)
}
pub fn application(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::APPLICATION | number)
}
pub fn context_specific(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::CONTEXT_SPECIFIC| number)
}
pub fn private(number: u8) -> Self {
assert!(number < 31);
Tag(Tag::PRIVATE | number)
}
pub fn take_from<S: decode::Source>(
source: &mut S,
) -> Result<(Self, bool), S::Err> {
let byte = source.take_u8()?;
if (byte & 0x1F) == 0x1F {
xerr!(return Err(decode::Error::Unimplemented.into()))
}
Ok((Tag(byte & 0xdf), byte & 0x20 != 0))
}
pub fn take_from_if<S: decode::Source>(
self,
source: &mut S,
) -> Result<Option<bool>, S::Err> {
if source.request(1)? == 0 {
return Ok(None)
}
let byte = source.slice()[0];
let (tag, compressed) = (Tag(byte & 0xdf), byte & 0x20 != 0);
if tag == self {
source.advance(1)?;
Ok(Some(compressed))
}
else {
Ok(None)
}
}
#[allow(trivially_copy_pass_by_ref)] pub fn encoded_len(&self) -> usize {
1
}
#[allow(trivially_copy_pass_by_ref)] pub fn write_encoded<W: io::Write>(
&self,
constructed: bool,
target: &mut W
) -> Result<(), io::Error> {
let mut buf = [self.0];
if constructed {
buf[0] |= 0x20
}
target.write_all(&buf)
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Tag::BOOLEAN => write!(f, "BOOLEAN"),
Tag::INTEGER => write!(f, "INTEGER"),
Tag::BIT_STRING => write!(f, "BIT STRING"),
Tag::OCTET_STRING => write!(f, "OCTET STRING"),
Tag::NULL => write!(f, "NULL"),
Tag::OID => write!(f, "OBJECT IDENTIFIER"),
Tag::OBJECT_DESCRIPTOR => write!(f, "ObjectDescriptor"),
Tag::EXTERNAL => write!(f, "EXTERNAL"),
Tag::REAL => write!(f, "REAL"),
Tag::ENUMERATED => write!(f, "ENUMERATED"),
Tag::EMBEDDED_PDV => write!(f, "EMBEDDED PDV"),
Tag::UTF8_STRING => write!(f, "UTF8String"),
Tag::RELATIVE_OID => write!(f, "RELATIVE-OID"),
Tag::SEQUENCE => write!(f, "SEQUENCE"),
Tag::SET => write!(f, "SET"),
Tag::NUMERIC_STRING => write!(f, "NumericString"),
Tag::PRINTABLE_STRING => write!(f, "PrintableString"),
Tag::TELETEX_STRING => write!(f, "TeletexString"),
Tag::VIDEOTEX_STRING => write!(f, "VideotexString"),
Tag::IA5_STRING => write!(f, "IA5String"),
Tag::UTC_TIME => write!(f, "UTCTime"),
Tag::GENERALIZED_TIME => write!(f, "GeneralizedTime"),
Tag::GRAPHIC_STRING => write!(f, "GraphicString"),
Tag::VISIBLE_STRING => write!(f, "VisibleString"),
Tag::GENERAL_STRING => write!(f, "GeneralString"),
Tag::UNIVERSAL_STRING => write!(f, "UniversalString"),
Tag::BMP_STRING => write!(f, "BMPString"),
tag => {
match tag.0 & Tag::CLASS_MASK {
Tag::UNIVERSAL => write!(f, "[UNIVERSAL ")?,
Tag::APPLICATION => write!(f, "[APPLICATION ")?,
Tag::CONTEXT_SPECIFIC => write!(f, "[")?,
Tag::PRIVATE => write!(f, "[PRIVATE ")?,
_ => unreachable!()
}
write!(f, "{}]", tag.0 & !Tag::CLASS_MASK)
}
}
}
}
impl fmt::Debug for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Tag({})", self)
}
}