Skip to content

Commit

Permalink
🗓 Nov 26, 2023 11:03:28 AM
Browse files Browse the repository at this point in the history
✨ lz77 compress/decompress
🧪 tests added/updated
  • Loading branch information
securisec committed Nov 26, 2023
1 parent f0eed31 commit 7717dcc
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 55 deletions.
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ New ideas:
☐ ✨ amf encode/decode
☐ ✨ aes cmac
☐ ✨ whitespace encoding https://www.dcode.fr/whitespace-language
beaufort

Bug:

Expand Down
35 changes: 34 additions & 1 deletion chepy/modules/compression.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import stat
from typing import TypeVar
import lazy_import
from .internal.helpers import LZ77Compressor

LZ4 = lazy_import.lazy_module("lz4.frame")

Expand All @@ -25,7 +26,7 @@ def __tar_modes(self, mode): # pragma: no cover
assert mode in ["gz", "bz2", "xz", ""], "Valid modes are gz, bz2, xz"

@ChepyDecorators.call_stack
def fix_zip_header(self) -> CompressionT:
def fix_zip_header(self: CompressionT) -> CompressionT:
"""Fix the first 4 bytes of a zip file
Returns:
Expand Down Expand Up @@ -443,3 +444,35 @@ def lz4_decompress(self) -> CompressionT:
"""
self.state = LZ4.decompress(self._convert_to_bytes())
return self

@ChepyDecorators.call_stack
def lz77_compress(self, window_size: int = 13, lookahead_buffer_size: int = 6):
"""To LZ77 compression
Args:
window_size (int, optional): Window size. Defaults to 13.
lookahead_buffer_size (int, optional): Lookahead. Defaults to 6.
Returns:
Chepy: The Chepy object.
"""
self.state = LZ77Compressor(window_size, lookahead_buffer_size).compress(
self._convert_to_str()
)
return self

def lz77_decompress(self, window_size: int = 13, lookahead_buffer_size: int = 6):
"""From LZ77 compression
Args:
window_size (int, optional): Window size. Defaults to 13.
lookahead_buffer_size (int, optional): Lookahead. Defaults to 6.
Returns:
Chepy: The Chepy object.
"""
assert isinstance(self.state, list), "State is not a list"
self.state = LZ77Compressor(window_size, lookahead_buffer_size).decompress(
self.state
)
return self
2 changes: 2 additions & 0 deletions chepy/modules/compression.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ class Compression(ChepyCore):
def raw_deflate(self: CompressionT) -> CompressionT: ...
def lz4_compress(self: CompressionT) -> CompressionT: ...
def lz4_decompress(self: CompressionT) -> CompressionT: ...
def lz77_compress(self: CompressionT, window_size: int = 13, lookahead_buffer_size: int = 6) -> CompressionT: ...
def lz77_decompress(self: CompressionT, window_size: int = 13, lookahead_buffer_size: int = 6) -> CompressionT: ...
38 changes: 1 addition & 37 deletions chepy/modules/dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2047,7 +2047,7 @@ def to_uuencode(self, header: str = "-") -> DataFormatT:
return self

@ChepyDecorators.call_stack
def from_uuencode(self, header: str = "-") -> DataFormatT:
def from_uuencode(self: DataFormatT, header: str = "-") -> DataFormatT:
"""From UUEncode
Args:
Expand All @@ -2058,39 +2058,3 @@ def from_uuencode(self, header: str = "-") -> DataFormatT:
"""
self.state = UUEncoderDecoder(self._convert_to_bytes(), header).uudecode()
return self

@ChepyDecorators.call_stack
def to_lz77(
self, window_size: int = 13, lookahead_buffer_size: int = 6
) -> DataFormatT:
"""To LZ77 compression
Args:
window_size (int, optional): Window size. Defaults to 13.
lookahead_buffer_size (int, optional): Lookahead. Defaults to 6.
Returns:
Chepy: The Chepy object.
"""
self.state = LZ77Compressor(window_size, lookahead_buffer_size).compress(
self._convert_to_str()
)
return self

