1
1
import os
2
+ from pathlib import Path
2
3
from typing import Optional
3
4
4
5
import arpy
5
6
from structlog import get_logger
6
7
7
- from ...extractors import Command
8
- from ...file_utils import OffsetFile
9
- from ...models import File , Handler , HexString , ValidChunk
8
+ from ...file_utils import FileSystem , OffsetFile , iterate_file
9
+ from ...models import Extractor , ExtractResult , File , Handler , HexString , ValidChunk
10
+ from ...report import ExtractionProblem
10
11
11
12
logger = get_logger ()
12
13
15
16
SIGNATURE_LENGTH = 0x8
16
17
17
18
19
+ class ArExtractor (Extractor ):
20
+ def extract (self , inpath : Path , outdir : Path ) -> Optional [ExtractResult ]:
21
+ fs = FileSystem (outdir )
22
+
23
+ with arpy .Archive (inpath .as_posix ()) as archive :
24
+ archive .read_all_headers ()
25
+
26
+ for name in sorted (archive .archived_files ):
27
+ archived_file = archive .archived_files [name ]
28
+
29
+ try :
30
+ path = Path (name .decode ())
31
+ except UnicodeDecodeError :
32
+ path = Path (name .decode (errors = "replace" ))
33
+ fs .record_problem (
34
+ ExtractionProblem (
35
+ path = repr (name ),
36
+ problem = "Path is not a valid UTF/8 string" ,
37
+ resolution = f"Converted to { path } " ,
38
+ )
39
+ )
40
+
41
+ fs .write_chunks (
42
+ path ,
43
+ chunks = iterate_file (
44
+ archived_file ,
45
+ 0 ,
46
+ archived_file .header .size ,
47
+ ),
48
+ )
49
+
50
+ return ExtractResult (reports = fs .problems )
51
+
52
+
18
53
class ARHandler (Handler ):
19
54
NAME = "ar"
20
55
@@ -27,7 +62,7 @@ class ARHandler(Handler):
27
62
)
28
63
]
29
64
30
- EXTRACTOR = Command ( "unar" , "-no-directory" , "-o" , "{outdir}" , "{inpath}" )
65
+ EXTRACTOR = ArExtractor ( )
31
66
32
67
def calculate_chunk (self , file : File , start_offset : int ) -> Optional [ValidChunk ]:
33
68
offset_file = OffsetFile (file , start_offset )
0 commit comments