Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/compression/lzip.py: 61%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

23 statements  

1import io 

2 

3from structlog import get_logger 

4 

5from unblob.extractors import Command 

6 

7from ...file_utils import Endian, convert_int64 

8from ...models import ( 

9 File, 

10 Handler, 

11 HandlerDoc, 

12 HandlerType, 

13 HexString, 

14 Reference, 

15 ValidChunk, 

16) 

17 

18logger = get_logger() 

19 

20# magic (4 bytes) + VN (1 byte) + DS (1 byte) 

21HEADER_LEN = 4 + 1 + 1 

22# lzip does not pad the LZMA stream, so a member's total length can be odd; 

23# scan byte-by-byte so the member_size trailer is found at any offset 

24LZMA_ALIGNMENT = 1 

25 

26 

27class LZipHandler(Handler): 

28 NAME = "lzip" 

29 

30 PATTERNS = [HexString("4C 5A 49 50 01")] 

31 

32 EXTRACTOR = Command( 

33 "lziprecover", "-k", "-D0", "-i", "{inpath}", "-o", "{outdir}/lz.uncompressed" 

34 ) 

35 

36 DOC = HandlerDoc( 

37 name="Lzip", 

38 description="Lzip is a lossless compressed file format based on the LZMA algorithm. It features a simple header, CRC-checked integrity, and efficient compression for large files.", 

39 handler_type=HandlerType.COMPRESSION, 

40 vendor=None, 

41 references=[ 

42 Reference( 

43 title="Lzip File Format Documentation", 

44 url="https://www.nongnu.org/lzip/manual/lzip_manual.html", 

45 ), 

46 Reference( 

47 title="Lzip Wikipedia", 

48 url="https://en.wikipedia.org/wiki/Lzip", 

49 ), 

50 ], 

51 limitations=[], 

52 ) 

53 

54 def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk | None: 

55 file.seek(HEADER_LEN, io.SEEK_CUR) 

56 # quite the naive idea but it works 

57 # the idea is to read 8 bytes uint64 at every byte offset 

58 # until we end up reading the Member Size field which corresponds 

59 # to "the total size of the member, including header and trailer". 

60 # We either find it or reach EOF, which will be caught by finder. 

61 

62 while True: 

63 file.seek(LZMA_ALIGNMENT, io.SEEK_CUR) 

64 member_size = convert_int64(file.read(8), Endian.LITTLE) 

65 if member_size == (file.tell() - start_offset): 

66 end_offset = file.tell() 

67 break 

68 file.seek(-8, io.SEEK_CUR) 

69 

70 return ValidChunk(start_offset=start_offset, end_offset=end_offset)