|
61 | 61 | #![doc(html_logo_url = "https://raw.githubusercontent.com/musec/rusty-shark/master/artwork/wordmark.png")]
|
62 | 62 |
|
63 | 63 | extern crate byteorder;
|
| 64 | +extern crate num; |
64 | 65 | extern crate promising_future;
|
65 | 66 |
|
66 |
| -use byteorder::ReadBytesExt; |
| 67 | +use byteorder::ByteOrder; |
67 | 68 | pub use promising_future::Future;
|
68 | 69 | use std::fmt;
|
69 |
| -use std::io; |
70 | 70 |
|
71 | 71 |
|
72 | 72 | /// A description of a protocol, including code that can parse it.
|
@@ -121,6 +121,14 @@ pub enum Val {
|
121 | 121 | }
|
122 | 122 |
|
123 | 123 | impl Val {
|
| 124 | + pub fn unsigned<T>(x: T) -> Result<Val> |
| 125 | + where T: num::ToPrimitive + std::fmt::Display |
| 126 | + { |
| 127 | + x.to_u64() |
| 128 | + .map(Val::Unsigned) |
| 129 | + .ok_or(Error::InvalidData(format!["Cannot convert {} to u64", x])) |
| 130 | + } |
| 131 | + |
124 | 132 | pub fn pretty_print(self, indent_level:usize) -> String {
|
125 | 133 | match self {
|
126 | 134 | Val::Subpacket(values) => {
|
@@ -194,72 +202,47 @@ pub type Result<T=Val> = ::std::result::Result<T,Error>;
|
194 | 202 | /// A named value-or-error.
|
195 | 203 | pub type NamedValue = (String,Result<Val>);
|
196 | 204 |
|
197 |
| -/// Little- or big-endian integer representations. |
198 |
| -pub enum Endianness { |
199 |
| - BigEndian, |
200 |
| - LittleEndian, |
201 |
| -} |
202 | 205 |
|
203 | 206 | /// Parse a signed integer of a given endianness from a byte buffer.
|
204 | 207 | ///
|
205 | 208 | /// The size of the buffer will be used to determine the size of the integer
|
206 |
| -/// that should be parsed (i8, i16, i32 or i64), but the result will be stored |
207 |
| -/// in an i64. |
208 |
| -pub fn signed(buffer: &[u8], endianness: Endianness) -> Result<i64> { |
209 |
| - let mut reader = io::Cursor::new(buffer); |
210 |
| - |
211 |
| - match endianness { |
212 |
| - Endianness::BigEndian => { |
213 |
| - match buffer.len() { |
214 |
| - 1 => Ok(buffer[0] as i64), |
215 |
| - 2 => Ok(reader.read_i16::<byteorder::BigEndian>().unwrap() as i64), |
216 |
| - 4 => Ok(reader.read_i32::<byteorder::BigEndian>().unwrap() as i64), |
217 |
| - 8 => Ok(reader.read_i64::<byteorder::BigEndian>().unwrap()), |
218 |
| - x => Err(Error::InvalidData(format!["Invalid integer size: {} B", x])), |
219 |
| - } |
220 |
| - } |
221 |
| - |
222 |
| - Endianness::LittleEndian => { |
223 |
| - match buffer.len() { |
224 |
| - 1 => Ok(buffer[0] as i64), |
225 |
| - 2 => Ok(reader.read_i16::<byteorder::LittleEndian>().unwrap() as i64), |
226 |
| - 4 => Ok(reader.read_i32::<byteorder::LittleEndian>().unwrap() as i64), |
227 |
| - 8 => Ok(reader.read_i64::<byteorder::LittleEndian>().unwrap()), |
228 |
| - x => Err(Error::InvalidData(format!["Invalid integer size: {} B", x])), |
229 |
| - } |
230 |
| - } |
| 209 | +/// that should be parsed (i8, i16, i32 or i64). |
| 210 | +pub fn signed<T, E>(buffer: &[u8]) -> Result<T> |
| 211 | + where T: num::FromPrimitive, E: ByteOrder |
| 212 | +{ |
| 213 | + let len = buffer.len(); |
| 214 | + let conversion_error = "Failed to convert integer"; |
| 215 | + |
| 216 | + match len { |
| 217 | + 1 => T::from_u8(buffer[0]).ok_or(conversion_error), |
| 218 | + 2 => T::from_i16(E::read_i16(buffer)).ok_or(conversion_error), |
| 219 | + 4 => T::from_i32(E::read_i32(buffer)).ok_or(conversion_error), |
| 220 | + 8 => T::from_i64(E::read_i64(buffer)).ok_or(conversion_error), |
| 221 | + _ => Err("Invalid integer size"), |
231 | 222 | }
|
| 223 | + .map_err(|s| format!["{} ({} B)", s, len]) |
| 224 | + .map_err(Error::InvalidData) |
232 | 225 | }
|
233 | 226 |
|
234 |
| -/// Parse a signed integer of a given endianness from a byte buffer. |
| 227 | +/// Parse an unsigned integer of a given endianness from a byte buffer. |
235 | 228 | ///
|
236 | 229 | /// The size of the buffer will be used to determine the size of the integer
|
237 |
| -/// that should be parsed (u8, u16, u32 or u64), but the result will be stored |
238 |
| -/// in a u64. |
239 |
| -pub fn unsigned(buffer: &[u8], endianness: Endianness) -> Result<u64> { |
240 |
| - let mut reader = io::Cursor::new(buffer); |
241 |
| - |
242 |
| - match endianness { |
243 |
| - Endianness::BigEndian => { |
244 |
| - match buffer.len() { |
245 |
| - 1 => Ok(buffer[0] as u64), |
246 |
| - 2 => Ok(reader.read_u16::<byteorder::BigEndian>().unwrap() as u64), |
247 |
| - 4 => Ok(reader.read_u32::<byteorder::BigEndian>().unwrap() as u64), |
248 |
| - 8 => Ok(reader.read_u64::<byteorder::BigEndian>().unwrap()), |
249 |
| - x => Err(Error::InvalidData(format!["Invalid integer size: {} B", x])), |
250 |
| - } |
251 |
| - } |
252 |
| - |
253 |
| - Endianness::LittleEndian => { |
254 |
| - match buffer.len() { |
255 |
| - 1 => Ok(buffer[0] as u64), |
256 |
| - 2 => Ok(reader.read_u16::<byteorder::LittleEndian>().unwrap() as u64), |
257 |
| - 4 => Ok(reader.read_u32::<byteorder::LittleEndian>().unwrap() as u64), |
258 |
| - 8 => Ok(reader.read_u64::<byteorder::LittleEndian>().unwrap()), |
259 |
| - x => Err(Error::InvalidData(format!["Invalid integer size: {} B", x])), |
260 |
| - } |
261 |
| - } |
| 230 | +/// that should be parsed (u8, u16, u32 or u64). |
| 231 | +pub fn unsigned<T, E>(buffer: &[u8]) -> Result<T> |
| 232 | + where T: num::FromPrimitive, E: ByteOrder |
| 233 | +{ |
| 234 | + let len = buffer.len(); |
| 235 | + let conversion_error = "Failed to convert {} B integer"; |
| 236 | + |
| 237 | + match len { |
| 238 | + 1 => T::from_u8(buffer[0]).ok_or(conversion_error), |
| 239 | + 2 => T::from_u16(E::read_u16(buffer)).ok_or(conversion_error), |
| 240 | + 4 => T::from_u32(E::read_u32(buffer)).ok_or(conversion_error), |
| 241 | + 8 => T::from_u64(E::read_u64(buffer)).ok_or(conversion_error), |
| 242 | + _ => Err("Invalid integer size: {}"), |
262 | 243 | }
|
| 244 | + .map_err(|s| format!["{} ({} B)", s, len]) |
| 245 | + .map_err(Error::InvalidData) |
263 | 246 | }
|
264 | 247 |
|
265 | 248 |
|
|
0 commit comments