// Copyright 2016 Huton. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

/// Encoder and decoder for the crypt(3) encoding.
pub struct Crypt;

/// Decoder for last character for a tripcode.
/// The last character in a tripcode can only be one of ".26AEIMQUYcgkosw".
pub struct CryptLastChar;

/// Encoder and decoder for base64 encoding.
pub struct Base64;

/// Encoder and decoder for _2ch.sc_'s 15-character tripcode (15桁トリップ).
pub struct Sc15;

/// Encoder for _2ch.sc_'s katakana tripcode (カタカナトリップ).
pub struct ScKatakana;

/// Encoder and decoder for _2ch.sc_'s katakana tripcode (カタカナトリップ) encoded in Shift-JIS.
pub struct ScSjisKatakana;

/// Encoder and decoder methods for conversions between 6-bit binary strings and characters
/// such as base64 encoding.
pub trait EncoderDecoder {
    /// Returns a reference to an array that maps an ASCII character to a 6-bit value.
    /// The array returns `0x40` when the index is an invalid character for the encoding.
    // TODO: Replace by associated_consts once it has been stabilized.
    fn decoding_map() -> &'static [u64; 0x100];

    /// Returns a reference to an array that maps a 6-bit value to an ASCII character.
    fn encoding_map() -> &'static [u8; 64];

    /// Decodes an ASCII character into a 6-bit value.
    /// Returns `0x40` when passed an invalid character.
    fn decode(c: u8) -> u64 {
        Self::decoding_map()[c as usize]
    }

    /// Encodes a 6-bit value into an ASCII character.
    fn encode(b: usize) -> u8 {
        Self::encoding_map()[b]
    }
}

impl EncoderDecoder for Crypt {
    fn decoding_map() -> &'static [u64; 0x100] {
        const D: &'static [u64; 0x100] = &[
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x01,
            0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
            0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
            0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        ];
        D
    }

    fn encoding_map() -> &'static [u8; 64] {
        b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    }
}

impl EncoderDecoder for CryptLastChar {
    fn decoding_map() -> &'static [u64; 0x100] {
        const D: &'static [u64; 0x100] = &[
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x40,
            0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x0C, 0x40, 0x40, 0x40, 0x10, 0x40, 0x40, 0x40, 0x14, 0x40, 0x40, 0x40, 0x18, 0x40, 0x40,
            0x40, 0x1C, 0x40, 0x40, 0x40, 0x20, 0x40, 0x40, 0x40, 0x24, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x28, 0x40, 0x40, 0x40, 0x2C, 0x40, 0x40, 0x40, 0x30, 0x40, 0x40, 0x40, 0x34,
            0x40, 0x40, 0x40, 0x38, 0x40, 0x40, 0x40, 0x3C, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        ];
        D
    }

    fn encoding_map() -> &'static [u8; 64] {
        Crypt::encoding_map()
    }
}

impl EncoderDecoder for Base64 {
    fn decoding_map() -> &'static [u64; 0x100] {
        const D: &'static [u64; 0x100] = &[
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x3E, 0x40, 0x40, 0x40, 0x3F,
            0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
            0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
            0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33 ,0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        ];
        D
    }

    fn encoding_map() -> &'static [u8; 64] {
        b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    }
}

impl EncoderDecoder for Sc15 {
    fn decoding_map() -> &'static [u64; 0x100] {
        const D: &'static [u64; 0x100] = &[
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x3F, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x3E, 0x40,
            0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
            0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
            0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        ];
        D
    }

    fn encoding_map() -> &'static [u8; 64] {
        b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.!"
    }
}

impl EncoderDecoder for ScSjisKatakana {
    fn decoding_map() -> &'static [u64; 0x100] {
        const D: &'static [u64; 0x100] = &[
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x3F, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x00, 0x01, 0x02, 0x03, 0x04,
            0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
            0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
            0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x3E,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
            0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        ];
        D
    }

    fn encoding_map() -> &'static [u8; 64] {
        const E: &'static [u8; 64] = &[
            0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA,
            0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
            0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
            0xDB, 0xDC, 0xDD, 0xDE, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xDF, b'!',
        ];
        E
    }
}

