File: auto.py

package info (click to toggle)
game-data-packager 87
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 33,392 kB
  • sloc: python: 15,387; sh: 704; ansic: 95; makefile: 50
file content (85 lines) | stat: -rw-r--r-- 2,254 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/python3
# encoding=utf-8
#
# Copyright © 2015 Simon McVittie <smcv@debian.org>
# Copyright © 2015 Alexandre Detiste <alexandre@detiste.be>
# SPDX-License-Identifier: GPL-2.0-or-later

import tarfile
import zipfile
from typing import BinaryIO

from . import (StreamUnpackable, TarUnpacker, ZipUnpacker)


def get_makeself_offset(
    archive: str,
    reader: BinaryIO | None = None,
) -> int:
    """Sniff Makeself archives, returning the offset to the embedded
    tar file, or 0 if not a makeself archive.

    http://megastep.org/makeself/
    """
    skip: int = 0
    line_number: int = 0
    trailer: bytes | None = None

    SHEBANG = bytes('/bin/sh', 'ascii')
    HEADER_V1 = bytes('# This script was generated using Makeself 1.', 'ascii')
    HEADER_V2 = bytes('# This script was generated using Makeself 2.', 'ascii')
    TRAILER_V1 = bytes('END_OF_STUB', 'ascii')
    TRAILER_V2 = bytes('eval $finish; exit $res', 'ascii')

    if reader is None:
        reader = open(archive, 'rb')

    for line in reader:
        line_number += 1
        skip += len(line)

        if line_number == 1 and SHEBANG not in line:
            return 0
        elif trailer:
            if trailer in line:
                return skip
        elif HEADER_V1 in line:
            trailer = TRAILER_V1
        elif HEADER_V2 in line:
            trailer = TRAILER_V2
        elif line_number > 3:
            return 0

    return 0


def automatic_unpacker(
    archive: str,
    reader: BinaryIO | None = None,
) -> StreamUnpackable | None:
    if reader is None:
        is_plain_file = True
        reader = open(archive, 'rb')
    else:
        is_plain_file = False

    if reader.seekable():
        skip = get_makeself_offset(archive, reader)

        if skip > 0:
            reader.seek(0)
            return TarUnpacker(
                archive, reader=reader, skip=skip, compression='gz')

        if zipfile.is_zipfile(reader):
            return ZipUnpacker(reader)

        if archive.endswith(('.umod', '.exe')):
            from .umod import (Umod, is_umod)
            if is_umod(reader):
                return Umod(reader)

    if is_plain_file and tarfile.is_tarfile(archive):
        return TarUnpacker(archive)

    return None