xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/lzma.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Interface to the liblzma compression library.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerThis module provides a class for reading and writing compressed files,
4*cda5da8dSAndroid Build Coastguard Workerclasses for incremental (de)compression, and convenience functions for
5*cda5da8dSAndroid Build Coastguard Workerone-shot (de)compression.
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard WorkerThese classes and functions support both the XZ and legacy LZMA
8*cda5da8dSAndroid Build Coastguard Workercontainer formats, as well as raw compressed data streams.
9*cda5da8dSAndroid Build Coastguard Worker"""
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker__all__ = [
12*cda5da8dSAndroid Build Coastguard Worker    "CHECK_NONE", "CHECK_CRC32", "CHECK_CRC64", "CHECK_SHA256",
13*cda5da8dSAndroid Build Coastguard Worker    "CHECK_ID_MAX", "CHECK_UNKNOWN",
14*cda5da8dSAndroid Build Coastguard Worker    "FILTER_LZMA1", "FILTER_LZMA2", "FILTER_DELTA", "FILTER_X86", "FILTER_IA64",
15*cda5da8dSAndroid Build Coastguard Worker    "FILTER_ARM", "FILTER_ARMTHUMB", "FILTER_POWERPC", "FILTER_SPARC",
16*cda5da8dSAndroid Build Coastguard Worker    "FORMAT_AUTO", "FORMAT_XZ", "FORMAT_ALONE", "FORMAT_RAW",
17*cda5da8dSAndroid Build Coastguard Worker    "MF_HC3", "MF_HC4", "MF_BT2", "MF_BT3", "MF_BT4",
18*cda5da8dSAndroid Build Coastguard Worker    "MODE_FAST", "MODE_NORMAL", "PRESET_DEFAULT", "PRESET_EXTREME",
19*cda5da8dSAndroid Build Coastguard Worker
20*cda5da8dSAndroid Build Coastguard Worker    "LZMACompressor", "LZMADecompressor", "LZMAFile", "LZMAError",
21*cda5da8dSAndroid Build Coastguard Worker    "open", "compress", "decompress", "is_check_supported",
22*cda5da8dSAndroid Build Coastguard Worker]
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Workerimport builtins
25*cda5da8dSAndroid Build Coastguard Workerimport io
26*cda5da8dSAndroid Build Coastguard Workerimport os
27*cda5da8dSAndroid Build Coastguard Workerfrom _lzma import *
28*cda5da8dSAndroid Build Coastguard Workerfrom _lzma import _encode_filter_properties, _decode_filter_properties
29*cda5da8dSAndroid Build Coastguard Workerimport _compression
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker_MODE_CLOSED   = 0
33*cda5da8dSAndroid Build Coastguard Worker_MODE_READ     = 1
34*cda5da8dSAndroid Build Coastguard Worker# Value 2 no longer used
35*cda5da8dSAndroid Build Coastguard Worker_MODE_WRITE    = 3
36*cda5da8dSAndroid Build Coastguard Worker
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Workerclass LZMAFile(_compression.BaseStream):
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker    """A file object providing transparent LZMA (de)compression.
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Worker    An LZMAFile can act as a wrapper for an existing file object, or
43*cda5da8dSAndroid Build Coastguard Worker    refer directly to a named file on disk.
44*cda5da8dSAndroid Build Coastguard Worker
45*cda5da8dSAndroid Build Coastguard Worker    Note that LZMAFile provides a *binary* file interface - data read
46*cda5da8dSAndroid Build Coastguard Worker    is returned as bytes, and data to be written must be given as bytes.
47*cda5da8dSAndroid Build Coastguard Worker    """
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, filename=None, mode="r", *,
50*cda5da8dSAndroid Build Coastguard Worker                 format=None, check=-1, preset=None, filters=None):
51*cda5da8dSAndroid Build Coastguard Worker        """Open an LZMA-compressed file in binary mode.
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker        filename can be either an actual file name (given as a str,
54*cda5da8dSAndroid Build Coastguard Worker        bytes, or PathLike object), in which case the named file is
55*cda5da8dSAndroid Build Coastguard Worker        opened, or it can be an existing file object to read from or
56*cda5da8dSAndroid Build Coastguard Worker        write to.
57*cda5da8dSAndroid Build Coastguard Worker
58*cda5da8dSAndroid Build Coastguard Worker        mode can be "r" for reading (default), "w" for (over)writing,
59*cda5da8dSAndroid Build Coastguard Worker        "x" for creating exclusively, or "a" for appending. These can
60*cda5da8dSAndroid Build Coastguard Worker        equivalently be given as "rb", "wb", "xb" and "ab" respectively.
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Worker        format specifies the container format to use for the file.
63*cda5da8dSAndroid Build Coastguard Worker        If mode is "r", this defaults to FORMAT_AUTO. Otherwise, the
64*cda5da8dSAndroid Build Coastguard Worker        default is FORMAT_XZ.
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Worker        check specifies the integrity check to use. This argument can
67*cda5da8dSAndroid Build Coastguard Worker        only be used when opening a file for writing. For FORMAT_XZ,
68*cda5da8dSAndroid Build Coastguard Worker        the default is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not
69*cda5da8dSAndroid Build Coastguard Worker        support integrity checks - for these formats, check must be
70*cda5da8dSAndroid Build Coastguard Worker        omitted, or be CHECK_NONE.
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker        When opening a file for reading, the *preset* argument is not
73*cda5da8dSAndroid Build Coastguard Worker        meaningful, and should be omitted. The *filters* argument should
74*cda5da8dSAndroid Build Coastguard Worker        also be omitted, except when format is FORMAT_RAW (in which case
75*cda5da8dSAndroid Build Coastguard Worker        it is required).
76*cda5da8dSAndroid Build Coastguard Worker
77*cda5da8dSAndroid Build Coastguard Worker        When opening a file for writing, the settings used by the
78*cda5da8dSAndroid Build Coastguard Worker        compressor can be specified either as a preset compression
79*cda5da8dSAndroid Build Coastguard Worker        level (with the *preset* argument), or in detail as a custom
80*cda5da8dSAndroid Build Coastguard Worker        filter chain (with the *filters* argument). For FORMAT_XZ and
81*cda5da8dSAndroid Build Coastguard Worker        FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset
82*cda5da8dSAndroid Build Coastguard Worker        level. For FORMAT_RAW, the caller must always specify a filter
83*cda5da8dSAndroid Build Coastguard Worker        chain; the raw compressor does not support preset compression
84*cda5da8dSAndroid Build Coastguard Worker        levels.
85*cda5da8dSAndroid Build Coastguard Worker
86*cda5da8dSAndroid Build Coastguard Worker        preset (if provided) should be an integer in the range 0-9,
87*cda5da8dSAndroid Build Coastguard Worker        optionally OR-ed with the constant PRESET_EXTREME.
88*cda5da8dSAndroid Build Coastguard Worker
89*cda5da8dSAndroid Build Coastguard Worker        filters (if provided) should be a sequence of dicts. Each dict
90*cda5da8dSAndroid Build Coastguard Worker        should have an entry for "id" indicating ID of the filter, plus
91*cda5da8dSAndroid Build Coastguard Worker        additional entries for options to the filter.
92*cda5da8dSAndroid Build Coastguard Worker        """
93*cda5da8dSAndroid Build Coastguard Worker        self._fp = None
94*cda5da8dSAndroid Build Coastguard Worker        self._closefp = False
95*cda5da8dSAndroid Build Coastguard Worker        self._mode = _MODE_CLOSED
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker        if mode in ("r", "rb"):
98*cda5da8dSAndroid Build Coastguard Worker            if check != -1:
99*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("Cannot specify an integrity check "
100*cda5da8dSAndroid Build Coastguard Worker                                 "when opening a file for reading")
101*cda5da8dSAndroid Build Coastguard Worker            if preset is not None:
102*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("Cannot specify a preset compression "
103*cda5da8dSAndroid Build Coastguard Worker                                 "level when opening a file for reading")
104*cda5da8dSAndroid Build Coastguard Worker            if format is None:
105*cda5da8dSAndroid Build Coastguard Worker                format = FORMAT_AUTO
106*cda5da8dSAndroid Build Coastguard Worker            mode_code = _MODE_READ
107*cda5da8dSAndroid Build Coastguard Worker        elif mode in ("w", "wb", "a", "ab", "x", "xb"):
108*cda5da8dSAndroid Build Coastguard Worker            if format is None:
109*cda5da8dSAndroid Build Coastguard Worker                format = FORMAT_XZ
110*cda5da8dSAndroid Build Coastguard Worker            mode_code = _MODE_WRITE
111*cda5da8dSAndroid Build Coastguard Worker            self._compressor = LZMACompressor(format=format, check=check,
112*cda5da8dSAndroid Build Coastguard Worker                                              preset=preset, filters=filters)
113*cda5da8dSAndroid Build Coastguard Worker            self._pos = 0
114*cda5da8dSAndroid Build Coastguard Worker        else:
115*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Invalid mode: {!r}".format(mode))
116*cda5da8dSAndroid Build Coastguard Worker
117*cda5da8dSAndroid Build Coastguard Worker        if isinstance(filename, (str, bytes, os.PathLike)):
118*cda5da8dSAndroid Build Coastguard Worker            if "b" not in mode:
119*cda5da8dSAndroid Build Coastguard Worker                mode += "b"
120*cda5da8dSAndroid Build Coastguard Worker            self._fp = builtins.open(filename, mode)
121*cda5da8dSAndroid Build Coastguard Worker            self._closefp = True
122*cda5da8dSAndroid Build Coastguard Worker            self._mode = mode_code
123*cda5da8dSAndroid Build Coastguard Worker        elif hasattr(filename, "read") or hasattr(filename, "write"):
124*cda5da8dSAndroid Build Coastguard Worker            self._fp = filename
125*cda5da8dSAndroid Build Coastguard Worker            self._mode = mode_code
126*cda5da8dSAndroid Build Coastguard Worker        else:
127*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("filename must be a str, bytes, file or PathLike object")
128*cda5da8dSAndroid Build Coastguard Worker
129*cda5da8dSAndroid Build Coastguard Worker        if self._mode == _MODE_READ:
130*cda5da8dSAndroid Build Coastguard Worker            raw = _compression.DecompressReader(self._fp, LZMADecompressor,
131*cda5da8dSAndroid Build Coastguard Worker                trailing_error=LZMAError, format=format, filters=filters)
132*cda5da8dSAndroid Build Coastguard Worker            self._buffer = io.BufferedReader(raw)
133*cda5da8dSAndroid Build Coastguard Worker
134*cda5da8dSAndroid Build Coastguard Worker    def close(self):
135*cda5da8dSAndroid Build Coastguard Worker        """Flush and close the file.
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker        May be called more than once without error. Once the file is
138*cda5da8dSAndroid Build Coastguard Worker        closed, any other operation on it will raise a ValueError.
139*cda5da8dSAndroid Build Coastguard Worker        """
140*cda5da8dSAndroid Build Coastguard Worker        if self._mode == _MODE_CLOSED:
141*cda5da8dSAndroid Build Coastguard Worker            return
142*cda5da8dSAndroid Build Coastguard Worker        try:
143*cda5da8dSAndroid Build Coastguard Worker            if self._mode == _MODE_READ:
144*cda5da8dSAndroid Build Coastguard Worker                self._buffer.close()
145*cda5da8dSAndroid Build Coastguard Worker                self._buffer = None
146*cda5da8dSAndroid Build Coastguard Worker            elif self._mode == _MODE_WRITE:
147*cda5da8dSAndroid Build Coastguard Worker                self._fp.write(self._compressor.flush())
148*cda5da8dSAndroid Build Coastguard Worker                self._compressor = None
149*cda5da8dSAndroid Build Coastguard Worker        finally:
150*cda5da8dSAndroid Build Coastguard Worker            try:
151*cda5da8dSAndroid Build Coastguard Worker                if self._closefp:
152*cda5da8dSAndroid Build Coastguard Worker                    self._fp.close()
153*cda5da8dSAndroid Build Coastguard Worker            finally:
154*cda5da8dSAndroid Build Coastguard Worker                self._fp = None
155*cda5da8dSAndroid Build Coastguard Worker                self._closefp = False
156*cda5da8dSAndroid Build Coastguard Worker                self._mode = _MODE_CLOSED
157*cda5da8dSAndroid Build Coastguard Worker
158*cda5da8dSAndroid Build Coastguard Worker    @property
159*cda5da8dSAndroid Build Coastguard Worker    def closed(self):
160*cda5da8dSAndroid Build Coastguard Worker        """True if this file is closed."""
161*cda5da8dSAndroid Build Coastguard Worker        return self._mode == _MODE_CLOSED
162*cda5da8dSAndroid Build Coastguard Worker
163*cda5da8dSAndroid Build Coastguard Worker    def fileno(self):
164*cda5da8dSAndroid Build Coastguard Worker        """Return the file descriptor for the underlying file."""
165*cda5da8dSAndroid Build Coastguard Worker        self._check_not_closed()
166*cda5da8dSAndroid Build Coastguard Worker        return self._fp.fileno()
167*cda5da8dSAndroid Build Coastguard Worker
168*cda5da8dSAndroid Build Coastguard Worker    def seekable(self):
169*cda5da8dSAndroid Build Coastguard Worker        """Return whether the file supports seeking."""
170*cda5da8dSAndroid Build Coastguard Worker        return self.readable() and self._buffer.seekable()
171*cda5da8dSAndroid Build Coastguard Worker
172*cda5da8dSAndroid Build Coastguard Worker    def readable(self):
173*cda5da8dSAndroid Build Coastguard Worker        """Return whether the file was opened for reading."""
174*cda5da8dSAndroid Build Coastguard Worker        self._check_not_closed()
175*cda5da8dSAndroid Build Coastguard Worker        return self._mode == _MODE_READ
176*cda5da8dSAndroid Build Coastguard Worker
177*cda5da8dSAndroid Build Coastguard Worker    def writable(self):
178*cda5da8dSAndroid Build Coastguard Worker        """Return whether the file was opened for writing."""
179*cda5da8dSAndroid Build Coastguard Worker        self._check_not_closed()
180*cda5da8dSAndroid Build Coastguard Worker        return self._mode == _MODE_WRITE
181*cda5da8dSAndroid Build Coastguard Worker
182*cda5da8dSAndroid Build Coastguard Worker    def peek(self, size=-1):
183*cda5da8dSAndroid Build Coastguard Worker        """Return buffered data without advancing the file position.
184*cda5da8dSAndroid Build Coastguard Worker
185*cda5da8dSAndroid Build Coastguard Worker        Always returns at least one byte of data, unless at EOF.
186*cda5da8dSAndroid Build Coastguard Worker        The exact number of bytes returned is unspecified.
187*cda5da8dSAndroid Build Coastguard Worker        """
188*cda5da8dSAndroid Build Coastguard Worker        self._check_can_read()
189*cda5da8dSAndroid Build Coastguard Worker        # Relies on the undocumented fact that BufferedReader.peek() always
190*cda5da8dSAndroid Build Coastguard Worker        # returns at least one byte (except at EOF)
191*cda5da8dSAndroid Build Coastguard Worker        return self._buffer.peek(size)
192*cda5da8dSAndroid Build Coastguard Worker
193*cda5da8dSAndroid Build Coastguard Worker    def read(self, size=-1):
194*cda5da8dSAndroid Build Coastguard Worker        """Read up to size uncompressed bytes from the file.
195*cda5da8dSAndroid Build Coastguard Worker
196*cda5da8dSAndroid Build Coastguard Worker        If size is negative or omitted, read until EOF is reached.
197*cda5da8dSAndroid Build Coastguard Worker        Returns b"" if the file is already at EOF.
198*cda5da8dSAndroid Build Coastguard Worker        """
199*cda5da8dSAndroid Build Coastguard Worker        self._check_can_read()
200*cda5da8dSAndroid Build Coastguard Worker        return self._buffer.read(size)
201*cda5da8dSAndroid Build Coastguard Worker
202*cda5da8dSAndroid Build Coastguard Worker    def read1(self, size=-1):
203*cda5da8dSAndroid Build Coastguard Worker        """Read up to size uncompressed bytes, while trying to avoid
204*cda5da8dSAndroid Build Coastguard Worker        making multiple reads from the underlying stream. Reads up to a
205*cda5da8dSAndroid Build Coastguard Worker        buffer's worth of data if size is negative.
206*cda5da8dSAndroid Build Coastguard Worker
207*cda5da8dSAndroid Build Coastguard Worker        Returns b"" if the file is at EOF.
208*cda5da8dSAndroid Build Coastguard Worker        """
209*cda5da8dSAndroid Build Coastguard Worker        self._check_can_read()
210*cda5da8dSAndroid Build Coastguard Worker        if size < 0:
211*cda5da8dSAndroid Build Coastguard Worker            size = io.DEFAULT_BUFFER_SIZE
212*cda5da8dSAndroid Build Coastguard Worker        return self._buffer.read1(size)
213*cda5da8dSAndroid Build Coastguard Worker
214*cda5da8dSAndroid Build Coastguard Worker    def readline(self, size=-1):
215*cda5da8dSAndroid Build Coastguard Worker        """Read a line of uncompressed bytes from the file.
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Worker        The terminating newline (if present) is retained. If size is
218*cda5da8dSAndroid Build Coastguard Worker        non-negative, no more than size bytes will be read (in which
219*cda5da8dSAndroid Build Coastguard Worker        case the line may be incomplete). Returns b'' if already at EOF.
220*cda5da8dSAndroid Build Coastguard Worker        """
221*cda5da8dSAndroid Build Coastguard Worker        self._check_can_read()
222*cda5da8dSAndroid Build Coastguard Worker        return self._buffer.readline(size)
223*cda5da8dSAndroid Build Coastguard Worker
224*cda5da8dSAndroid Build Coastguard Worker    def write(self, data):
225*cda5da8dSAndroid Build Coastguard Worker        """Write a bytes object to the file.
226*cda5da8dSAndroid Build Coastguard Worker
227*cda5da8dSAndroid Build Coastguard Worker        Returns the number of uncompressed bytes written, which is
228*cda5da8dSAndroid Build Coastguard Worker        always the length of data in bytes. Note that due to buffering,
229*cda5da8dSAndroid Build Coastguard Worker        the file on disk may not reflect the data written until close()
230*cda5da8dSAndroid Build Coastguard Worker        is called.
231*cda5da8dSAndroid Build Coastguard Worker        """
232*cda5da8dSAndroid Build Coastguard Worker        self._check_can_write()
233*cda5da8dSAndroid Build Coastguard Worker        if isinstance(data, (bytes, bytearray)):
234*cda5da8dSAndroid Build Coastguard Worker            length = len(data)
235*cda5da8dSAndroid Build Coastguard Worker        else:
236*cda5da8dSAndroid Build Coastguard Worker            # accept any data that supports the buffer protocol
237*cda5da8dSAndroid Build Coastguard Worker            data = memoryview(data)
238*cda5da8dSAndroid Build Coastguard Worker            length = data.nbytes
239*cda5da8dSAndroid Build Coastguard Worker
240*cda5da8dSAndroid Build Coastguard Worker        compressed = self._compressor.compress(data)
241*cda5da8dSAndroid Build Coastguard Worker        self._fp.write(compressed)
242*cda5da8dSAndroid Build Coastguard Worker        self._pos += length
243*cda5da8dSAndroid Build Coastguard Worker        return length
244*cda5da8dSAndroid Build Coastguard Worker
245*cda5da8dSAndroid Build Coastguard Worker    def seek(self, offset, whence=io.SEEK_SET):
246*cda5da8dSAndroid Build Coastguard Worker        """Change the file position.
247*cda5da8dSAndroid Build Coastguard Worker
248*cda5da8dSAndroid Build Coastguard Worker        The new position is specified by offset, relative to the
249*cda5da8dSAndroid Build Coastguard Worker        position indicated by whence. Possible values for whence are:
250*cda5da8dSAndroid Build Coastguard Worker
251*cda5da8dSAndroid Build Coastguard Worker            0: start of stream (default): offset must not be negative
252*cda5da8dSAndroid Build Coastguard Worker            1: current stream position
253*cda5da8dSAndroid Build Coastguard Worker            2: end of stream; offset must not be positive
254*cda5da8dSAndroid Build Coastguard Worker
255*cda5da8dSAndroid Build Coastguard Worker        Returns the new file position.
256*cda5da8dSAndroid Build Coastguard Worker
257*cda5da8dSAndroid Build Coastguard Worker        Note that seeking is emulated, so depending on the parameters,
258*cda5da8dSAndroid Build Coastguard Worker        this operation may be extremely slow.
259*cda5da8dSAndroid Build Coastguard Worker        """
260*cda5da8dSAndroid Build Coastguard Worker        self._check_can_seek()
261*cda5da8dSAndroid Build Coastguard Worker        return self._buffer.seek(offset, whence)
262*cda5da8dSAndroid Build Coastguard Worker
263*cda5da8dSAndroid Build Coastguard Worker    def tell(self):
264*cda5da8dSAndroid Build Coastguard Worker        """Return the current file position."""
265*cda5da8dSAndroid Build Coastguard Worker        self._check_not_closed()
266*cda5da8dSAndroid Build Coastguard Worker        if self._mode == _MODE_READ:
267*cda5da8dSAndroid Build Coastguard Worker            return self._buffer.tell()
268*cda5da8dSAndroid Build Coastguard Worker        return self._pos
269*cda5da8dSAndroid Build Coastguard Worker
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Workerdef open(filename, mode="rb", *,
272*cda5da8dSAndroid Build Coastguard Worker         format=None, check=-1, preset=None, filters=None,
273*cda5da8dSAndroid Build Coastguard Worker         encoding=None, errors=None, newline=None):
274*cda5da8dSAndroid Build Coastguard Worker    """Open an LZMA-compressed file in binary or text mode.
275*cda5da8dSAndroid Build Coastguard Worker
276*cda5da8dSAndroid Build Coastguard Worker    filename can be either an actual file name (given as a str, bytes,
277*cda5da8dSAndroid Build Coastguard Worker    or PathLike object), in which case the named file is opened, or it
278*cda5da8dSAndroid Build Coastguard Worker    can be an existing file object to read from or write to.
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker    The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb",
281*cda5da8dSAndroid Build Coastguard Worker    "a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text
282*cda5da8dSAndroid Build Coastguard Worker    mode.
283*cda5da8dSAndroid Build Coastguard Worker
284*cda5da8dSAndroid Build Coastguard Worker    The format, check, preset and filters arguments specify the
285*cda5da8dSAndroid Build Coastguard Worker    compression settings, as for LZMACompressor, LZMADecompressor and
286*cda5da8dSAndroid Build Coastguard Worker    LZMAFile.
287*cda5da8dSAndroid Build Coastguard Worker
288*cda5da8dSAndroid Build Coastguard Worker    For binary mode, this function is equivalent to the LZMAFile
289*cda5da8dSAndroid Build Coastguard Worker    constructor: LZMAFile(filename, mode, ...). In this case, the
290*cda5da8dSAndroid Build Coastguard Worker    encoding, errors and newline arguments must not be provided.
291*cda5da8dSAndroid Build Coastguard Worker
292*cda5da8dSAndroid Build Coastguard Worker    For text mode, an LZMAFile object is created, and wrapped in an
293*cda5da8dSAndroid Build Coastguard Worker    io.TextIOWrapper instance with the specified encoding, error
294*cda5da8dSAndroid Build Coastguard Worker    handling behavior, and line ending(s).
295*cda5da8dSAndroid Build Coastguard Worker
296*cda5da8dSAndroid Build Coastguard Worker    """
297*cda5da8dSAndroid Build Coastguard Worker    if "t" in mode:
298*cda5da8dSAndroid Build Coastguard Worker        if "b" in mode:
299*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Invalid mode: %r" % (mode,))
300*cda5da8dSAndroid Build Coastguard Worker    else:
301*cda5da8dSAndroid Build Coastguard Worker        if encoding is not None:
302*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Argument 'encoding' not supported in binary mode")
303*cda5da8dSAndroid Build Coastguard Worker        if errors is not None:
304*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Argument 'errors' not supported in binary mode")
305*cda5da8dSAndroid Build Coastguard Worker        if newline is not None:
306*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Argument 'newline' not supported in binary mode")
307*cda5da8dSAndroid Build Coastguard Worker
308*cda5da8dSAndroid Build Coastguard Worker    lz_mode = mode.replace("t", "")
309*cda5da8dSAndroid Build Coastguard Worker    binary_file = LZMAFile(filename, lz_mode, format=format, check=check,
310*cda5da8dSAndroid Build Coastguard Worker                           preset=preset, filters=filters)
311*cda5da8dSAndroid Build Coastguard Worker
312*cda5da8dSAndroid Build Coastguard Worker    if "t" in mode:
313*cda5da8dSAndroid Build Coastguard Worker        encoding = io.text_encoding(encoding)
314*cda5da8dSAndroid Build Coastguard Worker        return io.TextIOWrapper(binary_file, encoding, errors, newline)
315*cda5da8dSAndroid Build Coastguard Worker    else:
316*cda5da8dSAndroid Build Coastguard Worker        return binary_file
317*cda5da8dSAndroid Build Coastguard Worker
318*cda5da8dSAndroid Build Coastguard Worker
319*cda5da8dSAndroid Build Coastguard Workerdef compress(data, format=FORMAT_XZ, check=-1, preset=None, filters=None):
320*cda5da8dSAndroid Build Coastguard Worker    """Compress a block of data.
321*cda5da8dSAndroid Build Coastguard Worker
322*cda5da8dSAndroid Build Coastguard Worker    Refer to LZMACompressor's docstring for a description of the
323*cda5da8dSAndroid Build Coastguard Worker    optional arguments *format*, *check*, *preset* and *filters*.
324*cda5da8dSAndroid Build Coastguard Worker
325*cda5da8dSAndroid Build Coastguard Worker    For incremental compression, use an LZMACompressor instead.
326*cda5da8dSAndroid Build Coastguard Worker    """
327*cda5da8dSAndroid Build Coastguard Worker    comp = LZMACompressor(format, check, preset, filters)
328*cda5da8dSAndroid Build Coastguard Worker    return comp.compress(data) + comp.flush()
329*cda5da8dSAndroid Build Coastguard Worker
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Workerdef decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None):
332*cda5da8dSAndroid Build Coastguard Worker    """Decompress a block of data.
333*cda5da8dSAndroid Build Coastguard Worker
334*cda5da8dSAndroid Build Coastguard Worker    Refer to LZMADecompressor's docstring for a description of the
335*cda5da8dSAndroid Build Coastguard Worker    optional arguments *format*, *check* and *filters*.
336*cda5da8dSAndroid Build Coastguard Worker
337*cda5da8dSAndroid Build Coastguard Worker    For incremental decompression, use an LZMADecompressor instead.
338*cda5da8dSAndroid Build Coastguard Worker    """
339*cda5da8dSAndroid Build Coastguard Worker    results = []
340*cda5da8dSAndroid Build Coastguard Worker    while True:
341*cda5da8dSAndroid Build Coastguard Worker        decomp = LZMADecompressor(format, memlimit, filters)
342*cda5da8dSAndroid Build Coastguard Worker        try:
343*cda5da8dSAndroid Build Coastguard Worker            res = decomp.decompress(data)
344*cda5da8dSAndroid Build Coastguard Worker        except LZMAError:
345*cda5da8dSAndroid Build Coastguard Worker            if results:
346*cda5da8dSAndroid Build Coastguard Worker                break  # Leftover data is not a valid LZMA/XZ stream; ignore it.
347*cda5da8dSAndroid Build Coastguard Worker            else:
348*cda5da8dSAndroid Build Coastguard Worker                raise  # Error on the first iteration; bail out.
349*cda5da8dSAndroid Build Coastguard Worker        results.append(res)
350*cda5da8dSAndroid Build Coastguard Worker        if not decomp.eof:
351*cda5da8dSAndroid Build Coastguard Worker            raise LZMAError("Compressed data ended before the "
352*cda5da8dSAndroid Build Coastguard Worker                            "end-of-stream marker was reached")
353*cda5da8dSAndroid Build Coastguard Worker        data = decomp.unused_data
354*cda5da8dSAndroid Build Coastguard Worker        if not data:
355*cda5da8dSAndroid Build Coastguard Worker            break
356*cda5da8dSAndroid Build Coastguard Worker    return b"".join(results)
357