impl ScKatakana {
    pub fn encode(b: usize) -> &'static [u8] {
        const E: &'static [&'static [u8]; 64] = &[
            &[0xEF, 0xBD, 0xAB], &[0xEF, 0xBD, 0xAC], &[0xEF, 0xBD, 0xAD], &[0xEF, 0xBD, 0xAE],
            &[0xEF, 0xBD, 0xAF], &[0xEF, 0xBD, 0xB0], &[0xEF, 0xBD, 0xB1], &[0xEF, 0xBD, 0xB2],
            &[0xEF, 0xBD, 0xB3], &[0xEF, 0xBD, 0xB4], &[0xEF, 0xBD, 0xB5], &[0xEF, 0xBD, 0xB6],
            &[0xEF, 0xBD, 0xB7], &[0xEF, 0xBD, 0xB8], &[0xEF, 0xBD, 0xB9], &[0xEF, 0xBD, 0xBA],
            &[0xEF, 0xBD, 0xBB], &[0xEF, 0xBD, 0xBC], &[0xEF, 0xBD, 0xBD], &[0xEF, 0xBD, 0xBE],
            &[0xEF, 0xBD, 0xBF], &[0xEF, 0xBE, 0x80], &[0xEF, 0xBE, 0x81], &[0xEF, 0xBE, 0x82],
            &[0xEF, 0xBE, 0x83], &[0xEF, 0xBE, 0x84], &[0xEF, 0xBE, 0x85], &[0xEF, 0xBE, 0x86],
            &[0xEF, 0xBE, 0x87], &[0xEF, 0xBE, 0x88], &[0xEF, 0xBE, 0x89], &[0xEF, 0xBE, 0x8A],
            &[0xEF, 0xBE, 0x8B], &[0xEF, 0xBE, 0x8C], &[0xEF, 0xBE, 0x8D], &[0xEF, 0xBE, 0x8E],
            &[0xEF, 0xBE, 0x8F], &[0xEF, 0xBE, 0x90], &[0xEF, 0xBE, 0x91], &[0xEF, 0xBE, 0x92],
            &[0xEF, 0xBE, 0x93], &[0xEF, 0xBE, 0x94], &[0xEF, 0xBE, 0x95], &[0xEF, 0xBE, 0x96],
            &[0xEF, 0xBE, 0x97], &[0xEF, 0xBE, 0x98], &[0xEF, 0xBE, 0x99], &[0xEF, 0xBE, 0x9A],
            &[0xEF, 0xBE, 0x9B], &[0xEF, 0xBE, 0x9C], &[0xEF, 0xBE, 0x9D], &[0xEF, 0xBE, 0x9E],
            &[0xEF, 0xBD, 0xA1], &[0xEF, 0xBD, 0xA2], &[0xEF, 0xBD, 0xA3], &[0xEF, 0xBD, 0xA4],
            &[0xEF, 0xBD, 0xA5], &[0xEF, 0xBD, 0xA6], &[0xEF, 0xBD, 0xA7], &[0xEF, 0xBD, 0xA8],
            &[0xEF, 0xBD, 0xA9], &[0xEF, 0xBD, 0xAA], &[0xEF, 0xBE, 0x9F], b"!",
        ];
        E[b]
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! test_fn {
        ($encoder:ty, $enc_dec:ident, $invalid:ident) => {
            #[test]
            fn $enc_dec() {
                for i in 0..0x40 {
                    assert_eq!(i, <$encoder>::decode(<$encoder>::encode(i)) as usize);
                }
            }

            #[test]
            fn $invalid() {
                for c in (0..0x100).map(|c| c as u8).filter(|c| !<$encoder>::encoding_map().contains(&c)) {
                    assert_eq!(0x40, <$encoder>::decode(c));
                }
            }
        }
    }

    test_fn!(Base64, b64_enc_dec, b64_invalid);
    test_fn!(Crypt, crypt_enc_dec, crypt_invalid);
    test_fn!(ScSjisKatakana, sc_sjis_enc_dec, sc_sjis_invalid);

    #[test]
    fn crypt_dec_eot() {
        // Set of characters which the last character of a tripcode can be.
        const EOT: &'static [u8] = b".26AEIMQUYcgkosw";

        for &c in EOT {
            assert_eq!(c, CryptLastChar::encode(CryptLastChar::decode(c) as usize));
        }

        for c in (0..0x100).map(|c| c as u8).filter(|c| !EOT.contains(&c)) {
            assert_eq!(0x40, CryptLastChar::decode(c));
        }
    }
}
