forked from dhondta/python-codext
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlz78.py
More file actions
81 lines (69 loc) · 2.46 KB
/
Copy pathlz78.py
File metadata and controls
81 lines (69 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# -*- coding: UTF-8 -*-
"""LZ78 Codec - Lempel-Ziv 1978 compression algorithm.
NB: Not an encoding properly speaking.
This codec:
- en/decodes strings from str to str
- en/decodes strings from bytes to bytes
- decodes file content to str (read)
- encodes file content from str to bytes (write)
Inspired from: https://github.com/mileswatson/lempel-ziv-compression
"""
from ..__common__ import *
__examples__ = {'enc-dec(lz78)': ["test", "This is a test", "@random{512,1024,2048}"]}
def lz78_compress(input, errors="strict"):
""" Compresses the given data by applying LZ78 compression algorithm. """
data = tuple(c if isinstance(c, int) else ord(c) for c in input)
if len(data) == 0:
return "", 0
out = (data[0], )
d = {tuple(): (0, ), (data[0], ): (1, )}
a, b, ctr = 1, 1, [2]
while b < len(data):
if not data[a:b+1] in d:
w = d[data[a:b]]
out += w + tuple(0 for i in range(len(ctr) - len(w) - int(sum(ctr) == 1))) + (data[b], )
d[data[a:b+1]] = tuple(ctr)
for i in range(len(ctr)):
ctr[i] += 1
if ctr[i] != 256:
break
else:
ctr[i] = 0
if i == len(ctr) - 1:
ctr.append(1)
a = b + 1
b += 1
if data[a:b] in d and a != b:
w = tuple(d[data[a:b]])
out += w + tuple(0 for i in range(len(ctr) - len(w)))
return "".join(chr(i) for i in out), len(out)
def lz78_decompress(input, errors="strict"):
""" Decompresses the given data. """
data = tuple(c if isinstance(c, int) else ord(c) for c in input)
if len(data) == 0:
return "", 0
out = (data[0], )
l = [tuple(), out]
a, b, c, i, char = 1, 1, 256, 0, False
try:
while a < len(data):
if char:
out += (data[a], )
l.append(l[i] + (data[a], ))
char = False
a += 1
if len(l) == c + 1:
b += 1
c *= 256
else:
i, m = 0, 1
for j in range(b):
i += data[a + j] * m
m *= 256
out += l[i]
a += b
char = True
except:
return handle_error("lz78", errors, decode=True)(chr(data[a]), a), len(input)
return "".join(chr(i) for i in out), len(out)
add("lz78", lz78_compress, lz78_decompress)