OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / multiformats / go-multihash / opts / opts.go
1 // Package opts helps to write commands which may take multihash
2 // options.
3 package opts
4
5 import (
6         "bytes"
7         "errors"
8         "flag"
9         "fmt"
10         "io"
11         "io/ioutil"
12         "sort"
13         "strings"
14
15         mh "github.com/multiformats/go-multihash"
16 )
17
18 // package errors
19 var (
20         ErrMatch = errors.New("multihash checksums did not match")
21 )
22
23 // Options is a struct used to parse cli flags.
24 type Options struct {
25         Encoding      string
26         Algorithm     string
27         AlgorithmCode uint64
28         Length        int
29
30         fs *flag.FlagSet
31 }
32
33 // FlagValues are the values the various option flags can take.
34 var FlagValues = struct {
35         Encodings  []string
36         Algorithms []string
37 }{
38         Encodings: []string{"raw", "hex", "base58", "base64"},
39         Algorithms: func() []string {
40                 names := make([]string, 0, len(mh.Names))
41                 for n := range mh.Names {
42                         // There are too many of these for now.
43                         // We can figure something better out later.
44                         if strings.HasPrefix(n, "blake2") {
45                                 switch n {
46                                 case "blake2s-256":
47                                 case "blake2b-128":
48                                 case "blake2b-224":
49                                 case "blake2b-256":
50                                 case "blake2b-384":
51                                 case "blake2b-512":
52                                 default:
53                                         continue
54                                 }
55                         }
56                         names = append(names, n)
57                 }
58                 sort.Strings(names)
59                 return names
60         }(),
61 }
62
63 // SetupFlags adds multihash related options to given flagset.
64 func SetupFlags(f *flag.FlagSet) *Options {
65         // TODO: add arg for adding opt prefix and/or overriding opts
66
67         o := new(Options)
68         algoStr := "one of: " + strings.Join(FlagValues.Algorithms, ", ")
69         f.StringVar(&o.Algorithm, "algorithm", "sha2-256", algoStr)
70         f.StringVar(&o.Algorithm, "a", "sha2-256", algoStr+" (shorthand)")
71
72         encStr := "one of: " + strings.Join(FlagValues.Encodings, ", ")
73         f.StringVar(&o.Encoding, "encoding", "base58", encStr)
74         f.StringVar(&o.Encoding, "e", "base58", encStr+" (shorthand)")
75
76         lengthStr := "checksums length in bits (truncate). -1 is default"
77         f.IntVar(&o.Length, "length", -1, lengthStr)
78         f.IntVar(&o.Length, "l", -1, lengthStr+" (shorthand)")
79         return o
80 }
81
82 // Parse parses the values of flags from given argument slice.
83 // It is equivalent to flags.Parse(args)
84 func (o *Options) Parse(args []string) error {
85         if err := o.fs.Parse(args); err != nil {
86                 return err
87         }
88         return o.ParseError()
89 }
90
91 // ParseError checks the parsed options for errors.
92 func (o *Options) ParseError() error {
93         if !strIn(o.Encoding, FlagValues.Encodings) {
94                 return fmt.Errorf("encoding '%s' not %s", o.Encoding, FlagValues.Encodings)
95         }
96
97         if !strIn(o.Algorithm, FlagValues.Algorithms) {
98                 return fmt.Errorf("algorithm '%s' not %s", o.Algorithm, FlagValues.Algorithms)
99         }
100
101         var found bool
102         o.AlgorithmCode, found = mh.Names[o.Algorithm]
103         if !found {
104                 return fmt.Errorf("algorithm '%s' not found (lib error, pls report).", o.Algorithm)
105         }
106
107         if o.Length >= 0 {
108                 if o.Length%8 != 0 {
109                         return fmt.Errorf("length must be multiple of 8")
110                 }
111                 o.Length = o.Length / 8
112
113                 if o.Length > mh.DefaultLengths[o.AlgorithmCode] {
114                         o.Length = mh.DefaultLengths[o.AlgorithmCode]
115                 }
116         }
117         return nil
118 }
119
120 // strIn checks wither string a is in set.
121 func strIn(a string, set []string) bool {
122         for _, s := range set {
123                 if s == a {
124                         return true
125                 }
126         }
127         return false
128 }
129
130 // Check reads all the data in r, calculates its multihash,
131 // and checks it matches h1
132 func (o *Options) Check(r io.Reader, h1 mh.Multihash) error {
133         h2, err := o.Multihash(r)
134         if err != nil {
135                 return err
136         }
137
138         if !bytes.Equal(h1, h2) {
139                 return fmt.Errorf("computed checksum did not match")
140         }
141
142         return nil
143 }
144
145 // Multihash reads all the data in r and calculates its multihash.
146 func (o *Options) Multihash(r io.Reader) (mh.Multihash, error) {
147         b, err := ioutil.ReadAll(r)
148         if err != nil {
149                 return nil, err
150         }
151
152         return mh.Sum(b, o.AlgorithmCode, o.Length)
153 }