PyCatFile 0.24.2__py3-none-any.whl → 0.24.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pycatfile-0.24.2.data → pycatfile-0.24.6.data}/scripts/catfile.py +32 -52
- {pycatfile-0.24.2.dist-info → pycatfile-0.24.6.dist-info}/METADATA +1 -1
- pycatfile-0.24.6.dist-info/RECORD +10 -0
- pycatfile.py +312 -658
- pycatfile-0.24.2.dist-info/RECORD +0 -10
- {pycatfile-0.24.2.data → pycatfile-0.24.6.data}/scripts/catneofile.py +0 -0
- {pycatfile-0.24.2.data → pycatfile-0.24.6.data}/scripts/neocatfile.py +0 -0
- {pycatfile-0.24.2.dist-info → pycatfile-0.24.6.dist-info}/WHEEL +0 -0
- {pycatfile-0.24.2.dist-info → pycatfile-0.24.6.dist-info}/licenses/LICENSE +0 -0
- {pycatfile-0.24.2.dist-info → pycatfile-0.24.6.dist-info}/top_level.txt +0 -0
- {pycatfile-0.24.2.dist-info → pycatfile-0.24.6.dist-info}/zip-safe +0 -0
pycatfile.py
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
Copyright 2018-2024 Game Maker 2k - http://intdb.sourceforge.net/
|
|
15
15
|
Copyright 2018-2024 Kazuki Przyborowski - https://github.com/KazukiPrzyborowski
|
|
16
16
|
|
|
17
|
-
$FileInfo: pycatfile.py - Last Update:
|
|
17
|
+
$FileInfo: pycatfile.py - Last Update: 11/3/2025 Ver. 0.24.6 RC 1 - Author: cooldude2k $
|
|
18
18
|
'''
|
|
19
19
|
|
|
20
20
|
from __future__ import absolute_import, division, print_function, unicode_literals, generators, with_statement, nested_scopes
|
|
@@ -33,10 +33,10 @@ import socket
|
|
|
33
33
|
import struct
|
|
34
34
|
import hashlib
|
|
35
35
|
import inspect
|
|
36
|
-
import datetime
|
|
37
36
|
import logging
|
|
38
37
|
import zipfile
|
|
39
38
|
import binascii
|
|
39
|
+
import datetime
|
|
40
40
|
import platform
|
|
41
41
|
from io import StringIO, BytesIO
|
|
42
42
|
from collections import namedtuple
|
|
@@ -413,7 +413,12 @@ def is_only_nonprintable(var):
|
|
|
413
413
|
__file_format_multi_dict__ = {}
|
|
414
414
|
__file_format_default__ = "CatFile"
|
|
415
415
|
__include_defaults__ = True
|
|
416
|
-
__use_inmemfile__ =
|
|
416
|
+
__use_inmemfile__ = True
|
|
417
|
+
__use_spoolfile__ = False
|
|
418
|
+
__use_spooldir__ = tempfile.gettempdir()
|
|
419
|
+
BYTES_PER_MiB = 1024 * 1024
|
|
420
|
+
DEFAULT_SPOOL_MAX = 8 * BYTES_PER_MiB
|
|
421
|
+
__spoolfile_size__ = DEFAULT_SPOOL_MAX
|
|
417
422
|
__program_name__ = "Py"+__file_format_default__
|
|
418
423
|
__use_env_file__ = True
|
|
419
424
|
__use_ini_file__ = True
|
|
@@ -450,6 +455,8 @@ if __use_ini_file__ and os.path.exists(__config_file__):
|
|
|
450
455
|
__program_name__ = decode_unicode_escape(config.get('config', 'proname'))
|
|
451
456
|
__include_defaults__ = config.getboolean('config', 'includedef')
|
|
452
457
|
__use_inmemfile__ = config.getboolean('config', 'inmemfile')
|
|
458
|
+
__use_spoolfile__ = config.getboolean('config', 'usespoolfile')
|
|
459
|
+
__spoolfile_size__ = config.getint('config', 'spoolfilesize')
|
|
453
460
|
# Loop through all sections
|
|
454
461
|
for section in config.sections():
|
|
455
462
|
if section == "config":
|
|
@@ -543,6 +550,8 @@ elif __use_json_file__ and os.path.exists(__config_file__):
|
|
|
543
550
|
__program_name__ = decode_unicode_escape(_get(cfg_config, 'proname', ''))
|
|
544
551
|
__include_defaults__ = _to_bool(_get(cfg_config, 'includedef', False))
|
|
545
552
|
__use_inmemfile__ = _to_bool(_get(cfg_config, 'inmemfile', False))
|
|
553
|
+
__use_spoolfile__ = _to_bool(_get(cfg_config, 'usespoolfile', False))
|
|
554
|
+
__spoolfile_size__ = _to_int(_get(cfg_config, 'spoolfilesize', DEFAULT_SPOOL_MAX))
|
|
546
555
|
|
|
547
556
|
# --- iterate format sections (everything except "config") ---
|
|
548
557
|
required_keys = [
|
|
@@ -629,13 +638,15 @@ __use_alt_inode__ = __file_format_multi_dict__[__file_format_default__]['use_alt
|
|
|
629
638
|
__file_format_extension__ = __file_format_multi_dict__[__file_format_default__]['format_extension']
|
|
630
639
|
__file_format_dict__ = __file_format_multi_dict__[__file_format_default__]
|
|
631
640
|
__project__ = __program_name__
|
|
641
|
+
__program_alt_name__ = __program_name__
|
|
632
642
|
__project_url__ = "https://github.com/GameMaker2k/PyCatFile"
|
|
633
|
-
|
|
634
|
-
|
|
643
|
+
__project_release_url__ = __project_url__+"/releases/latest"
|
|
644
|
+
__version_info__ = (0, 24, 6, "RC 1", 1)
|
|
645
|
+
__version_date_info__ = (2025, 11, 3, "RC 1", 1)
|
|
635
646
|
__version_date__ = str(__version_date_info__[0]) + "." + str(
|
|
636
647
|
__version_date_info__[1]).zfill(2) + "." + str(__version_date_info__[2]).zfill(2)
|
|
637
648
|
__revision__ = __version_info__[3]
|
|
638
|
-
__revision_id__ = "$Id:
|
|
649
|
+
__revision_id__ = "$Id: d68fe3665e19a576beefb4e2c06db1bf32d5f94a $"
|
|
639
650
|
if(__version_info__[4] is not None):
|
|
640
651
|
__version_date_plusrc__ = __version_date__ + \
|
|
641
652
|
"-" + str(__version_date_info__[4])
|
|
@@ -647,6 +658,78 @@ if(__version_info__[3] is not None):
|
|
|
647
658
|
if(__version_info__[3] is None):
|
|
648
659
|
__version__ = str(__version_info__[0]) + "." + str(__version_info__[1]) + "." + str(__version_info__[2])
|
|
649
660
|
|
|
661
|
+
# From: https://stackoverflow.com/a/28568003
|
|
662
|
+
# By Phaxmohdem
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def versiontuple(v):
|
|
666
|
+
filled = []
|
|
667
|
+
for point in v.split("."):
|
|
668
|
+
filled.append(point.zfill(8))
|
|
669
|
+
return tuple(filled)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def version_check(myvercheck, newvercheck):
|
|
673
|
+
vercheck = 0
|
|
674
|
+
try:
|
|
675
|
+
from packaging import version
|
|
676
|
+
vercheck = 1
|
|
677
|
+
except ImportError:
|
|
678
|
+
try:
|
|
679
|
+
from distutils.version import LooseVersion, StrictVersion
|
|
680
|
+
vercheck = 2
|
|
681
|
+
except ImportError:
|
|
682
|
+
try:
|
|
683
|
+
from pkg_resources import parse_version
|
|
684
|
+
vercheck = 3
|
|
685
|
+
except ImportError:
|
|
686
|
+
return 5
|
|
687
|
+
# print(myvercheck, newvercheck)
|
|
688
|
+
if (vercheck == 1):
|
|
689
|
+
if (version.parse(myvercheck) == version.parse(newvercheck)):
|
|
690
|
+
return 0
|
|
691
|
+
elif (version.parse(myvercheck) < version.parse(newvercheck)):
|
|
692
|
+
return 1
|
|
693
|
+
elif (version.parse(myvercheck) > version.parse(newvercheck)):
|
|
694
|
+
return 2
|
|
695
|
+
else:
|
|
696
|
+
return 3
|
|
697
|
+
elif (vercheck == 2):
|
|
698
|
+
if (StrictVersion(myvercheck) == StrictVersion(newvercheck)):
|
|
699
|
+
return 0
|
|
700
|
+
elif (StrictVersion(myvercheck) < StrictVersion(newvercheck)):
|
|
701
|
+
return 1
|
|
702
|
+
elif (StrictVersion(myvercheck) > StrictVersion(newvercheck)):
|
|
703
|
+
return 2
|
|
704
|
+
else:
|
|
705
|
+
return 3
|
|
706
|
+
elif (vercheck == 3):
|
|
707
|
+
if (parse_version(myvercheck) == parse_version(newvercheck)):
|
|
708
|
+
return 0
|
|
709
|
+
elif (parse_version(myvercheck) < parse_version(newvercheck)):
|
|
710
|
+
return 1
|
|
711
|
+
elif (parse_version(myvercheck) > parse_version(newvercheck)):
|
|
712
|
+
return 2
|
|
713
|
+
else:
|
|
714
|
+
return 3
|
|
715
|
+
else:
|
|
716
|
+
if (versiontuple(myvercheck) == versiontuple(newvercheck)):
|
|
717
|
+
return 0
|
|
718
|
+
elif (versiontuple(myvercheck) < versiontuple(newvercheck)):
|
|
719
|
+
return 1
|
|
720
|
+
elif (versiontuple(myvercheck) > versiontuple(newvercheck)):
|
|
721
|
+
return 2
|
|
722
|
+
else:
|
|
723
|
+
return 3
|
|
724
|
+
return 4
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
def check_version_number(myversion=__version__, proname=__program_alt_name__, newverurl=__project_release_url__):
|
|
728
|
+
prevercheck = download_from_url(newverurl, geturls_headers, geturls_cj)
|
|
729
|
+
newvercheck = re.findall(proname + " ([0-9\\.]+)<\\/a\\>", prevercheck['Content'].decode("UTF-8"))[0]
|
|
730
|
+
myvercheck = re.findall("([0-9\\.]+)", myversion)[0]
|
|
731
|
+
return version_check(myvercheck, newvercheck)
|
|
732
|
+
|
|
650
733
|
# ===== Module-level type code table & helpers (reuse anywhere) =====
|
|
651
734
|
|
|
652
735
|
FT = {
|
|
@@ -747,6 +830,7 @@ try:
|
|
|
747
830
|
compressionsupport.append("lz4")
|
|
748
831
|
except ImportError:
|
|
749
832
|
pass
|
|
833
|
+
'''
|
|
750
834
|
try:
|
|
751
835
|
import lzo
|
|
752
836
|
compressionsupport.append("lzo")
|
|
@@ -754,6 +838,7 @@ try:
|
|
|
754
838
|
except ImportError:
|
|
755
839
|
lzo = None
|
|
756
840
|
pass
|
|
841
|
+
'''
|
|
757
842
|
try:
|
|
758
843
|
import zstandard
|
|
759
844
|
compressionsupport.append("zst")
|
|
@@ -813,11 +898,13 @@ if('lzo' in compressionsupport):
|
|
|
813
898
|
compressionlistalt.append('lzo')
|
|
814
899
|
outextlist.append('lzo')
|
|
815
900
|
outextlistwd.append('.lzo')
|
|
901
|
+
'''
|
|
816
902
|
if('lzop' in compressionsupport):
|
|
817
903
|
compressionlist.append('lzop')
|
|
818
904
|
compressionlistalt.append('lzop')
|
|
819
905
|
outextlist.append('lzop')
|
|
820
906
|
outextlistwd.append('.lzop')
|
|
907
|
+
'''
|
|
821
908
|
if('lzma' in compressionsupport):
|
|
822
909
|
compressionlist.append('lzma')
|
|
823
910
|
compressionlistalt.append('lzma')
|
|
@@ -1963,7 +2050,7 @@ def _normalize_initial_data(data, isbytes, encoding, errors=None):
|
|
|
1963
2050
|
|
|
1964
2051
|
|
|
1965
2052
|
def MkTempFile(data=None,
|
|
1966
|
-
inmem=
|
|
2053
|
+
inmem=__use_inmemfile__,
|
|
1967
2054
|
isbytes=True,
|
|
1968
2055
|
prefix="",
|
|
1969
2056
|
delete=True,
|
|
@@ -1971,9 +2058,9 @@ def MkTempFile(data=None,
|
|
|
1971
2058
|
newline=None, # text mode only; in-memory objects ignore newline semantics
|
|
1972
2059
|
dir=None,
|
|
1973
2060
|
suffix="",
|
|
1974
|
-
use_spool=
|
|
1975
|
-
spool_max=
|
|
1976
|
-
spool_dir=
|
|
2061
|
+
use_spool=__use_spoolfile__,
|
|
2062
|
+
spool_max=__spoolfile_size__,
|
|
2063
|
+
spool_dir=__use_spooldir__):
|
|
1977
2064
|
"""
|
|
1978
2065
|
Return a file-like handle with consistent behavior on Py2.7 and Py3.x.
|
|
1979
2066
|
|
|
@@ -2416,7 +2503,7 @@ class ZlibFile(object):
|
|
|
2416
2503
|
|
|
2417
2504
|
def __init__(self, file_path=None, fileobj=None, mode='rb', level=6, wbits=15,
|
|
2418
2505
|
encoding=None, errors=None, newline=None,
|
|
2419
|
-
tolerant_read=False, scan_bytes=(64 << 10), spool_threshold=
|
|
2506
|
+
tolerant_read=False, scan_bytes=(64 << 10), spool_threshold=__spoolfile_size__):
|
|
2420
2507
|
|
|
2421
2508
|
if file_path is None and fileobj is None:
|
|
2422
2509
|
raise ValueError("Either file_path or fileobj must be provided")
|
|
@@ -2903,7 +2990,7 @@ class GzipFile(object):
|
|
|
2903
2990
|
|
|
2904
2991
|
def __init__(self, file_path=None, fileobj=None, mode='rb',
|
|
2905
2992
|
level=6, encoding=None, errors=None, newline=None,
|
|
2906
|
-
tolerant_read=False, scan_bytes=(64 << 10), spool_threshold=
|
|
2993
|
+
tolerant_read=False, scan_bytes=(64 << 10), spool_threshold=__spoolfile_size__):
|
|
2907
2994
|
|
|
2908
2995
|
if file_path is None and fileobj is None:
|
|
2909
2996
|
raise ValueError("Either file_path or fileobj must be provided")
|
|
@@ -3327,519 +3414,6 @@ def gzip_decompress_bytes_all_members(blob):
|
|
|
3327
3414
|
"""
|
|
3328
3415
|
return _gzip_decompress_multimember(bytes(blob))
|
|
3329
3416
|
|
|
3330
|
-
|
|
3331
|
-
# ---------- Simple LZO container (NOT real .lzop) ----------
|
|
3332
|
-
# File layout (concatenated members allowed):
|
|
3333
|
-
# [MAGIC 8B] [FLAGS 1B] [ULEN 8B] [CRC32 4B] [CCHUNK...] | repeat...
|
|
3334
|
-
# where:
|
|
3335
|
-
# MAGIC = b'\x89LZO\x0D\x0A\x1A\n'
|
|
3336
|
-
# FLAGS = bit0: 1 => member has ULEN+CRC, 0 => no header (legacy)
|
|
3337
|
-
# ULEN = uncompressed length (u64 BE)
|
|
3338
|
-
# CRC32 = CRC32 of uncompressed data (u32 BE)
|
|
3339
|
-
# CCHUNK = one or more compressed chunks:
|
|
3340
|
-
# [u32BE chunk_size][chunk_data] ... then a zero-size u32 terminator
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
class LzopFile(object):
|
|
3344
|
-
MAGIC = b'\x89LZO\x0D\x0A\x1A\n'
|
|
3345
|
-
FLAG_HAS_UHDR = 0x01
|
|
3346
|
-
RAW_CHUNK = 256 * 1024 # 256 KiB per raw (pre-compress) chunk
|
|
3347
|
-
|
|
3348
|
-
def __init__(self, file_path=None, fileobj=None, mode='rb',
|
|
3349
|
-
level=9, encoding=None, errors=None, newline=None,
|
|
3350
|
-
write_header=True,
|
|
3351
|
-
tolerant_read=False, scan_bytes=(64 << 10),
|
|
3352
|
-
spool_threshold=(8 << 20)):
|
|
3353
|
-
"""
|
|
3354
|
-
Custom LZO file (NOT the lzop(1) format).
|
|
3355
|
-
- streaming write/read, supports concatenated members
|
|
3356
|
-
- optional per-member header (uncompressed length + CRC32)
|
|
3357
|
-
- spooled reads to limit RAM, strict text mode with newline control
|
|
3358
|
-
- tolerant_read: scan forward (up to scan_bytes) to first MAGIC
|
|
3359
|
-
|
|
3360
|
-
:param write_header: if True, include ULEN+CRC32 per member
|
|
3361
|
-
:param tolerant_read: skip leading junk up to scan_bytes to find MAGIC
|
|
3362
|
-
:param scan_bytes: max bytes to scan when tolerant_read=True
|
|
3363
|
-
:param spool_threshold: SpooledTemporaryFile RAM threshold before spill
|
|
3364
|
-
"""
|
|
3365
|
-
if lzo is None:
|
|
3366
|
-
raise ImportError("python-lzo is required for LzopFile")
|
|
3367
|
-
|
|
3368
|
-
if file_path is None and fileobj is None:
|
|
3369
|
-
raise ValueError("Either file_path or fileobj must be provided")
|
|
3370
|
-
if file_path is not None and fileobj is not None:
|
|
3371
|
-
raise ValueError("Only one of file_path or fileobj should be provided")
|
|
3372
|
-
|
|
3373
|
-
if 'b' not in mode and 't' not in mode:
|
|
3374
|
-
mode += 'b'
|
|
3375
|
-
if 'x' in mode and PY2:
|
|
3376
|
-
raise ValueError("Exclusive creation mode 'x' is not supported on Python 2")
|
|
3377
|
-
|
|
3378
|
-
self.file_path = file_path
|
|
3379
|
-
self.file = fileobj
|
|
3380
|
-
self.mode = mode
|
|
3381
|
-
self.level = int(level) # effective: 1 or 9 (clamped)
|
|
3382
|
-
self.encoding = encoding
|
|
3383
|
-
self.errors = errors
|
|
3384
|
-
self.newline = newline
|
|
3385
|
-
self._text_mode = ('t' in mode)
|
|
3386
|
-
|
|
3387
|
-
self._write_header = bool(write_header)
|
|
3388
|
-
|
|
3389
|
-
# Config (read path)
|
|
3390
|
-
self.tolerant_read = bool(tolerant_read)
|
|
3391
|
-
self.scan_bytes = int(scan_bytes)
|
|
3392
|
-
self.spool_threshold = int(spool_threshold)
|
|
3393
|
-
|
|
3394
|
-
# Write state
|
|
3395
|
-
self._crc = 0
|
|
3396
|
-
self._ulen = 0
|
|
3397
|
-
self._open_member = False
|
|
3398
|
-
self._member_header_pos = None # position *after* ULEN+CRC placeholders
|
|
3399
|
-
|
|
3400
|
-
# Read state
|
|
3401
|
-
self._spool = None
|
|
3402
|
-
self._text_reader = None
|
|
3403
|
-
self._position = 0
|
|
3404
|
-
self.closed = False
|
|
3405
|
-
|
|
3406
|
-
internal_mode = mode.replace('t', 'b')
|
|
3407
|
-
if self.file is None:
|
|
3408
|
-
if 'x' in internal_mode and os.path.exists(file_path):
|
|
3409
|
-
raise IOError("File exists: '{}'".format(file_path))
|
|
3410
|
-
self.file = open(file_path, internal_mode)
|
|
3411
|
-
else:
|
|
3412
|
-
if 'r' in internal_mode and not hasattr(self.file, 'read'):
|
|
3413
|
-
raise ValueError("fileobj must support read() in read mode")
|
|
3414
|
-
if any(ch in internal_mode for ch in ('w', 'a', 'x')) and not hasattr(self.file, 'write'):
|
|
3415
|
-
raise ValueError("fileobj must support write() in write/append mode")
|
|
3416
|
-
|
|
3417
|
-
self._fp = self.file
|
|
3418
|
-
if any(ch in internal_mode for ch in ('w', 'a', 'x')):
|
|
3419
|
-
# Start a new member at EOF for append
|
|
3420
|
-
if 'a' in internal_mode:
|
|
3421
|
-
try:
|
|
3422
|
-
self.file.seek(0, os.SEEK_END)
|
|
3423
|
-
except Exception:
|
|
3424
|
-
pass
|
|
3425
|
-
# Defer writing header until first write so empty files don’t get empty members
|
|
3426
|
-
elif 'r' in internal_mode:
|
|
3427
|
-
self._load_all_members_spooled()
|
|
3428
|
-
else:
|
|
3429
|
-
raise ValueError("Unsupported mode: {}".format(mode))
|
|
3430
|
-
|
|
3431
|
-
# ---------- helpers ----------
|
|
3432
|
-
@property
|
|
3433
|
-
def name(self):
|
|
3434
|
-
return self.file_path
|
|
3435
|
-
|
|
3436
|
-
def readable(self):
|
|
3437
|
-
return 'r' in self.mode
|
|
3438
|
-
|
|
3439
|
-
def writable(self):
|
|
3440
|
-
return any(ch in self.mode for ch in ('w', 'a', 'x'))
|
|
3441
|
-
|
|
3442
|
-
def seekable(self):
|
|
3443
|
-
return True if self._spool is not None else bool(getattr(self.file, 'seek', None))
|
|
3444
|
-
|
|
3445
|
-
def _normalize_newlines_for_write(self, s):
|
|
3446
|
-
nl = self.newline if self.newline is not None else "\n"
|
|
3447
|
-
return s.replace("\r\n", "\n").replace("\r", "\n").replace("\n", nl)
|
|
3448
|
-
|
|
3449
|
-
def _reader(self):
|
|
3450
|
-
return self._text_reader if self._text_mode else self._spool
|
|
3451
|
-
|
|
3452
|
-
# ---------- Write path ----------
|
|
3453
|
-
def _ensure_member_header(self):
|
|
3454
|
-
if self._open_member:
|
|
3455
|
-
return
|
|
3456
|
-
flags = self.FLAG_HAS_UHDR if self._write_header else 0
|
|
3457
|
-
self.file.write(self.MAGIC)
|
|
3458
|
-
self.file.write(struct.pack(">B", flags))
|
|
3459
|
-
if self._write_header:
|
|
3460
|
-
# placeholders for ULEN+CRC; we’ll backfill on finalize
|
|
3461
|
-
self.file.write(struct.pack(">Q", 0))
|
|
3462
|
-
self.file.write(struct.pack(">I", 0))
|
|
3463
|
-
# position *after* ULEN+CRC placeholders (or after FLAGS if no header)
|
|
3464
|
-
self._member_header_pos = self.file.tell()
|
|
3465
|
-
self._open_member = True
|
|
3466
|
-
# reset member stats
|
|
3467
|
-
self._crc = 0
|
|
3468
|
-
self._ulen = 0
|
|
3469
|
-
|
|
3470
|
-
def write(self, data):
|
|
3471
|
-
if 'r' in self.mode:
|
|
3472
|
-
raise IOError("File not open for writing")
|
|
3473
|
-
|
|
3474
|
-
if self._text_mode:
|
|
3475
|
-
enc = self.encoding or 'UTF-8'
|
|
3476
|
-
errs = self.errors or 'strict'
|
|
3477
|
-
if not isinstance(data, text_type):
|
|
3478
|
-
raise TypeError("write() expects text (unicode/str) in text mode")
|
|
3479
|
-
data = self._normalize_newlines_for_write(data).encode(enc, errs)
|
|
3480
|
-
else:
|
|
3481
|
-
if not isinstance(data, binary_types):
|
|
3482
|
-
raise TypeError("write() expects bytes-like in binary mode")
|
|
3483
|
-
|
|
3484
|
-
# Normalize Py3 memoryview / Py2 bytearray
|
|
3485
|
-
if (not PY2) and isinstance(data, memoryview):
|
|
3486
|
-
data = data.tobytes()
|
|
3487
|
-
elif PY2 and isinstance(data, bytearray):
|
|
3488
|
-
data = bytes(data)
|
|
3489
|
-
|
|
3490
|
-
if not data:
|
|
3491
|
-
return 0
|
|
3492
|
-
|
|
3493
|
-
# Begin member and write header on first write
|
|
3494
|
-
self._ensure_member_header()
|
|
3495
|
-
|
|
3496
|
-
# Update integrity stats
|
|
3497
|
-
self._crc = _crc32u(data, self._crc)
|
|
3498
|
-
self._ulen += len(data)
|
|
3499
|
-
|
|
3500
|
-
# Stream in RAW_CHUNK-sized pieces. Each piece becomes one compressed chunk record.
|
|
3501
|
-
mv = memoryview(data)
|
|
3502
|
-
# clamp level to {1, 9}
|
|
3503
|
-
lvl = 9 if self.level >= 9 else 1
|
|
3504
|
-
for off in range(0, len(data), self.RAW_CHUNK):
|
|
3505
|
-
raw = mv[off:off + self.RAW_CHUNK].tobytes()
|
|
3506
|
-
c = lzo.compress(raw, lvl)
|
|
3507
|
-
self.file.write(struct.pack(">I", len(c)))
|
|
3508
|
-
self.file.write(c)
|
|
3509
|
-
|
|
3510
|
-
return len(data)
|
|
3511
|
-
|
|
3512
|
-
def _flush_member_only(self):
|
|
3513
|
-
"""Finalize the current member: write terminator and backfill header."""
|
|
3514
|
-
if not self._open_member:
|
|
3515
|
-
return
|
|
3516
|
-
# write zero-length chunk terminator
|
|
3517
|
-
self.file.write(struct.pack(">I", 0))
|
|
3518
|
-
if self._write_header:
|
|
3519
|
-
# ULEN is at (_member_header_pos - 12), CRC at (_member_header_pos - 4)
|
|
3520
|
-
ulen_pos = self._member_header_pos - 12
|
|
3521
|
-
crc_pos = self._member_header_pos - 4
|
|
3522
|
-
cur = self.file.tell()
|
|
3523
|
-
# backfill ULEN
|
|
3524
|
-
self.file.seek(ulen_pos, os.SEEK_SET)
|
|
3525
|
-
self.file.write(struct.pack(">Q", self._ulen))
|
|
3526
|
-
# backfill CRC32
|
|
3527
|
-
self.file.seek(crc_pos, os.SEEK_SET)
|
|
3528
|
-
self.file.write(struct.pack(">I", self._crc))
|
|
3529
|
-
# restore position
|
|
3530
|
-
self.file.seek(cur, os.SEEK_SET)
|
|
3531
|
-
# reset for potential new member
|
|
3532
|
-
self._open_member = False
|
|
3533
|
-
self._crc = 0
|
|
3534
|
-
self._ulen = 0
|
|
3535
|
-
self._member_header_pos = None
|
|
3536
|
-
|
|
3537
|
-
def flush(self):
|
|
3538
|
-
if self.closed:
|
|
3539
|
-
return
|
|
3540
|
-
# finalize any open member
|
|
3541
|
-
if any(ch in self.mode for ch in ('w', 'a', 'x')) and self._open_member:
|
|
3542
|
-
self._flush_member_only()
|
|
3543
|
-
if hasattr(self.file, 'flush'):
|
|
3544
|
-
self.file.flush()
|
|
3545
|
-
|
|
3546
|
-
def close(self):
|
|
3547
|
-
if self.closed:
|
|
3548
|
-
return
|
|
3549
|
-
try:
|
|
3550
|
-
# Ensure a clean member terminator & header backfill if needed
|
|
3551
|
-
if any(ch in self.mode for ch in ('w', 'a', 'x')) and self._open_member:
|
|
3552
|
-
self._flush_member_only()
|
|
3553
|
-
if hasattr(self.file, 'flush'):
|
|
3554
|
-
try:
|
|
3555
|
-
self.file.flush()
|
|
3556
|
-
except Exception:
|
|
3557
|
-
pass
|
|
3558
|
-
finally:
|
|
3559
|
-
if self.file_path and self.file is not None:
|
|
3560
|
-
try:
|
|
3561
|
-
self.file.close()
|
|
3562
|
-
except Exception:
|
|
3563
|
-
pass
|
|
3564
|
-
# tear down read handles
|
|
3565
|
-
try:
|
|
3566
|
-
if self._text_reader is not None:
|
|
3567
|
-
self._text_reader.detach()
|
|
3568
|
-
except Exception:
|
|
3569
|
-
pass
|
|
3570
|
-
try:
|
|
3571
|
-
if self._spool is not None:
|
|
3572
|
-
self._spool.close()
|
|
3573
|
-
except Exception:
|
|
3574
|
-
pass
|
|
3575
|
-
self.closed = True
|
|
3576
|
-
|
|
3577
|
-
# ---------- Read path (spooled, multi-member, tolerant scan) ----------
|
|
3578
|
-
def _load_all_members_spooled(self):
|
|
3579
|
-
# Seek to start if possible
|
|
3580
|
-
try:
|
|
3581
|
-
self.file.seek(0)
|
|
3582
|
-
except Exception:
|
|
3583
|
-
pass
|
|
3584
|
-
|
|
3585
|
-
self._spool = tempfile.SpooledTemporaryFile(max_size=self.spool_threshold)
|
|
3586
|
-
|
|
3587
|
-
def read_exact(n, abs_off_ref):
|
|
3588
|
-
"""Read exactly n bytes, updating abs_off_ref[0]."""
|
|
3589
|
-
b = b""
|
|
3590
|
-
while len(b) < n:
|
|
3591
|
-
part = self.file.read(n - len(b))
|
|
3592
|
-
if not part:
|
|
3593
|
-
break
|
|
3594
|
-
b += part
|
|
3595
|
-
abs_off_ref[0] += len(part)
|
|
3596
|
-
return b
|
|
3597
|
-
|
|
3598
|
-
CHUNK = 1 << 20
|
|
3599
|
-
abs_off = [0] # track absolute file offset
|
|
3600
|
-
scanned = 0
|
|
3601
|
-
|
|
3602
|
-
while True:
|
|
3603
|
-
# Locate MAGIC (support tolerant scan across chunk boundaries)
|
|
3604
|
-
head = read_exact(len(self.MAGIC), abs_off)
|
|
3605
|
-
if not head:
|
|
3606
|
-
break # EOF
|
|
3607
|
-
if head != self.MAGIC:
|
|
3608
|
-
# Tolerant scan: slide-by-one until found or limit exceeded
|
|
3609
|
-
buf = head
|
|
3610
|
-
while True:
|
|
3611
|
-
if self.tolerant_read and scanned < self.scan_bytes:
|
|
3612
|
-
nxt = read_exact(1, abs_off)
|
|
3613
|
-
if not nxt:
|
|
3614
|
-
# EOF without finding magic
|
|
3615
|
-
raise ValueError("Invalid LZO container: magic not found before EOF")
|
|
3616
|
-
buf = buf[1:] + nxt
|
|
3617
|
-
scanned += 1
|
|
3618
|
-
if buf == self.MAGIC:
|
|
3619
|
-
break
|
|
3620
|
-
continue
|
|
3621
|
-
raise ValueError("Invalid LZO container magic near offset {}".format(abs_off[0] - len(buf)))
|
|
3622
|
-
# found MAGIC; proceed
|
|
3623
|
-
|
|
3624
|
-
# FLAGS
|
|
3625
|
-
f_b = read_exact(1, abs_off)
|
|
3626
|
-
if len(f_b) != 1:
|
|
3627
|
-
raise ValueError("Truncated header (flags) at offset {}".format(abs_off[0]))
|
|
3628
|
-
flags = ord(f_b) if PY2 else f_b[0]
|
|
3629
|
-
|
|
3630
|
-
# Optional ULEN/CRC
|
|
3631
|
-
ulen = None
|
|
3632
|
-
expect_crc = None
|
|
3633
|
-
if flags & self.FLAG_HAS_UHDR:
|
|
3634
|
-
ulen_b = read_exact(8, abs_off)
|
|
3635
|
-
crc_b = read_exact(4, abs_off)
|
|
3636
|
-
if len(ulen_b) != 8 or len(crc_b) != 4:
|
|
3637
|
-
raise ValueError("Truncated ULEN/CRC header at offset {}".format(abs_off[0]))
|
|
3638
|
-
ulen = struct.unpack(">Q", ulen_b)[0]
|
|
3639
|
-
expect_crc = struct.unpack(">I", crc_b)[0]
|
|
3640
|
-
|
|
3641
|
-
# Chunk loop
|
|
3642
|
-
m_crc = 0
|
|
3643
|
-
m_len = 0
|
|
3644
|
-
while True:
|
|
3645
|
-
sz_b = read_exact(4, abs_off)
|
|
3646
|
-
if len(sz_b) != 4:
|
|
3647
|
-
raise ValueError("Truncated chunk size at offset {}".format(abs_off[0]))
|
|
3648
|
-
csz = struct.unpack(">I", sz_b)[0]
|
|
3649
|
-
if csz == 0:
|
|
3650
|
-
break # end of member
|
|
3651
|
-
cdata = read_exact(csz, abs_off)
|
|
3652
|
-
if len(cdata) != csz:
|
|
3653
|
-
raise ValueError("Truncated chunk payload at offset {}".format(abs_off[0]))
|
|
3654
|
-
try:
|
|
3655
|
-
raw = lzo.decompress(cdata)
|
|
3656
|
-
except Exception as e:
|
|
3657
|
-
raise ValueError("LZO decompression error at offset {}: {}".format(abs_off[0], e))
|
|
3658
|
-
self._spool.write(raw)
|
|
3659
|
-
m_len += len(raw)
|
|
3660
|
-
m_crc = _crc32u(raw, m_crc)
|
|
3661
|
-
|
|
3662
|
-
# Validate member integrity if header present
|
|
3663
|
-
if ulen is not None and m_len != ulen:
|
|
3664
|
-
raise ValueError("Member length mismatch ({} != {})".format(m_len, ulen))
|
|
3665
|
-
if expect_crc is not None and m_crc != expect_crc:
|
|
3666
|
-
raise ValueError("Member CRC32 mismatch (got 0x{:08x}, want 0x{:08x})"
|
|
3667
|
-
.format(m_crc, expect_crc))
|
|
3668
|
-
|
|
3669
|
-
# Prepare read handles
|
|
3670
|
-
try:
|
|
3671
|
-
self._spool.seek(0)
|
|
3672
|
-
except Exception:
|
|
3673
|
-
pass
|
|
3674
|
-
|
|
3675
|
-
if self._text_mode:
|
|
3676
|
-
enc = self.encoding or 'UTF-8'
|
|
3677
|
-
errs = self.errors or 'strict'
|
|
3678
|
-
# newline=None => universal newline translation; exact string if provided
|
|
3679
|
-
self._text_reader = io.TextIOWrapper(self._spool, encoding=enc, errors=errs, newline=self.newline)
|
|
3680
|
-
try:
|
|
3681
|
-
self._text_reader.seek(0)
|
|
3682
|
-
except Exception:
|
|
3683
|
-
pass
|
|
3684
|
-
|
|
3685
|
-
self._position = 0
|
|
3686
|
-
|
|
3687
|
-
# ---------- Buffered read API (delegates to spool/text wrapper) ----------
|
|
3688
|
-
def read(self, size=-1):
|
|
3689
|
-
if self.closed:
|
|
3690
|
-
raise ValueError("I/O operation on closed file")
|
|
3691
|
-
if 'r' not in self.mode:
|
|
3692
|
-
raise IOError("File not open for reading")
|
|
3693
|
-
r = self._reader()
|
|
3694
|
-
if r is None:
|
|
3695
|
-
raise IOError("Reader not initialized")
|
|
3696
|
-
out = r.read() if (size is None or size < 0) else r.read(int(size))
|
|
3697
|
-
try:
|
|
3698
|
-
self._position = r.tell()
|
|
3699
|
-
except Exception:
|
|
3700
|
-
pass
|
|
3701
|
-
return out
|
|
3702
|
-
|
|
3703
|
-
def readline(self, size=-1):
|
|
3704
|
-
if self.closed:
|
|
3705
|
-
raise ValueError("I/O operation on closed file")
|
|
3706
|
-
if 'r' not in self.mode:
|
|
3707
|
-
raise IOError("File not open for reading")
|
|
3708
|
-
r = self._reader()
|
|
3709
|
-
if r is None:
|
|
3710
|
-
raise IOError("Reader not initialized")
|
|
3711
|
-
out = r.readline() if (size is None or size < 0) else r.readline(int(size))
|
|
3712
|
-
try:
|
|
3713
|
-
self._position = r.tell()
|
|
3714
|
-
except Exception:
|
|
3715
|
-
pass
|
|
3716
|
-
if not self._text_mode and out is None:
|
|
3717
|
-
return b""
|
|
3718
|
-
if self._text_mode and out is None:
|
|
3719
|
-
return text_type("")
|
|
3720
|
-
return out
|
|
3721
|
-
|
|
3722
|
-
def __iter__(self):
|
|
3723
|
-
return self
|
|
3724
|
-
|
|
3725
|
-
def __next__(self):
|
|
3726
|
-
line = self.readline()
|
|
3727
|
-
if (self._text_mode and line == "") or (not self._text_mode and line == b""):
|
|
3728
|
-
raise StopIteration
|
|
3729
|
-
return line
|
|
3730
|
-
|
|
3731
|
-
if PY2:
|
|
3732
|
-
next = __next__
|
|
3733
|
-
|
|
3734
|
-
def seek(self, offset, whence=0):
|
|
3735
|
-
if self.closed:
|
|
3736
|
-
raise ValueError("I/O operation on closed file")
|
|
3737
|
-
if 'r' not in self.mode:
|
|
3738
|
-
raise IOError("File not open for reading")
|
|
3739
|
-
r = self._reader()
|
|
3740
|
-
if r is None:
|
|
3741
|
-
raise IOError("Reader not initialized")
|
|
3742
|
-
newpos = r.seek(int(offset), int(whence))
|
|
3743
|
-
self._position = newpos
|
|
3744
|
-
return newpos
|
|
3745
|
-
|
|
3746
|
-
def tell(self):
|
|
3747
|
-
if self._reader() is not None:
|
|
3748
|
-
try:
|
|
3749
|
-
self._position = self._reader().tell()
|
|
3750
|
-
except Exception:
|
|
3751
|
-
pass
|
|
3752
|
-
return self._position
|
|
3753
|
-
|
|
3754
|
-
# ---------- Misc ----------
|
|
3755
|
-
def fileno(self):
|
|
3756
|
-
if hasattr(self.file, 'fileno'):
|
|
3757
|
-
return self.file.fileno()
|
|
3758
|
-
raise OSError("Underlying file object does not support fileno()")
|
|
3759
|
-
|
|
3760
|
-
def isatty(self):
|
|
3761
|
-
return bool(getattr(self.file, 'isatty', lambda: False)())
|
|
3762
|
-
|
|
3763
|
-
def truncate(self, size=None):
|
|
3764
|
-
# Prevent corruption of compressed streams
|
|
3765
|
-
raise OSError("truncate() is not supported for compressed streams")
|
|
3766
|
-
|
|
3767
|
-
# ---------- Convenience constructors ----------
|
|
3768
|
-
@classmethod
|
|
3769
|
-
def open(cls, path, mode='rb', **kw):
|
|
3770
|
-
"""
|
|
3771
|
-
Mirror built-in open() but for LzopFile.
|
|
3772
|
-
Example:
|
|
3773
|
-
with LzopFile.open("data.lzo", "rt", encoding="utf-8") as f:
|
|
3774
|
-
print(f.readline())
|
|
3775
|
-
"""
|
|
3776
|
-
return cls(file_path=path, mode=mode, **kw)
|
|
3777
|
-
|
|
3778
|
-
@classmethod
|
|
3779
|
-
def from_fileobj(cls, fileobj, mode='rb', **kw):
|
|
3780
|
-
"""
|
|
3781
|
-
Wrap an existing file-like object (caller retains ownership).
|
|
3782
|
-
"""
|
|
3783
|
-
return cls(fileobj=fileobj, mode=mode, **kw)
|
|
3784
|
-
|
|
3785
|
-
@classmethod
|
|
3786
|
-
def from_bytes(cls, data, mode='rb', **kw):
|
|
3787
|
-
"""
|
|
3788
|
-
Read from an in-memory bytes buffer.
|
|
3789
|
-
Example:
|
|
3790
|
-
f = LzopFile.from_bytes(blob, mode='rt', encoding='utf-8', tolerant_read=True)
|
|
3791
|
-
text = f.read()
|
|
3792
|
-
"""
|
|
3793
|
-
if not isinstance(data, (bytes, bytearray, memoryview)):
|
|
3794
|
-
raise TypeError("from_bytes() expects a bytes-like object")
|
|
3795
|
-
bio = io.BytesIO(bytes(data) if not isinstance(data, bytes) else data)
|
|
3796
|
-
return cls(fileobj=bio, mode=mode, **kw)
|
|
3797
|
-
|
|
3798
|
-
# compatibility aliases for unwrapping utilities
|
|
3799
|
-
@property
|
|
3800
|
-
def fileobj(self):
|
|
3801
|
-
return self.file
|
|
3802
|
-
|
|
3803
|
-
@property
|
|
3804
|
-
def myfileobj(self):
|
|
3805
|
-
return self.file
|
|
3806
|
-
|
|
3807
|
-
# ---------- Top-level helpers ----------
|
|
3808
|
-
def lzop_compress_bytes(payload, level=9, text=False, **kw):
|
|
3809
|
-
"""
|
|
3810
|
-
Compress 'payload' into a single LZO member (our custom container) and return bytes.
|
|
3811
|
-
- text=True: 'payload' is text; encoding/newline/errors handled via LzopFile('wt')
|
|
3812
|
-
- text=False: 'payload' is bytes-like; written via LzopFile('wb')
|
|
3813
|
-
Kwargs forwarded: write_header (default True), newline/encoding/errors, etc.
|
|
3814
|
-
"""
|
|
3815
|
-
bio = io.BytesIO()
|
|
3816
|
-
mode = 'wt' if text else 'wb'
|
|
3817
|
-
f = LzopFile(fileobj=bio, mode=mode, level=level, **kw)
|
|
3818
|
-
try:
|
|
3819
|
-
f.write(payload)
|
|
3820
|
-
f.flush() # finalize member (writes terminator + backfills header)
|
|
3821
|
-
finally:
|
|
3822
|
-
f.close()
|
|
3823
|
-
return bio.getvalue()
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
def lzop_decompress_bytes(blob, mode='rb', tolerant_read=False, scan_bytes=(64 << 10),
|
|
3827
|
-
spool_threshold=(8 << 20), **kw):
|
|
3828
|
-
"""
|
|
3829
|
-
Decompress bytes produced by this custom container.
|
|
3830
|
-
- mode='rb' -> returns bytes; mode='rt' -> returns text (set encoding/errors/newline in kw)
|
|
3831
|
-
- tolerant_read/scan_bytes/spool_threshold forwarded to LzopFile
|
|
3832
|
-
"""
|
|
3833
|
-
if not isinstance(blob, (bytes, bytearray, memoryview)):
|
|
3834
|
-
raise TypeError("lzop_decompress_bytes() expects a bytes-like object")
|
|
3835
|
-
f = LzopFile.from_bytes(blob, mode=mode, tolerant_read=tolerant_read,
|
|
3836
|
-
scan_bytes=scan_bytes, spool_threshold=spool_threshold, **kw)
|
|
3837
|
-
try:
|
|
3838
|
-
return f.read()
|
|
3839
|
-
finally:
|
|
3840
|
-
f.close()
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
3417
|
def TarFileCheck(infile):
|
|
3844
3418
|
try:
|
|
3845
3419
|
if is_tarfile(infile):
|
|
@@ -4322,6 +3896,49 @@ _CRC_SPECS = {
|
|
|
4322
3896
|
"crc64_iso": CRCSpec(64, 0x000000000000001B, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, True, True),
|
|
4323
3897
|
}
|
|
4324
3898
|
|
|
3899
|
+
# --- helpers --------------------------------------------------------------
|
|
3900
|
+
|
|
3901
|
+
try:
|
|
3902
|
+
# Python 2 may not have algorithms_available
|
|
3903
|
+
_ALGORITHMS_AVAILABLE = set(hashlib.algorithms_available)
|
|
3904
|
+
except AttributeError:
|
|
3905
|
+
_ALGORITHMS_AVAILABLE = set(getattr(hashlib, "algorithms", []))
|
|
3906
|
+
|
|
3907
|
+
|
|
3908
|
+
def _coerce_bytes(data):
|
|
3909
|
+
"""Return `data` as a bytes object (Py2 / Py3)."""
|
|
3910
|
+
if isinstance(data, memoryview):
|
|
3911
|
+
# Py3 has .tobytes(), Py2 falls back to bytes()
|
|
3912
|
+
try:
|
|
3913
|
+
return data.tobytes()
|
|
3914
|
+
except AttributeError:
|
|
3915
|
+
return bytes(data)
|
|
3916
|
+
|
|
3917
|
+
if isinstance(data, bytearray):
|
|
3918
|
+
return bytes(data)
|
|
3919
|
+
|
|
3920
|
+
if not isinstance(data, bytes):
|
|
3921
|
+
# E.g. list of ints, unicode, etc.
|
|
3922
|
+
return bytes(bytearray(data))
|
|
3923
|
+
|
|
3924
|
+
return data
|
|
3925
|
+
|
|
3926
|
+
|
|
3927
|
+
def _bytes_to_int(b):
|
|
3928
|
+
"""Big-endian bytes -> int, Py2/3 safe."""
|
|
3929
|
+
if not isinstance(b, (bytes, bytearray)):
|
|
3930
|
+
b = _coerce_bytes(b)
|
|
3931
|
+
|
|
3932
|
+
value = 0
|
|
3933
|
+
for ch in b:
|
|
3934
|
+
if not isinstance(ch, int): # Py2: ch is a 1-char string
|
|
3935
|
+
ch = ord(ch)
|
|
3936
|
+
value = (value << 8) | ch
|
|
3937
|
+
return value
|
|
3938
|
+
|
|
3939
|
+
|
|
3940
|
+
# --- your existing CRCContext (unchanged) ---------------------------------
|
|
3941
|
+
|
|
4325
3942
|
class CRCContext(object):
|
|
4326
3943
|
__slots__ = ("spec", "table", "mask", "shift", "crc")
|
|
4327
3944
|
|
|
@@ -4335,10 +3952,11 @@ class CRCContext(object):
|
|
|
4335
3952
|
def update(self, data):
|
|
4336
3953
|
if not isinstance(data, (bytes, bytearray, memoryview)):
|
|
4337
3954
|
data = bytes(bytearray(data))
|
|
3955
|
+
buf = _mv_tobytes(memoryview(data))
|
|
4338
3956
|
if self.spec.refin:
|
|
4339
3957
|
c = self.crc
|
|
4340
3958
|
tbl = self.table
|
|
4341
|
-
for b in
|
|
3959
|
+
for b in buf:
|
|
4342
3960
|
if not isinstance(b, int): # Py2
|
|
4343
3961
|
b = ord(b)
|
|
4344
3962
|
c = tbl[(c ^ b) & 0xFF] ^ (c >> 8)
|
|
@@ -4348,7 +3966,7 @@ class CRCContext(object):
|
|
|
4348
3966
|
tbl = self.table
|
|
4349
3967
|
sh = self.shift
|
|
4350
3968
|
msk = self.mask
|
|
4351
|
-
for b in
|
|
3969
|
+
for b in buf:
|
|
4352
3970
|
if not isinstance(b, int):
|
|
4353
3971
|
b = ord(b)
|
|
4354
3972
|
c = tbl[((c >> sh) ^ b) & 0xFF] ^ ((c << 8) & msk)
|
|
@@ -4365,6 +3983,82 @@ class CRCContext(object):
|
|
|
4365
3983
|
width_hex = (self.spec.width + 3) // 4
|
|
4366
3984
|
return format(self.digest_int(), "0{}x".format(width_hex)).lower()
|
|
4367
3985
|
|
|
3986
|
+
|
|
3987
|
+
# --- hashlib-backed implementation ---------------------------------------
|
|
3988
|
+
|
|
3989
|
+
class _HashlibCRCWrapper(object):
|
|
3990
|
+
"""
|
|
3991
|
+
Wrap a hashlib object to present the same interface as CRCContext
|
|
3992
|
+
(update, digest_int, hexdigest).
|
|
3993
|
+
|
|
3994
|
+
Assumes the hashlib algorithm already implements the exact CRC
|
|
3995
|
+
specification (refin/refout/xorout/etc.).
|
|
3996
|
+
"""
|
|
3997
|
+
__slots__ = ("_h", "spec", "mask", "width_hex")
|
|
3998
|
+
|
|
3999
|
+
def __init__(self, algo_name, spec):
|
|
4000
|
+
self._h = hashlib.new(algo_name)
|
|
4001
|
+
self.spec = spec
|
|
4002
|
+
self.mask = (1 << spec.width) - 1
|
|
4003
|
+
self.width_hex = (spec.width + 3) // 4
|
|
4004
|
+
|
|
4005
|
+
def update(self, data):
|
|
4006
|
+
self._h.update(_coerce_bytes(data))
|
|
4007
|
+
return self
|
|
4008
|
+
|
|
4009
|
+
def digest_int(self):
|
|
4010
|
+
# Convert final digest bytes to an integer and mask to width
|
|
4011
|
+
value = _bytes_to_int(self._h.digest())
|
|
4012
|
+
return value & self.mask
|
|
4013
|
+
|
|
4014
|
+
def hexdigest(self):
|
|
4015
|
+
h = self._h.hexdigest().lower()
|
|
4016
|
+
# Normalize to the same number of hex digits as CRCContext
|
|
4017
|
+
if len(h) < self.width_hex:
|
|
4018
|
+
h = ("0" * (self.width_hex - len(h))) + h
|
|
4019
|
+
elif len(h) > self.width_hex:
|
|
4020
|
+
h = h[-self.width_hex:]
|
|
4021
|
+
return h
|
|
4022
|
+
|
|
4023
|
+
|
|
4024
|
+
# --- public class: choose hashlib or fallback -----------------------------
|
|
4025
|
+
|
|
4026
|
+
class CRC(object):
|
|
4027
|
+
"""
|
|
4028
|
+
CRC wrapper that uses hashlib if available, otherwise falls back to
|
|
4029
|
+
the pure-Python CRCContext.
|
|
4030
|
+
|
|
4031
|
+
spec.hashlib_name (preferred) or spec.name is used as the hashlib
|
|
4032
|
+
algorithm name, e.g. 'crc32', 'crc32c', etc.
|
|
4033
|
+
"""
|
|
4034
|
+
|
|
4035
|
+
__slots__ = ("spec", "_impl")
|
|
4036
|
+
|
|
4037
|
+
def __init__(self, spec):
|
|
4038
|
+
self.spec = spec
|
|
4039
|
+
|
|
4040
|
+
algo_name = getattr(spec, "hashlib_name", None) or getattr(spec, "name", None)
|
|
4041
|
+
impl = None
|
|
4042
|
+
|
|
4043
|
+
if algo_name and algo_name in _ALGORITHMS_AVAILABLE:
|
|
4044
|
+
# Use hashlib-backed implementation
|
|
4045
|
+
impl = _HashlibCRCWrapper(algo_name, spec)
|
|
4046
|
+
else:
|
|
4047
|
+
# Fallback to your pure-Python implementation
|
|
4048
|
+
impl = CRCContext(spec)
|
|
4049
|
+
|
|
4050
|
+
self._impl = impl
|
|
4051
|
+
|
|
4052
|
+
def update(self, data):
|
|
4053
|
+
self._impl.update(data)
|
|
4054
|
+
return self
|
|
4055
|
+
|
|
4056
|
+
def digest_int(self):
|
|
4057
|
+
return self._impl.digest_int()
|
|
4058
|
+
|
|
4059
|
+
def hexdigest(self):
|
|
4060
|
+
return self._impl.hexdigest()
|
|
4061
|
+
|
|
4368
4062
|
def crc_context_from_name(name_norm):
|
|
4369
4063
|
spec = _CRC_SPECS.get(name_norm)
|
|
4370
4064
|
if spec is None:
|
|
@@ -5212,7 +4906,7 @@ def ReadFileHeaderDataWithContentToArray(fp, listonly=False, contentasfile=True,
|
|
|
5212
4906
|
pyhascontents = False
|
|
5213
4907
|
fcontents.seek(0, 0)
|
|
5214
4908
|
newfccs = GetFileChecksum(
|
|
5215
|
-
|
|
4909
|
+
version = "0.24.6" HeaderOut[-3].lower(), False, formatspecs)
|
|
5216
4910
|
fcontents.seek(0, 0)
|
|
5217
4911
|
if(fccs != newfccs and not skipchecksum and not listonly):
|
|
5218
4912
|
VerbosePrintOut("File Content Checksum Error with file " +
|
|
@@ -7091,9 +6785,9 @@ def AppendFilesWithContentFromZipFile(infile, fp, extradata=[], jsondata={}, com
|
|
|
7091
6785
|
if(verbose):
|
|
7092
6786
|
VerbosePrintOut(fname)
|
|
7093
6787
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
7094
|
-
fpremode = int(stat.S_IFDIR
|
|
6788
|
+
fpremode = int(stat.S_IFDIR | 0x1ff)
|
|
7095
6789
|
else:
|
|
7096
|
-
fpremode = int(stat.S_IFREG
|
|
6790
|
+
fpremode = int(stat.S_IFREG | 0x1b6)
|
|
7097
6791
|
flinkcount = 0
|
|
7098
6792
|
ftype = 0
|
|
7099
6793
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
@@ -7122,37 +6816,42 @@ def AppendFilesWithContentFromZipFile(infile, fp, extradata=[], jsondata={}, com
|
|
|
7122
6816
|
fbtime = format(
|
|
7123
6817
|
int(time.mktime(member.date_time + (0, 0, -1))), 'x').lower()
|
|
7124
6818
|
if(zipinfo.create_system == 0 or zipinfo.create_system == 10):
|
|
7125
|
-
fwinattributes = format(int(zipinfo.external_attr), 'x').lower()
|
|
6819
|
+
fwinattributes = format(int(zipinfo.external_attr & 0xFFFF), 'x').lower()
|
|
7126
6820
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
7127
|
-
fmode = format(int(stat.S_IFDIR
|
|
7128
|
-
fchmode = stat.S_IMODE(int(stat.S_IFDIR
|
|
7129
|
-
ftypemod = stat.S_IFMT(int(stat.S_IFDIR
|
|
6821
|
+
fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
|
|
6822
|
+
fchmode = stat.S_IMODE(int(stat.S_IFDIR | 0x1ff))
|
|
6823
|
+
ftypemod = stat.S_IFMT(int(stat.S_IFDIR | 0x1ff))
|
|
7130
6824
|
else:
|
|
7131
|
-
fmode = format(int(stat.S_IFREG
|
|
7132
|
-
fchmode = stat.S_IMODE(int(stat.S_IFREG
|
|
7133
|
-
ftypemod = stat.S_IFMT(int(stat.S_IFREG
|
|
6825
|
+
fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
|
|
6826
|
+
fchmode = stat.S_IMODE(int(stat.S_IFREG | 0x1b6))
|
|
6827
|
+
ftypemod = stat.S_IFMT(int(stat.S_IFREG | 0x1b6))
|
|
7134
6828
|
elif(zipinfo.create_system == 3):
|
|
7135
|
-
fwinattributes = format(int(
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
6829
|
+
fwinattributes = format(int(zipinfo.external_attr & 0xFFFF), 'x').lower()
|
|
6830
|
+
fmode = format(int((zipinfo.external_attr >> 16) & 0xFFFF), 'x').lower()
|
|
6831
|
+
prefmode = int((zipinfo.external_attr >> 16) & 0xFFFF)
|
|
6832
|
+
if (prefmode == 0):
|
|
6833
|
+
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
6834
|
+
fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
|
|
6835
|
+
prefmode = int(stat.S_IFDIR | 0x1ff)
|
|
6836
|
+
fchmode = stat.S_IMODE(prefmode)
|
|
6837
|
+
ftypemod = stat.S_IFMT(prefmode)
|
|
6838
|
+
else:
|
|
6839
|
+
fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
|
|
6840
|
+
prefmode = int(stat.S_IFREG | 0x1b6)
|
|
6841
|
+
fchmode = stat.S_IMODE(prefmode)
|
|
6842
|
+
ftypemod = stat.S_IFMT(prefmode)
|
|
6843
|
+
fchmode = stat.S_IMODE(prefmode)
|
|
6844
|
+
ftypemod = stat.S_IFMT(prefmode)
|
|
6845
|
+
else:
|
|
6846
|
+
fwinattributes = format(int(zipinfo.external_attr & 0xFFFF), 'x').lower()
|
|
7148
6847
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
7149
|
-
fmode = format(int(stat.S_IFDIR
|
|
7150
|
-
prefmode = int(stat.S_IFDIR
|
|
6848
|
+
fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
|
|
6849
|
+
prefmode = int(stat.S_IFDIR | 0x1ff)
|
|
7151
6850
|
fchmode = stat.S_IMODE(prefmode)
|
|
7152
6851
|
ftypemod = stat.S_IFMT(prefmode)
|
|
7153
6852
|
else:
|
|
7154
|
-
fmode = format(int(stat.S_IFREG
|
|
7155
|
-
prefmode = int(stat.S_IFREG
|
|
6853
|
+
fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
|
|
6854
|
+
prefmode = int(stat.S_IFREG | 0x1b6)
|
|
7156
6855
|
fchmode = stat.S_IMODE(prefmode)
|
|
7157
6856
|
ftypemod = stat.S_IFMT(prefmode)
|
|
7158
6857
|
fcompression = ""
|
|
@@ -7334,11 +7033,11 @@ if(rarfile_support):
|
|
|
7334
7033
|
if(is_unix and member.external_attr != 0):
|
|
7335
7034
|
fpremode = int(member.external_attr)
|
|
7336
7035
|
elif(member.is_file()):
|
|
7337
|
-
fpremode = int(stat.S_IFREG
|
|
7036
|
+
fpremode = int(stat.S_IFREG | 0x1b6)
|
|
7338
7037
|
elif(member.is_symlink()):
|
|
7339
|
-
fpremode = int(stat.S_IFLNK
|
|
7038
|
+
fpremode = int(stat.S_IFLNK | 0x1b6)
|
|
7340
7039
|
elif(member.is_dir()):
|
|
7341
|
-
fpremode = int(stat.S_IFDIR
|
|
7040
|
+
fpremode = int(stat.S_IFDIR | 0x1ff)
|
|
7342
7041
|
if(is_windows and member.external_attr != 0):
|
|
7343
7042
|
fwinattributes = format(int(member.external_attr), 'x').lower()
|
|
7344
7043
|
else:
|
|
@@ -7391,23 +7090,23 @@ if(rarfile_support):
|
|
|
7391
7090
|
ftypemod = format(
|
|
7392
7091
|
int(stat.S_IFMT(member.external_attr)), 'x').lower()
|
|
7393
7092
|
elif(member.is_file()):
|
|
7394
|
-
fmode = format(int(stat.S_IFREG
|
|
7093
|
+
fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
|
|
7395
7094
|
fchmode = format(
|
|
7396
|
-
int(stat.S_IMODE(int(stat.S_IFREG
|
|
7095
|
+
int(stat.S_IMODE(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7397
7096
|
ftypemod = format(
|
|
7398
|
-
int(stat.S_IFMT(int(stat.S_IFREG
|
|
7097
|
+
int(stat.S_IFMT(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7399
7098
|
elif(member.is_symlink()):
|
|
7400
|
-
fmode = format(int(stat.S_IFLNK
|
|
7099
|
+
fmode = format(int(stat.S_IFLNK | 0x1b6), 'x').lower()
|
|
7401
7100
|
fchmode = format(
|
|
7402
|
-
int(stat.S_IMODE(int(stat.S_IFREG
|
|
7101
|
+
int(stat.S_IMODE(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7403
7102
|
ftypemod = format(
|
|
7404
|
-
int(stat.S_IFMT(int(stat.S_IFREG
|
|
7103
|
+
int(stat.S_IFMT(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7405
7104
|
elif(member.is_dir()):
|
|
7406
|
-
fmode = format(int(stat.S_IFDIR
|
|
7105
|
+
fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
|
|
7407
7106
|
fchmode = format(
|
|
7408
|
-
int(stat.S_IMODE(int(stat.S_IFDIR
|
|
7107
|
+
int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff))), 'x').lower()
|
|
7409
7108
|
ftypemod = format(
|
|
7410
|
-
int(stat.S_IFMT(int(stat.S_IFDIR
|
|
7109
|
+
int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff))), 'x').lower()
|
|
7411
7110
|
try:
|
|
7412
7111
|
fuid = format(int(os.getuid()), 'x').lower()
|
|
7413
7112
|
except AttributeError:
|
|
@@ -7511,11 +7210,11 @@ if(rarfile_support):
|
|
|
7511
7210
|
return fp
|
|
7512
7211
|
|
|
7513
7212
|
if(not py7zr_support):
|
|
7514
|
-
def
|
|
7213
|
+
def AppendFilesWithContentFromSevenZipFile(infile, fp, extradata=[], jsondata={}, compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_dict__, verbose=False):
|
|
7515
7214
|
return False
|
|
7516
7215
|
|
|
7517
7216
|
if(py7zr_support):
|
|
7518
|
-
def
|
|
7217
|
+
def AppendFilesWithContentFromSevenZipFile(infile, fp, extradata=[], jsondata={}, compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_dict__, verbose=False):
|
|
7519
7218
|
if(not hasattr(fp, "write")):
|
|
7520
7219
|
return False
|
|
7521
7220
|
if(verbose):
|
|
@@ -7558,9 +7257,9 @@ if(py7zr_support):
|
|
|
7558
7257
|
if(verbose):
|
|
7559
7258
|
VerbosePrintOut(fname)
|
|
7560
7259
|
if(not member.is_directory):
|
|
7561
|
-
fpremode = int(stat.S_IFREG
|
|
7260
|
+
fpremode = int(stat.S_IFREG | 0x1b6)
|
|
7562
7261
|
elif(member.is_directory):
|
|
7563
|
-
fpremode = int(stat.S_IFDIR
|
|
7262
|
+
fpremode = int(stat.S_IFDIR | 0x1ff)
|
|
7564
7263
|
fwinattributes = format(int(0), 'x').lower()
|
|
7565
7264
|
fcompression = ""
|
|
7566
7265
|
fcsize = format(int(0), 'x').lower()
|
|
@@ -7584,17 +7283,17 @@ if(py7zr_support):
|
|
|
7584
7283
|
fctime = format(int(member.creationtime.timestamp()), 'x').lower()
|
|
7585
7284
|
fbtime = format(int(member.creationtime.timestamp()), 'x').lower()
|
|
7586
7285
|
if(member.is_directory):
|
|
7587
|
-
fmode = format(int(stat.S_IFDIR
|
|
7286
|
+
fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
|
|
7588
7287
|
fchmode = format(
|
|
7589
|
-
int(stat.S_IMODE(int(stat.S_IFDIR
|
|
7288
|
+
int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff))), 'x').lower()
|
|
7590
7289
|
ftypemod = format(
|
|
7591
|
-
int(stat.S_IFMT(int(stat.S_IFDIR
|
|
7290
|
+
int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff))), 'x').lower()
|
|
7592
7291
|
else:
|
|
7593
|
-
fmode = format(int(stat.S_IFREG
|
|
7292
|
+
fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
|
|
7594
7293
|
fchmode = format(
|
|
7595
|
-
int(stat.S_IMODE(int(stat.S_IFREG
|
|
7294
|
+
int(stat.S_IMODE(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7596
7295
|
ftypemod = format(
|
|
7597
|
-
int(stat.S_IFMT(int(stat.S_IFREG
|
|
7296
|
+
int(stat.S_IFMT(int(stat.S_IFREG | 0x1b6))), 'x').lower()
|
|
7598
7297
|
try:
|
|
7599
7298
|
fuid = format(int(os.getuid()), 'x').lower()
|
|
7600
7299
|
except AttributeError:
|
|
@@ -8233,11 +7932,11 @@ def AppendFilesWithContentFromRarFileToStackedOutFile(infiles, outfile, fmttype=
|
|
|
8233
7932
|
return returnout
|
|
8234
7933
|
|
|
8235
7934
|
if(not py7zr_support):
|
|
8236
|
-
def
|
|
7935
|
+
def AppendFilesWithContentFromSevenZipFileToOutFile(infiles, outfile, fmttype="auto", compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, extradata=[], jsondata={}, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_multi_dict__, verbose=False, returnfp=False):
|
|
8237
7936
|
return False
|
|
8238
7937
|
|
|
8239
7938
|
if(py7zr_support):
|
|
8240
|
-
def
|
|
7939
|
+
def AppendFilesWithContentFromSevenZipFileToOutFile(infiles, outfile, fmttype="auto", compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, extradata=[], jsondata={}, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_multi_dict__, verbose=False, returnfp=False):
|
|
8241
7940
|
if(IsNestedDict(formatspecs) and fmttype=="auto" and
|
|
8242
7941
|
(outfile != "-" and outfile is not None and not hasattr(outfile, "read") and not hasattr(outfile, "write"))):
|
|
8243
7942
|
get_in_ext = os.path.splitext(outfile)
|
|
@@ -8279,7 +7978,7 @@ if(py7zr_support):
|
|
|
8279
7978
|
fp = CompressOpenFile(outfile, compresswholefile, compressionlevel)
|
|
8280
7979
|
except PermissionError:
|
|
8281
7980
|
return False
|
|
8282
|
-
|
|
7981
|
+
AppendFilesWithContentFromSevenZipFile(infiles, fp, extradata, jsondata, compression,
|
|
8283
7982
|
compresswholefile, compressionlevel, compressionuselist, checksumtype, formatspecs, verbose)
|
|
8284
7983
|
if(outfile == "-" or outfile is None or hasattr(outfile, "read") or hasattr(outfile, "write")):
|
|
8285
7984
|
fp = CompressOpenFileAlt(
|
|
@@ -8317,12 +8016,12 @@ if(py7zr_support):
|
|
|
8317
8016
|
fp.close()
|
|
8318
8017
|
return True
|
|
8319
8018
|
|
|
8320
|
-
def
|
|
8019
|
+
def AppendFilesWithContentFromSevenZipFileToStackedOutFile(infiles, outfile, fmttype="auto", compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, extradata=[], jsondata={}, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_multi_dict__, verbose=False, returnfp=False):
|
|
8321
8020
|
if not isinstance(infiles, list):
|
|
8322
8021
|
infiles = [infiles]
|
|
8323
8022
|
returnout = False
|
|
8324
8023
|
for infileslist in infiles:
|
|
8325
|
-
returnout =
|
|
8024
|
+
returnout = AppendFilesWithContentFromSevenZipFileToOutFile(infileslist, outfile, fmttype, compression, compresswholefile, compressionlevel, compressionuselist, extradata, jsondata, checksumtype, formatspecs, verbose, True)
|
|
8326
8025
|
if(not returnout):
|
|
8327
8026
|
break
|
|
8328
8027
|
else:
|
|
@@ -9026,8 +8725,6 @@ def CheckCompressionSubType(infile, formatspecs=__file_format_multi_dict__, file
|
|
|
9026
8725
|
fp = pyzstd.zstdfile.ZstdFile(infile, mode="rb")
|
|
9027
8726
|
else:
|
|
9028
8727
|
return Flase
|
|
9029
|
-
elif((compresscheck == "lzo" or compresscheck == "lzop") and compresscheck in compressionsupport):
|
|
9030
|
-
fp = LzopFile(infile, mode="rb")
|
|
9031
8728
|
elif((compresscheck == "lzma" or compresscheck == "xz") and compresscheck in compressionsupport):
|
|
9032
8729
|
fp = lzma.open(infile, "rb")
|
|
9033
8730
|
elif(compresscheck == "zlib" and compresscheck in compressionsupport):
|
|
@@ -9150,8 +8847,6 @@ def UncompressFileAlt(fp, formatspecs=__file_format_multi_dict__, filestart=0,
|
|
|
9150
8847
|
return False
|
|
9151
8848
|
elif kind == "lz4" and "lz4" in compressionsupport:
|
|
9152
8849
|
wrapped = lz4.frame.LZ4FrameFile(src, mode="rb")
|
|
9153
|
-
elif kind in ("lzo","lzop") and (("lzo" in compressionsupport) or ("lzop" in compressionsupport)):
|
|
9154
|
-
wrapped = LzopFile(fileobj=src, mode="rb")
|
|
9155
8850
|
elif kind == "zlib" and "zlib" in compressionsupport:
|
|
9156
8851
|
wrapped = ZlibFile(fileobj=src, mode="rb")
|
|
9157
8852
|
else:
|
|
@@ -9223,8 +8918,6 @@ def UncompressFile(infile, formatspecs=__file_format_multi_dict__, mode="rb",
|
|
|
9223
8918
|
return False
|
|
9224
8919
|
elif (compresscheck == "lz4" and "lz4" in compressionsupport):
|
|
9225
8920
|
fp = lz4.frame.open(infile, mode)
|
|
9226
|
-
elif ((compresscheck == "lzo" or compresscheck == "lzop") and "lzop" in compressionsupport):
|
|
9227
|
-
fp = LzopFile(infile, mode=mode)
|
|
9228
8921
|
elif ((compresscheck == "lzma" or compresscheck == "xz") and "xz" in compressionsupport):
|
|
9229
8922
|
fp = lzma.open(infile, mode)
|
|
9230
8923
|
elif (compresscheck == "zlib" and "zlib" in compressionsupport):
|
|
@@ -9792,7 +9485,7 @@ def fast_copy(infp, outfp, bufsize=1 << 20):
|
|
|
9792
9485
|
outfp.write(data)
|
|
9793
9486
|
|
|
9794
9487
|
|
|
9795
|
-
def copy_file_to_mmap_dest(src_path, outfp, chunk_size=
|
|
9488
|
+
def copy_file_to_mmap_dest(src_path, outfp, chunk_size=__spoolfile_size__):
|
|
9796
9489
|
"""
|
|
9797
9490
|
Copy a disk file into an mmap-backed destination (FileLikeAdapter).
|
|
9798
9491
|
Falls back to buffered copy if the source cannot be mmapped.
|
|
@@ -10018,9 +9711,6 @@ def CompressOpenFile(outfile, compressionenable=True, compressionlevel=None,
|
|
|
10018
9711
|
elif (fextname == ".lz4" and "lz4" in compressionsupport):
|
|
10019
9712
|
outfp = FileLikeAdapter(lz4.frame.open(outfile, mode, compression_level=compressionlevel), mode="wb")
|
|
10020
9713
|
|
|
10021
|
-
elif (fextname == ".lzo" and "lzop" in compressionsupport):
|
|
10022
|
-
outfp = FileLikeAdapter(LzopFile(outfile, mode=mode, level=compressionlevel), mode="wb")
|
|
10023
|
-
|
|
10024
9714
|
elif (fextname == ".lzma" and "lzma" in compressionsupport):
|
|
10025
9715
|
try:
|
|
10026
9716
|
outfp = FileLikeAdapter(
|
|
@@ -10142,7 +9832,7 @@ if(not py7zr_support):
|
|
|
10142
9832
|
|
|
10143
9833
|
if(py7zr_support):
|
|
10144
9834
|
def PackCatFileFromSevenZipFile(infile, outfile, fmttype="auto", compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32", "crc32"], extradata=[], jsondata={}, formatspecs=__file_format_dict__, verbose=False, returnfp=False):
|
|
10145
|
-
return
|
|
9835
|
+
return AppendFilesWithContentFromSevenZipFileToOutFile(infile, outfile, fmttype, compression, compresswholefile, compressionlevel, compressionuselist, extradata, jsondata, checksumtype, formatspecs, verbose, returnfp)
|
|
10146
9836
|
|
|
10147
9837
|
|
|
10148
9838
|
def PackCatFileFromInFile(infile, outfile, fmttype="auto", compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32"], extradata=[], jsondata={}, formatspecs=__file_format_dict__, verbose=False, returnfp=False):
|
|
@@ -10250,14 +9940,6 @@ def CatFileValidate(infile, fmttype="auto", filestart=0,
|
|
|
10250
9940
|
checkcompressfile = CheckCompressionSubType(fp, formatspecs, filestart, True)
|
|
10251
9941
|
if(IsNestedDict(formatspecs) and checkcompressfile in formatspecs):
|
|
10252
9942
|
formatspecs = formatspecs[checkcompressfile]
|
|
10253
|
-
if(checkcompressfile == "tarfile" and TarFileCheck(infile)):
|
|
10254
|
-
return TarFileToArray(infile, 0, 0, listonly, contentasfile, skipchecksum, formatspecs, seektoend, returnfp)
|
|
10255
|
-
elif(checkcompressfile == "zipfile" and zipfile.is_zipfile(infile)):
|
|
10256
|
-
return ZipFileToArray(infile, 0, 0, listonly, contentasfile, skipchecksum, formatspecs, seektoend, returnfp)
|
|
10257
|
-
elif(rarfile_support and checkcompressfile == "rarfile" and (rarfile.is_rarfile(infile) or rarfile.is_rarfile_sfx(infile))):
|
|
10258
|
-
return RarFileToArray(infile, 0, 0, listonly, contentasfile, skipchecksum, formatspecs, seektoend, returnfp)
|
|
10259
|
-
elif(py7zr_support and checkcompressfile == "7zipfile" and py7zr.is_7zfile(infile)):
|
|
10260
|
-
return SevenZipFileToArray(infile, 0, 0, listonly, contentasfile, skipchecksum, formatspecs, seektoend, returnfp)
|
|
10261
9943
|
elif(IsSingleDict(formatspecs) and checkcompressfile != formatspecs['format_magic']):
|
|
10262
9944
|
return False
|
|
10263
9945
|
elif(IsNestedDict(formatspecs) and checkcompressfile not in formatspecs):
|
|
@@ -10619,9 +10301,10 @@ def StackedCatFileValidate(infile, fmttype="auto", filestart=0, formatspecs=__fi
|
|
|
10619
10301
|
while True:
|
|
10620
10302
|
if outstartfile >= outfsize: # stop when function signals False
|
|
10621
10303
|
break
|
|
10622
|
-
is_valid_file =
|
|
10304
|
+
is_valid_file = ArchiveFileValidate(infile, fmttype, outstartfile, formatspecs, seektoend, verbose, True)
|
|
10623
10305
|
if is_valid_file is False: # stop when function signals False
|
|
10624
10306
|
outretval.append(is_valid_file)
|
|
10307
|
+
break
|
|
10625
10308
|
else:
|
|
10626
10309
|
outretval.append(True)
|
|
10627
10310
|
infile = is_valid_file
|
|
@@ -11627,35 +11310,6 @@ def MultipleCatFileListFiles(infile, fmttype="auto", filestart=0, seekstart=0, s
|
|
|
11627
11310
|
return outretval
|
|
11628
11311
|
|
|
11629
11312
|
|
|
11630
|
-
def StackedCatFileValidate(infile, fmttype="auto", filestart=0, formatspecs=__file_format_multi_dict__, seektoend=False, verbose=False, returnfp=False):
|
|
11631
|
-
outretval = []
|
|
11632
|
-
outstartfile = filestart
|
|
11633
|
-
outfsize = float('inf')
|
|
11634
|
-
while True:
|
|
11635
|
-
if outstartfile >= outfsize: # stop when function signals False
|
|
11636
|
-
break
|
|
11637
|
-
is_valid_file = CatFileValidate(infile, fmttype, filestart, formatspecs, seektoend, verbose, True)
|
|
11638
|
-
if is_valid_file is False: # stop when function signals False
|
|
11639
|
-
outretval.append(is_valid_file)
|
|
11640
|
-
else:
|
|
11641
|
-
outretval.append(True)
|
|
11642
|
-
infile = is_valid_file
|
|
11643
|
-
outstartfile = infile.tell()
|
|
11644
|
-
try:
|
|
11645
|
-
infile.seek(0, 2)
|
|
11646
|
-
except OSError:
|
|
11647
|
-
SeekToEndOfFile(infile)
|
|
11648
|
-
except ValueError:
|
|
11649
|
-
SeekToEndOfFile(infile)
|
|
11650
|
-
outfsize = infile.tell()
|
|
11651
|
-
infile.seek(outstartfile, 0)
|
|
11652
|
-
if(returnfp):
|
|
11653
|
-
return infile
|
|
11654
|
-
else:
|
|
11655
|
-
infile.close()
|
|
11656
|
-
return outretval
|
|
11657
|
-
|
|
11658
|
-
|
|
11659
11313
|
def StackedCatFileListFiles(infile, fmttype="auto", filestart=0, seekstart=0, seekend=0, skipchecksum=False, formatspecs=__file_format_multi_dict__, seektoend=False, verbose=False, newstyle=False, returnfp=False):
|
|
11660
11314
|
outretval = []
|
|
11661
11315
|
outstartfile = filestart
|
|
@@ -11866,11 +11520,11 @@ def ZipFileListFiles(infile, verbose=False, returnfp=False):
|
|
|
11866
11520
|
if(zipinfo.create_system == 0 or zipinfo.create_system == 10):
|
|
11867
11521
|
fwinattributes = int(zipinfo.external_attr)
|
|
11868
11522
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
11869
|
-
fmode = int(stat.S_IFDIR
|
|
11870
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR
|
|
11871
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR
|
|
11523
|
+
fmode = int(stat.S_IFDIR | 0x1ff)
|
|
11524
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff)))
|
|
11525
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff)))
|
|
11872
11526
|
else:
|
|
11873
|
-
fmode = int(stat.S_IFREG
|
|
11527
|
+
fmode = int(stat.S_IFREG | 0x1b6)
|
|
11874
11528
|
fchmode = int(stat.S_IMODE(fmode))
|
|
11875
11529
|
ftypemod = int(stat.S_IFMT(fmode))
|
|
11876
11530
|
elif(zipinfo.create_system == 3):
|
|
@@ -11886,11 +11540,11 @@ def ZipFileListFiles(infile, verbose=False, returnfp=False):
|
|
|
11886
11540
|
else:
|
|
11887
11541
|
fwinattributes = int(0)
|
|
11888
11542
|
if ((hasattr(member, "is_dir") and member.is_dir()) or member.filename.endswith('/')):
|
|
11889
|
-
fmode = int(stat.S_IFDIR
|
|
11890
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR
|
|
11891
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR
|
|
11543
|
+
fmode = int(stat.S_IFDIR | 0x1ff)
|
|
11544
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff)))
|
|
11545
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff)))
|
|
11892
11546
|
else:
|
|
11893
|
-
fmode = int(stat.S_IFREG
|
|
11547
|
+
fmode = int(stat.S_IFREG | 0x1b6)
|
|
11894
11548
|
fchmode = int(stat.S_IMODE(fmode))
|
|
11895
11549
|
ftypemod = int(stat.S_IFMT(fmode))
|
|
11896
11550
|
returnval.update({lcfi: member.filename})
|
|
@@ -12001,11 +11655,11 @@ if(rarfile_support):
|
|
|
12001
11655
|
if(is_unix and member.external_attr != 0):
|
|
12002
11656
|
fpremode = int(member.external_attr)
|
|
12003
11657
|
elif(member.is_file()):
|
|
12004
|
-
fpremode = int(stat.S_IFREG
|
|
11658
|
+
fpremode = int(stat.S_IFREG | 0x1b6)
|
|
12005
11659
|
elif(member.is_symlink()):
|
|
12006
|
-
fpremode = int(stat.S_IFLNK
|
|
11660
|
+
fpremode = int(stat.S_IFLNK | 0x1b6)
|
|
12007
11661
|
elif(member.is_dir()):
|
|
12008
|
-
fpremode = int(stat.S_IFDIR
|
|
11662
|
+
fpremode = int(stat.S_IFDIR | 0x1ff)
|
|
12009
11663
|
if(is_windows and member.external_attr != 0):
|
|
12010
11664
|
fwinattributes = int(member.external_attr)
|
|
12011
11665
|
else:
|
|
@@ -12015,17 +11669,17 @@ if(rarfile_support):
|
|
|
12015
11669
|
fchmode = int(stat.S_IMODE(member.external_attr))
|
|
12016
11670
|
ftypemod = int(stat.S_IFMT(member.external_attr))
|
|
12017
11671
|
elif(member.is_file()):
|
|
12018
|
-
fmode = int(stat.S_IFREG
|
|
12019
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFREG
|
|
12020
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFREG
|
|
11672
|
+
fmode = int(stat.S_IFREG | 0x1b6)
|
|
11673
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFREG | 0x1b6)))
|
|
11674
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFREG | 0x1b6)))
|
|
12021
11675
|
elif(member.is_symlink()):
|
|
12022
|
-
fmode = int(stat.S_IFLNK
|
|
12023
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFLNK
|
|
12024
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK
|
|
11676
|
+
fmode = int(stat.S_IFLNK | 0x1b6)
|
|
11677
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFLNK | 0x1b6)))
|
|
11678
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK | 0x1b6)))
|
|
12025
11679
|
elif(member.is_dir()):
|
|
12026
|
-
fmode = int(stat.S_IFDIR
|
|
12027
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR
|
|
12028
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR
|
|
11680
|
+
fmode = int(stat.S_IFDIR | 0x1ff)
|
|
11681
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff)))
|
|
11682
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff)))
|
|
12029
11683
|
returnval.update({lcfi: member.filename})
|
|
12030
11684
|
if(not verbose):
|
|
12031
11685
|
VerbosePrintOut(member.filename)
|
|
@@ -12121,18 +11775,18 @@ if(py7zr_support):
|
|
|
12121
11775
|
else:
|
|
12122
11776
|
fname = "./"+member.filename
|
|
12123
11777
|
if(not member.is_directory):
|
|
12124
|
-
fpremode = int(stat.S_IFREG
|
|
11778
|
+
fpremode = int(stat.S_IFREG | 0x1b6)
|
|
12125
11779
|
elif(member.is_directory):
|
|
12126
|
-
fpremode = int(stat.S_IFDIR
|
|
11780
|
+
fpremode = int(stat.S_IFDIR | 0x1ff)
|
|
12127
11781
|
fwinattributes = int(0)
|
|
12128
11782
|
if(member.is_directory):
|
|
12129
|
-
fmode = int(stat.S_IFDIR
|
|
12130
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR
|
|
12131
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR
|
|
11783
|
+
fmode = int(stat.S_IFDIR | 0x1ff)
|
|
11784
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFDIR | 0x1ff)))
|
|
11785
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff)))
|
|
12132
11786
|
else:
|
|
12133
|
-
fmode = int(stat.S_IFLNK
|
|
12134
|
-
fchmode = int(stat.S_IMODE(int(stat.S_IFLNK
|
|
12135
|
-
ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK
|
|
11787
|
+
fmode = int(stat.S_IFLNK | 0x1b6)
|
|
11788
|
+
fchmode = int(stat.S_IMODE(int(stat.S_IFLNK | 0x1b6)))
|
|
11789
|
+
ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK | 0x1b6)))
|
|
12136
11790
|
returnval.update({lcfi: member.filename})
|
|
12137
11791
|
if(not verbose):
|
|
12138
11792
|
VerbosePrintOut(member.filename)
|