Skip to content

Commit

Permalink
add custom error type
Browse files Browse the repository at this point in the history
  • Loading branch information
getreu committed Jan 28, 2017
1 parent f31fda0 commit f35da89
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stringsext"
version = "1.4.2"
version = "1.4.3"
authors = ["Jens Getreu <getreu@web.de>"]

[dependencies]
Expand Down
7 changes: 5 additions & 2 deletions doc/src/stringsext--man.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ search for multi-byte encoded strings in binary data.
:Date: 2017-01-13
:Version: 1.4.1
:Date: 2017-01-16
:Version: 1.4.2
:Author: Jens Getreu
:Date: 2017-01-16
:Version: 1.4.2
:Date: 2017-01-28
:Version: 1.4.3
:Copyright: Apache License, Version 2.0 (for details see COPYING section)
:Manual section: 1
:Manual group: Forensic Tools
Expand Down
8 changes: 4 additions & 4 deletions make-doc
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ mkdir -p ./doc/build
mkdir --parents ./man/man1

# Man page
rst2man.py ./doc/src/stringsext--man.rst > ./man/man1/stringsext.1
rst2html.py --stylesheet=./doc/src/docutils_basic.css ./doc/src/stringsext--man.rst ./doc/build/stringsext--man.html
rst2man ./doc/src/stringsext--man.rst > ./man/man1/stringsext.1
rst2html --stylesheet=./doc/src/docutils_basic.css ./doc/src/stringsext--man.rst ./doc/build/stringsext--man.html
# You can also use pandoc
#pandoc -s doc/src/stringsext--man.rst -t man -o man/man1/stringsext.1
gzip man/man1/stringsext.1

# index page
rst2html.py --stylesheet=./doc/src/docutils_basic.css ./doc/src/README.rst ./doc/build/README.html
# Readme page
rst2html --stylesheet=./doc/src/docutils_basic.css ./doc/src/README.rst ./doc/build/README.html


ln -sf ./doc/build/README.html ./README.html
Expand Down
108 changes: 79 additions & 29 deletions src/mission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use std::fmt;
use std::process;
use std::cmp::{Ord,Eq};
use std::cmp;
use std::num::ParseIntError;
use std::str::FromStr;
use std::num;
use std::error;
use options::ARGS;
extern crate encoding;
use encoding::EncodingRef;
Expand Down Expand Up @@ -134,6 +135,55 @@ impl fmt::Debug for Mission {
}


// We derive `Debug` because all types should probably derive `Debug`.
// This gives us a reasonable human readable description of `CliError` values.
#[derive(Debug,PartialEq)]
/// Possible errors when parsing command line options
enum CliError {
/// Wrapper for ParseIntError
Format(num::ParseIntError),
/// The `--encoding ` option value can have max 4 comma separated tokens:
/// ENC == ENCNAME,MIN,UNICODEBLOCK,UNICODEBLOCK
TooManyTokensError,
}

impl From<num::ParseIntError> for CliError {
fn from(err: num::ParseIntError) -> CliError {
CliError::Format(err)
}
}

impl fmt::Display for CliError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
// The underlying error already impl `Display`, so we defer to
// its implementation.
CliError::Format(ref err) => write!(f, "Format error: {}", err),
CliError::TooManyTokensError =>
write!(f, "Format error: too many comma separated tokens"),
}
}
}

impl error::Error for CliError {
fn description(&self) -> &str {
// The underlying error already impl `Error`, so we defer to its
// implementation.
match *self {
CliError::Format(ref err) => err.description(),
CliError::TooManyTokensError => "too many comma separated tokens",
}
}

fn cause(&self) -> Option<&error::Error> {
match *self {
CliError::Format(ref err) => Some(err),
_ => None,
}
}
}




