github.com/linuxboot/fiano@v1.2.0/pkg/compression/systemlzma.go (about) 1 // Copyright 2018 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package compression 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "os/exec" 11 ) 12 13 // SystemLZMA implements Compression and calls out to the system's compressor 14 // (except for Decode which uses the Go-based decompressor). The sytem's 15 // compressor is typically faster and generates smaller files than the Go-based 16 // implementation. 17 type SystemLZMA struct { 18 xzPath string 19 } 20 21 // Name returns the type of compression employed. 22 func (c *SystemLZMA) Name() string { 23 return "LZMA" 24 } 25 26 // Decode decodes a byte slice of LZMA data. 27 func (c *SystemLZMA) Decode(encodedData []byte) ([]byte, error) { 28 // When the xz command compresses, it stores an End-Of-Stream (EOS) 29 // marker at the end and 0xFFFFFFFFFFFFFFFF in the header. EDK2's 30 // decompressor is primitive and will try to allocate 31 // 0xFFFFFFFFFFFFFFFF bytes and fail. So, the Encode function writes 32 // the size in the header which works for EDK2's tool. Unfortunately, 33 // xz considers an lzma file which has both a valid size and EOS corrupt, 34 // but will still decompress it and return exit status 1 (false 35 // positive). We simply use the Go decompressor despite being slow. 36 return (&LZMA{}).Decode(encodedData) 37 } 38 39 // Encode encodes a byte slice with LZMA. 40 func (c *SystemLZMA) Encode(decodedData []byte) ([]byte, error) { 41 cmd := exec.Command(c.xzPath, "--format=lzma", "-7", "--stdout") 42 cmd.Stdin = bytes.NewBuffer(decodedData) 43 encodedData, err := cmd.Output() 44 if err != nil { 45 return nil, err 46 } 47 48 // Quoting the XZ Utils manpage: 49 // 50 // xz supports decompressing .lzma files with or without 51 // end-of-payload marker, but all .lzma files created by xz will 52 // use end-of-payload marker and have uncompressed size marked as 53 // unknown in the .lzma header. This may be a problem in some 54 // uncommon situations. For example, a .lzma decompressor in an 55 // embedded device might work only with files that have known 56 // uncompressed size. 57 // 58 // This also affects some UEFI implementations, so the size must be 59 // written to the header. 60 buf := &bytes.Buffer{} 61 if err := binary.Write(buf, binary.LittleEndian, uint64(len(decodedData))); err != nil { 62 return nil, err 63 } 64 copy(encodedData[5:5+8], buf.Bytes()) 65 return encodedData, nil 66 }