#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_root_url = "https://docs.rs/const-oid/0.4.4"
)]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[macro_use]
mod macros;
mod arcs;
mod encoder;
mod error;
mod parser;
pub use crate::{
arcs::{Arc, Arcs},
error::{Error, Result},
};
use crate::arcs::RootArcs;
use core::{convert::TryFrom, fmt, str::FromStr};
pub const MIN_ARCS: usize = 3;
#[deprecated(since = "0.4.4", note = "Please use the `MAX_LEN` instead")]
pub const MAX_ARCS: usize = 12;
pub const MAX_LEN: usize = 23;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ObjectIdentifier {
bytes: [u8; MAX_LEN],
length: u8,
}
#[allow(clippy::len_without_is_empty)]
impl ObjectIdentifier {
pub const fn new(arcs: &[Arc]) -> Self {
const_assert!(arcs.len() >= MIN_ARCS, "OID too short (minimum 3 arcs)");
let mut encoder = encoder::Encoder::new();
macro_rules! encode_arc {
($($n:expr),+) => {
$(
if arcs.len() > $n {
encoder = encoder.encode(arcs[$n]);
}
)+
};
}
encode_arc!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
encoder.finish()
}
pub const fn parse(s: &str) -> Self {
parser::Parser::parse(s).finish()
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..self.length as usize]
}
pub fn arc(&self, index: usize) -> Option<Arc> {
self.arcs().nth(index)
}
pub fn arcs(&self) -> Arcs<'_> {
Arcs::new(self)
}
pub fn len(&self) -> usize {
self.arcs().count()
}
pub fn from_ber(ber_bytes: &[u8]) -> Result<Self> {
let len = ber_bytes.len();
if !(2..=MAX_LEN).contains(&len) {
return Err(Error);
}
ber_bytes
.get(0)
.cloned()
.ok_or(Error)
.and_then(RootArcs::try_from)?;
let mut arc_offset = 1;
let mut arc_bytes = 0;
while arc_offset < len {
match ber_bytes.get(arc_offset + arc_bytes).cloned() {
Some(byte) => {
arc_bytes += 1;
if arc_bytes == 4 && byte & 0b11110000 != 0 {
return Err(Error);
}
if byte & 0b10000000 == 0 {
arc_offset += arc_bytes;
arc_bytes = 0;
}
}
None => return Err(Error), }
}
let mut bytes = [0u8; MAX_LEN];
bytes[..len].copy_from_slice(ber_bytes);
Ok(Self {
bytes,
length: len as u8,
})
}
#[deprecated(since = "0.4.4", note = "Please use the `as_bytes()` function instead")]
pub fn ber_len(&self) -> usize {
self.as_bytes().len()
}
#[deprecated(since = "0.4.4", note = "Please use the `as_bytes()` function instead")]
pub fn write_ber<'a>(&self, bytes: &'a mut [u8]) -> Result<&'a [u8]> {
let len = self.as_bytes().len();
if bytes.len() < len {
return Err(Error);
}
bytes[..len].copy_from_slice(self.as_bytes());
Ok(&bytes[..len])
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[deprecated(since = "0.4.4", note = "Please use the `as_bytes()` function instead")]
pub fn to_ber(&self) -> alloc::vec::Vec<u8> {
self.as_bytes().to_vec()
}
}
impl AsRef<[u8]> for ObjectIdentifier {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl FromStr for ObjectIdentifier {
type Err = Error;
fn from_str(string: &str) -> Result<Self> {
let mut split = string.split('.');
let first_arc = split.next().and_then(|s| s.parse().ok()).ok_or(Error)?;
let second_arc = split.next().and_then(|s| s.parse().ok()).ok_or(Error)?;
let mut bytes = [0u8; MAX_LEN];
bytes[0] = RootArcs::new(first_arc, second_arc)?.into();
let mut offset = 1;
for s in split {
let arc = s.parse().map_err(|_| Error)?;
offset += encoder::write_base128(&mut bytes[offset..], arc)?;
}
if offset > 1 {
Ok(Self {
bytes,
length: offset as u8,
})
} else {
Err(Error)
}
}
}
impl TryFrom<&[Arc]> for ObjectIdentifier {
type Error = Error;
fn try_from(arcs: &[Arc]) -> Result<Self> {
if arcs.len() < MIN_ARCS {
return Err(Error);
}
let mut bytes = [0u8; MAX_LEN];
bytes[0] = RootArcs::new(arcs[0], arcs[1])?.into();
let mut offset = 1;
for &arc in &arcs[2..] {
offset += encoder::write_base128(&mut bytes[offset..], arc)?;
}
Ok(Self {
bytes,
length: offset as u8,
})
}
}
impl From<&ObjectIdentifier> for ObjectIdentifier {
fn from(oid: &ObjectIdentifier) -> ObjectIdentifier {
*oid
}
}
impl fmt::Debug for ObjectIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ObjectIdentifier({})", self)
}
}
impl fmt::Display for ObjectIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let len = self.len();
for (i, arc) in self.arcs().enumerate() {
write!(f, "{}", arc)?;
if i < len - 1 {
write!(f, ".")?;
}
}
Ok(())
}
}