use std::io::Write;
use std::fs::File;
use std::mem;
use byteorder::{ByteOrder, BigEndian, LittleEndian, WriteBytesExt};
use super::DMImage;
use super::dmtypes::*;
use super::taggroup_entries::{Key, Tag, TagGroup};
use super::taggroup_entries::Key::*;
use super::taggroup_entries::Tag::*;
use Result;
pub trait DMImageWriteByVersion {
fn write_by_version(dmwriter: &mut DMImageWriter, val: usize) -> Result<usize>;
fn write_by_version_to_buffer(buffer: &mut Vec<u8>, val: usize) -> Result<usize>;
fn write_header(dmwriter: &mut DMImageWriter) -> Result<usize>;
fn write_taggroup_size(dmwriter: &mut DMImageWriter, val: usize) -> Result<usize>;
}
pub struct DMImageWriter<'a> {
buffer: Vec<u8>,
image: &'a DMImage,
}
impl DMImageWriteByVersion for DM3Writer {
#[inline]
fn write_by_version(dmwriter: &mut DMImageWriter, val: usize) -> Result<usize> {
debug!("DM3::write_by_version()");
dmwriter.buffer.write_u32::<BigEndian>(val as u32)?;
let bytes = 4;
debug!("DM3::write_by_version() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_header(dmwriter: &mut DMImageWriter) -> Result<usize> {
debug!("DM3::write_header()");
dmwriter.buffer.write_u32::<BigEndian>(3)?;
let tg_size = dmwriter.image.tg_size;
dmwriter.buffer.write_u32::<BigEndian>(tg_size as u32)?;
let bigendian = if dmwriter.image.bigendian {
BIG_ENDIAN
} else {
LITTLE_ENDIAN
};
dmwriter.buffer.write_u32::<BigEndian>(bigendian as u32)?;
let bytes = 12;
debug!("DM3::write_header() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_by_version_to_buffer(buffer: &mut Vec<u8>, t: usize) -> Result<usize> {
debug!("DM3:write_by_version_to_buffer()");
buffer.write_u32::<BigEndian>(D_ZERO as u32)?;
buffer.write_u32::<BigEndian>(t as u32)?;
let bytes = 8;
debug!("DM3:write_by_version_to_buffer() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_taggroup_size(_dmwriter: &mut DMImageWriter, _size: usize) -> Result<usize> {
Ok(0)
}
}
impl DMImageWriteByVersion for DM4Writer {
fn write_by_version(dmwriter: &mut DMImageWriter, val: usize) -> Result<usize> {
debug!("DM4::write_by_version()");
dmwriter.buffer.write_u32::<BigEndian>(val as u32)?;
let bytes = 8;
debug!("DM4::write_by_version() -> {} bytes written", bytes);
Ok(bytes)
}
fn write_header(dmwriter: &mut DMImageWriter) -> Result<usize> {
debug!("DM4::write_header()");
dmwriter.buffer.write_u32::<BigEndian>(4)?;
let tg_size = dmwriter.image.tg_size;
dmwriter.buffer.write_u64::<BigEndian>(tg_size as u64)?;
let bigendian = if dmwriter.image.bigendian {
BIG_ENDIAN
} else {
LITTLE_ENDIAN
};
dmwriter.buffer.write_u32::<BigEndian>(bigendian as u32)?;
let bytes =16;
debug!("DM4::write_header() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_by_version_to_buffer(buffer: &mut Vec<u8>, t: usize) -> Result<usize> {
debug!("DM4:write_by_version_to_buffer()");
buffer.write_u64::<BigEndian>(D_ZERO as u64)?;
buffer.write_u64::<BigEndian>(t as u64)?;
let bytes = 16;
debug!("DM4:write_by_version_to_buffer() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_taggroup_size(dmwriter: &mut DMImageWriter, size: usize) -> Result<usize> {
dmwriter.buffer.write_u64::<BigEndian>(size as u64)?;
Ok(8)
}
}
impl<'a> DMImageWriter<'a> {
pub fn new(image: &'a DMImage) -> DMImageWriter<'a> {
DMImageWriter {
buffer: Vec::new(),
image,
}
}
pub fn from(image: &'a DMImage) -> DMImageWriter<'a> {
DMImageWriter {
buffer: Vec::with_capacity(image.tg_size + 16),
image,
}
}
pub fn write_to_file<R: DMImageWriteByVersion>(&mut self, mut file: File) -> Result<()> {
debug!("DMImageWriter::write_to_file()");
let buffer = self.serialize::<R>()?;
debug!("DMImageWriter::write_to_file() -> serialization completed");
file.write_all(&buffer[..])?;
debug!("DMImageWriter::write_to_file() -> file written, {} bytes total", buffer.len());
Ok(())
}
pub fn serialize<R: DMImageWriteByVersion>(&mut self) -> Result<Vec<u8>> {
debug!("DMImageWriter::serialize()");
let mut bytes = 0;
bytes += R::write_header(self)?;
if self.image.bigendian {
bytes += self.write_taggroup::<R, BigEndian>(&self.image.root)?;
} else {
bytes += self.write_taggroup::<R, LittleEndian>(&self.image.root)?;
}
self.buffer.append(&mut vec![0u8; 8]);
bytes += 8;
let final_file_size = self.buffer.len() - 16;
BigEndian::write_u32(&mut self.buffer[4..8], final_file_size as u32);
debug!("DMImageWriter::serialize() -> file size {}, total bytes {}", final_file_size, bytes);
let new_buffer= Vec::new();
let buffer = mem::replace(&mut self.buffer, new_buffer);
Ok(buffer)
}
#[inline]
fn write_taggroup<R: DMImageWriteByVersion, T: ByteOrder>(&mut self, tg: &TagGroup) -> Result<usize> {
debug!("DMImageWriter::write_taggroup()");
self.buffer.write_u8(
if tg.sorted() { B_TRUE } else { B_FALSE },
)?;
self.buffer.write_u8(
if tg.opened() { B_TRUE } else { B_FALSE },
)?;
let mut bytes = 2;
bytes += R::write_by_version(self, tg.len())?;
for (key, tag) in tg.iter() {
bytes += self.write_tag_entry::<R, T>(key, tag)?;
}
debug!("DMImageWriter::write_taggroup() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_tag_entry<R: DMImageWriteByVersion, T: ByteOrder>(&mut self, key: &Key, tag: &Tag) -> Result<usize> {
debug!("DMImageWriter::write_tag_entry()");
let mut bytes = 0;
let label = match *key {
Label(ref string) => string.clone(),
Index(_) => String::from(""),
};
match *tag {
TagGroupEntry(ref tg) => {
self.buffer.write_u8(T_GROUP)?;
self.buffer.write_u16::<BigEndian>(label.len() as u16)?;
bytes += 3 + label.len();
self.buffer.append(&mut label.into_bytes());
bytes += R::write_taggroup_size(self, 0)?; bytes += self.write_taggroup::<R, T>(tg)?;
}
_ => {
self.buffer.write_u8(T_TAG)?;
self.buffer.write_u16::<BigEndian>(label.len() as u16)?;
bytes += 3 + label.len();
self.buffer.append(&mut label.into_bytes());
bytes += R::write_taggroup_size(self, 0)?; bytes += self.write_tag::<R, T>(tag)?;
}
}
debug!("DMImageWriter::write_tag_entry() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_tag<R: DMImageWriteByVersion, T: ByteOrder>(&mut self, val: &Tag) -> Result<usize> {
debug!("DMImageWriter::write_tag()");
self.buffer.append(&mut String::from("%%%%").into_bytes());
let mut bytes = 4;
match *val {
Empty => return Err(From::from("TagEntry has type Empty! Cannot write")),
Short(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_SHORT)?;
self.buffer.write_i16::<T>(val)?;
bytes += 2;
}
Long(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_LONG)?;
self.buffer.write_i32::<T>(val)?;
bytes += 4;
}
UShort(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_USHORT)?;
self.buffer.write_u16::<T>(val)?;
bytes += 2;
}
ULong(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_ULONG)?;
self.buffer.write_u32::<T>(val)?;
bytes += 4;
}
Float(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_FLOAT)?;
self.buffer.write_f32::<T>(val)?;
bytes += 4;
}
Double(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_DOUBLE)?;
self.buffer.write_f64::<T>(val)?;
bytes += 8;
}
Boolean(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_BOOLEAN)?;
self.buffer.push(if val { B_TRUE } else { B_FALSE });
bytes += 1;
}
Char(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_CHAR)?;
self.buffer.push(val as u8);
bytes += 1;
}
Octet(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_OCTET)?;
self.buffer.push(val);
bytes += 1;
}
ULongLong(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_ULONGLONG)?;
self.buffer.write_u64::<T>(val)?;
bytes += 8;
}
Unknown64(val) => {
bytes += R::write_by_version(self, T_SIMPLE)?;
bytes += R::write_by_version(self, D_UNKNOWN64)?;
self.buffer.write_u64::<T>(val)?;
bytes += 8;
}
CharSeq(ref val) => {
bytes += R::write_by_version(self, T_STRING)?;
bytes += R::write_by_version(self, D_STRING)?;
let mut string = val.clone().into_bytes();
bytes += R::write_by_version(self, string.len())?;
bytes += string.len();
self.buffer.append(&mut string);
}
ArrayShort(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_SHORT)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_i16::<T>(*elem)?;
bytes += 2;
}
}
ArrayLong(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_LONG)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_i32::<T>(*elem)?;
bytes += 4;
}
}
ArrayUShort(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_USHORT)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_u16::<T>(*elem)?;
bytes += 2;
}
}
ArrayULong(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_ULONG)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_u32::<T>(*elem)?;
bytes += 4;
}
}
ArrayFloat(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_FLOAT)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_f32::<T>(*elem)?;
bytes += 4;
}
}
ArrayDouble(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_DOUBLE)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_f64::<T>(*elem)?;
bytes += 8;
}
}
ArrayBoolean(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_BOOLEAN)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.push(if *elem { B_TRUE } else { B_FALSE });
bytes += 1;
}
}
ArrayChar(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_CHAR)?;
bytes += R::write_by_version(self, arr.len())?;
self.buffer.append(&mut arr.clone().into_bytes());
bytes += arr.len();
}
ArrayOctet(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_OCTET)?;
bytes += R::write_by_version(self, arr.len())?;
self.buffer.append(&mut arr.clone());
bytes += arr.len();
}
ArrayULongLong(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_ULONGLONG)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_u64::<T>(*elem)?;
bytes += 8;
}
}
ArrayUnknown64(ref arr) => {
bytes += R::write_by_version(self, T_ARRAY)?;
bytes += R::write_by_version(self, D_ARRAY)?;
bytes += R::write_by_version(self, D_UNKNOWN64)?;
bytes += R::write_by_version(self, arr.len())?;
for elem in arr.iter() {
self.buffer.write_u64::<T>(*elem)?;
bytes += 8;
}
}
Struct(ref arr) => {
bytes += self.write_struct::<R, T>(arr)?;
}
ComplexArray(ref arr) => {
bytes += self.write_complex_array::<R, T>(arr)?;
}
_ => return Err(From::from("Did not expect this type, corrupt data")),
}
debug!("DMImageWriter::write_tag() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_struct<R: DMImageWriteByVersion, T: ByteOrder>(&mut self, struct_tg: &[Tag]) -> Result<usize> {
debug!("DMImageWriter::write_struct()");
let mut bytes = 0;
let number_fields = struct_tg.len();
let info_size = 2 * number_fields + 4;
bytes += R::write_by_version(self, info_size - 1)?;
bytes += R::write_by_version(self, D_STRUCT)?;
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, number_fields)?;
let mut data_buf = Vec::new();
for val in struct_tg.iter() {
match *val {
Short(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_SHORT)?;
data_buf.write_i16::<T>(val)?;
}
Long(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_LONG)?;
data_buf.write_i32::<T>(val)?;
}
UShort(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_USHORT)?;
data_buf.write_u16::<T>(val)?;
}
ULong(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_ULONG)?;
data_buf.write_u32::<T>(val)?;
}
Float(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_FLOAT)?;
data_buf.write_f32::<T>(val)?;
}
Double(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_DOUBLE)?;
data_buf.write_f64::<T>(val)?;
}
Boolean(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_BOOLEAN)?;
data_buf.push(if val { B_TRUE } else { B_FALSE });
}
Char(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_CHAR)?;
data_buf.push(val as u8);
}
Octet(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_OCTET)?;
data_buf.push(val);
}
ULongLong(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_ULONGLONG)?;
data_buf.write_u64::<T>(val)?;
}
Unknown64(val) => {
bytes += R::write_by_version(self, D_ZERO)?;
bytes += R::write_by_version(self, D_UNKNOWN64)?;
data_buf.write_u64::<T>(val)?;
}
_ => return Err(From::from("Write struct: Unexpected data type in struct!")),
}
}
self.buffer.append(&mut data_buf);
bytes += data_buf.len();
debug!("DMImageWriter::write_struct() -> {} bytes written", bytes);
Ok(bytes)
}
#[inline]
fn write_complex_array<R: DMImageWriteByVersion, T: ByteOrder>(&mut self, array: &[Tag]) -> Result<usize> {
debug!("DMImageWriter::write_complex_array()");
let info_size = match self.image.version {
DM3 => 4 * 4, DM4 => 4 * 8, _ => return Err(From::from("Unknown DMImage version, cannot write...")),
};
let mut info_buf = vec![0u8; info_size];
match self.image.version {
DM3 => {
BigEndian::write_u32(&mut info_buf[4..8], D_ARRAY as u32);
BigEndian::write_u32(&mut info_buf[8..12], D_STRUCT as u32);
BigEndian::write_u32(&mut info_buf[12..16], D_ZERO as u32);
},
DM4 => {
BigEndian::write_u64(&mut info_buf[8..16], D_ARRAY as u64);
BigEndian::write_u64(&mut info_buf[16..24], D_STRUCT as u64);
BigEndian::write_u64(&mut info_buf[24..32], D_ZERO as u64);
},
_ => return Err(From::from("Unknown DMImage version, cannot write...")),
}
let mut struct_elements = 0usize;
let mut type_buf = Vec::new();
let mut data_buf = Vec::new();
for arr_elem in array.iter() {
match *arr_elem {
Struct(ref arr_str) => {
struct_elements = arr_str.len();
type_buf = Vec::new();
for elem in arr_str.iter() {
match *elem {
Short(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_SHORT)?;
data_buf.write_i16::<T>(val)?;
}
Long(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_LONG)?;
data_buf.write_i32::<T>(val)?;
}
UShort(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_USHORT)?;
data_buf.write_u16::<T>(val)?;
}
ULong(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_ULONG)?;
data_buf.write_u32::<T>(val)?;
}
Float(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_FLOAT)?;
data_buf.write_f32::<T>(val)?;
}
Double(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_DOUBLE)?;
data_buf.write_f64::<T>(val)?;
}
Boolean(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_BOOLEAN)?;
data_buf.push(if val { B_TRUE } else { B_FALSE });
}
Char(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_CHAR)?;
data_buf.push(val as u8);
}
Octet(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_OCTET)?;
data_buf.push(val);
}
ULongLong(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_ULONGLONG)?;
data_buf.write_u64::<T>(val)?;
}
Unknown64(val) => {
R::write_by_version_to_buffer(&mut type_buf, D_UNKNOWN64)?;
data_buf.write_u64::<T>(val)?;
}
_ => return Err(From::from("Unknown data type for complex array")),
}
}
}
_ => {
return Err(From::from(
"Expected a Tag::Struct inside the Tag::ComplexArray",
))
}
}
}
match self.image.version {
DM3 => BigEndian::write_u32(&mut info_buf[0..4], 5u32 + struct_elements as u32 * 2u32),
DM4 => BigEndian::write_u64(&mut info_buf[0..8], 5u64 + struct_elements as u64 * 2u64),
_ => return Err(From::from("Unknown DMImage version, cannot write...")),
}
let mut bytes = 0;
self.buffer.append(&mut info_buf);
bytes += info_buf.len();
bytes += R::write_by_version(self, struct_elements)?;
self.buffer.append(&mut type_buf);
bytes += type_buf.len();
bytes += R::write_by_version(self, array.len())?;
self.buffer.append(&mut data_buf);
bytes += data_buf.len();
debug!("DMImageWriter::write_complex_array() -> {} bytes written", bytes);
Ok(bytes)
}
}