1use std::collections::HashMap;
2use error::*;
3use std::io::{Read, Write};
4use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5
6#[derive(Debug, Clone, PartialEq)]
7pub enum TableEntry {
8 Bool(bool),
9 ShortShortInt(i8),
10 ShortShortUint(u8),
11 ShortInt(i16),
12 ShortUint(u16),
13 LongInt(i32),
14 LongUint(u32),
15 LongLongInt(i64),
16 LongLongUint(u64),
17 Float(f32),
18 Double(f64),
19 DecimalValue(u8, u32),
20 LongString(String),
22 FieldArray(Vec<TableEntry>),
23 Timestamp(u64),
24 FieldTable(Table),
25 Void,
26}
27
28pub type Table = HashMap<String, TableEntry>;
29
30pub trait Init {
31 fn new() -> Self;
32}
33
34impl Init for Table {
35 fn new() -> Self {
36 HashMap::new()
37 }
38}
39
40fn read_table_entry<T>(reader: &mut T) -> Result<(TableEntry, usize)> where T: Read {
41 let (entry, entry_size) = match try!(reader.read_u8()) {
42 b't' => (TableEntry::Bool(!try!(reader.read_u8()) != 0), 1),
43 b'b' => (TableEntry::ShortShortInt(try!(reader.read_i8())), 1),
44 b'B' => (TableEntry::ShortShortUint(try!(reader.read_u8())), 1),
45 b'U' => (TableEntry::ShortInt(try!(reader.read_i16::<BigEndian>())), 2),
46 b'u' => (TableEntry::ShortUint(try!(reader.read_u16::<BigEndian>())), 2),
47 b'I' => (TableEntry::LongInt(try!(reader.read_i32::<BigEndian>())), 4),
48 b'i' => (TableEntry::LongUint(try!(reader.read_u32::<BigEndian>())), 4),
49 b'L' => (TableEntry::LongLongInt(try!(reader.read_i64::<BigEndian>())), 8),
50 b'l' => (TableEntry::LongLongUint(try!(reader.read_u64::<BigEndian>())), 8),
51 b'f' => (TableEntry::Float(try!(reader.read_f32::<BigEndian>())), 4),
52 b'd' => (TableEntry::Double(try!(reader.read_f64::<BigEndian>())), 8),
53 b'D' => ({
54 TableEntry::DecimalValue(try!(reader.read_u8()), try!(reader.read_u32::<BigEndian>()))
55 }, 5),
56 b'S' => {
63 let size = try!(reader.read_u32::<BigEndian>()) as usize;
64 let mut buffer: Vec<u8> = vec![0u8; size];
65 try!(reader.read(&mut buffer[..]));
66 let string = String::from_utf8_lossy(&buffer).to_string();
67 let entry = TableEntry::LongString(string);
68 (entry, 4 + size)
69 },
70 b'A' => {
71 let array_len = try!(reader.read_u32::<BigEndian>()) as usize;
72 let mut read_len = 0;
73 let mut arr = Vec::new();
74 while read_len < array_len {
75 let (entry, entry_len) = try!(read_table_entry(reader));
76 read_len += entry_len;
77 arr.push(entry)
78 }
79 let entry = TableEntry::FieldArray(arr);
80 (entry, 4 + array_len)
81 },
82 b'T' => (TableEntry::Timestamp(try!(reader.read_u64::<BigEndian>())), 8),
83 b'F' => {
84 let (table, table_size) = try!(decode_table(reader));
85 let entry = TableEntry::FieldTable(table);
86 (entry, table_size)
87 },
88 b'V' => (TableEntry::Void, 0),
89 x => {
90 debug!("Unknown type: {}", x);
91 return Err(ErrorKind::Protocol("Unknown type".to_string()).into());
92 }
93 };
94 Ok((entry, entry_size + 1)) }
96
97fn write_table_entry(writer: &mut Vec<u8>, table_entry: &TableEntry) -> Result<()> {
98 match *table_entry {
99 TableEntry::Bool(val) => {
100 try!(writer.write_u8(b't'));
101 try!(writer.write_u8(val as u8));
102 }
103 TableEntry::ShortShortInt(val) => {
104 try!(writer.write_u8(b'b'));
105 try!(writer.write_i8(val));
106 }
107 TableEntry::ShortShortUint(val) => {
108 try!(writer.write_u8(b'B'));
109 try!(writer.write_u8(val));
110 }
111 TableEntry::ShortInt(val) => {
112 try!(writer.write_u8(b'U'));
113 try!(writer.write_i16::<BigEndian>(val));
114 }
115 TableEntry::ShortUint(val) => {
116 try!(writer.write_u8(b'u'));
117 try!(writer.write_u16::<BigEndian>(val));
118 }
119 TableEntry::LongInt(val) => {
120 try!(writer.write_u8(b'I'));
121 try!(writer.write_i32::<BigEndian>(val));
122 }
123 TableEntry::LongUint(val) => {
124 try!(writer.write_u8(b'i'));
125 try!(writer.write_u32::<BigEndian>(val));
126 }
127 TableEntry::LongLongInt(val) => {
128 try!(writer.write_u8(b'L'));
129 try!(writer.write_i64::<BigEndian>(val));
130 }
131 TableEntry::LongLongUint(val) => {
132 try!(writer.write_u8(b'l'));
133 try!(writer.write_u64::<BigEndian>(val));
134 }
135 TableEntry::Float(val) => {
136 try!(writer.write_u8(b'f'));
137 try!(writer.write_f32::<BigEndian>(val));
138 }
139 TableEntry::Double(val) => {
140 try!(writer.write_u8(b'd'));
141 try!(writer.write_f64::<BigEndian>(val));
142 }
143 TableEntry::DecimalValue(scale, value) => {
144 try!(writer.write_u8(b'D'));
145 try!(writer.write_u8(scale));
146 try!(writer.write_u32::<BigEndian>(value));
147 }
148 TableEntry::LongString(ref str) => {
154 try!(writer.write_u8(b'S'));
155 try!(writer.write_u32::<BigEndian>(str.len() as u32));
156 try!(writer.write_all(str.as_bytes()));
157 }
158 TableEntry::FieldArray(ref arr) => {
159 try!(writer.write_u8(b'A'));
160 let mut tmp_buffer = vec![];
161 for item in arr.iter() {
162 try!(write_table_entry(&mut tmp_buffer, item));
163 }
164 try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
165 try!(writer.write(&tmp_buffer));
166 }
167 TableEntry::Timestamp(val) => {
168 try!(writer.write_u8(b'T'));
169 try!(writer.write_u64::<BigEndian>(val))
170 }
171 TableEntry::FieldTable(ref table) => {
172 try!(writer.write_u8(b'F'));
173 try!(encode_table(writer, table));
174 }
175 TableEntry::Void => try!(writer.write_u8(b'V')),
176 }
177 Ok(())
178}
179
180pub fn decode_table<T>(reader: &mut T) -> Result<(Table, usize)> where T: Read {
181 let mut table = Table::new();
182 let table_len = try!(reader.read_u32::<BigEndian>()) as usize;
183 debug!("decoding table, len: {}", table_len);
184 let mut bytes_read = 0;
185
186 while bytes_read < table_len {
187 let field_name_len = try!(reader.read_u8()) as usize;
188 let mut field_name: Vec<u8> = vec![0u8; field_name_len];
189 try!(reader.read(&mut field_name[..]));
190 let (table_entry, table_entry_size) = try!(read_table_entry(reader));
191 let stringified_field_name = String::from_utf8_lossy(&field_name).to_string();
192 debug!("Read table entry: {:?}:{} = {:?}", stringified_field_name, table_entry_size, table_entry);
193 table.insert(stringified_field_name, table_entry);
194 bytes_read += 1 + field_name_len + table_entry_size; debug!("bytes_read: {} of {}", bytes_read, table_len);
196 }
197 debug!("table decoded, table len: {}, bytes_read: {}", table_len, bytes_read);
198 Ok((table, bytes_read + 4)) }
200
201pub fn encode_table<T: Write>(writer: &mut T, table: &Table) -> Result<()> {
202 let mut tmp_buffer = vec![];
203 for (field_name, table_entry) in table.iter() {
204 try!(tmp_buffer.write_u8(field_name.len() as u8));
205 try!(tmp_buffer.write_all(field_name.as_bytes()));
206 try!(write_table_entry(&mut tmp_buffer, table_entry));
207 }
208 try!(writer.write_u32::<BigEndian>(tmp_buffer.len() as u32));
209 try!(writer.write_all(&tmp_buffer));
210 Ok(())
211}