parse.go 2.23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
package chunk

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)

Kejie Zhang's avatar
Kejie Zhang committed
11 12 13 14
var (
	ErrRabinMin = errors.New("rabin min must be greater than 16")
	ErrSize     = errors.New("chunker size muster greater than 0")
)
Kejie Zhang's avatar
Kejie Zhang committed
15

16
// FromString returns a Splitter depending on the given string:
Jakub Sztandera's avatar
Jakub Sztandera committed
17 18
// it supports "default" (""), "size-{size}", "rabin", "rabin-{blocksize}",
// "rabin-{min}-{avg}-{max}" and "buzhash".
19 20 21
func FromString(r io.Reader, chunker string) (Splitter, error) {
	switch {
	case chunker == "" || chunker == "default":
22
		return DefaultSplitter(r), nil
23 24 25 26 27 28

	case strings.HasPrefix(chunker, "size-"):
		sizeStr := strings.Split(chunker, "-")[1]
		size, err := strconv.Atoi(sizeStr)
		if err != nil {
			return nil, err
Kejie Zhang's avatar
Kejie Zhang committed
29 30
		} else if size <= 0 {
			return nil, ErrSize
31 32 33 34 35 36
		}
		return NewSizeSplitter(r, int64(size)), nil

	case strings.HasPrefix(chunker, "rabin"):
		return parseRabinString(r, chunker)

Jakub Sztandera's avatar
Jakub Sztandera committed
37 38 39
	case chunker == "buzhash":
		return NewBuzhash(r), nil

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
	default:
		return nil, fmt.Errorf("unrecognized chunker option: %s", chunker)
	}
}

func parseRabinString(r io.Reader, chunker string) (Splitter, error) {
	parts := strings.Split(chunker, "-")
	switch len(parts) {
	case 1:
		return NewRabin(r, uint64(DefaultBlockSize)), nil
	case 2:
		size, err := strconv.Atoi(parts[1])
		if err != nil {
			return nil, err
		}
		return NewRabin(r, uint64(size)), nil
	case 4:
		sub := strings.Split(parts[1], ":")
		if len(sub) > 1 && sub[0] != "min" {
			return nil, errors.New("first label must be min")
		}
		min, err := strconv.Atoi(sub[len(sub)-1])
Kejie Zhang's avatar
Kejie Zhang committed
62
		if err != nil {
63 64
			return nil, err
		}
65
		if min < 16 {
Kejie Zhang's avatar
Kejie Zhang committed
66
			return nil, ErrRabinMin
67
		}
68 69
		sub = strings.Split(parts[2], ":")
		if len(sub) > 1 && sub[0] != "avg" {
Kejie Zhang's avatar
Kejie Zhang committed
70
			log.Error("sub == ", sub)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
			return nil, errors.New("second label must be avg")
		}
		avg, err := strconv.Atoi(sub[len(sub)-1])
		if err != nil {
			return nil, err
		}

		sub = strings.Split(parts[3], ":")
		if len(sub) > 1 && sub[0] != "max" {
			return nil, errors.New("final label must be max")
		}
		max, err := strconv.Atoi(sub[len(sub)-1])
		if err != nil {
			return nil, err
		}

		return NewRabinMinMax(r, uint64(min), uint64(avg), uint64(max)), nil
	default:
		return nil, errors.New("incorrect format (expected 'rabin' 'rabin-[avg]' or 'rabin-[min]-[avg]-[max]'")
	}
}