package dsd import ( "bytes" "compress/gzip" "errors" "github.com/safing/portbase/formats/varint" ) // DumpAndCompress stores the interface as a dsd formatted data structure and compresses the resulting data. func DumpAndCompress(t interface{}, format SerializationFormat, compression CompressionFormat) ([]byte, error) { // Check if compression format is valid. compression, ok := compression.ValidateCompressionFormat() if !ok { return nil, ErrIncompatibleFormat } // Dump the given data with the given format. data, err := Dump(t, format) if err != nil { return nil, err } // prepare writer packetFormat := varint.Pack8(uint8(compression)) buf := bytes.NewBuffer(nil) buf.Write(packetFormat) // compress switch compression { case GZIP: // create gzip writer gzipWriter, err := gzip.NewWriterLevel(buf, gzip.BestCompression) if err != nil { return nil, err } // write data n, err := gzipWriter.Write(data) if err != nil { return nil, err } if n != len(data) { return nil, errors.New("failed to fully write to gzip compressor") } // flush and write gzip footer err = gzipWriter.Close() if err != nil { return nil, err } default: return nil, ErrIncompatibleFormat } return buf.Bytes(), nil } // DecompressAndLoad decompresses the data using the specified compression format and then loads the resulting data blob into the interface. func DecompressAndLoad(data []byte, compression CompressionFormat, t interface{}) (format SerializationFormat, err error) { // Check if compression format is valid. compression, ok := compression.ValidateCompressionFormat() if !ok { return 0, ErrIncompatibleFormat } // prepare reader buf := bytes.NewBuffer(nil) // decompress switch compression { case GZIP: // create gzip reader gzipReader, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return 0, err } // read uncompressed data _, err = buf.ReadFrom(gzipReader) if err != nil { return 0, err } // flush and verify gzip footer err = gzipReader.Close() if err != nil { return 0, err } default: return 0, ErrIncompatibleFormat } // assign decompressed data data = buf.Bytes() formatID, read, err := loadFormat(data) if err != nil { return 0, err } format, ok = SerializationFormat(formatID).ValidateSerializationFormat() if !ok { return 0, ErrIncompatibleFormat } return format, LoadAsFormat(data[read:], format, t) }