1"""Stuffit handlers.
2
3We currently support detecting two specific Stuffit file formats:
4
5 - Stuffit SIT (with 'SIT!' magic)
6
7 - Stuffit 5 (with 'StuffIt (c)1997-' magic)
8
9Due to lack of access to sample files, source code, and really old
10packing tools, we don't support the following Stuffit file formats at
11the moment:
12
13 - Stuffit X ('StuffIt!' or 'StuffIt?' magic)
14
15 - Stuffit Delux ('SITD' magic)
16
17If you have the resources to add support for these archive formats,
18feel free to do so !
19"""
20
21from typing import Optional
22
23from structlog import get_logger
24
25from ...extractors import Command
26from ...file_utils import Endian
27from ...models import (
28 File,
29 HandlerDoc,
30 HandlerType,
31 HexString,
32 Reference,
33 StructHandler,
34 ValidChunk,
35)
36
37logger = get_logger()
38
39
40class _StuffItHandlerBase(StructHandler):
41 """A common base for all StuffIt formats."""
42
43 def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
44 header = self.parse_header(file, endian=Endian.BIG)
45
46 return ValidChunk(
47 start_offset=start_offset,
48 end_offset=start_offset + header.archive_length,
49 )
50
51 EXTRACTOR = Command("unar", "-no-directory", "-o", "{outdir}", "{inpath}")
52
53
54class StuffItSITHandler(_StuffItHandlerBase):
55 NAME = "stuffit"
56
57 PATTERNS = [
58 HexString(
59 """
60 // "SIT!\\x00", then 6 bytes (uint16 number of files and uint32 size), then "rLau".
61 53 49 54 21 [6] 72 4C 61 75
62 """
63 )
64 ]
65
66 C_DEFINITIONS = r"""
67 typedef struct sit_header
68 {
69 char signature[4];
70 uint16 num_files;
71 uint32 archive_length;
72 char signature2[4];
73 } sit_header_t;
74 """
75 HEADER_STRUCT = "sit_header_t"
76
77 EXTRACTOR = Command("unar", "-no-directory", "-o", "{outdir}", "{inpath}")
78
79 DOC = HandlerDoc(
80 name="Stuffit SIT",
81 description="StuffIt SIT archives is a legacy compressed archive format commonly used on macOS and earlier Apple systems.",
82 handler_type=HandlerType.ARCHIVE,
83 vendor="StuffIt Technologies",
84 references=[
85 Reference(
86 title="StuffIt SIT File Format Documentation",
87 url="https://en.wikipedia.org/wiki/StuffIt",
88 )
89 ],
90 limitations=[],
91 )
92
93
94class StuffIt5Handler(_StuffItHandlerBase):
95 NAME = "stuffit5"
96
97 PATTERNS = [
98 HexString(
99 """
100 // "StuffIt (c)1997-"
101 53 74 75 66 66 49 74 20 28 63 29 31 39 39 37 2D
102 """
103 )
104 ]
105
106 C_DEFINITIONS = r"""
107 typedef struct stuffit5_header
108 {
109 char signature[80];
110 uint32 unknown;
111 uint32 archive_length;
112 uint32 entry_offset;
113 uint16 num_root_dir_entries;
114 uint32 first_entry_offset;
115 } stuffit5_header_t;
116 """
117 HEADER_STRUCT = "stuffit5_header_t"
118
119 EXTRACTOR = Command("unar", "-no-directory", "-o", "{outdir}", "{inpath}")
120
121 DOC = HandlerDoc(
122 name="Stuffit SIT (v5)",
123 description="StuffIt SIT archives is a legacy compressed archive format commonly used on macOS and earlier Apple systems.",
124 handler_type=HandlerType.ARCHIVE,
125 vendor="StuffIt Technologies",
126 references=[
127 Reference(
128 title="StuffIt SIT File Format Documentation",
129 url="https://en.wikipedia.org/wiki/StuffIt",
130 )
131 ],
132 limitations=[],
133 )