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.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: 10/31/2025 Ver. 0.24.2 RC 1 - Author: cooldude2k $
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__ = False
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
- __version_info__ = (0, 24, 2, "RC 1", 1)
634
- __version_date_info__ = (2025, 10, 31, "RC 1", 1)
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: a457db17e60184130c861d8d0790717b035aa222 $"
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=True,
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=False,
1975
- spool_max=8 * 1024 * 1024,
1976
- spool_dir=None):
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=(8 << 20)):
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=(8 << 20)):
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 memoryview(data).tobytes():
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 memoryview(data).tobytes():
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
- fcontents.read(), HeaderOut[-3].lower(), False, formatspecs)
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 + 511)
6788
+ fpremode = int(stat.S_IFDIR | 0x1ff)
7095
6789
  else:
7096
- fpremode = int(stat.S_IFREG + 438)
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 + 511), 'x').lower()
7128
- fchmode = stat.S_IMODE(int(stat.S_IFDIR + 511))
7129
- ftypemod = stat.S_IFMT(int(stat.S_IFDIR + 511))
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 + 438), 'x').lower()
7132
- fchmode = stat.S_IMODE(int(stat.S_IFREG + 438))
7133
- ftypemod = stat.S_IFMT(int(stat.S_IFREG + 438))
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(0), 'x').lower()
7136
- try:
7137
- fmode = format(int(zipinfo.external_attr), 'x').lower()
7138
- prefmode = int(zipinfo.external_attr)
7139
- fchmode = stat.S_IMODE(prefmode)
7140
- ftypemod = stat.S_IFMT(prefmode)
7141
- except OverflowError:
7142
- fmode = format(int(zipinfo.external_attr >> 16), 'x').lower()
7143
- prefmode = int(zipinfo.external_attr >> 16)
7144
- fchmode = stat.S_IMODE(prefmode)
7145
- ftypemod = stat.S_IFMT(prefmode)
7146
- else:
7147
- fwinattributes = format(int(0), 'x').lower()
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 + 511), 'x').lower()
7150
- prefmode = int(stat.S_IFDIR + 511)
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 + 438), 'x').lower()
7155
- prefmode = int(stat.S_IFREG + 438)
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 + 438)
7036
+ fpremode = int(stat.S_IFREG | 0x1b6)
7338
7037
  elif(member.is_symlink()):
7339
- fpremode = int(stat.S_IFLNK + 438)
7038
+ fpremode = int(stat.S_IFLNK | 0x1b6)
7340
7039
  elif(member.is_dir()):
7341
- fpremode = int(stat.S_IFDIR + 511)
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 + 438), 'x').lower()
7093
+ fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
7395
7094
  fchmode = format(
7396
- int(stat.S_IMODE(int(stat.S_IFREG + 438))), 'x').lower()
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 + 438))), 'x').lower()
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 + 438), 'x').lower()
7099
+ fmode = format(int(stat.S_IFLNK | 0x1b6), 'x').lower()
7401
7100
  fchmode = format(
7402
- int(stat.S_IMODE(int(stat.S_IFREG + 438))), 'x').lower()
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 + 438))), 'x').lower()
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 + 511), 'x').lower()
7105
+ fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
7407
7106
  fchmode = format(
7408
- int(stat.S_IMODE(int(stat.S_IFDIR + 511))), 'x').lower()
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 + 511))), 'x').lower()
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 AppendFilesWithContentFromSevenZip(infile, fp, extradata=[], jsondata={}, compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_dict__, verbose=False):
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 AppendFilesWithContentFromSevenZip(infile, fp, extradata=[], jsondata={}, compression="auto", compresswholefile=True, compressionlevel=None, compressionuselist=compressionlistalt, checksumtype=["crc32", "crc32", "crc32", "crc32"], formatspecs=__file_format_dict__, verbose=False):
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 + 438)
7260
+ fpremode = int(stat.S_IFREG | 0x1b6)
7562
7261
  elif(member.is_directory):
7563
- fpremode = int(stat.S_IFDIR + 511)
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 + 511), 'x').lower()
7286
+ fmode = format(int(stat.S_IFDIR | 0x1ff), 'x').lower()
7588
7287
  fchmode = format(
7589
- int(stat.S_IMODE(int(stat.S_IFDIR + 511))), 'x').lower()
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 + 511))), 'x').lower()
7290
+ int(stat.S_IFMT(int(stat.S_IFDIR | 0x1ff))), 'x').lower()
7592
7291
  else:
7593
- fmode = format(int(stat.S_IFREG + 438), 'x').lower()
7292
+ fmode = format(int(stat.S_IFREG | 0x1b6), 'x').lower()
7594
7293
  fchmode = format(
7595
- int(stat.S_IMODE(int(stat.S_IFREG + 438))), 'x').lower()
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 + 438))), 'x').lower()
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 AppendFilesWithContentFromSevenZipToOutFile(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):
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 AppendFilesWithContentFromSevenZipToOutFile(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):
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
- AppendFilesWithContentFromSevenZip(infiles, fp, extradata, jsondata, compression,
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 AppendFilesWithContentFromSevenZipToStackedOutFile(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):
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 = AppendFilesWithContentFromSevenZipToOutFile(infileslist, outfile, fmttype, compression, compresswholefile, compressionlevel, compressionuselist, extradata, jsondata, checksumtype, formatspecs, verbose, True)
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=8 << 20):
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 AppendFilesWithContentFromSevenZipToOutFile(infile, outfile, fmttype, compression, compresswholefile, compressionlevel, compressionuselist, extradata, jsondata, checksumtype, formatspecs, verbose, returnfp)
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 = CatFileValidate(infile, fmttype, filestart, formatspecs, seektoend, verbose, True)
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 + 511)
11870
- fchmode = int(stat.S_IMODE(int(stat.S_IFDIR + 511)))
11871
- ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR + 511)))
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 + 438)
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 + 511)
11890
- fchmode = int(stat.S_IMODE(int(stat.S_IFDIR + 511)))
11891
- ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR + 511)))
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 + 438)
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 + 438)
11658
+ fpremode = int(stat.S_IFREG | 0x1b6)
12005
11659
  elif(member.is_symlink()):
12006
- fpremode = int(stat.S_IFLNK + 438)
11660
+ fpremode = int(stat.S_IFLNK | 0x1b6)
12007
11661
  elif(member.is_dir()):
12008
- fpremode = int(stat.S_IFDIR + 511)
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 + 438)
12019
- fchmode = int(stat.S_IMODE(int(stat.S_IFREG + 438)))
12020
- ftypemod = int(stat.S_IFMT(int(stat.S_IFREG + 438)))
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 + 438)
12023
- fchmode = int(stat.S_IMODE(int(stat.S_IFLNK + 438)))
12024
- ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK + 438)))
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 + 511)
12027
- fchmode = int(stat.S_IMODE(int(stat.S_IFDIR + 511)))
12028
- ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR + 511)))
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 + 438)
11778
+ fpremode = int(stat.S_IFREG | 0x1b6)
12125
11779
  elif(member.is_directory):
12126
- fpremode = int(stat.S_IFDIR + 511)
11780
+ fpremode = int(stat.S_IFDIR | 0x1ff)
12127
11781
  fwinattributes = int(0)
12128
11782
  if(member.is_directory):
12129
- fmode = int(stat.S_IFDIR + 511)
12130
- fchmode = int(stat.S_IMODE(int(stat.S_IFDIR + 511)))
12131
- ftypemod = int(stat.S_IFMT(int(stat.S_IFDIR + 511)))
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 + 438)
12134
- fchmode = int(stat.S_IMODE(int(stat.S_IFLNK + 438)))
12135
- ftypemod = int(stat.S_IFMT(int(stat.S_IFLNK + 438)))
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)