vatfluid 0.1.0

UTF-8 slice validation, with incomplete results to support byte streams.
Documentation
// Copyright (c) 2016 vatfluid developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! nom based UTF-8 parser
mod error;
mod parser;

pub use error::UTF8Validation;
pub use parser::{validate, Success};

#[cfg(test)]
mod tests {
    use error::UTF8Validation;
    use parser::{self, Success};

    // Smallest 1-byte (U+0000)
    const V1: [u8; 1] = [0x00];
    // 1-byte (U+0014)
    const V2: [u8; 1] = [0x14];
    // Largest valid 1-byte (U+007F)
    const V3: [u8; 1] = [0x7F];
    // Smallest 2-byte. (U+0080)
    // Smallest 11-bits code point 1000 0000 (U+0080), that won't fit in 7 bits.
    // 110 00000 10 000000
    const V4: [u8; 2] = [0xc2, 0x80];
    // 2-byte ¢ (U+00A2)
    const V5: [u8; 2] = [0xc2, 0xa2];
    // Largest 2-byte. (U+07FF)
    // Largest 11-bits code point 11111111111
    // 110 11111 10 111111
    const V6: [u8; 2] = [0xdf, 0xbf];
    // Smallest 3-byte (U+0800)
    // Smallest 16-bits code-point 00001000 00000000 (U+0800), that won't fit in 11 bits.
    // 1110 0000 10 100000 10 000000
    const V7: [u8; 3] = [0xe0, 0xa0, 0x80];
    /// 3-byte € (U+20AC)
    const V8: [u8; 3] = [0xe2, 0x82, 0xac];
    // Largest 3-byte (U+FFFF)
    // Largest 16-bits code-point 11111111 11111111 (U+FFFF)
    // 1110 1111 10 111111 10 111111
    const V9: [u8; 3] = [0xef, 0xbf, 0xbf];
    // Smallest 4-byte. (U+10000)
    // Smallest 21-bits code-point 00001 00000000 00000000 (U+10000), that won't fit in 16 bits.
    // 11110 000 10 010000 10 000000 10 000000
    const V10: [u8; 4] = [0xf0, 0x90, 0x80, 0x80];
    // 4-byte (U+10348)
    const V11: [u8; 4] = [0xf0, 0x90, 0x8d, 0x88];
    // Largest 4-byte
    // Largest 21-bits code point 10000 11111111 11111111 (U+10FFFF), allowed by spec.
    // 11110 100 10 001111 10 111111 10 111111
    const V12: [u8; 4] = [0xf4, 0x8f, 0xbf, 0xbf];

    // Invalid two-byte continuation byte. Must be 0x80 - 0xbf.
    const C1: [u8; 2] = [0xc0, 0x00];
    const C2: [u8; 2] = [0xc0, 0x7f];
    const C3: [u8; 2] = [0xc0, 0xc0];
    const C4: [u8; 2] = [0xc0, 0xff];

    // Invalid three-byte continuation byte in second byte. Must be 0x80 - 0xbf.
    const C5: [u8; 3] = [0xe0, 0x00, 0x80];
    const C6: [u8; 3] = [0xe0, 0x7f, 0x80];
    const C7: [u8; 3] = [0xe0, 0xc0, 0x80];
    const C8: [u8; 3] = [0xe0, 0xff, 0x80];

    // Invalid three-byte continuation byte in third byte. Must be 0x80 - 0xbf.
    const C9: [u8; 3] = [0xe0, 0x80, 0x00];
    const C10: [u8; 3] = [0xe0, 0x80, 0x7f];
    const C11: [u8; 3] = [0xe0, 0x80, 0xc0];
    const C12: [u8; 3] = [0xe0, 0x80, 0xff];

    // Invalid four-byte continuation byte in second byte. Must be 0x80 - 0xbf.
    const C13: [u8; 4] = [0xf0, 0x00, 0x80, 0x80];
    const C14: [u8; 4] = [0xf0, 0x7f, 0x80, 0x80];
    const C15: [u8; 4] = [0xf0, 0xc0, 0x80, 0x80];
    const C16: [u8; 4] = [0xf0, 0xff, 0x80, 0x80];

    // Invalid four-byte continuation byte in third byte. Must be 0x80 - 0xbf.
    const C17: [u8; 4] = [0xf0, 0x80, 0x00, 0x80];
    const C18: [u8; 4] = [0xf0, 0x80, 0x7f, 0x80];
    const C19: [u8; 4] = [0xf0, 0x80, 0xc0, 0x80];
    const C20: [u8; 4] = [0xf0, 0x80, 0xff, 0x80];

