Created
January 3, 2025 19:27
-
-
Save JarbasAl/738fa64f48ad1bc2077b060b96958449 to your computer and use it in GitHub Desktop.
base 100 with padding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from typing import Union | |
| class B100P: | |
| """ | |
| B100P is a class that provides encoding and decoding methods for transforming text into an emoji-based representation | |
| with a custom padding mechanism. The first byte of the encoded data indicates how many padding bytes were added | |
| during encoding, which is then removed during decoding. | |
| The padding is added to make the data length a multiple of 4, and the padding size is included as part of the encoded data. | |
| When decoding, the padding size is read from the first byte and used to strip the padding from the decoded data. | |
| """ | |
| @classmethod | |
| def encode(cls, data: Union[str, bytes], encoding: str = "utf-8") -> bytes: | |
| """ | |
| Encodes text into an emoji representation with padding, and prepends the padding size. | |
| Args: | |
| data (Union[str, bytes]): The input text to be encoded. This can either be a string (plaintext) or bytes. | |
| encoding (str): The encoding to use if `data` is provided as a string. Default is 'utf-8'. | |
| Returns: | |
| bytes: The emoji-encoded byte sequence with appropriate padding and padding size indication. | |
| Notes: | |
| The padding is applied to ensure the length of the encoded data is a multiple of 4. The first byte in the | |
| returned byte sequence represents the number of padding bytes added. This allows for proper decoding with | |
| padding removal. | |
| """ | |
| if isinstance(data, str): | |
| data = data.encode(encoding) | |
| padding = (4 - len(data) % 4) % 4 # Padding to make the length a multiple of 4 | |
| data += b'\x00' * padding | |
| # The first byte indicates how many padding bytes were added | |
| encoded_data = [padding] + [240, 159, 0, 0] * len(data) | |
| for i, b in enumerate(data): | |
| encoded_data[4 * i + 3] = (b + 55) // 64 + 143 | |
| encoded_data[4 * i + 4] = (b + 55) % 64 + 128 | |
| return bytes(encoded_data) | |
| @classmethod | |
| def decode(cls, encoded_data: Union[str, bytes], encoding: str = "utf-8") -> bytes: | |
| """ | |
| Decodes an emoji representation back into text, removing padding as indicated by the first byte. | |
| Args: | |
| encoded_data (Union[str, bytes]): The emoji-encoded byte sequence or string to be decoded. | |
| encoding (str): The encoding to use if `encoded_data` is provided as a string. Default is 'utf-8'. | |
| Returns: | |
| bytes: The decoded byte sequence of text with padding removed. | |
| Raises: | |
| ValueError: If the length of the input data is not divisible by 4 or contains invalid emoji encoding. | |
| Notes: | |
| The first byte of the encoded data indicates the padding size, and this padding is removed during decoding. | |
| """ | |
| if isinstance(encoded_data, str): | |
| encoded_data = encoded_data.encode(encoding) | |
| if len(encoded_data) == 0: | |
| return encoded_data | |
| # Ensure the length of data is divisible by 4 (with 1 extra byte for padding size) | |
| if len(encoded_data) % 4 != 1: | |
| raise ValueError('Invalid data length, should be divisible by 4 with 1 extra byte for padding indicator.') | |
| padding = encoded_data[0] # Read the padding size from the first byte | |
| if padding < 0 or padding > 3: | |
| raise ValueError('Padding size must be between 0 and 3.') | |
| # Extract the actual encoded data (excluding the padding size byte) | |
| encoded_data = encoded_data[1:] | |
| tmp = 0 | |
| out = [None] * (len(encoded_data) // 4) | |
| for i, b in enumerate(encoded_data): | |
| if i % 4 == 2: | |
| tmp = ((b - 143) * 64) % 256 | |
| elif i % 4 == 3: | |
| out[i // 4] = (b - 128 + tmp - 55) & 0xff | |
| # Return decoded bytes, removing the indicated padding | |
| decoded = bytes(out) | |
| return decoded[:-padding] if padding else decoded # Remove the padding |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import unittest | |
| class TestB100P(unittest.TestCase): | |
| def test_encode_empty(self): | |
| """Test encoding an empty byte sequence.""" | |
| self.assertEqual(B100P.encode(b''), b'\x00') | |
| self.assertEqual(B100P.encode(''), b'\x00') | |
| def test_decode_empty(self): | |
| """Test decoding an empty string.""" | |
| self.assertEqual(B100P.decode(b'\x00'), b'') | |
| self.assertEqual(B100P.decode(''), b'') | |
| self.assertEqual(B100P.decode(b''), b'') | |
| def test_encode_single_byte(self): | |
| """Test encoding a single byte.""" | |
| self.assertEqual(b'A', B100P.decode(B100P.encode(b'A'))) | |
| self.assertEqual(b'B', B100P.decode(B100P.encode('B'))) | |
| self.assertEqual(b'_~', B100P.decode(B100P.encode(b'_~'))) | |
| self.assertEqual(b'_~', B100P.decode(B100P.encode('_~'))) | |
| def test_encode_short_string(self): | |
| """Test encoding a short string.""" | |
| self.assertEqual(b'hello', B100P.decode(B100P.encode(b'hello'))) | |
| def test_encode_decode_round_trip(self): | |
| """Test encoding and decoding round-trip.""" | |
| data = b'The quick brown fox jumps over the lazy dog.' | |
| encoded = B100P.encode(data) | |
| decoded = B100P.decode(encoded) | |
| self.assertEqual(decoded, data) | |
| def test_encode_unicode_string(self): | |
| """Test encoding a Unicode string.""" | |
| data = 'こんにちは' # Japanese for "hello" | |
| encoded = B100P.encode(data) | |
| decoded = B100P.decode(encoded) | |
| self.assertEqual(decoded.decode('utf-8'), data) | |
| def test_decode_invalid_character(self): | |
| """Test decoding with invalid Base91 characters.""" | |
| with self.assertRaises(ValueError): | |
| B100P.decode('Invalid🎉Chars') | |
| def test_encode_large_data(self): | |
| """Test encoding a large byte sequence.""" | |
| data = b'\xff' * 1000 | |
| encoded = B100P.encode(data) | |
| decoded = B100P.decode(encoded) | |
| self.assertEqual(decoded, data) | |
| def test_padding_single_byte(self): | |
| """Test encoding and decoding with one byte that requires padding.""" | |
| data = b'\x01' # Single byte, should get padded with 3 \x00 bytes | |
| encoded = B100P.encode(data) | |
| self.assertEqual(encoded[0], 3) # Check padding byte | |
| self.assertEqual(B100P.decode(encoded), data) | |
| def test_padding_two_bytes(self): | |
| """Test encoding and decoding with two bytes that require padding.""" | |
| data = b'\x01\x01' # Two bytes, should get padded with 2 \x00 bytes | |
| encoded = B100P.encode(data) | |
| self.assertEqual(encoded[0], 2) # Check padding byte | |
| self.assertEqual(B100P.decode(encoded), data) | |
| def test_padding_three_bytes(self): | |
| """Test encoding and decoding with three bytes that require padding.""" | |
| data = b'\x01\x01\x01' # Three bytes, should get padded with 1 \x00 byte | |
| encoded = B100P.encode(data) | |
| self.assertEqual(encoded[0], 1) # Check padding byte | |
| self.assertEqual(B100P.decode(encoded), data) | |
| def test_no_padding_needed(self): | |
| """Test encoding and decoding with data that doesn't need padding.""" | |
| data = b'\x01\x01\x01\x01' # Exactly 4 bytes, no padding | |
| encoded = B100P.encode(data) | |
| self.assertEqual(encoded[0], 0) # No padding | |
| self.assertEqual(B100P.decode(encoded), data) | |
| def test_round_trip_padding(self): | |
| """Test round-trip encoding and decoding with padding.""" | |
| data = b'\x01\x01\x01' # Less than 4 bytes, needs padding | |
| encoded = B100P.encode(data) | |
| decoded = B100P.decode(encoded) | |
| self.assertEqual(decoded, data) # Ensure padding is correctly removed | |
| def test_padding_removal_after_decoding(self): | |
| """Test ensuring padding is correctly removed after decoding.""" | |
| data = b'\x01\x01\x01' # Less than 4 bytes, needs padding | |
| encoded = B100P.encode(data) | |
| self.assertEqual(encoded[0], 1) # Padding size is 1 | |
| decoded = B100P.decode(encoded) | |
| self.assertEqual(decoded, data) # Padding should be removed | |
| if __name__ == '__main__': | |
| unittest.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment