mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
bpo-28080: Add support for the fallback encoding in ZIP files (GH-32007)
* Add the metadata_encoding parameter in the zipfile.ZipFile constructor. * Add the --metadata-encoding option in the zipfile CLI. Co-authored-by: Stephen J. Turnbull <stephen@xemacs.org>
This commit is contained in:
parent
c6cd3cc93c
commit
a25a985535
5 changed files with 211 additions and 11 deletions
|
@ -480,7 +480,7 @@ class ZipInfo (object):
|
|||
|
||||
def _encodeFilenameFlags(self):
|
||||
try:
|
||||
return self.filename.encode('ascii'), self.flag_bits
|
||||
return self.filename.encode('ascii'), self.flag_bits & ~_MASK_UTF_FILENAME
|
||||
except UnicodeEncodeError:
|
||||
return self.filename.encode('utf-8'), self.flag_bits | _MASK_UTF_FILENAME
|
||||
|
||||
|
@ -1240,7 +1240,7 @@ class ZipFile:
|
|||
_windows_illegal_name_trans_table = None
|
||||
|
||||
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
|
||||
compresslevel=None, *, strict_timestamps=True):
|
||||
compresslevel=None, *, strict_timestamps=True, metadata_encoding=None):
|
||||
"""Open the ZIP file with mode read 'r', write 'w', exclusive create 'x',
|
||||
or append 'a'."""
|
||||
if mode not in ('r', 'w', 'x', 'a'):
|
||||
|
@ -1259,6 +1259,12 @@ class ZipFile:
|
|||
self.pwd = None
|
||||
self._comment = b''
|
||||
self._strict_timestamps = strict_timestamps
|
||||
self.metadata_encoding = metadata_encoding
|
||||
|
||||
# Check that we don't try to write with nonconforming codecs
|
||||
if self.metadata_encoding and mode != 'r':
|
||||
raise ValueError(
|
||||
"metadata_encoding is only supported for reading files")
|
||||
|
||||
# Check if we were passed a file-like object
|
||||
if isinstance(file, os.PathLike):
|
||||
|
@ -1389,13 +1395,13 @@ class ZipFile:
|
|||
if self.debug > 2:
|
||||
print(centdir)
|
||||
filename = fp.read(centdir[_CD_FILENAME_LENGTH])
|
||||
flags = centdir[5]
|
||||
flags = centdir[_CD_FLAG_BITS]
|
||||
if flags & _MASK_UTF_FILENAME:
|
||||
# UTF-8 file names extension
|
||||
filename = filename.decode('utf-8')
|
||||
else:
|
||||
# Historical ZIP filename encoding
|
||||
filename = filename.decode('cp437')
|
||||
filename = filename.decode(self.metadata_encoding or 'cp437')
|
||||
# Create ZipInfo instance to store file information
|
||||
x = ZipInfo(filename)
|
||||
x.extra = fp.read(centdir[_CD_EXTRA_FIELD_LENGTH])
|
||||
|
@ -1572,7 +1578,7 @@ class ZipFile:
|
|||
# UTF-8 filename
|
||||
fname_str = fname.decode("utf-8")
|
||||
else:
|
||||
fname_str = fname.decode("cp437")
|
||||
fname_str = fname.decode(self.metadata_encoding or "cp437")
|
||||
|
||||
if fname_str != zinfo.orig_filename:
|
||||
raise BadZipFile(
|
||||
|
@ -2461,11 +2467,15 @@ def main(args=None):
|
|||
help='Create zipfile from sources')
|
||||
group.add_argument('-t', '--test', metavar='<zipfile>',
|
||||
help='Test if a zipfile is valid')
|
||||
parser.add_argument('--metadata-encoding', metavar='<encoding>',
|
||||
help='Specify encoding of member names for -l, -e and -t')
|
||||
args = parser.parse_args(args)
|
||||
|
||||
encoding = args.metadata_encoding
|
||||
|
||||
if args.test is not None:
|
||||
src = args.test
|
||||
with ZipFile(src, 'r') as zf:
|
||||
with ZipFile(src, 'r', metadata_encoding=encoding) as zf:
|
||||
badfile = zf.testzip()
|
||||
if badfile:
|
||||
print("The following enclosed file is corrupted: {!r}".format(badfile))
|
||||
|
@ -2473,15 +2483,20 @@ def main(args=None):
|
|||
|
||||
elif args.list is not None:
|
||||
src = args.list
|
||||
with ZipFile(src, 'r') as zf:
|
||||
with ZipFile(src, 'r', metadata_encoding=encoding) as zf:
|
||||
zf.printdir()
|
||||
|
||||
elif args.extract is not None:
|
||||
src, curdir = args.extract
|
||||
with ZipFile(src, 'r') as zf:
|
||||
with ZipFile(src, 'r', metadata_encoding=encoding) as zf:
|
||||
zf.extractall(curdir)
|
||||
|
||||
elif args.create is not None:
|
||||
if encoding:
|
||||
print("Non-conforming encodings not supported with -c.",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
zip_name = args.create.pop(0)
|
||||
files = args.create
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue