Skip to content

Commit d3f65d8

Browse files
committed
fix: allow parsing double-dash date offsets
Negative date offsets seem to occour with double-dashes, too.
1 parent 74ce863 commit d3f65d8

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

gix-actor/src/signature/decode.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub(crate) mod function {
22
use bstr::ByteSlice;
33
use btoi::btoi;
44
use gix_date::{time::Sign, OffsetInSeconds, SecondsSinceUnixEpoch, Time};
5+
use nom::multi::many1_count;
56
use nom::{
67
branch::alt,
78
bytes::complete::{tag, take, take_until, take_while_m_n},
@@ -10,6 +11,7 @@ pub(crate) mod function {
1011
sequence::{terminated, tuple},
1112
IResult,
1213
};
14+
use std::cell::RefCell;
1315

1416
use crate::{IdentityRef, SignatureRef};
1517

@@ -19,7 +21,9 @@ pub(crate) mod function {
1921
pub fn decode<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
2022
i: &'a [u8],
2123
) -> IResult<&'a [u8], SignatureRef<'a>, E> {
22-
let (i, (identity, _, time, tzsign, hours, minutes)) = context(
24+
use nom::Parser;
25+
let tzsign = RefCell::new(b'-'); // TODO: there should be no need for this.
26+
let (i, (identity, _, time, _tzsign_count, hours, minutes)) = context(
2327
"<name> <<email>> <timestamp> <+|-><HHMM>",
2428
tuple((
2529
identity,
@@ -31,7 +35,13 @@ pub(crate) mod function {
3135
.map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))
3236
})
3337
}),
34-
context("+|-", alt((tag(b"-"), tag(b"+")))),
38+
context(
39+
"+|-",
40+
alt((
41+
many1_count(tag(b"-")).map(|_| *tzsign.borrow_mut() = b'-'), // TODO: this should be a non-allocating consumer of consecutive tags
42+
many1_count(tag(b"+")).map(|_| *tzsign.borrow_mut() = b'+'),
43+
)),
44+
),
3545
context("HH", |i| {
3646
take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| {
3747
btoi::<OffsetInSeconds>(v)
@@ -40,7 +50,7 @@ pub(crate) mod function {
4050
})
4151
}),
4252
context("MM", |i| {
43-
take_while_m_n(2usize, 2, is_digit)(i).and_then(|(i, v)| {
53+
take_while_m_n(1usize, 2, is_digit)(i).and_then(|(i, v)| {
4454
btoi::<OffsetInSeconds>(v)
4555
.map(|v| (i, v))
4656
.map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))
@@ -49,8 +59,9 @@ pub(crate) mod function {
4959
)),
5060
)(i)?;
5161

52-
debug_assert!(tzsign[0] == b'-' || tzsign[0] == b'+', "parser assure it's +|- only");
53-
let sign = if tzsign[0] == b'-' { Sign::Minus } else { Sign::Plus }; //
62+
let tzsign = tzsign.into_inner();
63+
debug_assert!(tzsign == b'-' || tzsign == b'+', "parser assure it's +|- only");
64+
let sign = if tzsign == b'-' { Sign::Minus } else { Sign::Plus }; //
5465
let offset = (hours * 3600 + minutes * 60) * if sign == Sign::Minus { -1 } else { 1 };
5566

5667
Ok((
@@ -148,6 +159,16 @@ mod tests {
148159
);
149160
}
150161

162+
#[test]
163+
fn negative_offset_double_dash() {
164+
assert_eq!(
165+
decode(b"name <[email protected]> 1288373970 --700")
166+
.expect("parse to work")
167+
.1,
168+
signature("name", "[email protected]", 1288373970, Sign::Minus, -252000)
169+
);
170+
}
171+
151172
#[test]
152173
fn empty_name_and_email() {
153174
assert_eq!(

0 commit comments

Comments
 (0)