1*cda5da8dSAndroid Build Coastguard Worker"""Functions that read and write gzipped files. 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard WorkerThe user of the file doesn't have to worry about the compression, 4*cda5da8dSAndroid Build Coastguard Workerbut random access is not allowed.""" 5*cda5da8dSAndroid Build Coastguard Worker 6*cda5da8dSAndroid Build Coastguard Worker# based on Andrew Kuchling's minigzip.py distributed with the zlib module 7*cda5da8dSAndroid Build Coastguard Worker 8*cda5da8dSAndroid Build Coastguard Workerimport struct, sys, time, os 9*cda5da8dSAndroid Build Coastguard Workerimport zlib 10*cda5da8dSAndroid Build Coastguard Workerimport builtins 11*cda5da8dSAndroid Build Coastguard Workerimport io 12*cda5da8dSAndroid Build Coastguard Workerimport _compression 13*cda5da8dSAndroid Build Coastguard Worker 14*cda5da8dSAndroid Build Coastguard Worker__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"] 15*cda5da8dSAndroid Build Coastguard Worker 16*cda5da8dSAndroid Build Coastguard WorkerFTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 17*cda5da8dSAndroid Build Coastguard Worker 18*cda5da8dSAndroid Build Coastguard WorkerREAD, WRITE = 1, 2 19*cda5da8dSAndroid Build Coastguard Worker 20*cda5da8dSAndroid Build Coastguard Worker_COMPRESS_LEVEL_FAST = 1 21*cda5da8dSAndroid Build Coastguard Worker_COMPRESS_LEVEL_TRADEOFF = 6 22*cda5da8dSAndroid Build Coastguard Worker_COMPRESS_LEVEL_BEST = 9 23*cda5da8dSAndroid Build Coastguard Worker 24*cda5da8dSAndroid Build Coastguard Worker 25*cda5da8dSAndroid Build Coastguard Workerdef open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST, 26*cda5da8dSAndroid Build Coastguard Worker encoding=None, errors=None, newline=None): 27*cda5da8dSAndroid Build Coastguard Worker """Open a gzip-compressed file in binary or text mode. 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Worker The filename argument can be an actual filename (a str or bytes object), or 30*cda5da8dSAndroid Build Coastguard Worker an existing file object to read from or write to. 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Worker The mode argument can be "r", "rb", "w", "wb", "x", "xb", "a" or "ab" for 33*cda5da8dSAndroid Build Coastguard Worker binary mode, or "rt", "wt", "xt" or "at" for text mode. The default mode is 34*cda5da8dSAndroid Build Coastguard Worker "rb", and the default compresslevel is 9. 35*cda5da8dSAndroid Build Coastguard Worker 36*cda5da8dSAndroid Build Coastguard Worker For binary mode, this function is equivalent to the GzipFile constructor: 37*cda5da8dSAndroid Build Coastguard Worker GzipFile(filename, mode, compresslevel). In this case, the encoding, errors 38*cda5da8dSAndroid Build Coastguard Worker and newline arguments must not be provided. 39*cda5da8dSAndroid Build Coastguard Worker 40*cda5da8dSAndroid Build Coastguard Worker For text mode, a GzipFile object is created, and wrapped in an 41*cda5da8dSAndroid Build Coastguard Worker io.TextIOWrapper instance with the specified encoding, error handling 42*cda5da8dSAndroid Build Coastguard Worker behavior, and line ending(s). 43*cda5da8dSAndroid Build Coastguard Worker 44*cda5da8dSAndroid Build Coastguard Worker """ 45*cda5da8dSAndroid Build Coastguard Worker if "t" in mode: 46*cda5da8dSAndroid Build Coastguard Worker if "b" in mode: 47*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Invalid mode: %r" % (mode,)) 48*cda5da8dSAndroid Build Coastguard Worker else: 49*cda5da8dSAndroid Build Coastguard Worker if encoding is not None: 50*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Argument 'encoding' not supported in binary mode") 51*cda5da8dSAndroid Build Coastguard Worker if errors is not None: 52*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Argument 'errors' not supported in binary mode") 53*cda5da8dSAndroid Build Coastguard Worker if newline is not None: 54*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Argument 'newline' not supported in binary mode") 55*cda5da8dSAndroid Build Coastguard Worker 56*cda5da8dSAndroid Build Coastguard Worker gz_mode = mode.replace("t", "") 57*cda5da8dSAndroid Build Coastguard Worker if isinstance(filename, (str, bytes, os.PathLike)): 58*cda5da8dSAndroid Build Coastguard Worker binary_file = GzipFile(filename, gz_mode, compresslevel) 59*cda5da8dSAndroid Build Coastguard Worker elif hasattr(filename, "read") or hasattr(filename, "write"): 60*cda5da8dSAndroid Build Coastguard Worker binary_file = GzipFile(None, gz_mode, compresslevel, filename) 61*cda5da8dSAndroid Build Coastguard Worker else: 62*cda5da8dSAndroid Build Coastguard Worker raise TypeError("filename must be a str or bytes object, or a file") 63*cda5da8dSAndroid Build Coastguard Worker 64*cda5da8dSAndroid Build Coastguard Worker if "t" in mode: 65*cda5da8dSAndroid Build Coastguard Worker encoding = io.text_encoding(encoding) 66*cda5da8dSAndroid Build Coastguard Worker return io.TextIOWrapper(binary_file, encoding, errors, newline) 67*cda5da8dSAndroid Build Coastguard Worker else: 68*cda5da8dSAndroid Build Coastguard Worker return binary_file 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Workerdef write32u(output, value): 71*cda5da8dSAndroid Build Coastguard Worker # The L format writes the bit pattern correctly whether signed 72*cda5da8dSAndroid Build Coastguard Worker # or unsigned. 73*cda5da8dSAndroid Build Coastguard Worker output.write(struct.pack("<L", value)) 74*cda5da8dSAndroid Build Coastguard Worker 75*cda5da8dSAndroid Build Coastguard Workerclass _PaddedFile: 76*cda5da8dSAndroid Build Coastguard Worker """Minimal read-only file object that prepends a string to the contents 77*cda5da8dSAndroid Build Coastguard Worker of an actual file. Shouldn't be used outside of gzip.py, as it lacks 78*cda5da8dSAndroid Build Coastguard Worker essential functionality.""" 79*cda5da8dSAndroid Build Coastguard Worker 80*cda5da8dSAndroid Build Coastguard Worker def __init__(self, f, prepend=b''): 81*cda5da8dSAndroid Build Coastguard Worker self._buffer = prepend 82*cda5da8dSAndroid Build Coastguard Worker self._length = len(prepend) 83*cda5da8dSAndroid Build Coastguard Worker self.file = f 84*cda5da8dSAndroid Build Coastguard Worker self._read = 0 85*cda5da8dSAndroid Build Coastguard Worker 86*cda5da8dSAndroid Build Coastguard Worker def read(self, size): 87*cda5da8dSAndroid Build Coastguard Worker if self._read is None: 88*cda5da8dSAndroid Build Coastguard Worker return self.file.read(size) 89*cda5da8dSAndroid Build Coastguard Worker if self._read + size <= self._length: 90*cda5da8dSAndroid Build Coastguard Worker read = self._read 91*cda5da8dSAndroid Build Coastguard Worker self._read += size 92*cda5da8dSAndroid Build Coastguard Worker return self._buffer[read:self._read] 93*cda5da8dSAndroid Build Coastguard Worker else: 94*cda5da8dSAndroid Build Coastguard Worker read = self._read 95*cda5da8dSAndroid Build Coastguard Worker self._read = None 96*cda5da8dSAndroid Build Coastguard Worker return self._buffer[read:] + \ 97*cda5da8dSAndroid Build Coastguard Worker self.file.read(size-self._length+read) 98*cda5da8dSAndroid Build Coastguard Worker 99*cda5da8dSAndroid Build Coastguard Worker def prepend(self, prepend=b''): 100*cda5da8dSAndroid Build Coastguard Worker if self._read is None: 101*cda5da8dSAndroid Build Coastguard Worker self._buffer = prepend 102*cda5da8dSAndroid Build Coastguard Worker else: # Assume data was read since the last prepend() call 103*cda5da8dSAndroid Build Coastguard Worker self._read -= len(prepend) 104*cda5da8dSAndroid Build Coastguard Worker return 105*cda5da8dSAndroid Build Coastguard Worker self._length = len(self._buffer) 106*cda5da8dSAndroid Build Coastguard Worker self._read = 0 107*cda5da8dSAndroid Build Coastguard Worker 108*cda5da8dSAndroid Build Coastguard Worker def seek(self, off): 109*cda5da8dSAndroid Build Coastguard Worker self._read = None 110*cda5da8dSAndroid Build Coastguard Worker self._buffer = None 111*cda5da8dSAndroid Build Coastguard Worker return self.file.seek(off) 112*cda5da8dSAndroid Build Coastguard Worker 113*cda5da8dSAndroid Build Coastguard Worker def seekable(self): 114*cda5da8dSAndroid Build Coastguard Worker return True # Allows fast-forwarding even in unseekable streams 115*cda5da8dSAndroid Build Coastguard Worker 116*cda5da8dSAndroid Build Coastguard Worker 117*cda5da8dSAndroid Build Coastguard Workerclass BadGzipFile(OSError): 118*cda5da8dSAndroid Build Coastguard Worker """Exception raised in some cases for invalid gzip files.""" 119*cda5da8dSAndroid Build Coastguard Worker 120*cda5da8dSAndroid Build Coastguard Worker 121*cda5da8dSAndroid Build Coastguard Workerclass GzipFile(_compression.BaseStream): 122*cda5da8dSAndroid Build Coastguard Worker """The GzipFile class simulates most of the methods of a file object with 123*cda5da8dSAndroid Build Coastguard Worker the exception of the truncate() method. 124*cda5da8dSAndroid Build Coastguard Worker 125*cda5da8dSAndroid Build Coastguard Worker This class only supports opening files in binary mode. If you need to open a 126*cda5da8dSAndroid Build Coastguard Worker compressed file in text mode, use the gzip.open() function. 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Worker """ 129*cda5da8dSAndroid Build Coastguard Worker 130*cda5da8dSAndroid Build Coastguard Worker # Overridden with internal file object to be closed, if only a filename 131*cda5da8dSAndroid Build Coastguard Worker # is passed in 132*cda5da8dSAndroid Build Coastguard Worker myfileobj = None 133*cda5da8dSAndroid Build Coastguard Worker 134*cda5da8dSAndroid Build Coastguard Worker def __init__(self, filename=None, mode=None, 135*cda5da8dSAndroid Build Coastguard Worker compresslevel=_COMPRESS_LEVEL_BEST, fileobj=None, mtime=None): 136*cda5da8dSAndroid Build Coastguard Worker """Constructor for the GzipFile class. 137*cda5da8dSAndroid Build Coastguard Worker 138*cda5da8dSAndroid Build Coastguard Worker At least one of fileobj and filename must be given a 139*cda5da8dSAndroid Build Coastguard Worker non-trivial value. 140*cda5da8dSAndroid Build Coastguard Worker 141*cda5da8dSAndroid Build Coastguard Worker The new class instance is based on fileobj, which can be a regular 142*cda5da8dSAndroid Build Coastguard Worker file, an io.BytesIO object, or any other object which simulates a file. 143*cda5da8dSAndroid Build Coastguard Worker It defaults to None, in which case filename is opened to provide 144*cda5da8dSAndroid Build Coastguard Worker a file object. 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker When fileobj is not None, the filename argument is only used to be 147*cda5da8dSAndroid Build Coastguard Worker included in the gzip file header, which may include the original 148*cda5da8dSAndroid Build Coastguard Worker filename of the uncompressed file. It defaults to the filename of 149*cda5da8dSAndroid Build Coastguard Worker fileobj, if discernible; otherwise, it defaults to the empty string, 150*cda5da8dSAndroid Build Coastguard Worker and in this case the original filename is not included in the header. 151*cda5da8dSAndroid Build Coastguard Worker 152*cda5da8dSAndroid Build Coastguard Worker The mode argument can be any of 'r', 'rb', 'a', 'ab', 'w', 'wb', 'x', or 153*cda5da8dSAndroid Build Coastguard Worker 'xb' depending on whether the file will be read or written. The default 154*cda5da8dSAndroid Build Coastguard Worker is the mode of fileobj if discernible; otherwise, the default is 'rb'. 155*cda5da8dSAndroid Build Coastguard Worker A mode of 'r' is equivalent to one of 'rb', and similarly for 'w' and 156*cda5da8dSAndroid Build Coastguard Worker 'wb', 'a' and 'ab', and 'x' and 'xb'. 157*cda5da8dSAndroid Build Coastguard Worker 158*cda5da8dSAndroid Build Coastguard Worker The compresslevel argument is an integer from 0 to 9 controlling the 159*cda5da8dSAndroid Build Coastguard Worker level of compression; 1 is fastest and produces the least compression, 160*cda5da8dSAndroid Build Coastguard Worker and 9 is slowest and produces the most compression. 0 is no compression 161*cda5da8dSAndroid Build Coastguard Worker at all. The default is 9. 162*cda5da8dSAndroid Build Coastguard Worker 163*cda5da8dSAndroid Build Coastguard Worker The mtime argument is an optional numeric timestamp to be written 164*cda5da8dSAndroid Build Coastguard Worker to the last modification time field in the stream when compressing. 165*cda5da8dSAndroid Build Coastguard Worker If omitted or None, the current time is used. 166*cda5da8dSAndroid Build Coastguard Worker 167*cda5da8dSAndroid Build Coastguard Worker """ 168*cda5da8dSAndroid Build Coastguard Worker 169*cda5da8dSAndroid Build Coastguard Worker if mode and ('t' in mode or 'U' in mode): 170*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Invalid mode: {!r}".format(mode)) 171*cda5da8dSAndroid Build Coastguard Worker if mode and 'b' not in mode: 172*cda5da8dSAndroid Build Coastguard Worker mode += 'b' 173*cda5da8dSAndroid Build Coastguard Worker if fileobj is None: 174*cda5da8dSAndroid Build Coastguard Worker fileobj = self.myfileobj = builtins.open(filename, mode or 'rb') 175*cda5da8dSAndroid Build Coastguard Worker if filename is None: 176*cda5da8dSAndroid Build Coastguard Worker filename = getattr(fileobj, 'name', '') 177*cda5da8dSAndroid Build Coastguard Worker if not isinstance(filename, (str, bytes)): 178*cda5da8dSAndroid Build Coastguard Worker filename = '' 179*cda5da8dSAndroid Build Coastguard Worker else: 180*cda5da8dSAndroid Build Coastguard Worker filename = os.fspath(filename) 181*cda5da8dSAndroid Build Coastguard Worker origmode = mode 182*cda5da8dSAndroid Build Coastguard Worker if mode is None: 183*cda5da8dSAndroid Build Coastguard Worker mode = getattr(fileobj, 'mode', 'rb') 184*cda5da8dSAndroid Build Coastguard Worker 185*cda5da8dSAndroid Build Coastguard Worker if mode.startswith('r'): 186*cda5da8dSAndroid Build Coastguard Worker self.mode = READ 187*cda5da8dSAndroid Build Coastguard Worker raw = _GzipReader(fileobj) 188*cda5da8dSAndroid Build Coastguard Worker self._buffer = io.BufferedReader(raw) 189*cda5da8dSAndroid Build Coastguard Worker self.name = filename 190*cda5da8dSAndroid Build Coastguard Worker 191*cda5da8dSAndroid Build Coastguard Worker elif mode.startswith(('w', 'a', 'x')): 192*cda5da8dSAndroid Build Coastguard Worker if origmode is None: 193*cda5da8dSAndroid Build Coastguard Worker import warnings 194*cda5da8dSAndroid Build Coastguard Worker warnings.warn( 195*cda5da8dSAndroid Build Coastguard Worker "GzipFile was opened for writing, but this will " 196*cda5da8dSAndroid Build Coastguard Worker "change in future Python releases. " 197*cda5da8dSAndroid Build Coastguard Worker "Specify the mode argument for opening it for writing.", 198*cda5da8dSAndroid Build Coastguard Worker FutureWarning, 2) 199*cda5da8dSAndroid Build Coastguard Worker self.mode = WRITE 200*cda5da8dSAndroid Build Coastguard Worker self._init_write(filename) 201*cda5da8dSAndroid Build Coastguard Worker self.compress = zlib.compressobj(compresslevel, 202*cda5da8dSAndroid Build Coastguard Worker zlib.DEFLATED, 203*cda5da8dSAndroid Build Coastguard Worker -zlib.MAX_WBITS, 204*cda5da8dSAndroid Build Coastguard Worker zlib.DEF_MEM_LEVEL, 205*cda5da8dSAndroid Build Coastguard Worker 0) 206*cda5da8dSAndroid Build Coastguard Worker self._write_mtime = mtime 207*cda5da8dSAndroid Build Coastguard Worker else: 208*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Invalid mode: {!r}".format(mode)) 209*cda5da8dSAndroid Build Coastguard Worker 210*cda5da8dSAndroid Build Coastguard Worker self.fileobj = fileobj 211*cda5da8dSAndroid Build Coastguard Worker 212*cda5da8dSAndroid Build Coastguard Worker if self.mode == WRITE: 213*cda5da8dSAndroid Build Coastguard Worker self._write_gzip_header(compresslevel) 214*cda5da8dSAndroid Build Coastguard Worker 215*cda5da8dSAndroid Build Coastguard Worker @property 216*cda5da8dSAndroid Build Coastguard Worker def filename(self): 217*cda5da8dSAndroid Build Coastguard Worker import warnings 218*cda5da8dSAndroid Build Coastguard Worker warnings.warn("use the name attribute", DeprecationWarning, 2) 219*cda5da8dSAndroid Build Coastguard Worker if self.mode == WRITE and self.name[-3:] != ".gz": 220*cda5da8dSAndroid Build Coastguard Worker return self.name + ".gz" 221*cda5da8dSAndroid Build Coastguard Worker return self.name 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker @property 224*cda5da8dSAndroid Build Coastguard Worker def mtime(self): 225*cda5da8dSAndroid Build Coastguard Worker """Last modification time read from stream, or None""" 226*cda5da8dSAndroid Build Coastguard Worker return self._buffer.raw._last_mtime 227*cda5da8dSAndroid Build Coastguard Worker 228*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 229*cda5da8dSAndroid Build Coastguard Worker s = repr(self.fileobj) 230*cda5da8dSAndroid Build Coastguard Worker return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>' 231*cda5da8dSAndroid Build Coastguard Worker 232*cda5da8dSAndroid Build Coastguard Worker def _init_write(self, filename): 233*cda5da8dSAndroid Build Coastguard Worker self.name = filename 234*cda5da8dSAndroid Build Coastguard Worker self.crc = zlib.crc32(b"") 235*cda5da8dSAndroid Build Coastguard Worker self.size = 0 236*cda5da8dSAndroid Build Coastguard Worker self.writebuf = [] 237*cda5da8dSAndroid Build Coastguard Worker self.bufsize = 0 238*cda5da8dSAndroid Build Coastguard Worker self.offset = 0 # Current file offset for seek(), tell(), etc 239*cda5da8dSAndroid Build Coastguard Worker 240*cda5da8dSAndroid Build Coastguard Worker def _write_gzip_header(self, compresslevel): 241*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(b'\037\213') # magic header 242*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(b'\010') # compression method 243*cda5da8dSAndroid Build Coastguard Worker try: 244*cda5da8dSAndroid Build Coastguard Worker # RFC 1952 requires the FNAME field to be Latin-1. Do not 245*cda5da8dSAndroid Build Coastguard Worker # include filenames that cannot be represented that way. 246*cda5da8dSAndroid Build Coastguard Worker fname = os.path.basename(self.name) 247*cda5da8dSAndroid Build Coastguard Worker if not isinstance(fname, bytes): 248*cda5da8dSAndroid Build Coastguard Worker fname = fname.encode('latin-1') 249*cda5da8dSAndroid Build Coastguard Worker if fname.endswith(b'.gz'): 250*cda5da8dSAndroid Build Coastguard Worker fname = fname[:-3] 251*cda5da8dSAndroid Build Coastguard Worker except UnicodeEncodeError: 252*cda5da8dSAndroid Build Coastguard Worker fname = b'' 253*cda5da8dSAndroid Build Coastguard Worker flags = 0 254*cda5da8dSAndroid Build Coastguard Worker if fname: 255*cda5da8dSAndroid Build Coastguard Worker flags = FNAME 256*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(chr(flags).encode('latin-1')) 257*cda5da8dSAndroid Build Coastguard Worker mtime = self._write_mtime 258*cda5da8dSAndroid Build Coastguard Worker if mtime is None: 259*cda5da8dSAndroid Build Coastguard Worker mtime = time.time() 260*cda5da8dSAndroid Build Coastguard Worker write32u(self.fileobj, int(mtime)) 261*cda5da8dSAndroid Build Coastguard Worker if compresslevel == _COMPRESS_LEVEL_BEST: 262*cda5da8dSAndroid Build Coastguard Worker xfl = b'\002' 263*cda5da8dSAndroid Build Coastguard Worker elif compresslevel == _COMPRESS_LEVEL_FAST: 264*cda5da8dSAndroid Build Coastguard Worker xfl = b'\004' 265*cda5da8dSAndroid Build Coastguard Worker else: 266*cda5da8dSAndroid Build Coastguard Worker xfl = b'\000' 267*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(xfl) 268*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(b'\377') 269*cda5da8dSAndroid Build Coastguard Worker if fname: 270*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(fname + b'\000') 271*cda5da8dSAndroid Build Coastguard Worker 272*cda5da8dSAndroid Build Coastguard Worker def write(self,data): 273*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 274*cda5da8dSAndroid Build Coastguard Worker if self.mode != WRITE: 275*cda5da8dSAndroid Build Coastguard Worker import errno 276*cda5da8dSAndroid Build Coastguard Worker raise OSError(errno.EBADF, "write() on read-only GzipFile object") 277*cda5da8dSAndroid Build Coastguard Worker 278*cda5da8dSAndroid Build Coastguard Worker if self.fileobj is None: 279*cda5da8dSAndroid Build Coastguard Worker raise ValueError("write() on closed GzipFile object") 280*cda5da8dSAndroid Build Coastguard Worker 281*cda5da8dSAndroid Build Coastguard Worker if isinstance(data, (bytes, bytearray)): 282*cda5da8dSAndroid Build Coastguard Worker length = len(data) 283*cda5da8dSAndroid Build Coastguard Worker else: 284*cda5da8dSAndroid Build Coastguard Worker # accept any data that supports the buffer protocol 285*cda5da8dSAndroid Build Coastguard Worker data = memoryview(data) 286*cda5da8dSAndroid Build Coastguard Worker length = data.nbytes 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker if length > 0: 289*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(self.compress.compress(data)) 290*cda5da8dSAndroid Build Coastguard Worker self.size += length 291*cda5da8dSAndroid Build Coastguard Worker self.crc = zlib.crc32(data, self.crc) 292*cda5da8dSAndroid Build Coastguard Worker self.offset += length 293*cda5da8dSAndroid Build Coastguard Worker 294*cda5da8dSAndroid Build Coastguard Worker return length 295*cda5da8dSAndroid Build Coastguard Worker 296*cda5da8dSAndroid Build Coastguard Worker def read(self, size=-1): 297*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 298*cda5da8dSAndroid Build Coastguard Worker if self.mode != READ: 299*cda5da8dSAndroid Build Coastguard Worker import errno 300*cda5da8dSAndroid Build Coastguard Worker raise OSError(errno.EBADF, "read() on write-only GzipFile object") 301*cda5da8dSAndroid Build Coastguard Worker return self._buffer.read(size) 302*cda5da8dSAndroid Build Coastguard Worker 303*cda5da8dSAndroid Build Coastguard Worker def read1(self, size=-1): 304*cda5da8dSAndroid Build Coastguard Worker """Implements BufferedIOBase.read1() 305*cda5da8dSAndroid Build Coastguard Worker 306*cda5da8dSAndroid Build Coastguard Worker Reads up to a buffer's worth of data if size is negative.""" 307*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 308*cda5da8dSAndroid Build Coastguard Worker if self.mode != READ: 309*cda5da8dSAndroid Build Coastguard Worker import errno 310*cda5da8dSAndroid Build Coastguard Worker raise OSError(errno.EBADF, "read1() on write-only GzipFile object") 311*cda5da8dSAndroid Build Coastguard Worker 312*cda5da8dSAndroid Build Coastguard Worker if size < 0: 313*cda5da8dSAndroid Build Coastguard Worker size = io.DEFAULT_BUFFER_SIZE 314*cda5da8dSAndroid Build Coastguard Worker return self._buffer.read1(size) 315*cda5da8dSAndroid Build Coastguard Worker 316*cda5da8dSAndroid Build Coastguard Worker def peek(self, n): 317*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 318*cda5da8dSAndroid Build Coastguard Worker if self.mode != READ: 319*cda5da8dSAndroid Build Coastguard Worker import errno 320*cda5da8dSAndroid Build Coastguard Worker raise OSError(errno.EBADF, "peek() on write-only GzipFile object") 321*cda5da8dSAndroid Build Coastguard Worker return self._buffer.peek(n) 322*cda5da8dSAndroid Build Coastguard Worker 323*cda5da8dSAndroid Build Coastguard Worker @property 324*cda5da8dSAndroid Build Coastguard Worker def closed(self): 325*cda5da8dSAndroid Build Coastguard Worker return self.fileobj is None 326*cda5da8dSAndroid Build Coastguard Worker 327*cda5da8dSAndroid Build Coastguard Worker def close(self): 328*cda5da8dSAndroid Build Coastguard Worker fileobj = self.fileobj 329*cda5da8dSAndroid Build Coastguard Worker if fileobj is None: 330*cda5da8dSAndroid Build Coastguard Worker return 331*cda5da8dSAndroid Build Coastguard Worker self.fileobj = None 332*cda5da8dSAndroid Build Coastguard Worker try: 333*cda5da8dSAndroid Build Coastguard Worker if self.mode == WRITE: 334*cda5da8dSAndroid Build Coastguard Worker fileobj.write(self.compress.flush()) 335*cda5da8dSAndroid Build Coastguard Worker write32u(fileobj, self.crc) 336*cda5da8dSAndroid Build Coastguard Worker # self.size may exceed 2 GiB, or even 4 GiB 337*cda5da8dSAndroid Build Coastguard Worker write32u(fileobj, self.size & 0xffffffff) 338*cda5da8dSAndroid Build Coastguard Worker elif self.mode == READ: 339*cda5da8dSAndroid Build Coastguard Worker self._buffer.close() 340*cda5da8dSAndroid Build Coastguard Worker finally: 341*cda5da8dSAndroid Build Coastguard Worker myfileobj = self.myfileobj 342*cda5da8dSAndroid Build Coastguard Worker if myfileobj: 343*cda5da8dSAndroid Build Coastguard Worker self.myfileobj = None 344*cda5da8dSAndroid Build Coastguard Worker myfileobj.close() 345*cda5da8dSAndroid Build Coastguard Worker 346*cda5da8dSAndroid Build Coastguard Worker def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH): 347*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 348*cda5da8dSAndroid Build Coastguard Worker if self.mode == WRITE: 349*cda5da8dSAndroid Build Coastguard Worker # Ensure the compressor's buffer is flushed 350*cda5da8dSAndroid Build Coastguard Worker self.fileobj.write(self.compress.flush(zlib_mode)) 351*cda5da8dSAndroid Build Coastguard Worker self.fileobj.flush() 352*cda5da8dSAndroid Build Coastguard Worker 353*cda5da8dSAndroid Build Coastguard Worker def fileno(self): 354*cda5da8dSAndroid Build Coastguard Worker """Invoke the underlying file object's fileno() method. 355*cda5da8dSAndroid Build Coastguard Worker 356*cda5da8dSAndroid Build Coastguard Worker This will raise AttributeError if the underlying file object 357*cda5da8dSAndroid Build Coastguard Worker doesn't support fileno(). 358*cda5da8dSAndroid Build Coastguard Worker """ 359*cda5da8dSAndroid Build Coastguard Worker return self.fileobj.fileno() 360*cda5da8dSAndroid Build Coastguard Worker 361*cda5da8dSAndroid Build Coastguard Worker def rewind(self): 362*cda5da8dSAndroid Build Coastguard Worker '''Return the uncompressed stream file position indicator to the 363*cda5da8dSAndroid Build Coastguard Worker beginning of the file''' 364*cda5da8dSAndroid Build Coastguard Worker if self.mode != READ: 365*cda5da8dSAndroid Build Coastguard Worker raise OSError("Can't rewind in write mode") 366*cda5da8dSAndroid Build Coastguard Worker self._buffer.seek(0) 367*cda5da8dSAndroid Build Coastguard Worker 368*cda5da8dSAndroid Build Coastguard Worker def readable(self): 369*cda5da8dSAndroid Build Coastguard Worker return self.mode == READ 370*cda5da8dSAndroid Build Coastguard Worker 371*cda5da8dSAndroid Build Coastguard Worker def writable(self): 372*cda5da8dSAndroid Build Coastguard Worker return self.mode == WRITE 373*cda5da8dSAndroid Build Coastguard Worker 374*cda5da8dSAndroid Build Coastguard Worker def seekable(self): 375*cda5da8dSAndroid Build Coastguard Worker return True 376*cda5da8dSAndroid Build Coastguard Worker 377*cda5da8dSAndroid Build Coastguard Worker def seek(self, offset, whence=io.SEEK_SET): 378*cda5da8dSAndroid Build Coastguard Worker if self.mode == WRITE: 379*cda5da8dSAndroid Build Coastguard Worker if whence != io.SEEK_SET: 380*cda5da8dSAndroid Build Coastguard Worker if whence == io.SEEK_CUR: 381*cda5da8dSAndroid Build Coastguard Worker offset = self.offset + offset 382*cda5da8dSAndroid Build Coastguard Worker else: 383*cda5da8dSAndroid Build Coastguard Worker raise ValueError('Seek from end not supported') 384*cda5da8dSAndroid Build Coastguard Worker if offset < self.offset: 385*cda5da8dSAndroid Build Coastguard Worker raise OSError('Negative seek in write mode') 386*cda5da8dSAndroid Build Coastguard Worker count = offset - self.offset 387*cda5da8dSAndroid Build Coastguard Worker chunk = b'\0' * 1024 388*cda5da8dSAndroid Build Coastguard Worker for i in range(count // 1024): 389*cda5da8dSAndroid Build Coastguard Worker self.write(chunk) 390*cda5da8dSAndroid Build Coastguard Worker self.write(b'\0' * (count % 1024)) 391*cda5da8dSAndroid Build Coastguard Worker elif self.mode == READ: 392*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 393*cda5da8dSAndroid Build Coastguard Worker return self._buffer.seek(offset, whence) 394*cda5da8dSAndroid Build Coastguard Worker 395*cda5da8dSAndroid Build Coastguard Worker return self.offset 396*cda5da8dSAndroid Build Coastguard Worker 397*cda5da8dSAndroid Build Coastguard Worker def readline(self, size=-1): 398*cda5da8dSAndroid Build Coastguard Worker self._check_not_closed() 399*cda5da8dSAndroid Build Coastguard Worker return self._buffer.readline(size) 400*cda5da8dSAndroid Build Coastguard Worker 401*cda5da8dSAndroid Build Coastguard Worker 402*cda5da8dSAndroid Build Coastguard Workerdef _read_exact(fp, n): 403*cda5da8dSAndroid Build Coastguard Worker '''Read exactly *n* bytes from `fp` 404*cda5da8dSAndroid Build Coastguard Worker 405*cda5da8dSAndroid Build Coastguard Worker This method is required because fp may be unbuffered, 406*cda5da8dSAndroid Build Coastguard Worker i.e. return short reads. 407*cda5da8dSAndroid Build Coastguard Worker ''' 408*cda5da8dSAndroid Build Coastguard Worker data = fp.read(n) 409*cda5da8dSAndroid Build Coastguard Worker while len(data) < n: 410*cda5da8dSAndroid Build Coastguard Worker b = fp.read(n - len(data)) 411*cda5da8dSAndroid Build Coastguard Worker if not b: 412*cda5da8dSAndroid Build Coastguard Worker raise EOFError("Compressed file ended before the " 413*cda5da8dSAndroid Build Coastguard Worker "end-of-stream marker was reached") 414*cda5da8dSAndroid Build Coastguard Worker data += b 415*cda5da8dSAndroid Build Coastguard Worker return data 416*cda5da8dSAndroid Build Coastguard Worker 417*cda5da8dSAndroid Build Coastguard Worker 418*cda5da8dSAndroid Build Coastguard Workerdef _read_gzip_header(fp): 419*cda5da8dSAndroid Build Coastguard Worker '''Read a gzip header from `fp` and progress to the end of the header. 420*cda5da8dSAndroid Build Coastguard Worker 421*cda5da8dSAndroid Build Coastguard Worker Returns last mtime if header was present or None otherwise. 422*cda5da8dSAndroid Build Coastguard Worker ''' 423*cda5da8dSAndroid Build Coastguard Worker magic = fp.read(2) 424*cda5da8dSAndroid Build Coastguard Worker if magic == b'': 425*cda5da8dSAndroid Build Coastguard Worker return None 426*cda5da8dSAndroid Build Coastguard Worker 427*cda5da8dSAndroid Build Coastguard Worker if magic != b'\037\213': 428*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile('Not a gzipped file (%r)' % magic) 429*cda5da8dSAndroid Build Coastguard Worker 430*cda5da8dSAndroid Build Coastguard Worker (method, flag, last_mtime) = struct.unpack("<BBIxx", _read_exact(fp, 8)) 431*cda5da8dSAndroid Build Coastguard Worker if method != 8: 432*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile('Unknown compression method') 433*cda5da8dSAndroid Build Coastguard Worker 434*cda5da8dSAndroid Build Coastguard Worker if flag & FEXTRA: 435*cda5da8dSAndroid Build Coastguard Worker # Read & discard the extra field, if present 436*cda5da8dSAndroid Build Coastguard Worker extra_len, = struct.unpack("<H", _read_exact(fp, 2)) 437*cda5da8dSAndroid Build Coastguard Worker _read_exact(fp, extra_len) 438*cda5da8dSAndroid Build Coastguard Worker if flag & FNAME: 439*cda5da8dSAndroid Build Coastguard Worker # Read and discard a null-terminated string containing the filename 440*cda5da8dSAndroid Build Coastguard Worker while True: 441*cda5da8dSAndroid Build Coastguard Worker s = fp.read(1) 442*cda5da8dSAndroid Build Coastguard Worker if not s or s==b'\000': 443*cda5da8dSAndroid Build Coastguard Worker break 444*cda5da8dSAndroid Build Coastguard Worker if flag & FCOMMENT: 445*cda5da8dSAndroid Build Coastguard Worker # Read and discard a null-terminated string containing a comment 446*cda5da8dSAndroid Build Coastguard Worker while True: 447*cda5da8dSAndroid Build Coastguard Worker s = fp.read(1) 448*cda5da8dSAndroid Build Coastguard Worker if not s or s==b'\000': 449*cda5da8dSAndroid Build Coastguard Worker break 450*cda5da8dSAndroid Build Coastguard Worker if flag & FHCRC: 451*cda5da8dSAndroid Build Coastguard Worker _read_exact(fp, 2) # Read & discard the 16-bit header CRC 452*cda5da8dSAndroid Build Coastguard Worker return last_mtime 453*cda5da8dSAndroid Build Coastguard Worker 454*cda5da8dSAndroid Build Coastguard Worker 455*cda5da8dSAndroid Build Coastguard Workerclass _GzipReader(_compression.DecompressReader): 456*cda5da8dSAndroid Build Coastguard Worker def __init__(self, fp): 457*cda5da8dSAndroid Build Coastguard Worker super().__init__(_PaddedFile(fp), zlib.decompressobj, 458*cda5da8dSAndroid Build Coastguard Worker wbits=-zlib.MAX_WBITS) 459*cda5da8dSAndroid Build Coastguard Worker # Set flag indicating start of a new member 460*cda5da8dSAndroid Build Coastguard Worker self._new_member = True 461*cda5da8dSAndroid Build Coastguard Worker self._last_mtime = None 462*cda5da8dSAndroid Build Coastguard Worker 463*cda5da8dSAndroid Build Coastguard Worker def _init_read(self): 464*cda5da8dSAndroid Build Coastguard Worker self._crc = zlib.crc32(b"") 465*cda5da8dSAndroid Build Coastguard Worker self._stream_size = 0 # Decompressed size of unconcatenated stream 466*cda5da8dSAndroid Build Coastguard Worker 467*cda5da8dSAndroid Build Coastguard Worker def _read_gzip_header(self): 468*cda5da8dSAndroid Build Coastguard Worker last_mtime = _read_gzip_header(self._fp) 469*cda5da8dSAndroid Build Coastguard Worker if last_mtime is None: 470*cda5da8dSAndroid Build Coastguard Worker return False 471*cda5da8dSAndroid Build Coastguard Worker self._last_mtime = last_mtime 472*cda5da8dSAndroid Build Coastguard Worker return True 473*cda5da8dSAndroid Build Coastguard Worker 474*cda5da8dSAndroid Build Coastguard Worker def read(self, size=-1): 475*cda5da8dSAndroid Build Coastguard Worker if size < 0: 476*cda5da8dSAndroid Build Coastguard Worker return self.readall() 477*cda5da8dSAndroid Build Coastguard Worker # size=0 is special because decompress(max_length=0) is not supported 478*cda5da8dSAndroid Build Coastguard Worker if not size: 479*cda5da8dSAndroid Build Coastguard Worker return b"" 480*cda5da8dSAndroid Build Coastguard Worker 481*cda5da8dSAndroid Build Coastguard Worker # For certain input data, a single 482*cda5da8dSAndroid Build Coastguard Worker # call to decompress() may not return 483*cda5da8dSAndroid Build Coastguard Worker # any data. In this case, retry until we get some data or reach EOF. 484*cda5da8dSAndroid Build Coastguard Worker while True: 485*cda5da8dSAndroid Build Coastguard Worker if self._decompressor.eof: 486*cda5da8dSAndroid Build Coastguard Worker # Ending case: we've come to the end of a member in the file, 487*cda5da8dSAndroid Build Coastguard Worker # so finish up this member, and read a new gzip header. 488*cda5da8dSAndroid Build Coastguard Worker # Check the CRC and file size, and set the flag so we read 489*cda5da8dSAndroid Build Coastguard Worker # a new member 490*cda5da8dSAndroid Build Coastguard Worker self._read_eof() 491*cda5da8dSAndroid Build Coastguard Worker self._new_member = True 492*cda5da8dSAndroid Build Coastguard Worker self._decompressor = self._decomp_factory( 493*cda5da8dSAndroid Build Coastguard Worker **self._decomp_args) 494*cda5da8dSAndroid Build Coastguard Worker 495*cda5da8dSAndroid Build Coastguard Worker if self._new_member: 496*cda5da8dSAndroid Build Coastguard Worker # If the _new_member flag is set, we have to 497*cda5da8dSAndroid Build Coastguard Worker # jump to the next member, if there is one. 498*cda5da8dSAndroid Build Coastguard Worker self._init_read() 499*cda5da8dSAndroid Build Coastguard Worker if not self._read_gzip_header(): 500*cda5da8dSAndroid Build Coastguard Worker self._size = self._pos 501*cda5da8dSAndroid Build Coastguard Worker return b"" 502*cda5da8dSAndroid Build Coastguard Worker self._new_member = False 503*cda5da8dSAndroid Build Coastguard Worker 504*cda5da8dSAndroid Build Coastguard Worker # Read a chunk of data from the file 505*cda5da8dSAndroid Build Coastguard Worker buf = self._fp.read(io.DEFAULT_BUFFER_SIZE) 506*cda5da8dSAndroid Build Coastguard Worker 507*cda5da8dSAndroid Build Coastguard Worker uncompress = self._decompressor.decompress(buf, size) 508*cda5da8dSAndroid Build Coastguard Worker if self._decompressor.unconsumed_tail != b"": 509*cda5da8dSAndroid Build Coastguard Worker self._fp.prepend(self._decompressor.unconsumed_tail) 510*cda5da8dSAndroid Build Coastguard Worker elif self._decompressor.unused_data != b"": 511*cda5da8dSAndroid Build Coastguard Worker # Prepend the already read bytes to the fileobj so they can 512*cda5da8dSAndroid Build Coastguard Worker # be seen by _read_eof() and _read_gzip_header() 513*cda5da8dSAndroid Build Coastguard Worker self._fp.prepend(self._decompressor.unused_data) 514*cda5da8dSAndroid Build Coastguard Worker 515*cda5da8dSAndroid Build Coastguard Worker if uncompress != b"": 516*cda5da8dSAndroid Build Coastguard Worker break 517*cda5da8dSAndroid Build Coastguard Worker if buf == b"": 518*cda5da8dSAndroid Build Coastguard Worker raise EOFError("Compressed file ended before the " 519*cda5da8dSAndroid Build Coastguard Worker "end-of-stream marker was reached") 520*cda5da8dSAndroid Build Coastguard Worker 521*cda5da8dSAndroid Build Coastguard Worker self._add_read_data( uncompress ) 522*cda5da8dSAndroid Build Coastguard Worker self._pos += len(uncompress) 523*cda5da8dSAndroid Build Coastguard Worker return uncompress 524*cda5da8dSAndroid Build Coastguard Worker 525*cda5da8dSAndroid Build Coastguard Worker def _add_read_data(self, data): 526*cda5da8dSAndroid Build Coastguard Worker self._crc = zlib.crc32(data, self._crc) 527*cda5da8dSAndroid Build Coastguard Worker self._stream_size = self._stream_size + len(data) 528*cda5da8dSAndroid Build Coastguard Worker 529*cda5da8dSAndroid Build Coastguard Worker def _read_eof(self): 530*cda5da8dSAndroid Build Coastguard Worker # We've read to the end of the file 531*cda5da8dSAndroid Build Coastguard Worker # We check that the computed CRC and size of the 532*cda5da8dSAndroid Build Coastguard Worker # uncompressed data matches the stored values. Note that the size 533*cda5da8dSAndroid Build Coastguard Worker # stored is the true file size mod 2**32. 534*cda5da8dSAndroid Build Coastguard Worker crc32, isize = struct.unpack("<II", _read_exact(self._fp, 8)) 535*cda5da8dSAndroid Build Coastguard Worker if crc32 != self._crc: 536*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile("CRC check failed %s != %s" % (hex(crc32), 537*cda5da8dSAndroid Build Coastguard Worker hex(self._crc))) 538*cda5da8dSAndroid Build Coastguard Worker elif isize != (self._stream_size & 0xffffffff): 539*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile("Incorrect length of data produced") 540*cda5da8dSAndroid Build Coastguard Worker 541*cda5da8dSAndroid Build Coastguard Worker # Gzip files can be padded with zeroes and still have archives. 542*cda5da8dSAndroid Build Coastguard Worker # Consume all zero bytes and set the file position to the first 543*cda5da8dSAndroid Build Coastguard Worker # non-zero byte. See http://www.gzip.org/#faq8 544*cda5da8dSAndroid Build Coastguard Worker c = b"\x00" 545*cda5da8dSAndroid Build Coastguard Worker while c == b"\x00": 546*cda5da8dSAndroid Build Coastguard Worker c = self._fp.read(1) 547*cda5da8dSAndroid Build Coastguard Worker if c: 548*cda5da8dSAndroid Build Coastguard Worker self._fp.prepend(c) 549*cda5da8dSAndroid Build Coastguard Worker 550*cda5da8dSAndroid Build Coastguard Worker def _rewind(self): 551*cda5da8dSAndroid Build Coastguard Worker super()._rewind() 552*cda5da8dSAndroid Build Coastguard Worker self._new_member = True 553*cda5da8dSAndroid Build Coastguard Worker 554*cda5da8dSAndroid Build Coastguard Worker 555*cda5da8dSAndroid Build Coastguard Workerdef _create_simple_gzip_header(compresslevel: int, 556*cda5da8dSAndroid Build Coastguard Worker mtime = None) -> bytes: 557*cda5da8dSAndroid Build Coastguard Worker """ 558*cda5da8dSAndroid Build Coastguard Worker Write a simple gzip header with no extra fields. 559*cda5da8dSAndroid Build Coastguard Worker :param compresslevel: Compresslevel used to determine the xfl bytes. 560*cda5da8dSAndroid Build Coastguard Worker :param mtime: The mtime (must support conversion to a 32-bit integer). 561*cda5da8dSAndroid Build Coastguard Worker :return: A bytes object representing the gzip header. 562*cda5da8dSAndroid Build Coastguard Worker """ 563*cda5da8dSAndroid Build Coastguard Worker if mtime is None: 564*cda5da8dSAndroid Build Coastguard Worker mtime = time.time() 565*cda5da8dSAndroid Build Coastguard Worker if compresslevel == _COMPRESS_LEVEL_BEST: 566*cda5da8dSAndroid Build Coastguard Worker xfl = 2 567*cda5da8dSAndroid Build Coastguard Worker elif compresslevel == _COMPRESS_LEVEL_FAST: 568*cda5da8dSAndroid Build Coastguard Worker xfl = 4 569*cda5da8dSAndroid Build Coastguard Worker else: 570*cda5da8dSAndroid Build Coastguard Worker xfl = 0 571*cda5da8dSAndroid Build Coastguard Worker # Pack ID1 and ID2 magic bytes, method (8=deflate), header flags (no extra 572*cda5da8dSAndroid Build Coastguard Worker # fields added to header), mtime, xfl and os (255 for unknown OS). 573*cda5da8dSAndroid Build Coastguard Worker return struct.pack("<BBBBLBB", 0x1f, 0x8b, 8, 0, int(mtime), xfl, 255) 574*cda5da8dSAndroid Build Coastguard Worker 575*cda5da8dSAndroid Build Coastguard Worker 576*cda5da8dSAndroid Build Coastguard Workerdef compress(data, compresslevel=_COMPRESS_LEVEL_BEST, *, mtime=None): 577*cda5da8dSAndroid Build Coastguard Worker """Compress data in one shot and return the compressed string. 578*cda5da8dSAndroid Build Coastguard Worker 579*cda5da8dSAndroid Build Coastguard Worker compresslevel sets the compression level in range of 0-9. 580*cda5da8dSAndroid Build Coastguard Worker mtime can be used to set the modification time. The modification time is 581*cda5da8dSAndroid Build Coastguard Worker set to the current time by default. 582*cda5da8dSAndroid Build Coastguard Worker """ 583*cda5da8dSAndroid Build Coastguard Worker if mtime == 0: 584*cda5da8dSAndroid Build Coastguard Worker # Use zlib as it creates the header with 0 mtime by default. 585*cda5da8dSAndroid Build Coastguard Worker # This is faster and with less overhead. 586*cda5da8dSAndroid Build Coastguard Worker return zlib.compress(data, level=compresslevel, wbits=31) 587*cda5da8dSAndroid Build Coastguard Worker header = _create_simple_gzip_header(compresslevel, mtime) 588*cda5da8dSAndroid Build Coastguard Worker trailer = struct.pack("<LL", zlib.crc32(data), (len(data) & 0xffffffff)) 589*cda5da8dSAndroid Build Coastguard Worker # Wbits=-15 creates a raw deflate block. 590*cda5da8dSAndroid Build Coastguard Worker return (header + zlib.compress(data, level=compresslevel, wbits=-15) + 591*cda5da8dSAndroid Build Coastguard Worker trailer) 592*cda5da8dSAndroid Build Coastguard Worker 593*cda5da8dSAndroid Build Coastguard Worker 594*cda5da8dSAndroid Build Coastguard Workerdef decompress(data): 595*cda5da8dSAndroid Build Coastguard Worker """Decompress a gzip compressed string in one shot. 596*cda5da8dSAndroid Build Coastguard Worker Return the decompressed string. 597*cda5da8dSAndroid Build Coastguard Worker """ 598*cda5da8dSAndroid Build Coastguard Worker decompressed_members = [] 599*cda5da8dSAndroid Build Coastguard Worker while True: 600*cda5da8dSAndroid Build Coastguard Worker fp = io.BytesIO(data) 601*cda5da8dSAndroid Build Coastguard Worker if _read_gzip_header(fp) is None: 602*cda5da8dSAndroid Build Coastguard Worker return b"".join(decompressed_members) 603*cda5da8dSAndroid Build Coastguard Worker # Use a zlib raw deflate compressor 604*cda5da8dSAndroid Build Coastguard Worker do = zlib.decompressobj(wbits=-zlib.MAX_WBITS) 605*cda5da8dSAndroid Build Coastguard Worker # Read all the data except the header 606*cda5da8dSAndroid Build Coastguard Worker decompressed = do.decompress(data[fp.tell():]) 607*cda5da8dSAndroid Build Coastguard Worker if not do.eof or len(do.unused_data) < 8: 608*cda5da8dSAndroid Build Coastguard Worker raise EOFError("Compressed file ended before the end-of-stream " 609*cda5da8dSAndroid Build Coastguard Worker "marker was reached") 610*cda5da8dSAndroid Build Coastguard Worker crc, length = struct.unpack("<II", do.unused_data[:8]) 611*cda5da8dSAndroid Build Coastguard Worker if crc != zlib.crc32(decompressed): 612*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile("CRC check failed") 613*cda5da8dSAndroid Build Coastguard Worker if length != (len(decompressed) & 0xffffffff): 614*cda5da8dSAndroid Build Coastguard Worker raise BadGzipFile("Incorrect length of data produced") 615*cda5da8dSAndroid Build Coastguard Worker decompressed_members.append(decompressed) 616*cda5da8dSAndroid Build Coastguard Worker data = do.unused_data[8:].lstrip(b"\x00") 617*cda5da8dSAndroid Build Coastguard Worker 618*cda5da8dSAndroid Build Coastguard Worker 619*cda5da8dSAndroid Build Coastguard Workerdef main(): 620*cda5da8dSAndroid Build Coastguard Worker from argparse import ArgumentParser 621*cda5da8dSAndroid Build Coastguard Worker parser = ArgumentParser(description= 622*cda5da8dSAndroid Build Coastguard Worker "A simple command line interface for the gzip module: act like gzip, " 623*cda5da8dSAndroid Build Coastguard Worker "but do not delete the input file.") 624*cda5da8dSAndroid Build Coastguard Worker group = parser.add_mutually_exclusive_group() 625*cda5da8dSAndroid Build Coastguard Worker group.add_argument('--fast', action='store_true', help='compress faster') 626*cda5da8dSAndroid Build Coastguard Worker group.add_argument('--best', action='store_true', help='compress better') 627*cda5da8dSAndroid Build Coastguard Worker group.add_argument("-d", "--decompress", action="store_true", 628*cda5da8dSAndroid Build Coastguard Worker help="act like gunzip instead of gzip") 629*cda5da8dSAndroid Build Coastguard Worker 630*cda5da8dSAndroid Build Coastguard Worker parser.add_argument("args", nargs="*", default=["-"], metavar='file') 631*cda5da8dSAndroid Build Coastguard Worker args = parser.parse_args() 632*cda5da8dSAndroid Build Coastguard Worker 633*cda5da8dSAndroid Build Coastguard Worker compresslevel = _COMPRESS_LEVEL_TRADEOFF 634*cda5da8dSAndroid Build Coastguard Worker if args.fast: 635*cda5da8dSAndroid Build Coastguard Worker compresslevel = _COMPRESS_LEVEL_FAST 636*cda5da8dSAndroid Build Coastguard Worker elif args.best: 637*cda5da8dSAndroid Build Coastguard Worker compresslevel = _COMPRESS_LEVEL_BEST 638*cda5da8dSAndroid Build Coastguard Worker 639*cda5da8dSAndroid Build Coastguard Worker for arg in args.args: 640*cda5da8dSAndroid Build Coastguard Worker if args.decompress: 641*cda5da8dSAndroid Build Coastguard Worker if arg == "-": 642*cda5da8dSAndroid Build Coastguard Worker f = GzipFile(filename="", mode="rb", fileobj=sys.stdin.buffer) 643*cda5da8dSAndroid Build Coastguard Worker g = sys.stdout.buffer 644*cda5da8dSAndroid Build Coastguard Worker else: 645*cda5da8dSAndroid Build Coastguard Worker if arg[-3:] != ".gz": 646*cda5da8dSAndroid Build Coastguard Worker sys.exit(f"filename doesn't end in .gz: {arg!r}") 647*cda5da8dSAndroid Build Coastguard Worker f = open(arg, "rb") 648*cda5da8dSAndroid Build Coastguard Worker g = builtins.open(arg[:-3], "wb") 649*cda5da8dSAndroid Build Coastguard Worker else: 650*cda5da8dSAndroid Build Coastguard Worker if arg == "-": 651*cda5da8dSAndroid Build Coastguard Worker f = sys.stdin.buffer 652*cda5da8dSAndroid Build Coastguard Worker g = GzipFile(filename="", mode="wb", fileobj=sys.stdout.buffer, 653*cda5da8dSAndroid Build Coastguard Worker compresslevel=compresslevel) 654*cda5da8dSAndroid Build Coastguard Worker else: 655*cda5da8dSAndroid Build Coastguard Worker f = builtins.open(arg, "rb") 656*cda5da8dSAndroid Build Coastguard Worker g = open(arg + ".gz", "wb") 657*cda5da8dSAndroid Build Coastguard Worker while True: 658*cda5da8dSAndroid Build Coastguard Worker chunk = f.read(io.DEFAULT_BUFFER_SIZE) 659*cda5da8dSAndroid Build Coastguard Worker if not chunk: 660*cda5da8dSAndroid Build Coastguard Worker break 661*cda5da8dSAndroid Build Coastguard Worker g.write(chunk) 662*cda5da8dSAndroid Build Coastguard Worker if g is not sys.stdout.buffer: 663*cda5da8dSAndroid Build Coastguard Worker g.close() 664*cda5da8dSAndroid Build Coastguard Worker if f is not sys.stdin.buffer: 665*cda5da8dSAndroid Build Coastguard Worker f.close() 666*cda5da8dSAndroid Build Coastguard Worker 667*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__': 668*cda5da8dSAndroid Build Coastguard Worker main() 669