1
Fork 0
mirror of https://github.com/RGBCube/DML synced 2025-07-27 23:57:44 +00:00
DML/dml/fileutils.py
2022-03-19 22:15:26 +03:00

67 lines
2.1 KiB
Python

import typing as t
from .encoder import encode, decode
from .errors import DecodeError
from .symbols import symbols as s
__all__ = ("decode_file", "encode_file")
def encode_file(fp: str, *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
"""Encodes a file to DML.
Arguments:
fp (str): The filepath to the file to encode.
out (str): The filepath to write the encoded file to. If not specified, the encoded text will be returned as a generator.
Returns:
Optional[Generator[str, None, None]]: The encoded text as a generator.
"""
def read_file() -> t.Generator[str, None, None]:
with open(fp) as f_:
while char_ := f_.read(1):
yield char_
if out:
out = out + ".dml" if not out.endswith(".dml") else out
with open(out, "w") as f:
for char in encode(read_file()):
f.write(char)
else:
return encode(read_file())
def decode_file(fp: str, *, out: str = None) -> t.Optional[t.Generator[str, None, None]]:
"""Decodes a file that has DML encoded in it.
Arguments:
fp (str): The filepath to the file to decode.
out (str): The filepath to write the decoded file to. If not specified, the decoded text will be returned as a generator.
Returns:
Optional[Generator[str, None, None]]: The decoded text as a generator.
Raises:
DecodeError: If the file is not valid DML.
"""
def read_file() -> t.Generator[str, None, None]:
buffer = ""
with open(fp) as f_:
while char_ := f_.read(1):
if char_ not in s.values():
raise DecodeError(f"Invalid character: '{char_}', expected {s['1']}, {s['0']} or {s['stop']}")
elif char_ != s["stop"]:
buffer += char_
else:
yield buffer + s["stop"]
buffer = ""
if out:
out = out + ".dml" if not out.endswith(".dml") else out
with open(out, "w") as f:
for char in decode(read_file()):
f.write(char)
else:
return decode(read_file())