Skip to content

Correct BinHex 4.0 alphabet according to specifications#271

Merged
marshallpierce merged 1 commit into
marshallpierce:masterfrom
jobansd:patch-1
Apr 30, 2024
Merged

Correct BinHex 4.0 alphabet according to specifications#271
marshallpierce merged 1 commit into
marshallpierce:masterfrom
jobansd:patch-1

Conversation

@jobansd

@jobansd jobansd commented Apr 30, 2024

Copy link
Copy Markdown
Contributor

Description

This pull request addresses an inconsistency between the source code and the BinHex 4.0 specifications. Specifically, the variable BIN_HEX in alphabet.rs and corrects it to align with the specs.

Changes

pub const BIN_HEX: Alphabet = Alphabet::from_str_unchecked(
-    "!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdehijklmpqr",
+    "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr",
);

The new addition includes the character f and excludes the character 7, as per the spec.

References

Misc

#[cfg(test)]
mod tests {
    use base64::{
        alphabet::{self, Alphabet, ParseAlphabetError},
        engine::{self, GeneralPurposeConfig},
        Engine,
    };

    const BIN_HEX_NEW: Result<Alphabet, ParseAlphabetError> = alphabet::Alphabet::new(
        "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr",
    );

    const ENGINE_CONFIG: GeneralPurposeConfig = engine::GeneralPurposeConfig::new()
        .with_decode_allow_trailing_bits(true)
        .with_encode_padding(false)
        .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone);

    const SAMPLE_INPUT: &str = "Hello, world!";
    const EXPECTED_ENCODED_OUTPUT: &str = "5'9XE'mX)(G[FQaN)3";

    #[test]
    fn src_encode() {
        let engine_src = engine::GeneralPurpose::new(&alphabet::BIN_HEX, ENGINE_CONFIG);
        let res_enc = engine_src.encode(SAMPLE_INPUT);

        assert_eq!(res_enc, EXPECTED_ENCODED_OUTPUT);
    }

    #[test]
    fn src_decode() {
        let engine_src = engine::GeneralPurpose::new(&alphabet::BIN_HEX, ENGINE_CONFIG);
        let res_dec = engine_src.decode(EXPECTED_ENCODED_OUTPUT).unwrap();

        assert_eq!(res_dec, SAMPLE_INPUT.as_bytes());
    }

    #[test]
    fn new_encode() {
        let engine_new = engine::GeneralPurpose::new(&BIN_HEX_NEW.unwrap(), ENGINE_CONFIG);
        let res_enc = engine_new.encode(SAMPLE_INPUT);

        assert_eq!(res_enc, EXPECTED_ENCODED_OUTPUT);
    }

    #[test]
    fn new_decode() {
        let engine_new = engine::GeneralPurpose::new(&BIN_HEX_NEW.unwrap(), ENGINE_CONFIG);
        let res_dec = engine_new.decode(EXPECTED_ENCODED_OUTPUT).unwrap();

        assert_eq!(res_dec, SAMPLE_INPUT.as_bytes());
    }
}

Output

running 4 tests
test tests::new_encode ... ok
test tests::new_decode ... ok
test tests::src_decode ... FAILED
test tests::src_encode ... FAILED

failures:

