diff --git a/backend/utils/encoding.py b/backend/utils/encoding.py new file mode 100644 index 0000000..ef10989 --- /dev/null +++ b/backend/utils/encoding.py @@ -0,0 +1,48 @@ +from typing import Dict + +# Таблица Base64-подобного варианта +VariantBase64Table: str = ( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" +) +VariantBase64Dict: Dict[int, str] = { + i: VariantBase64Table[i] for i in range(len(VariantBase64Table)) +} +VariantBase64ReverseDict: Dict[str, int] = { + VariantBase64Table[i]: i for i in range(len(VariantBase64Table)) +} + + +def variant_base64_encode(bs: bytes) -> bytes: + """ + Пользовательский Base64 encode (малые блоки, little-endian). + + Аргументы: + - bs: bytes - исходные данные + + Возвращает: + - bytes: закодированные данные + """ + result: bytearray = bytearray() + blocks_count, left_bytes = divmod(len(bs), 3) + + # Полные блоки по 3 байта + for i in range(blocks_count): + b: bytes = bs[3*i:3*i+3] + coding_int: int = int.from_bytes(b, "little") + block: str = "".join( + VariantBase64Dict[(coding_int >> shift) & 0x3F] + for shift in (0, 6, 12, 18) + ) + result.extend(block.encode("ascii")) + + # Обработка оставшихся байт + if left_bytes: + b: bytes = bs[-left_bytes:] + coding_int: int = int.from_bytes(b, "little") + block: str = "".join( + VariantBase64Dict[(coding_int >> shift) & 0x3F] + for shift in range(0, left_bytes * 8 + 1, 6) + ) + result.extend(block.encode("ascii")) + + return bytes(result)