    // Invalid four-byte continuation byte in fourth byte. Must be 0x80 - 0xbf.
    const C21: [u8; 4] = [0xf0, 0x80, 0x80, 0x00];
    const C22: [u8; 4] = [0xf0, 0x80, 0x80, 0x7f];
    const C23: [u8; 4] = [0xf0, 0x80, 0x80, 0xc0];
    const C24: [u8; 4] = [0xf0, 0x80, 0x80, 0xff];

    // Smallest overlong 2-byte.
    // 110 00000 10 000000 (U+0000)
    const O1: [u8; 2] = [0xc0, 0x80];
    // Largest overlong 2-byte.
    // 110 00001 10 111111 (U+007F)
    const O2: [u8; 2] = [0xc1, 0xbf];
    // Smallest 3-byte overlong.
    // 1110 0000 10 000000 10 000000 (U+0000)
    const O3: [u8; 3] = [0xe0, 0x80, 0x80];
    // Larget 3-byte overlong.
    // 1110 0000 10 011111 10 111111 (U+07FF)
    const O4: [u8; 3] = [0xe0, 0x9f, 0xbf];
    // Smallest 4-byte overlong.
    // 11110 000 10 000000 10 000000 10 000000 (U+0000)
    const O5: [u8; 4] = [0xf0, 0x80, 0x80, 0x80];
    // Largest 4-byte overlong
    // 11110 000 10 00 1111 10 111111 10 111111 (U+FFFF)
    const O6: [u8; 4] = [0xf0, 0x8f, 0xbf, 0xbf];

    macro_rules! putf8(
        ($n:ident, $a:expr, $b:expr, $c:expr) => {
            #[test]
            fn $n() {
                let expected = $a;
                let res = parser::validate(&expected);
                if $b {
                    assert!(res.is_ok());
                } else {
                    assert!(res.is_err());
                }
                assert!(res == $c);
            }
        }
    );

    // Byte is beyond maximum allow code point.
    putf8!(greater_than_max_code_point,
           vec![0xf5],
           false,
           Err(UTF8Validation::MaximumCodePoint));

    // Two byte continuation errors
    putf8!(two_byte_continuation_0x00,
           C1,
           false,
           Err(UTF8Validation::TwoByteContinuation));
    putf8!(two_byte_continuation_0x7f,
           C2,
           false,
           Err(UTF8Validation::TwoByteContinuation));
    putf8!(two_byte_continuation_0xc0,
           C3,
           false,
           Err(UTF8Validation::TwoByteContinuation));
    putf8!(two_byte_continuation_0xff,
           C4,
           false,
           Err(UTF8Validation::TwoByteContinuation));

    // Three byte continuation errors, in second byte.
    putf8!(three_byte_continuation_0x00_0x80,
           C5,
           false,
           Err(UTF8Validation::ThreeByteContinuation(2)));
    putf8!(three_byte_continuation_0x7f_0x80,
           C6,
           false,
           Err(UTF8Validation::ThreeByteContinuation(2)));
    putf8!(three_byte_continuation_0xc0_0x80,
           C7,
           false,
           Err(UTF8Validation::ThreeByteContinuation(2)));
    putf8!(three_byte_continuation_0xff_0x80,
           C8,
           false,
           Err(UTF8Validation::ThreeByteContinuation(2)));

    // Three byte continuation errors, in third byte.
    putf8!(three_byte_continuation_0x80_0x00,
           C9,
           false,
           Err(UTF8Validation::ThreeByteContinuation(3)));
    putf8!(three_byte_continuation_0x80_0x7f,
           C10,
           false,
           Err(UTF8Validation::ThreeByteContinuation(3)));
    putf8!(three_byte_continuation_0x80_0xc0,
           C11,
           false,
           Err(UTF8Validation::ThreeByteContinuation(3)));
    putf8!(three_byte_continuation_0x80_0xff,
           C12,
           false,
           Err(UTF8Validation::ThreeByteContinuation(3)));

    // Four byte continuation errors, in second byte.
    putf8!(four_byte_continuation_0x00_0x80_0x80,
           C13,
           false,
           Err(UTF8Validation::FourByteContinuation(2)));
    putf8!(four_byte_continuation_0x7f_0x80_0x80,
           C14,
           false,
           Err(UTF8Validation::FourByteContinuation(2)));
    putf8!(four_byte_continuation_0xc0_0x80_0x80,
           C15,
           false,
           Err(UTF8Validation::FourByteContinuation(2)));
    putf8!(four_byte_continuation_0xff_0x80_0x80,
           C16,
           false,
           Err(UTF8Validation::FourByteContinuation(2)));

