use crate::buffer::Reader;
use crate::error::DecodeError;
use crate::fixint::{read_fix32, read_fix64};
use crate::json;
use crate::varint::read_uvarint;
use anyhow::Result;
use std::collections::BTreeMap;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::str;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum WireType {
VARINT = 0, I64 = 1, LEN = 2, #[deprecated]
SGROUP = 3, #[deprecated]
EGROUP = 4, I32 = 5, }
impl Display for WireType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
#[allow(deprecated)]
match self {
WireType::VARINT => {
write!(f, "varint")
}
WireType::I64 => {
write!(f, "64-bit")
}
WireType::LEN => {
write!(f, "length-delimited")
}
WireType::SGROUP => {
write!(f, "start group")
}
WireType::EGROUP => {
write!(f, "end group")
}
WireType::I32 => {
write!(f, "32-bit")
}
}
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum ProtoData {
Varint(u64),
Fix64(i64),
Fix32(i32),
Bytes(Vec<u8>),
String(String),
Repeated(Vec<ProtoData>),
Message(Map<u64, ProtoData>),
}
impl Display for ProtoData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProtoData::Varint(v) => {
write!(f, "{}", v)
}
ProtoData::Fix64(v) => {
write!(f, "{}", v)
}
ProtoData::Fix32(v) => {
write!(f, "{}", v)
}
ProtoData::Bytes(v) => {
write!(f, "\"{}\"", hex::encode(v))
}
ProtoData::String(v) => {
write!(f, "\"{}\"", json::escape_string(v))
}
ProtoData::Repeated(v) => {
write!(f, "[")?;
for (i, item) in v.iter().enumerate() {
if i != 0 && i != v.len() {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
ProtoData::Message(v) => {
write!(f, "{{")?;
for (i, (key, value)) in v.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "\"{}\": {}", key, value)?;
}
write!(f, "}}")
}
}
}
}
type MapImpl<K, V> = BTreeMap<K, V>;
#[derive(Debug)]
pub struct Map<K, V> {
map: MapImpl<K, V>,
}
impl Default for Map<u64, ProtoData> {
fn default() -> Self {
Map {
map: BTreeMap::new(),
}
}
}
impl Clone for Map<u64, ProtoData> {
#[inline]
fn clone(&self) -> Self {
Map {
map: self.map.clone(),
}
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.map.clone_from(&source.map);
}
}
impl PartialEq for Map<u64, ProtoData> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.map.eq(&other.map)
}
}
impl Eq for Map<u64, ProtoData> {}
impl Hash for Map<u64, ProtoData> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.map.hash(state);
}
}
impl Map<u64, ProtoData> {
pub fn new() -> Self {
Map {
map: MapImpl::new(),
}
}
pub fn clear(&mut self) {
self.map.clear();
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn contains_key(&self, key: u64) -> bool {
self.map.contains_key(&key)
}
pub fn get(&self, key: u64) -> Option<&ProtoData> {
self.map.get(&key)
}
pub fn get_mut(&mut self, key: u64) -> Option<&mut ProtoData> {
self.map.get_mut(&key)
}
pub fn insert(&mut self, key: u64, message: ProtoData) -> Option<ProtoData> {
self.map.insert(key, message)
}
pub fn remove(&mut self, key: u64) -> Option<ProtoData> {
self.map.remove(&key)
}
pub fn iter(&self) -> impl Iterator<Item = (&u64, &ProtoData)> {
self.map.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&u64, &mut ProtoData)> {
self.map.iter_mut()
}
pub fn keys(&self) -> impl Iterator<Item = &u64> {
self.map.keys()
}
pub fn values(&self) -> impl Iterator<Item = &ProtoData> {
self.map.values()
}
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut ProtoData> {
self.map.values_mut()
}
}
impl TryFrom<u64> for WireType {
type Error = DecodeError;
#[allow(deprecated)]
fn try_from(wire_type: u64) -> Result<Self, Self::Error> {
match wire_type {
0 => Ok(WireType::VARINT),
1 => Ok(WireType::I64),
2 => Ok(WireType::LEN),
3 => Ok(WireType::SGROUP),
4 => Ok(WireType::EGROUP),
5 => Ok(WireType::I32),
_ => Err(DecodeError::UnknownWireType(wire_type)),
}
}
}
pub fn read_tag<T>(buf: &mut Reader<T>) -> Result<(u64, WireType)>
where
T: AsRef<[u8]>,
{
let tag = read_uvarint(buf)?;
Ok((tag >> 3, WireType::try_from(tag & 0x07)?))
}
pub fn read_length_delimited<T>(buf: &mut Reader<T>) -> Result<Vec<ProtoData>>
where
T: AsRef<[u8]>,
{
let mut result: Vec<ProtoData> = Vec::new();
let len = read_uvarint(buf)?;
let mut data_buf = Reader::new(buf.read_bytes(len as usize)?);
loop {
match decode_protobuf(&mut data_buf) {
Ok(v) => match v {
ProtoData::Message(msg) => {
if msg.len() > 0 {
result.push(ProtoData::Message(msg));
} else {
return Ok(result);
}
}
_ => {}
},
Err(err) => match err.downcast_ref::<DecodeError>() {
Some(DecodeError::EOF) => return Ok(result),
_ => {
result.clear();
data_buf.reset();
break;
}
},
};
}
match str::from_utf8(data_buf.read_all_bytes()?) {
Ok(v) => {
result.push(ProtoData::String(v.to_string()));
return Ok(result);
}
_ => {
result.clear();
data_buf.reset();
}
}
result.push(ProtoData::Bytes(Vec::from(data_buf.read_all_bytes()?)));
Ok(result)
}
pub fn decode_protobuf_hex(data: &str) -> Result<ProtoData> {
decode_protobuf(&mut Reader::new(
hex::decode(data.replace(" ", ""))?.as_slice(),
))
}
pub fn decode_protobuf<T>(buf: &mut Reader<T>) -> Result<ProtoData>
where
T: AsRef<[u8]>,
{
let mut parsed_data = Map::default();
loop {
match read_tag(buf) {
Ok((field, wire_type)) => {
let data = match wire_type {
WireType::VARINT => ProtoData::Varint(read_uvarint(buf)?),
WireType::I64 => ProtoData::Fix64(read_fix64(buf)?),
WireType::I32 => ProtoData::Fix32(read_fix32(buf)?),
WireType::LEN => {
let mut list = read_length_delimited(buf)?;
if list.len() > 1 {
ProtoData::Repeated(list)
} else {
list.remove(0)
}
}
x => return Err(DecodeError::DeprecatedWireType(x).into()),
};
if parsed_data.contains_key(field) {
match parsed_data.get(field) {
None => {}
Some(ProtoData::Repeated(_)) => {
if let Some(ProtoData::Repeated(list)) = parsed_data.get_mut(field) {
list.push(data);
}
}
Some(v) => {
parsed_data.insert(field, ProtoData::Repeated(vec![v.clone(), data]));
}
};
} else {
parsed_data.insert(field, data);
}
}
Err(err) => match err.downcast_ref::<DecodeError>() {
Some(DecodeError::EOF) => break,
_ => return Err(err),
},
}
}
Ok(ProtoData::Message(parsed_data))
}