OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / cryptobyte / builder.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package cryptobyte
6
7 import (
8         "errors"
9         "fmt"
10 )
11
12 // A Builder builds byte strings from fixed-length and length-prefixed values.
13 // The zero value is a usable Builder that allocates space as needed.
14 type Builder struct {
15         err           error
16         result        []byte
17         fixedSize     bool
18         child         *Builder
19         offset        int
20         pendingLenLen int
21         pendingIsASN1 bool
22 }
23
24 // NewBuilder creates a Builder that appends its output to the given buffer.
25 // Like append(), the slice will be reallocated if its capacity is exceeded.
26 // Use Bytes to get the final buffer.
27 func NewBuilder(buffer []byte) *Builder {
28         return &Builder{
29                 result: buffer,
30         }
31 }
32
33 // NewFixedBuilder creates a Builder that appends its output into the given
34 // buffer. This builder does not reallocate the output buffer. Writes that
35 // would exceed the buffer's capacity are treated as an error.
36 func NewFixedBuilder(buffer []byte) *Builder {
37         return &Builder{
38                 result:    buffer,
39                 fixedSize: true,
40         }
41 }
42
43 // Bytes returns the bytes written by the builder or an error if one has
44 // occurred during during building.
45 func (b *Builder) Bytes() ([]byte, error) {
46         if b.err != nil {
47                 return nil, b.err
48         }
49         return b.result[b.offset:], nil
50 }
51
52 // BytesOrPanic returns the bytes written by the builder or panics if an error
53 // has occurred during building.
54 func (b *Builder) BytesOrPanic() []byte {
55         if b.err != nil {
56                 panic(b.err)
57         }
58         return b.result[b.offset:]
59 }
60
61 // AddUint8 appends an 8-bit value to the byte string.
62 func (b *Builder) AddUint8(v uint8) {
63         b.add(byte(v))
64 }
65
66 // AddUint16 appends a big-endian, 16-bit value to the byte string.
67 func (b *Builder) AddUint16(v uint16) {
68         b.add(byte(v>>8), byte(v))
69 }
70
71 // AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
72 // byte of the 32-bit input value is silently truncated.
73 func (b *Builder) AddUint24(v uint32) {
74         b.add(byte(v>>16), byte(v>>8), byte(v))
75 }
76
77 // AddUint32 appends a big-endian, 32-bit value to the byte string.
78 func (b *Builder) AddUint32(v uint32) {
79         b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
80 }
81
82 // AddBytes appends a sequence of bytes to the byte string.
83 func (b *Builder) AddBytes(v []byte) {
84         b.add(v...)
85 }
86
87 // BuilderContinuation is continuation-passing interface for building
88 // length-prefixed byte sequences. Builder methods for length-prefixed
89 // sequences (AddUint8LengthPrefixed etc.) will invoke the BuilderContinuation
90 // supplied to them. The child builder passed to the continuation can be used
91 // to build the content of the length-prefixed sequence. Example:
92 //
93 //   parent := cryptobyte.NewBuilder()
94 //   parent.AddUint8LengthPrefixed(func (child *Builder) {
95 //     child.AddUint8(42)
96 //     child.AddUint8LengthPrefixed(func (grandchild *Builder) {
97 //       grandchild.AddUint8(5)
98 //     })
99 //   })
100 //
101 // It is an error to write more bytes to the child than allowed by the reserved
102 // length prefix. After the continuation returns, the child must be considered
103 // invalid, i.e. users must not store any copies or references of the child
104 // that outlive the continuation.
105 type BuilderContinuation func(child *Builder)
106
107 // AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
108 func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
109         b.addLengthPrefixed(1, false, f)
110 }
111
112 // AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
113 func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
114         b.addLengthPrefixed(2, false, f)
115 }
116
117 // AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
118 func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
119         b.addLengthPrefixed(3, false, f)
120 }
121
122 func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
123         // Subsequent writes can be ignored if the builder has encountered an error.
124         if b.err != nil {
125                 return
126         }
127
128         offset := len(b.result)
129         b.add(make([]byte, lenLen)...)
130
131         b.child = &Builder{
132                 result:        b.result,
133                 fixedSize:     b.fixedSize,
134                 offset:        offset,
135                 pendingLenLen: lenLen,
136                 pendingIsASN1: isASN1,
137         }
138
139         f(b.child)
140         b.flushChild()
141         if b.child != nil {
142                 panic("cryptobyte: internal error")
143         }
144 }
145
146 func (b *Builder) flushChild() {
147         if b.child == nil {
148                 return
149         }
150         b.child.flushChild()
151         child := b.child
152         b.child = nil
153
154         if child.err != nil {
155                 b.err = child.err
156                 return
157         }
158
159         length := len(child.result) - child.pendingLenLen - child.offset
160
161         if length < 0 {
162                 panic("cryptobyte: internal error") // result unexpectedly shrunk
163         }
164
165         if child.pendingIsASN1 {
166                 // For ASN.1, we reserved a single byte for the length. If that turned out
167                 // to be incorrect, we have to move the contents along in order to make
168                 // space.
169                 if child.pendingLenLen != 1 {
170                         panic("cryptobyte: internal error")
171                 }
172                 var lenLen, lenByte uint8
173                 if int64(length) > 0xfffffffe {
174                         b.err = errors.New("pending ASN.1 child too long")
175                         return
176                 } else if length > 0xffffff {
177                         lenLen = 5
178                         lenByte = 0x80 | 4
179                 } else if length > 0xffff {
180                         lenLen = 4
181                         lenByte = 0x80 | 3
182                 } else if length > 0xff {
183                         lenLen = 3
184                         lenByte = 0x80 | 2
185                 } else if length > 0x7f {
186                         lenLen = 2
187                         lenByte = 0x80 | 1
188                 } else {
189                         lenLen = 1
190                         lenByte = uint8(length)
191                         length = 0
192                 }
193
194                 // Insert the initial length byte, make space for successive length bytes,
195                 // and adjust the offset.
196                 child.result[child.offset] = lenByte
197                 extraBytes := int(lenLen - 1)
198                 if extraBytes != 0 {
199                         child.add(make([]byte, extraBytes)...)
200                         childStart := child.offset + child.pendingLenLen
201                         copy(child.result[childStart+extraBytes:], child.result[childStart:])
202                 }
203                 child.offset++
204                 child.pendingLenLen = extraBytes
205         }
206
207         l := length
208         for i := child.pendingLenLen - 1; i >= 0; i-- {
209                 child.result[child.offset+i] = uint8(l)
210                 l >>= 8
211         }
212         if l != 0 {
213                 b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
214                 return
215         }
216
217         if !b.fixedSize {
218                 b.result = child.result // In case child reallocated result.
219         }
220 }
221
222 func (b *Builder) add(bytes ...byte) {
223         if b.err != nil {
224                 return
225         }
226         if b.child != nil {
227                 panic("attempted write while child is pending")
228         }
229         if len(b.result)+len(bytes) < len(bytes) {
230                 b.err = errors.New("cryptobyte: length overflow")
231         }
232         if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
233                 b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
234                 return
235         }
236         b.result = append(b.result, bytes...)
237 }
238
239 // A MarshalingValue marshals itself into a Builder.
240 type MarshalingValue interface {
241         // Marshal is called by Builder.AddValue. It receives a pointer to a builder
242         // to marshal itself into. It may return an error that occurred during
243         // marshaling, such as unset or invalid values.
244         Marshal(b *Builder) error
245 }
246
247 // AddValue calls Marshal on v, passing a pointer to the builder to append to.
248 // If Marshal returns an error, it is set on the Builder so that subsequent
249 // appends don't have an effect.
250 func (b *Builder) AddValue(v MarshalingValue) {
251         err := v.Marshal(b)
252         if err != nil {
253                 b.err = err
254         }
255 }