use crate::types::{MsgPackError, MsgPackValue, MsgPackEntry};
use byteorder::{ReadBytesExt, BigEndian};
use wasm_bindgen::prelude::*;
use std::io::{Cursor, Read};
use rmp::Marker;
#[wasm_bindgen]
pub fn unpack_json(data: &[u8], pretty: Option<bool>) -> Result<String, JsValue> {
let value = read_value(&mut Cursor::new(data))
.map_err(|e| JsValue::from_str(&e.to_string()))?;
if pretty.unwrap_or(false) { serde_json::to_string_pretty(&value) } else { serde_json::to_string(&value) }
.map_err(|e| JsValue::from_str(&e.to_string()))
}
pub fn unpack(data: &[u8]) -> Result<MsgPackEntry, MsgPackError> {
read_value(&mut Cursor::new(data))
}
fn read_value<R: Read>(reader: &mut R) -> Result<MsgPackEntry, MsgPackError> {
let raw_marker: u8 = reader.read_u8()?;
let marker: Marker = Marker::from_u8(raw_marker);
let value: MsgPackValue = match marker {
Marker::Null => MsgPackValue::Null,
Marker::False => MsgPackValue::Bool(false),
Marker::True => MsgPackValue::Bool(true),
Marker::FixPos(val) => MsgPackValue::FixPos(val),
Marker::FixNeg(val) => MsgPackValue::FixNeg(val),
Marker::U8 => { MsgPackValue::U8(reader.read_u8()?) }
Marker::U16 => { MsgPackValue::U16(reader.read_u16::<BigEndian>()?) }
Marker::U32 => { MsgPackValue::U32(reader.read_u32::<BigEndian>()?) }
Marker::U64 => { MsgPackValue::U64(reader.read_u64::<BigEndian>()?) }
Marker::I8 => { MsgPackValue::I8(reader.read_i8()?) }
Marker::I16 => { MsgPackValue::I16(reader.read_i16::<BigEndian>()?) }
Marker::I32 => { MsgPackValue::I32(reader.read_i32::<BigEndian>()?) }
Marker::I64 => { MsgPackValue::I64(reader.read_i64::<BigEndian>()?) }
Marker::F32 => { MsgPackValue::F32(reader.read_f32::<BigEndian>()?) }
Marker::F64 => { MsgPackValue::F64(reader.read_f64::<BigEndian>()?) }
Marker::FixStr(_)|Marker::Str8|Marker::Str16|Marker::Str32 => { read_str(reader, marker)? },
Marker::Bin8|Marker::Bin16|Marker::Bin32 => { read_bin(reader, marker)? },
Marker::FixArray(_)|Marker::Array16|Marker::Array32 => { read_array(reader, marker)? },
Marker::FixMap(_)|Marker::Map16|Marker::Map32 => { read_map(reader, marker)? },
Marker::Ext8|Marker::Ext16|Marker::Ext32|
Marker::FixExt1|Marker::FixExt2|Marker::FixExt4|Marker::FixExt8|Marker::FixExt16 => {
unimplemented!()
},
Marker::Reserved => {
unreachable!()
}
};
Ok(MsgPackEntry::new(raw_marker, value))
}
fn read_str<R: Read>(reader: &mut R, marker: Marker) -> Result<MsgPackValue, MsgPackError> {
let len: usize = match marker {
Marker::FixStr(val) => { usize::from(val & 0b0001_1111) } Marker::Str8 => { reader.read_u8()? as usize },
Marker::Str16 => { reader.read_u16::<BigEndian>()? as usize },
Marker::Str32 => { reader.read_u32::<BigEndian>()? as usize },
_ => unreachable!()
};
let mut buf: Vec<u8> = vec![0u8;len];
reader.read_exact(&mut buf)?;
let s=String::from_utf8(buf).map_err(|e| MsgPackError::Custom(format!("Invalid UTF-8: {}", e)))?;
let res: MsgPackValue = match marker {
Marker::FixStr(_) => { MsgPackValue::FixStr(s) }
Marker::Str8 => { MsgPackValue::Str8(s) },
Marker::Str16 => { MsgPackValue::Str16(s) },
Marker::Str32 => { MsgPackValue::Str32(s) },
_ => unreachable!()
};
Ok(res)
}
fn read_bin<R: Read>(reader: &mut R, marker: Marker) -> Result<MsgPackValue, MsgPackError> {
let len: usize = match marker {
Marker::Bin8 => { reader.read_u8()? as usize }
Marker::Bin16 => { reader.read_u16::<BigEndian>()? as usize }
Marker::Bin32 => { reader.read_u32::<BigEndian>()? as usize }
_ => unreachable!()
};
let mut buf: Vec<u8> = vec![0u8;len];
reader.read_exact(&mut buf)?;
let res: MsgPackValue = match marker {
Marker::Bin8 => { MsgPackValue::Bin8(buf) }
Marker::Bin16 => { MsgPackValue::Bin16(buf) }
Marker::Bin32 => { MsgPackValue::Bin32(buf) }
_ => unreachable!()
};
Ok(res)
}
fn read_array<R: Read>(reader: &mut R, marker: Marker) -> Result<MsgPackValue, MsgPackError> {
let len: usize = match marker {
Marker::FixArray(val) => { usize::from(val & 0b0000_1111) }, Marker::Array16 => { reader.read_u16::<BigEndian>()? as usize },
Marker::Array32 => { reader.read_u32::<BigEndian>()? as usize },
_ => unreachable!()
};
let mut array: Vec<MsgPackEntry> = Vec::with_capacity(len);
for _ in 0..len { array.push(read_value(reader)?); }
let res: MsgPackValue = match marker {
Marker::FixArray(_) => { MsgPackValue::FixArray(array) },
Marker::Array16 => { MsgPackValue::Array16(array) },
Marker::Array32 => { MsgPackValue::Array32(array) },
_ => unreachable!()
};
Ok(res)
}
fn read_map<R: Read>(reader: &mut R, marker: Marker) -> Result<MsgPackValue, MsgPackError> {
let len: usize = match marker {
Marker::FixMap(val) => { usize::from(val & 0b0000_1111) }, Marker::Map16 => { reader.read_u16::<BigEndian>()? as usize },
Marker::Map32 => { reader.read_u32::<BigEndian>()? as usize },
_ => unreachable!()
};
let mut map: Vec<_> = Vec::with_capacity(len);
for _ in 0..len {
let k: MsgPackEntry = read_value(reader)?;
let v: MsgPackEntry = read_value(reader)?;
map.push((k, v));
}
let res: MsgPackValue = match marker {
Marker::FixMap(_) => { MsgPackValue::FixMap(map) },
Marker::Map16 => { MsgPackValue::Map16(map) },
Marker::Map32 => { MsgPackValue::Map32(map) },
_ => unreachable!()
};
Ok(res)
}