blob: 2f78bab9bbbf9e74cf244ca14d0711f53a67bc17 [file] [log] [blame]
Simon Glass3ac7d832022-01-09 20:14:03 -07001# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2022 Google LLC
3#
4"""Utilities to compress and decompress data"""
5
6import struct
7import tempfile
8
Simon Glass9203c162022-01-09 20:14:06 -07009from binman import bintool
Simon Glass3ac7d832022-01-09 20:14:03 -070010from patman import tools
11
Simon Glass9203c162022-01-09 20:14:06 -070012LZ4 = bintool.Bintool.create('lz4')
13HAVE_LZ4 = LZ4.is_present()
14
Simon Glass84b0c222022-01-09 20:14:08 -070015LZMA_ALONE = bintool.Bintool.create('lzma_alone')
16HAVE_LZMA_ALONE = LZMA_ALONE.is_present()
17
Simon Glass9203c162022-01-09 20:14:06 -070018
Simon Glassdd5c14ec2022-01-09 20:14:04 -070019def compress(indata, algo, with_header=True):
Simon Glass3ac7d832022-01-09 20:14:03 -070020 """Compress some data using a given algorithm
21
22 Note that for lzma this uses an old version of the algorithm, not that
23 provided by xz.
24
25 This requires 'lz4' and 'lzma_alone' tools. It also requires an output
26 directory to be previously set up, by calling PrepareOutputDir().
27
28 Care is taken to use unique temporary files so that this function can be
29 called from multiple threads.
30
31 Args:
Simon Glassdd5c14ec2022-01-09 20:14:04 -070032 indata (bytes): Input data to compress
33 algo (str): Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
Simon Glass3ac7d832022-01-09 20:14:03 -070034
35 Returns:
Simon Glassdd5c14ec2022-01-09 20:14:04 -070036 bytes: Compressed data
Simon Glass3ac7d832022-01-09 20:14:03 -070037 """
38 if algo == 'none':
39 return indata
40 fname = tempfile.NamedTemporaryFile(prefix='%s.comp.tmp' % algo,
41 dir=tools.GetOutputDir()).name
42 tools.WriteFile(fname, indata)
43 if algo == 'lz4':
Simon Glass9203c162022-01-09 20:14:06 -070044 data = LZ4.compress(indata)
Simon Glass3ac7d832022-01-09 20:14:03 -070045 # cbfstool uses a very old version of lzma
46 elif algo == 'lzma':
Simon Glass84b0c222022-01-09 20:14:08 -070047 data = LZMA_ALONE.compress(indata)
Simon Glass3ac7d832022-01-09 20:14:03 -070048 elif algo == 'gzip':
49 data = tools.Run('gzip', '-c', fname, binary=True)
50 else:
51 raise ValueError("Unknown algorithm '%s'" % algo)
52 if with_header:
53 hdr = struct.pack('<I', len(data))
54 data = hdr + data
55 return data
56
Simon Glassdd5c14ec2022-01-09 20:14:04 -070057def decompress(indata, algo, with_header=True):
Simon Glass3ac7d832022-01-09 20:14:03 -070058 """Decompress some data using a given algorithm
59
60 Note that for lzma this uses an old version of the algorithm, not that
61 provided by xz.
62
63 This requires 'lz4' and 'lzma_alone' tools. It also requires an output
64 directory to be previously set up, by calling PrepareOutputDir().
65
66 Args:
Simon Glassdd5c14ec2022-01-09 20:14:04 -070067 indata (bytes): Input data to decompress
68 algo (str): Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
Simon Glass3ac7d832022-01-09 20:14:03 -070069
70 Returns:
Simon Glassdd5c14ec2022-01-09 20:14:04 -070071 (bytes) Compressed data
Simon Glass3ac7d832022-01-09 20:14:03 -070072 """
73 if algo == 'none':
74 return indata
75 if with_header:
76 data_len = struct.unpack('<I', indata[:4])[0]
77 indata = indata[4:4 + data_len]
78 fname = tools.GetOutputFilename('%s.decomp.tmp' % algo)
Simon Glassdd5c14ec2022-01-09 20:14:04 -070079 tools.WriteFile(fname, indata)
Simon Glass3ac7d832022-01-09 20:14:03 -070080 if algo == 'lz4':
Simon Glass9203c162022-01-09 20:14:06 -070081 data = LZ4.decompress(indata)
Simon Glass3ac7d832022-01-09 20:14:03 -070082 elif algo == 'lzma':
Simon Glass84b0c222022-01-09 20:14:08 -070083 data = LZMA_ALONE.decompress(indata)
Simon Glass3ac7d832022-01-09 20:14:03 -070084 elif algo == 'gzip':
85 data = tools.Run('gzip', '-cd', fname, binary=True)
86 else:
87 raise ValueError("Unknown algorithm '%s'" % algo)
88 return data