---- tests::src_decode stdout ----
thread 'tests::src_decode' panicked at src\main.rs:34:9:
assertion `left == right` failed
  left: [72, 101, 173, 112, 111, 45, 32, 119, 176, 118, 124, 165, 33]
 right: [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- tests::src_encode stdout ----
thread 'tests::src_encode' panicked at src\main.rs:26:9:
assertion `left == right` failed
  left: "5'8VD'mV)(FZEP`M)3"
 right: "5'9XE'mX)(G[FQaN)3"


failures:
    tests::src_decode
    tests::src_encode

test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

# Description

This pull request addresses an inconsistency between the source code and the [BinHex 4.0 specifications](https://files.stairways.com/other/binhex-40-specs-info.txt). Specifically, the variable `BIN_HEX` in [`alphabet.rs`](https://github.com/marshallpierce/rust-base64/blob/bf15ccf30af8bb6b1f326fffa025d7b0aaa3342f/src/alphabet.rs#L201C1-L206C3) and corrects it to align with the specs.

# Changes

```diff
pub const BIN_HEX: Alphabet = Alphabet::from_str_unchecked(
-    "!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdehijklmpqr",
+    "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr",
);
```

The new addition includes the character `f` and excludes the character `7`, as per the spec.

# References

- [BinHex 4.0 Definition](https://files.stairways.com/other/binhex-40-specs-info.txt)
- [RFC 1741 - MIME Content Type for BinHex Encoded Files](https://www.rfc-editor.org/rfc/rfc1741.txt)
- [MacMIME - How to send Macintosh files with MIME](https://www.iana.org/assignments/media-types/application/applefile)

# Misc

```rust
#[cfg(test)]
mod tests {
    use base64::{
        alphabet::{self, Alphabet, ParseAlphabetError},
        engine::{self, GeneralPurposeConfig},
        Engine,
    };

    const BIN_HEX_NEW: Result<Alphabet, ParseAlphabetError> = alphabet::Alphabet::new(
        "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr",
    );

    const ENGINE_CONFIG: GeneralPurposeConfig = engine::GeneralPurposeConfig::new()
        .with_decode_allow_trailing_bits(true)
        .with_encode_padding(false)
        .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone);

    const SAMPLE_INPUT: &str = "Hello, world!";
    const EXPECTED_ENCODED_OUTPUT: &str = "5'9XE'mX)(G[FQaN)3";

    #[test]
    fn src_encode() {
        let engine_src = engine::GeneralPurpose::new(&alphabet::BIN_HEX, ENGINE_CONFIG);
        let res_enc = engine_src.encode(SAMPLE_INPUT);

        assert_eq!(res_enc, EXPECTED_ENCODED_OUTPUT);
    }

    #[test]
    fn src_decode() {
        let engine_src = engine::GeneralPurpose::new(&alphabet::BIN_HEX, ENGINE_CONFIG);
        let res_dec = engine_src.decode(EXPECTED_ENCODED_OUTPUT).unwrap();

        assert_eq!(res_dec, SAMPLE_INPUT.as_bytes());
    }

    #[test]
    fn new_encode() {
        let engine_new = engine::GeneralPurpose::new(&BIN_HEX_NEW.unwrap(), ENGINE_CONFIG);
        let res_enc = engine_new.encode(SAMPLE_INPUT);

        assert_eq!(res_enc, EXPECTED_ENCODED_OUTPUT);
    }

    #[test]
    fn new_decode() {
        let engine_new = engine::GeneralPurpose::new(&BIN_HEX_NEW.unwrap(), ENGINE_CONFIG);
        let res_dec = engine_new.decode(EXPECTED_ENCODED_OUTPUT).unwrap();

        assert_eq!(res_dec, SAMPLE_INPUT.as_bytes());
    }
}
```

Output

```sh
running 4 tests
test tests::new_encode ... ok
test tests::new_decode ... ok
test tests::src_decode ... FAILED
test tests::src_encode ... FAILED

failures:

---- tests::src_decode stdout ----
thread 'tests::src_decode' panicked at src\main.rs:34:9:
assertion `left == right` failed
  left: [72, 101, 173, 112, 111, 45, 32, 119, 176, 118, 124, 165, 33]
 right: [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- tests::src_encode stdout ----
thread 'tests::src_encode' panicked at src\main.rs:26:9:
assertion `left == right` failed
  left: "5'8VD'mV)(FZEP`M)3"
 right: "5'9XE'mX)(G[FQaN)3"


failures:
    tests::src_decode
    tests::src_encode

test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
@marshallpierce

Copy link
Copy Markdown
Owner

Thanks for the delightful PR!

@marshallpierce marshallpierce merged commit 64cca59 into marshallpierce:master Apr 30, 2024
@marshallpierce

Copy link
Copy Markdown
Owner

Fix released in 0.22.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants