Version fonctionnelle
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
This commit is contained in:
61
pscheck/base45.py
Normal file
61
pscheck/base45.py
Normal file
@ -0,0 +1,61 @@
|
||||
"""
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2021, Kirei AB
|
||||
All rights reserved.
|
||||
"""
|
||||
|
||||
|
||||
from typing import Union
|
||||
|
||||
|
||||
BASE45_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
|
||||
BASE45_DICT = {v: i for i, v in enumerate(BASE45_CHARSET)}
|
||||
|
||||
|
||||
def b45encode(buf: bytes) -> bytes:
|
||||
"""Convert bytes to base45-encoded string"""
|
||||
res = ""
|
||||
buflen = len(buf)
|
||||
for i in range(0, buflen & ~1, 2):
|
||||
x = (buf[i] << 8) + buf[i + 1]
|
||||
e, x = divmod(x, 45 * 45)
|
||||
d, c = divmod(x, 45)
|
||||
res += BASE45_CHARSET[c] + BASE45_CHARSET[d] + BASE45_CHARSET[e]
|
||||
if buflen & 1:
|
||||
d, c = divmod(buf[-1], 45)
|
||||
res += BASE45_CHARSET[c] + BASE45_CHARSET[d]
|
||||
return res.encode()
|
||||
|
||||
|
||||
def b45decode(s: Union[bytes, str]) -> bytes:
|
||||
"""Decode base45-encoded string to bytes"""
|
||||
try:
|
||||
if isinstance(s, str):
|
||||
buf = [BASE45_DICT[c] for c in s.strip()]
|
||||
elif isinstance(s, bytes):
|
||||
buf = [BASE45_DICT[c] for c in s.decode()]
|
||||
else:
|
||||
raise TypeError("Type must be 'str' or 'bytes'")
|
||||
|
||||
buflen = len(buf)
|
||||
if buflen % 3 == 1:
|
||||
raise ValueError("Invalid base45 string")
|
||||
|
||||
res = []
|
||||
for i in range(0, buflen, 3):
|
||||
if buflen - i >= 3:
|
||||
x = buf[i] + buf[i + 1] * 45 + buf[i + 2] * 45 * 45
|
||||
if x > 0xFFFF:
|
||||
raise ValueError
|
||||
res.extend(divmod(x, 256))
|
||||
else:
|
||||
x = buf[i] + buf[i + 1] * 45
|
||||
if x > 0xFF:
|
||||
raise ValueError
|
||||
res.append(x)
|
||||
return bytes(res)
|
||||
except (ValueError, KeyError, AttributeError):
|
||||
raise ValueError("Invalid base45 string")
|
||||
|
||||
|
Reference in New Issue
Block a user