def from_lz77(
self, window_size: int = 13, lookahead_buffer_size: int = 6
) -> DataFormatT:
"""From LZ77 compression
Args:
window_size (int, optional): Window size. Defaults to 13.
lookahead_buffer_size (int, optional): Lookahead. Defaults to 6.
Returns:
Chepy: The Chepy object.
"""
assert isinstance(self.state, list), "State is not a list"
self.state = LZ77Compressor(window_size, lookahead_buffer_size).decompress(
self.state
)
return self
2 changes: 0 additions & 2 deletions chepy/modules/dataformat.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,3 @@ class DataFormat(ChepyCore):
def from_utf21(self: DataFormatT) -> DataFormatT: ...
def to_uuencode(self: DataFormatT, header: str='-') -> DataFormatT: ...
def from_uuencode(self: DataFormatT, header: str='-') -> DataFormatT: ...
def to_lz77(self: DataFormatT, window_size: int = 13, lookahead_buffer_size: int = 6) -> DataFormatT: ...
def from_lz77(self: DataFormatT, window_size: int = 13, lookahead_buffer_size: int = 6) -> DataFormatT: ...
15 changes: 15 additions & 0 deletions tests/test_compression.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from chepy import Chepy
import re


def test_fix_zip_header():
Expand Down Expand Up @@ -180,3 +181,17 @@ def test_lz4_decompress():
.o
== b"data"
)

def test_lz77():
input_str = "(0,0,O)(0,0,M)(0,0,G)(1,1,G)(3,3, )(0,0,Y)(10,1,U)(4,1,A)(0,0,R)(0,0,E)(4,1,C)(0,0,L)(9,1,S)(6,2,T)(5,1, )(3,1,H)(7,2,F)(13,1,A)(1,1,A)(2,2,G)(36,7,C)(28,5,C)(6,5,W)(3,1,L)(1,1, )(0,0,N)(10,1,W)(40,3,I)(15,1, )(3,3,T)(48,6,G)(5,1,E)(0,0,K)(22,1,{)(25,1,I)(38,1,E)(1,1,E)(3,3,E)(7,7,E)(15,15,_)(38,3,O)(2,2,O)(5,5,O)(11,11,O)(3,3,_)(63,23,})"
array_of_arrays = []
regex = r"\((\d+),(\d+),([A-Z\s_{}]+)\)"
matches = re.findall(regex, input_str)

for match in matches:
param1, param2, param3 = match
array_of_arrays.append([int(param1), int(param2), param3])

assert b'EKO{' in Chepy(array_of_arrays).lz77_decompress().o

assert Chepy('OMGGGGGG').lz77_compress(1).o[1] == [0, 0, 'M']
15 changes: 0 additions & 15 deletions tests/test_dataformat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from chepy import Chepy
import re


def test_eval():
Expand Down Expand Up @@ -735,17 +734,3 @@ def test_uuencode():
b"EKO{UUENC0DED_ENCRYPTED?}"
in Chepy(data).to_uuencode().from_uuencode().remove_nullbytes().o
)

def test_lz77():
input_str = "(0,0,O)(0,0,M)(0,0,G)(1,1,G)(3,3, )(0,0,Y)(10,1,U)(4,1,A)(0,0,R)(0,0,E)(4,1,C)(0,0,L)(9,1,S)(6,2,T)(5,1, )(3,1,H)(7,2,F)(13,1,A)(1,1,A)(2,2,G)(36,7,C)(28,5,C)(6,5,W)(3,1,L)(1,1, )(0,0,N)(10,1,W)(40,3,I)(15,1, )(3,3,T)(48,6,G)(5,1,E)(0,0,K)(22,1,{)(25,1,I)(38,1,E)(1,1,E)(3,3,E)(7,7,E)(15,15,_)(38,3,O)(2,2,O)(5,5,O)(11,11,O)(3,3,_)(63,23,})"
array_of_arrays = []
regex = r"\((\d+),(\d+),([A-Z\s_{}]+)\)"
matches = re.findall(regex, input_str)

for match in matches:
param1, param2, param3 = match
array_of_arrays.append([int(param1), int(param2), param3])

assert b'EKO{' in Chepy(array_of_arrays).from_lz77().o

assert Chepy('OMGGGGGG').to_lz77(1).o[1] == [0, 0, 'M']

0 comments on commit 7717dcc

Please sign in to comment.