From 6bd7a5b5e322e05e1f209f4b7ca139d779918b1e Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Sun, 28 Dec 2025 07:42:44 +0100 Subject: [PATCH] add checksum and hexdump support --- radicale/utils.py | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/radicale/utils.py b/radicale/utils.py index 5c0f6c03..6a1fdade 100644 --- a/radicale/utils.py +++ b/radicale/utils.py @@ -22,7 +22,9 @@ import os import ssl import sys import textwrap +from hashlib import sha256 from importlib import import_module, metadata +from string import ascii_letters, digits, punctuation from typing import Callable, Sequence, Tuple, Type, TypeVar, Union from radicale import config @@ -342,3 +344,114 @@ def limit_str(content: str, limit: int) -> str: def textwrap_str(content: str, limit: int = 2000) -> str: # TODO: add support for config option and prefix return textwrap.indent(limit_str(content, limit), " ", lambda line: True) + + +def dataToHex(data, count): + result = '' + for item in range(count): + if ((item > 0) and ((item % 8) == 0)): + result += ' ' + if (item < len(data)): + result += '%02x' % data[item] + ' ' + else: + result += ' ' + return result + + +def dataToAscii(data, count): + result = '' + for item in range(count): + if (item < len(data)): + char = chr(data[item]) + if char in ascii_letters or \ + char in digits or \ + char in punctuation or \ + char == ' ': + result += char + else: + result += '.' + return result + + +def dataToSpecial(data, count): + result = '' + for item in range(count): + if (item < len(data)): + char = chr(data[item]) + if char == '\r': + result += 'C' + elif char == '\n': + result += 'L' + elif ord(char) == 0xc2: + result += 'u' + else: + result += '.' + return result + + +def hexdump_str(content: str, limit: int = 2000) -> str: + + result = "" + index = 0 + size = 16 + bytestring = content.encode("utf-8") + length = len(bytestring) + + while (index < length) and (index < limit): + data = bytestring[index:index+size] + hex = dataToHex(data, size) + ascii = dataToAscii(data, size) + special = dataToSpecial(data, size) + result += '%08x ' % index + result += hex + result += '|' + result += '%-16s' % ascii + result += '|' + result += '%-16s' % special + result += '|' + result += '\n' + index += size + + return result + + +def hexdump_line(line: str, limit: int = 200) -> str: + result = "" + length_str = len(line) + bytestring = line.encode("utf-8") + length = len(bytestring) + size = length + if (size > limit): + size = limit + + hex = dataToHex(bytestring, size) + ascii = dataToAscii(bytestring, size) + special = dataToSpecial(bytestring, size) + result += '%3d/%3d' % (length_str, length) + result += ': ' + result += hex + result += '|' + result += ascii + result += '|' + result += special + result += '|' + result += '\n' + + return result + + +def hexdump_lines(lines: str, limit: int = 200) -> str: + result = "" + counter = 0 + for line in lines.splitlines(True): + result += '% 4d ' % counter + result += hexdump_line(line) + counter += 1 + + return result + + +def sha256_str(content: str) -> str: + _hash = sha256() + _hash.update(content.encode("utf-8")) + return _hash.hexdigest()