/// Every `--encoding` option is stored in a `Mission` object which are bound together in a
Expand Down Expand Up @@ -163,7 +213,7 @@ impl Missions {
Ok(r) => r,
Err(e) => {
writeln!(&mut std::io::stderr(),
"Error: {} parsing `{}`.",e,&enc_opt).unwrap();
"Error: {} while parsing `{}`.",e,&enc_opt).unwrap();
process::exit(1);
}
};
Expand Down Expand Up @@ -225,7 +275,7 @@ impl Missions {
/// Helper function to parse enc_opt.
fn parse_enc_opt <'a>(enc_opt:&'a str, nbytes_min_default:u8)
-> Result<(&'a str, u8, UnicodeBlockFilter, UnicodeBlockFilter),
ParseIntError> {
CliError> {

let mask = |(u_lower, u_upper):(u32, u32)| -> UnicodeBlockFilter {

Expand Down Expand Up @@ -260,7 +310,7 @@ impl Missions {
is_some: filtering}
};

let parse_range = |r:&str| -> Result<(u32, u32), ParseIntError> {
let parse_range = |r:&str| -> Result<(u32, u32), CliError> {
// Separate and parse the range string
let mut j = r.split_terminator("..")
.map(|s|s.trim_left_matches("U+"))
Expand All @@ -286,11 +336,8 @@ impl Missions {
let range2:&str = i.next().unwrap_or("");
let filter2 = mask(try!(parse_range(range2)));

if let Some(s) = i.next() {
writeln!(&mut std::io::stderr(),
"Error: Max. 2 Unicode-block-filter supported: \
Can not process `{}` in `{}`.",s,enc_opt).unwrap();
process::exit(1);
if let Some(_) = i.next() {
return Err(CliError::TooManyTokensError);
}

Ok( (enc_name, nbytes_min, filter1, filter2) )
Expand All @@ -303,29 +350,29 @@ impl Missions {
#[cfg(test)]
mod tests {
use std::str::FromStr;
use std::num::ParseIntError;
use mission::UnicodeBlockFilter;
use mission::CliError;

#[test]
fn test_enc_opt_parser () {
//let pie = ParseIntError {kind: std::num::InvalidDigit} //is private
let pie_invalid_digit: ParseIntError = u32::from_str("x").unwrap_err();
let pie_invalid_digit = CliError::Format(u32::from_str("x").unwrap_err());
//let pie = ParseIntError {kind: std::num::Overflow} //is private
let pie_overflow: ParseIntError = u8::from_str("257").unwrap_err();
let pie_overflow = CliError::Format(u8::from_str("257").unwrap_err());


assert_eq!(super::Missions::parse_enc_opt("ascii",8),
Ok(("ascii",8,UnicodeBlockFilter::new(),UnicodeBlockFilter::new())));
assert_eq!(super::Missions::parse_enc_opt("ascii",8).unwrap(),
("ascii",8,UnicodeBlockFilter::new(),UnicodeBlockFilter::new()));

// range in `ascii,U+41..U+67` extended to range `U+40..U+7f`
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+41..U+67",8),
Ok(("ascii",10,UnicodeBlockFilter::new2(0xffffffc0,0x40,true),
UnicodeBlockFilter::new())));
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+41..U+67",8).unwrap(),
("ascii",10,UnicodeBlockFilter::new2(0xffffffc0,0x40,true),
UnicodeBlockFilter::new()));

// small letters, range is extended to `U+60..U+7f`
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+61..U+7a",8),
Ok(("ascii",10,UnicodeBlockFilter::new2(0xffffffe0,0x60,true),
UnicodeBlockFilter::new())));
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+61..U+7a",8).unwrap(),
("ascii",10,UnicodeBlockFilter::new2(0xffffffe0,0x60,true),
UnicodeBlockFilter::new()));

assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+4?1..U+67",8).unwrap_err(),
pie_invalid_digit );
Expand All @@ -337,14 +384,14 @@ mod tests {
pie_invalid_digit );

// range in `ascii,U+401..U+482,10` extended to range `U+400..U+4ff`
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+401..U+482",8),
Ok(("ascii",10,UnicodeBlockFilter::new2(0xffffff00,0x400,true),
UnicodeBlockFilter::new())));
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+401..U+482",8).unwrap(),
("ascii",10,UnicodeBlockFilter::new2(0xffffff00,0x400,true),
UnicodeBlockFilter::new()));

// range in `ascii,10,U+40e..U+403,10` extended to range `U+400..U+40f`
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+40e..U+403",8),
Ok(("ascii",10,UnicodeBlockFilter::new2(0xfffffff0,0x400,true),
UnicodeBlockFilter::new())));
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+40e..U+403",8).unwrap(),
("ascii",10,UnicodeBlockFilter::new2(0xfffffff0,0x400,true),
UnicodeBlockFilter::new()));

assert_eq!(super::Missions::parse_enc_opt("ascii,256,U+41..U+67",8).unwrap_err(),
pie_overflow );
Expand All @@ -353,9 +400,12 @@ mod tests {
pie_overflow );

// range in `ascii,10,U+40e..U+403,10` extended to range `U+400..U+40f`
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+0..ff,U+40e..U+403",8),
Ok(("ascii",10,UnicodeBlockFilter::new2(0xffffff00,0x0,true),
UnicodeBlockFilter::new2(0xfffffff0,0x400,true))));
assert_eq!(super::Missions::parse_enc_opt("ascii,10,U+0..ff,U+40e..U+403",8).unwrap(),
("ascii",10,UnicodeBlockFilter::new2(0xffffff00,0x0,true),
UnicodeBlockFilter::new2(0xfffffff0,0x400,true)));

assert_eq!(super::Missions::parse_enc_opt("ascii,10,0..f,10..1f,20..2f",8).unwrap_err(),
CliError::TooManyTokensError );
}
}

0 comments on commit f35da89

Please sign in to comment.