    // Four byte continuation errors, in third byte.
    putf8!(four_byte_continuation_0x80_0x00_0x80,
           C17,
           false,
           Err(UTF8Validation::FourByteContinuation(3)));
    putf8!(four_byte_continuation_0x80_0x7f_0x80,
           C18,
           false,
           Err(UTF8Validation::FourByteContinuation(3)));
    putf8!(four_byte_continuation_0x80_0xc0_0x80,
           C19,
           false,
           Err(UTF8Validation::FourByteContinuation(3)));
    putf8!(four_byte_continuation_0x80_0xff_0x80,
           C20,
           false,
           Err(UTF8Validation::FourByteContinuation(3)));

    // Four byte continuation errors, in fourth byte.
    putf8!(four_byte_continuation_0x80_0x80_0x00,
           C21,
           false,
           Err(UTF8Validation::FourByteContinuation(4)));
    putf8!(four_byte_continuation_0x80_0x80_0x7f,
           C22,
           false,
           Err(UTF8Validation::FourByteContinuation(4)));
    putf8!(four_byte_continuation_0x80_0x80_0xc0,
           C23,
           false,
           Err(UTF8Validation::FourByteContinuation(4)));
    putf8!(four_byte_continuation_0x80_0x80_0xff,
           C24,
           false,
           Err(UTF8Validation::FourByteContinuation(4)));

    // Two byte overlong errors.
    putf8!(smallest_two_byte_overlong,
           O1,
           false,
           Err(UTF8Validation::TwoByteOverlong));
    putf8!(largest_two_byte_overlong,
           O2,
           false,
           Err(UTF8Validation::TwoByteOverlong));

    // Three byte overlong errors.
    putf8!(smallest_three_byte_overlong,
           O3,
           false,
           Err(UTF8Validation::ThreeByteOverlong));
    putf8!(largest_three_byte_overlong,
           O4,
           false,
           Err(UTF8Validation::ThreeByteOverlong));

    // Four byte overlong errors.
    putf8!(smallest_four_byte_overlong,
           O5,
           false,
           Err(UTF8Validation::FourByteOverlong));
    putf8!(largest_four_byte_overlong,
           O6,
           false,
           Err(UTF8Validation::FourByteOverlong));

    // Invalid first byte.
    putf8!(invalid_first_byte,
           vec![0x80],
           false,
           Err(UTF8Validation::InvalidFirstByte(0x80)));

    // Incomplete input tests.
    putf8!(empty, vec![], true, Ok(Success::Incomplete(1, 0)));
    putf8!(incomplete_two_byte,
           vec![0xc2],
           true,
           Ok(Success::Incomplete(2, 0)));
    putf8!(incomplete_two_byte_after_one_byte,
           vec![0x24, 0xc2],
           true,
           Ok(Success::Incomplete(2, 1)));
    putf8!(incomplete_two_after_two_byte,
           vec![0xc2, 0xa2, 0xc2],
           true,
           Ok(Success::Incomplete(2, 2)));

    // Valid input tests.
    putf8!(smallest_one_byte_code_point,
           V1,
           true,
           Ok(Success::Complete(V1.len())));
    putf8!(valid_one_byte_code_point,
           V2,
           true,
           Ok(Success::Complete(V2.len())));
    putf8!(largest_one_byte_code_point,
           V3,
           true,
           Ok(Success::Complete(V3.len())));
    putf8!(smallest_two_byte_code_point,
           V4,
           true,
           Ok(Success::Complete(V4.len())));
    putf8!(valid_two_byte_code_point,
           V5,
           true,
           Ok(Success::Complete(V5.len())));
    putf8!(largest_two_byte_code_point,
           V6,
           true,
           Ok(Success::Complete(V6.len())));
    putf8!(smallest_three_byte_code_point,
           V7,
           true,
           Ok(Success::Complete(V7.len())));
    putf8!(valid_three_byte_code_point,
           V8,
           true,
           Ok(Success::Complete(V8.len())));
    putf8!(largest_three_byte_code_point,
           V9,
           true,
           Ok(Success::Complete(V9.len())));
    putf8!(smallest_four_byte_code_point,
           V10,
           true,
           Ok(Success::Complete(V10.len())));
    putf8!(valid_four_byte_code_point,
           V11,
           true,
           Ok(Success::Complete(V11.len())));
    putf8!(largest_four_byte_code_point,
           V12,
           true,
           Ok(Success::Complete(V12.len())));
}