diff --git a/src/read_file.py b/src/read_file.py new file mode 100644 index 0000000..0f9ce86 --- /dev/null +++ b/src/read_file.py @@ -0,0 +1,67 @@ +import entry + +class FileFormatError(Exception): pass + +class VersionMismatch(Exception): pass + +def check_header(f): + """check_header(file(rb)) + Throw an error if the header isn't good""" + # Magic is b'WOT' + magic = f.read(3) + if magic != b'WOT': + raise FileFormatError('Invalid magic') + + # Version 0 is the current one + version = f.read(1) + if version == b'': + raise FileFormatError('Unexpected end of file') + if version != b'\0': + raise VersionMismatch('Version %i not supported' % version[0]) + +def read_entry(f): + """read_entry(file(rb)) → Entry / None + Returns None if the end of file has been reached""" + # u8[32]: salt + salt = f.read(32) + if len(salt) == 0: + # End of file has been reached, return None to mark that + return None + elif len(salt) != 32: + raise FileFormatError('Unexpected end of file') + + # u8[32]: hashed_host + hashed_host = f.read(32) + if len(hashed_host) != 32: + raise FileFormatError('Unexpected end of file') + + # u8[32]: fingerprint + fingerprint = f.read(32) + if len(fingerprint) != 32: + raise FileFormatError('Unexpected end of file') + + # u16le: comment_length + length_bytes = f.read(2) + if len(length_bytes) != 2: + raise FileFormatError('Unexpected end of file') + comment_length = length_bytes[0] | length_bytes[1] << 8 + + # u8[comment_length]: comment + comment = f.read(comment_length) + if len(comment) != comment_length: + raise FileFormatError('Unexpected end of file') + + return entry.Entry(salt, hashed_host, fingerprint, comment) + +def read(f): + """read_file(file(rb)) → [Entry]""" + check_header(f) + + entries = [] + while True: + # Read until we reach the end of file + entry = read_entry(f) + if entry is None: break + entries.append(entry) + + return entries