github.com/safing/portbase@v0.19.5/formats/dsd/compression.go (about)

     1  package dsd
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"errors"
     7  
     8  	"github.com/safing/portbase/formats/varint"
     9  )
    10  
    11  // DumpAndCompress stores the interface as a dsd formatted data structure and compresses the resulting data.
    12  func DumpAndCompress(t interface{}, format uint8, compression uint8) ([]byte, error) {
    13  	// Check if compression format is valid.
    14  	compression, ok := ValidateCompressionFormat(compression)
    15  	if !ok {
    16  		return nil, ErrIncompatibleFormat
    17  	}
    18  
    19  	// Dump the given data with the given format.
    20  	data, err := Dump(t, format)
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	// prepare writer
    26  	packetFormat := varint.Pack8(compression)
    27  	buf := bytes.NewBuffer(nil)
    28  	buf.Write(packetFormat)
    29  
    30  	// compress
    31  	switch compression {
    32  	case GZIP:
    33  		// create gzip writer
    34  		gzipWriter, err := gzip.NewWriterLevel(buf, gzip.BestCompression)
    35  		if err != nil {
    36  			return nil, err
    37  		}
    38  
    39  		// write data
    40  		n, err := gzipWriter.Write(data)
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  		if n != len(data) {
    45  			return nil, errors.New("failed to fully write to gzip compressor")
    46  		}
    47  
    48  		// flush and write gzip footer
    49  		err = gzipWriter.Close()
    50  		if err != nil {
    51  			return nil, err
    52  		}
    53  	default:
    54  		return nil, ErrIncompatibleFormat
    55  	}
    56  
    57  	return buf.Bytes(), nil
    58  }
    59  
    60  // DecompressAndLoad decompresses the data using the specified compression format and then loads the resulting data blob into the interface.
    61  func DecompressAndLoad(data []byte, compression uint8, t interface{}) (format uint8, err error) {
    62  	// Check if compression format is valid.
    63  	_, ok := ValidateCompressionFormat(compression)
    64  	if !ok {
    65  		return 0, ErrIncompatibleFormat
    66  	}
    67  
    68  	// prepare reader
    69  	buf := bytes.NewBuffer(nil)
    70  
    71  	// decompress
    72  	switch compression {
    73  	case GZIP:
    74  		// create gzip reader
    75  		gzipReader, err := gzip.NewReader(bytes.NewBuffer(data))
    76  		if err != nil {
    77  			return 0, err
    78  		}
    79  
    80  		// read uncompressed data
    81  		_, err = buf.ReadFrom(gzipReader)
    82  		if err != nil {
    83  			return 0, err
    84  		}
    85  
    86  		// flush and verify gzip footer
    87  		err = gzipReader.Close()
    88  		if err != nil {
    89  			return 0, err
    90  		}
    91  	default:
    92  		return 0, ErrIncompatibleFormat
    93  	}
    94  
    95  	// assign decompressed data
    96  	data = buf.Bytes()
    97  
    98  	format, read, err := loadFormat(data)
    99  	if err != nil {
   100  		return 0, err
   101  	}
   102  	return format, LoadAsFormat(data[read:], format, t)
   103  }