4
4
# -- partial winrar support?
5
5
from __future__ import annotations
6
6
import io
7
- from typing import List
7
+ from typing import Dict , List
8
8
9
9
from .. import core
10
10
from ..utils import binary
17
17
18
18
# TODO: calculate values matching .pvr offsets
19
19
class Entry (core .Struct ):
20
- # sum of unknown[2] is less than filesize
21
- # -- 79 bytes short of the total filesize
22
- # -- the last 79 bytes of FILES.PAK are NULL
23
- # look like lengths, but idk
24
- __slots__ = ["unknown" ]
20
+ unknown : int # name hash? unique for every entry
21
+ offset : int # -8
22
+ length : int
23
+ __slots__ = ["unknown" , "offset" , "length" ]
25
24
_format = "3I"
26
- _arrays = {"unknown" : 3 }
27
25
28
26
29
27
class Pak (base .Archive ):
30
28
ext = "*.pak"
31
29
_file : io .BytesIO
32
- entries : List [ Entry ]
33
- # entries: Dict[str, Entry]
30
+ entries : Dict [ str , Entry ]
31
+ # NOTE: names are currently placeholders
34
32
35
33
def __init__ (self ):
36
34
super ().__init__ ()
@@ -40,8 +38,18 @@ def __repr__(self) -> str:
40
38
descriptor = f"{ len (self .entries )} files"
41
39
return f"<{ self .__class__ .__name__ } { descriptor } @ 0x{ id (self ):016X} >"
42
40
43
- # TODO: def read(self, filepath: str) -> bytes:
44
- # TODO: def namelist(self) -> List[str]:
41
+ def read (self , filepath : str ) -> bytes :
42
+ assert filepath in self .entries
43
+ entry = self .entries [filepath ]
44
+ self ._file .seek (entry .offset + 8 )
45
+ return self ._file .read (entry .length )
46
+
47
+ def namelist (self ) -> List [str ]:
48
+ return [
49
+ f"{ entry .unknown :08X} "
50
+ for entry in sorted (
51
+ self .entries .values (),
52
+ key = lambda e : (e .offset , e .length ))]
45
53
46
54
@classmethod
47
55
def from_stream (cls , stream : io .BytesIO ) -> Pak :
@@ -50,14 +58,13 @@ def from_stream(cls, stream: io.BytesIO) -> Pak:
50
58
assert stream .read (4 ) == b"NPCK" , "not a .pak file"
51
59
# guessing
52
60
num_entries = binary .read_struct (stream , "I" )
53
- out .entries = [
54
- Entry .from_stream (stream )
55
- for i in range (num_entries )]
56
- # vaild file data starts right after this
57
- # unsure of length tho
58
- # 6942 bytes of configs (likely multiple files)
59
- # a few bytes of data (likely ints)
60
- # sega copyright message (small text file?)
61
- # not seeing any sort of filename table
62
- # however plaintext files reference filenames
61
+ out .entries = {
62
+ f"{ entry .unknown :08X} " : entry
63
+ for entry in [
64
+ Entry .from_stream (stream )
65
+ for i in range (num_entries )]}
66
+ # NOTE: entries are listed in ascending `unknown` order
67
+ # -- not in offset order
68
+ # NOTE: some entries are 0 bytes in length
69
+ # NOTE: 80 blank bytes at end of file unaccounted for?
63
70
return out
0 commit comments