use parse_display::Display;
use serde::{Deserialize, Serialize};
use std::io::Read;
#[derive(Debug, Display)]
pub enum Cause {
#[display("An error in another crate or module-- cf. source.")]
Other,
#[display("Uknown field type {}")]
BadFieldType(u8),
}
#[derive(Debug, Display)]
#[display("{cause} Source (if any): {source} Stack trace (if any): {trace}")]
pub struct Error {
#[display("XNDE error {}.")]
cause: Cause,
#[display("fields error caused by {:#?}.")]
source: Option<Box<dyn std::error::Error>>,
#[display("backtrace: {:#?}.")]
trace: Option<backtrace::Backtrace>,
}
impl Error {
fn new(cause: Cause) -> Error {
Error {
cause: cause,
source: None,
trace: Some(backtrace::Backtrace::new()),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.source {
Some(bx) => Some(bx.as_ref()),
None => None,
}
}
}
impl std::convert::From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error {
cause: Cause::Other,
source: Some(Box::new(err)),
trace: Some(backtrace::Backtrace::new()),
}
}
}
impl std::convert::From<std::string::FromUtf8Error> for Error {
fn from(err: std::string::FromUtf8Error) -> Self {
Error {
cause: Cause::Other,
source: Some(Box::new(err)),
trace: Some(backtrace::Backtrace::new()),
}
}
}
impl std::convert::From<std::string::FromUtf16Error> for Error {
fn from(err: std::string::FromUtf16Error) -> Self {
Error {
cause: Cause::Other,
source: Some(Box::new(err)),
trace: Some(backtrace::Backtrace::new()),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Deserialize, Display, PartialEq, Serialize)]
pub enum FieldType {
#[display("COLUMN")]
Column = 0,
#[display("INDEX")]
Index = 1,
#[display("REDIRECTOR")]
Redirector = 2,
#[display("STRING")]
String = 3,
#[display("INTEGER")]
Integer = 4,
#[display("BOOLEAN")]
Boolean = 5,
#[display("BINARY")]
Binary = 6,
#[display("GUID")]
Guid = 7,
#[display("PRIVATE")]
Private = 8,
#[display("FLOAT")]
Float = 9,
#[display("DATETIME")]
Datetime = 10,
#[display("LENGTH")]
Length = 11,
#[display("FILENAME")]
Filename = 12,
#[display("INT64")]
Int64 = 13,
#[display("BINARY32")]
Binary32 = 14,
#[display("INT128")]
Int128 = 15,
}
impl FieldType {
pub fn from(i: u8) -> Result<FieldType> {
match i {
0 => Ok(FieldType::Column),
1 => Ok(FieldType::Index),
2 => Ok(FieldType::Redirector),
3 => Ok(FieldType::String),
4 => Ok(FieldType::Integer),
5 => Ok(FieldType::Boolean),
6 => Ok(FieldType::Binary),
7 => Ok(FieldType::Guid),
8 => Ok(FieldType::Private),
9 => Ok(FieldType::Float),
10 => Ok(FieldType::Datetime),
11 => Ok(FieldType::Length),
12 => Ok(FieldType::Filename),
13 => Ok(FieldType::Int64),
14 => Ok(FieldType::Binary32),
15 => Ok(FieldType::Int128),
_ => Err(Error::new(Cause::BadFieldType(i))),
}
}
}
#[derive(Debug, Serialize)]
pub enum FieldValue {
Unknown,
Column((i32, String)),
Index((i32, i32)),
String(String),
Integer(i32),
Boolean(bool),
Float(f64),
Datetime(i32),
Length(i32),
Filename(std::path::PathBuf),
Int64(i64),
}
#[typetag::serde(tag = "type")]
pub trait NdeField: std::fmt::Display {
fn id(&self) -> i32;
fn type_id(&self) -> Option<FieldType>;
fn prev_field_pos(&self) -> u64;
fn next_field_pos(&self) -> u64;
fn value(&self) -> FieldValue;
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display(
"ID {id}, size: {max_size_on_disk}, prev: {prev_field_pos:#06x}, next: {next_field_pos:#06x}"
)]
pub struct NdeFieldBase {
id: i32,
max_size_on_disk: usize,
prev_field_pos: u64,
next_field_pos: u64,
}
impl NdeFieldBase {
fn new<R: Read>(rdr: &mut R, id: i32) -> Result<NdeFieldBase> {
let mut buf: [u8; 4] = [0; 4];
rdr.read_exact(&mut buf)?;
let max_size_on_disk = u32::from_le_bytes(buf) as usize;
rdr.read_exact(&mut buf)?;
let next_field_pos = u32::from_le_bytes(buf) as u64;
rdr.read_exact(&mut buf)?;
let prev_field_pos = u32::from_le_bytes(buf) as u64;
Ok(NdeFieldBase {
id: id,
max_size_on_disk: max_size_on_disk,
prev_field_pos: prev_field_pos,
next_field_pos: next_field_pos,
})
}
#[allow(dead_code)]
fn id(&self) -> i32 {
self.id
}
fn max_size_on_disk(&self) -> usize {
self.max_size_on_disk
}
#[allow(dead_code)]
fn next(&self) -> u64 {
self.next_field_pos
}
}
#[cfg(test)]
mod nde_field_base_tests {
#[test]
fn smoke() -> std::result::Result<(), String> {
use super::*;
let bytes: [u8; 12] = [
0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let b = match NdeFieldBase::new(&mut bytes.as_ref(), 11) {
Ok(x) => x,
Err(e) => {
return Err(format!("{}", e));
}
};
assert_eq!(b.id(), 11);
assert_eq!(b.next(), 20);
Ok(())
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("Unk {field_type}: {base} data: {bytes:#?}")]
pub struct UnsupportedNdeField {
base: NdeFieldBase,
field_type: FieldType,
bytes: Vec<u8>,
}
impl UnsupportedNdeField {
pub fn new<R: Read>(rdr: &mut R, id: i32, ft: FieldType) -> Result<UnsupportedNdeField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: Vec<u8> = Vec::with_capacity(base.max_size_on_disk());
buf.resize(base.max_size_on_disk(), 0);
rdr.read_exact(buf.as_mut_slice())?;
Ok(UnsupportedNdeField {
base: base,
field_type: ft,
bytes: buf,
})
}
}
#[typetag::serde]
impl NdeField for UnsupportedNdeField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
None
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Unknown
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("Column: {base}, {col_type}, {name}")]
pub struct ColumnField {
base: NdeFieldBase,
col_type: FieldType,
index_unique: bool,
name: String,
}
impl ColumnField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<ColumnField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 3] = [0; 3];
rdr.read_exact(&mut buf)?;
let col_type = FieldType::from(buf[0])?;
let index_unique = buf[1] != 0;
let cb = buf[2] as usize;
let mut buf: Vec<u8> = Vec::with_capacity(cb);
buf.resize(cb, 0);
rdr.read_exact(buf.as_mut_slice())?;
let name = String::from_utf8(buf)?;
Ok(ColumnField {
base: base,
col_type: col_type,
index_unique: index_unique,
name: name,
})
}
pub fn name(&self) -> String {
self.name.clone()
}
}
#[typetag::serde]
impl NdeField for ColumnField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Filename)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Column((self.id(), self.name.clone()))
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {data}")]
pub struct DatetimeField {
base: NdeFieldBase,
data: i32,
}
impl DatetimeField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<DatetimeField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 4] = [0; 4];
rdr.read_exact(&mut buf)?;
let data = i32::from_le_bytes(buf);
Ok(DatetimeField {
base: base,
data: data,
})
}
}
#[typetag::serde]
impl NdeField for DatetimeField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Datetime)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Datetime(self.data)
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {path:#?}")]
pub struct FilenameField {
base: StringField,
path: std::path::PathBuf,
}
impl FilenameField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<FilenameField> {
let base = StringField::new(rdr, id)?;
let path = std::path::PathBuf::from(base.text());
Ok(FilenameField {
base: base,
path: path,
})
}
}
#[typetag::serde]
impl NdeField for FilenameField {
fn id(&self) -> i32 {
self.base.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Filename)
}
fn prev_field_pos(&self) -> u64 {
self.base.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Filename(self.path.clone())
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base}, pos: {pos}, type: {ftype}, name: {name}")]
pub struct IndexField {
base: NdeFieldBase,
pos: u64,
ftype: i32,
name: String,
}
impl IndexField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<IndexField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 4] = [0; 4];
rdr.read_exact(&mut buf)?;
let pos = u32::from_le_bytes(buf) as u64;
rdr.read_exact(&mut buf)?;
let ftype = i32::from_le_bytes(buf);
let mut buf: [u8; 1] = [0; 1];
rdr.read_exact(&mut buf)?;
let cb = buf[0] as usize;
let mut buf: Vec<u8> = Vec::with_capacity(cb);
buf.resize(cb, 0);
rdr.read_exact(buf.as_mut_slice())?;
let name = String::from_utf8(buf)?;
Ok(IndexField {
base: base,
pos: pos,
ftype: ftype,
name: name,
})
}
}
#[typetag::serde]
impl NdeField for IndexField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Index)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Index((self.id(), self.ftype))
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {data}")]
pub struct Int64Field {
base: NdeFieldBase,
data: i64,
}
impl Int64Field {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<Int64Field> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 8] = [0; 8];
rdr.read_exact(&mut buf)?;
let data = i64::from_le_bytes(buf);
Ok(Int64Field {
base: base,
data: data,
})
}
}
#[typetag::serde]
impl NdeField for Int64Field {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Int64)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Int64(self.data)
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {data}")]
pub struct IntegerField {
base: NdeFieldBase,
data: i32,
}
impl IntegerField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<IntegerField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 4] = [0; 4];
rdr.read_exact(&mut buf)?;
let data = i32::from_le_bytes(buf);
Ok(IntegerField {
base: base,
data: data,
})
}
}
#[typetag::serde]
impl NdeField for IntegerField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Integer)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Integer(self.data)
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {data}")]
pub struct LengthField {
base: NdeFieldBase,
data: i32,
}
impl LengthField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<LengthField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 4] = [0; 4];
rdr.read_exact(&mut buf)?;
let data = i32::from_le_bytes(buf);
Ok(LengthField {
base: base,
data: data,
})
}
}
#[typetag::serde]
impl NdeField for LengthField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::Length)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::Length(self.data)
}
}
#[derive(Debug, Deserialize, Display, Serialize)]
#[display("{base} {text}")]
pub struct StringField {
base: NdeFieldBase,
text: String,
}
impl StringField {
pub fn new<R: Read>(rdr: &mut R, id: i32) -> Result<StringField> {
let base = NdeFieldBase::new(rdr, id)?;
let mut buf: [u8; 2] = [0; 2];
rdr.read_exact(&mut buf)?;
let cb = u16::from_le_bytes(buf) as usize;
if cb == 0 {
return Ok(StringField {
base: base,
text: String::new(),
});
}
let mut buf: Vec<u8> = Vec::with_capacity(cb);
buf.resize(cb, 0);
rdr.read_exact(buf.as_mut_slice())?;
let text = if cb >= 2 && cb % 2 == 0 && buf[0] == 0xff && buf[1] == 0xfe {
let mut buf16: Vec<u16> = Vec::with_capacity(cb - 2);
for i in (2..cb).step_by(2) {
let tmp = [buf[i], buf[i + 1]];
buf16.push(u16::from_le_bytes(tmp));
}
String::from_utf16(&buf16)?
} else if cb >= 2 && cb % 2 == 0 && buf[0] == 0xfe && buf[1] == 0xff {
let mut buf16: Vec<u16> = Vec::with_capacity(cb - 2);
for i in (2..cb).step_by(2) {
let tmp = [buf[i], buf[i + 1]];
buf16.push(u16::from_be_bytes(tmp));
}
String::from_utf16(&buf16)?
} else {
String::from_utf8(buf)?
};
Ok(StringField {
base: base,
text: text,
})
}
pub fn text(&self) -> String {
self.text.clone()
}
}
#[typetag::serde]
impl NdeField for StringField {
fn id(&self) -> i32 {
self.base.id
}
fn type_id(&self) -> Option<FieldType> {
Some(FieldType::String)
}
fn prev_field_pos(&self) -> u64 {
self.base.prev_field_pos
}
fn next_field_pos(&self) -> u64 {
self.base.next_field_pos
}
fn value(&self) -> FieldValue {
FieldValue::String(self.text.clone())
}
}
#[cfg(test)]
mod string_field_tests {
#[test]
fn string_field_smoke() -> Result<(), String> {
use super::*;
let bytes: [u8; 32] = [
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
0xff, 0xfe, 0x43, 0x00, 0x3a, 0x00, 0x5c, 0x00, 0x61, 0x00, 0x2e, 0x00, 0x6d, 0x00,
0x70, 0x00, 0x33, 0x00,
];
let s = match StringField::new(&mut bytes.as_ref(), 1) {
Ok(s) => s,
Err(err) => {
return Err(format!("{}", err));
}
};
let t = match s.value() {
FieldValue::String(t) => t,
_ => {
return Err(String::from("bad field value"));
}
};
eprintln!("t is {}", t);
assert_eq!(t, "C:\\a.mp3");
Ok(())
}
}
pub fn field_factory<R: Read>(rdr: &mut R, id: i32, ft: FieldType) -> Result<Box<dyn NdeField>> {
match ft {
FieldType::Column => Ok(Box::new(ColumnField::new(rdr, id)?)),
FieldType::Datetime => Ok(Box::new(DatetimeField::new(rdr, id)?)),
FieldType::Filename => Ok(Box::new(FilenameField::new(rdr, id)?)),
FieldType::Index => Ok(Box::new(IndexField::new(rdr, id)?)),
FieldType::Integer => Ok(Box::new(IntegerField::new(rdr, id)?)),
FieldType::Int64 => Ok(Box::new(Int64Field::new(rdr, id)?)),
FieldType::Length => Ok(Box::new(LengthField::new(rdr, id)?)),
FieldType::String => Ok(Box::new(StringField::new(rdr, id)?)),
_ => Ok(Box::new(UnsupportedNdeField::new(rdr, id, ft)?)),
}
}