Example #1
0
func TestEncode(t *testing.T) {
	// Prepare data
	// x := []int{1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}
	contents, err := ioutil.ReadFile("gettysburg.txt")
	if err != nil {
		t.Fatalf("%v", err)
	}
	x := []int{}
	for _, bt := range contents {
		for i := uint(0); i < 8; i++ {
			x = append(x, int(bt)&(1<<i)>>i)
		}
	}

	// Encode
	src := make(chan int)
	go func() {
		for _, b := range x {
			src <- b
		}
		close(src)
	}()

	encoded := []int{}
	dst := make(chan int)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for b := range dst {
			encoded = append(encoded, b)
		}
	}()

	witten.Encode(dst, src, NewCTW(make([]int, 48)))
	wg.Wait()
	t.Logf("encoded bits: %d, original bits: %d", len(encoded), len(x))

	// Decode
	dsrc := make(chan int)
	go func() {
		for i := range encoded {
			dsrc <- encoded[i]
		}
		close(dsrc)
	}()

	decoded := []int{}
	ddst := make(chan int)
	wg = sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		for b := range ddst {
			decoded = append(decoded, b)
		}
	}()

	if err := witten.Decode(ddst, dsrc, NewCTW(make([]int, 48)), int64(len(x))); err != nil {
		t.Fatalf("%v", err)
	}
	wg.Wait()

	// Check that the decoded result is correct.
	if len(x) != len(decoded) {
		t.Fatalf("%d != %d", len(x), len(decoded))
	}
	for i, b := range x {
		if decoded[i] != b {
			t.Errorf("%d: %d != %d", i, b, decoded[i])
		}
	}
}
Example #2
0
File: cmd.go Project: fumin/ctw
// Decompress decompress a compressed stream of bytes generated by Compress.
// Decompress reads the compressed bytes from r, and writes the decompressed result to w.
// Decompress expects the same Context Tree Weighting depth used in Compress.
func Decompress(w io.Writer, r io.Reader, depth int) error {
	var numBytes int64
	err := binary.Read(r, binary.BigEndian, &numBytes)
	if err != nil {
		return err
	}

	// Read bits from r and send them to the decoder through the src channel.
	// Errors during reading are surfaced through the errc channel.
	// Since the last byte might contain superfluous bits not belonging to the encoded result (there is no reason why the number of encoded bits should be multipies of 8),
	// we need a stopReader channel to avoid the reader goroutine from blocking indefinitely..
	src := make(chan int)
	srcErrc := make(chan error, 1)
	stopReader := make(chan struct{}, 1)
	go func() {
		defer close(src)
		srcErrc <- func() error {
			scanner := bufio.NewScanner(r)
			scanner.Split(bufio.ScanBytes)
			for scanner.Scan() {
				var bt byte = scanner.Bytes()[0]
				for i := uint(0); i < 8; i++ {
					select {
					case src <- ((int(bt) & (1 << i)) >> i):
					case <-stopReader:
						return nil
					}
				}
			}
			if err := scanner.Err(); err != nil {
				return err
			}
			return nil
		}()
	}()

	// Collect decoded bits and write them out as bytes.
	// Upon completion or error, signal the reader goroutine to terminate via the stopReader channel.
	dst := make(chan int)
	dstErrc := make(chan error, 1)
	go func() {
		dstErrc <- func() error {
			defer func() { stopReader <- struct{}{} }()
			buf := []byte{0}
			var bt *byte = &buf[0]
			var i uint = 0
			for b := range dst {
				if b == 1 {
					*bt |= (1 << i)
				}
				i += 1

				if i == 8 {
					if _, err := w.Write(buf); err != nil {
						return err
					}
					*bt = 0
					i = 0
				}
			}
			if i > 0 {
				if _, err := w.Write(buf); err != nil {
					return err
				}
			}
			return nil
		}()
	}()

	model := NewCTW(make([]int, depth))
	decodeErr := witten.Decode(dst, src, model, numBytes*8)

	if err := <-srcErrc; err != nil {
		return err
	}
	if err := <-dstErrc; err != nil {
		return err
	}
	if decodeErr != nil {
		return decodeErr
	}
	return nil
}