Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/archive/cab.py: 100%

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

16 statements  

1from structlog import get_logger 

2 

3from ...extractors import Command 

4from ...models import ( 

5 File, 

6 HandlerDoc, 

7 HandlerType, 

8 HexString, 

9 Reference, 

10 StructHandler, 

11 ValidChunk, 

12) 

13 

14logger = get_logger() 

15 

16 

17class CABHandler(StructHandler): 

18 NAME = "cab" 

19 

20 PATTERNS = [HexString("4D 53 43 46 00 00 00 00 // MSCF then reserved dword")] 

21 C_DEFINITIONS = r""" 

22 typedef struct cab_header 

23 { 

24 char signature[4]; /* cabinet file signature contains the characters 'M','S','C','F' (bytes 0x4D, 0x53, 0x43, 0x46). */ 

25 /* This field is used to assure that the file is a cabinet file. */ 

26 uint32 reserved1; /* reserved */ 

27 uint32 cbCabinet; /* size of this cabinet file in bytes */ 

28 uint32 reserved2; /* reserved */ 

29 uint32 coffFiles; /* offset of the first CFFILE entry */ 

30 uint32 reserved3; /* reserved */ 

31 uint8 versionMinor; /* cabinet file format version, minor */ 

32 uint8 versionMajor; /* cabinet file format version, major */ 

33 uint16 cFolders; /* number of CFFOLDER entries in this cabinet */ 

34 uint16 cFiles; /* number of CFFILE entries in this cabinet */ 

35 uint16 flags; /* cabinet file option indicators */ 

36 uint16 setID; /* must be the same for all cabinets in a set*/ 

37 uint16 iCabinet; /* number of this cabinet file in a set */ 

38 uint16 cbCFHeader; /* (optional) size of per-cabinet reserved area */ 

39 uint8 cbCFFolder; /* (optional) size of per-folder reserved area */ 

40 uint8 cbCFData; /* (optional) size of per-datablock reserved area */ 

41 uint8 szCabinetPrev[]; /* (optional) name of previous cabinet file */ 

42 uint8 szDiskPrev[]; /* (optional) name of previous disk */ 

43 uint8 szCabinetNext[]; /* (optional) name of next cabinet file */ 

44 uint8 szDiskNext[]; /* (optional) name of next disk */ 

45 } cab_header_t; 

46 """ 

47 HEADER_STRUCT = "cab_header_t" 

48 

49 EXTRACTOR = Command("7z", "x", "-y", "{inpath}", "-o{outdir}") 

50 

51 DOC = HandlerDoc( 

52 name="CAB", 

53 description="Microsoft Cabinet (CAB) archive files are used for compressed file storage and software installation.", 

54 handler_type=HandlerType.ARCHIVE, 

55 vendor="Microsoft", 

56 references=[ 

57 Reference( 

58 title="Microsoft Cabinet File Format Documentation", 

59 url="https://en.wikipedia.org/wiki/Cabinet_(file_format)", 

60 ), 

61 Reference( 

62 title="Ubuntu Manual - cabextract", 

63 url="https://manpages.ubuntu.com/manpages/focal/man1/cabextract.1.html", 

64 ), 

65 ], 

66 limitations=[], 

67 ) 

68 

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

70 header = self.parse_header(file) 

71 

72 if header.cbCabinet < len(header): 

73 return None 

74 

75 return ValidChunk( 

76 start_offset=start_offset, 

77 end_offset=start_offset + header.cbCabinet, 

78 )