diff --git a/buffer.go b/buffer.go new file mode 100644 index 0000000..d42f19d --- /dev/null +++ b/buffer.go @@ -0,0 +1,66 @@ +package meowlib + +import ( + "errors" + "strconv" +) + +func min(a, b int) int { + if a <= b { + return a + } + return b +} + +func BufferSplit(buffer []byte, parts uint8) (packets [][]byte, err error) { + if int(parts) > len(buffer) { + return nil, errors.New("too many parts(" + strconv.Itoa(int(parts)) + ") for buffer len(" + strconv.Itoa(len(buffer)) + ")") + } + chunksize := int(len(buffer)/int(parts)) + 1 + packets = make([][]byte, parts) + for c := 0; c < int(parts); c++ { + if c == 0 { + packets[c] = []byte{byte(c), byte(parts)} + } else { + packets[c] = []byte{byte(c)} + } + } + chunk := 0 + for i := 0; i < len(buffer); i += chunksize { + batch := buffer[i:min(i+chunksize, len(buffer))] + packets[chunk] = append(packets[chunk], batch...) + chunk++ + } + return packets, nil +} + +func BufferMerge(packets [][]byte) (buffer []byte, err error) { + var parts int + found := false + buffer = []byte{} + for _, b := range packets { + if b[0] == 0 { + parts = int(b[1]) + buffer = append(buffer, b[2:]...) + found = true + break + } + } + if !found { + return nil, errors.New("start packet not found") + } + for i := 1; i < parts; i++ { + found = false + for _, b := range packets { + if b[0] == byte(i) { + buffer = append(buffer, b[1:]...) + found = true + break + } + } + if !found { + return nil, errors.New("packet #" + strconv.Itoa(i) + " not found") + } + } + return buffer, nil +} diff --git a/buffer_test.go b/buffer_test.go new file mode 100644 index 0000000..c1aa516 --- /dev/null +++ b/buffer_test.go @@ -0,0 +1,24 @@ +package meowlib + +import ( + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBufferSplit(t *testing.T) { + + source := []byte("Hello World, I need to slice you, but in equal parts, not the capitalist way") + packets, err := BufferSplit(source, 3) + if err != nil { + log.Fatalln("Failed to encode address book:", err) + } + println(len(packets)) + destination, err := BufferMerge(packets) + if err != nil { + log.Fatalln("Failed to encode address book:", err) + } + println(string(destination)) + assert.Equal(t, source, destination, "The two buffers should be the same.") +} diff --git a/contactcard.go b/contactcard.go index 129bf72..7615a9b 100644 --- a/contactcard.go +++ b/contactcard.go @@ -43,17 +43,53 @@ func (contact *ContactCard) Compress() ([]byte, error) { return nil, err } var b bytes.Buffer - gz := gzip.NewWriter(&b) + gz, err := gzip.NewWriterLevel(&b, gzip.BestCompression) + if err != nil { + return nil, err + } if _, err := gz.Write(out); err != nil { - log.Fatal(err) + return nil, err } if err := gz.Close(); err != nil { - log.Fatal(err) + return nil, err } fmt.Println(b.Bytes()) return b.Bytes(), nil } +func (contact *ContactCard) Split(parts uint8) (packets [][]byte, err error) { + data, err := contact.Compress() + if err != nil { + return nil, err + } + return BufferSplit(data, parts) +} + +func NewContactCardFromCompressed(compressed []byte) (*ContactCard, error) { + cc := &ContactCard{} + reader := bytes.NewReader([]byte(compressed)) + gzreader, err := gzip.NewReader(reader) + if err != nil { + return nil, err + } + output, err := ioutil.ReadAll(gzreader) + if err != nil { + return nil, err + } + if err := proto.Unmarshal(output, cc); err != nil { + return nil, err + } + return cc, nil +} + +func NewContactCardFromSplit(packets [][]byte) (*ContactCard, error) { + data, err := BufferMerge(packets) + if err != nil { + return nil, err + } + return NewContactCardFromCompressed(data) +} + func (contact *ContactCard) WriteCompressed(filename string) error { out, err := contact.Compress() if err != nil {