// Copyright 2017 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package cryptobyteimport ()// A Builder builds byte strings from fixed-length and length-prefixed values.// Builders either allocate space as needed, or are ‘fixed’, which means that// they write into a given buffer and produce an error if it's exhausted.//// The zero value is a usable Builder that allocates space as needed.//// Simple values are marshaled and appended to a Builder using methods on the// Builder. Length-prefixed values are marshaled by providing a// BuilderContinuation, which is a function that writes the inner contents of// the value to a given Builder. See the documentation for BuilderContinuation// for details.typeBuilderstruct {errerrorresult []bytefixedSizeboolchild *BuilderoffsetintpendingLenLenintpendingIsASN1boolinContinuation *bool}// NewBuilder creates a Builder that appends its output to the given buffer.// Like append(), the slice will be reallocated if its capacity is exceeded.// Use Bytes to get the final buffer.func ( []byte) *Builder {return &Builder{result: , }}// NewFixedBuilder creates a Builder that appends its output into the given// buffer. This builder does not reallocate the output buffer. Writes that// would exceed the buffer's capacity are treated as an error.func ( []byte) *Builder {return &Builder{result: ,fixedSize: true, }}// SetError sets the value to be returned as the error from Bytes. Writes// performed after calling SetError are ignored.func ( *Builder) ( error) { .err = }// Bytes returns the bytes written by the builder or an error if one has// occurred during building.func ( *Builder) () ([]byte, error) {if .err != nil {returnnil, .err }return .result[.offset:], nil}// BytesOrPanic returns the bytes written by the builder or panics if an error// has occurred during building.func ( *Builder) () []byte {if .err != nil {panic(.err) }return .result[.offset:]}// AddUint8 appends an 8-bit value to the byte string.func ( *Builder) ( uint8) { .add(byte())}// AddUint16 appends a big-endian, 16-bit value to the byte string.func ( *Builder) ( uint16) { .add(byte(>>8), byte())}// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest// byte of the 32-bit input value is silently truncated.func ( *Builder) ( uint32) { .add(byte(>>16), byte(>>8), byte())}// AddUint32 appends a big-endian, 32-bit value to the byte string.func ( *Builder) ( uint32) { .add(byte(>>24), byte(>>16), byte(>>8), byte())}// AddUint64 appends a big-endian, 64-bit value to the byte string.func ( *Builder) ( uint64) { .add(byte(>>56), byte(>>48), byte(>>40), byte(>>32), byte(>>24), byte(>>16), byte(>>8), byte())}// AddBytes appends a sequence of bytes to the byte string.func ( *Builder) ( []byte) { .add(...)}// BuilderContinuation is a continuation-passing interface for building// length-prefixed byte sequences. Builder methods for length-prefixed// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation// supplied to them. The child builder passed to the continuation can be used// to build the content of the length-prefixed sequence. For example://// parent := cryptobyte.NewBuilder()// parent.AddUint8LengthPrefixed(func (child *Builder) {// child.AddUint8(42)// child.AddUint8LengthPrefixed(func (grandchild *Builder) {// grandchild.AddUint8(5)// })// })//// It is an error to write more bytes to the child than allowed by the reserved// length prefix. After the continuation returns, the child must be considered// invalid, i.e. users must not store any copies or references of the child// that outlive the continuation.//// If the continuation panics with a value of type BuildError then the inner// error will be returned as the error from Bytes. If the child panics// otherwise then Bytes will repanic with the same value.typeBuilderContinuationfunc(child *Builder)// BuildError wraps an error. If a BuilderContinuation panics with this value,// the panic will be recovered and the inner error will be returned from// Builder.Bytes.typeBuildErrorstruct {Errerror}// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.func ( *Builder) ( BuilderContinuation) { .addLengthPrefixed(1, false, )}// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.func ( *Builder) ( BuilderContinuation) { .addLengthPrefixed(2, false, )}// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.func ( *Builder) ( BuilderContinuation) { .addLengthPrefixed(3, false, )}// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.func ( *Builder) ( BuilderContinuation) { .addLengthPrefixed(4, false, )}func ( *Builder) ( BuilderContinuation, *Builder) {if !*.inContinuation { *.inContinuation = truedeferfunc() { *.inContinuation = false := recover()if == nil {return }if , := .(BuildError); { .err = .Err } else {panic() } }() } ()}func ( *Builder) ( int, bool, BuilderContinuation) {// Subsequent writes can be ignored if the builder has encountered an error.if .err != nil {return } := len(.result) .add(make([]byte, )...)if .inContinuation == nil { .inContinuation = new(bool) } .child = &Builder{result: .result,fixedSize: .fixedSize,offset: ,pendingLenLen: ,pendingIsASN1: ,inContinuation: .inContinuation, } .callContinuation(, .child) .flushChild()if .child != nil {panic("cryptobyte: internal error") }}func ( *Builder) () {if .child == nil {return } .child.() := .child .child = nilif .err != nil { .err = .errreturn } := len(.result) - .pendingLenLen - .offsetif < 0 {panic("cryptobyte: internal error") // result unexpectedly shrunk }if .pendingIsASN1 {// For ASN.1, we reserved a single byte for the length. If that turned out // to be incorrect, we have to move the contents along in order to make // space.if .pendingLenLen != 1 {panic("cryptobyte: internal error") }var , uint8ifint64() > 0xfffffffe { .err = errors.New("pending ASN.1 child too long")return } elseif > 0xffffff { = 5 = 0x80 | 4 } elseif > 0xffff { = 4 = 0x80 | 3 } elseif > 0xff { = 3 = 0x80 | 2 } elseif > 0x7f { = 2 = 0x80 | 1 } else { = 1 = uint8() = 0 }// Insert the initial length byte, make space for successive length bytes, // and adjust the offset. .result[.offset] = := int( - 1)if != 0 { .add(make([]byte, )...) := .offset + .pendingLenLencopy(.result[+:], .result[:]) } .offset++ .pendingLenLen = } := for := .pendingLenLen - 1; >= 0; -- { .result[.offset+] = uint8() >>= 8 }if != 0 { .err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", , .pendingLenLen)return }if .fixedSize && &.result[0] != &.result[0] {panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer") } .result = .result}func ( *Builder) ( ...byte) {if .err != nil {return }if .child != nil {panic("cryptobyte: attempted write while child is pending") }iflen(.result)+len() < len() { .err = errors.New("cryptobyte: length overflow") }if .fixedSize && len(.result)+len() > cap(.result) { .err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")return } .result = append(.result, ...)}// Unwrite rolls back non-negative n bytes written directly to the Builder.// An attempt by a child builder passed to a continuation to unwrite bytes// from its parent will panic.func ( *Builder) ( int) {if .err != nil {return }if .child != nil {panic("cryptobyte: attempted unwrite while child is pending") } := len(.result) - .pendingLenLen - .offsetif < 0 {panic("cryptobyte: internal error") }if < 0 {panic("cryptobyte: attempted to unwrite negative number of bytes") }if > {panic("cryptobyte: attempted to unwrite more than was written") } .result = .result[:len(.result)-]}// A MarshalingValue marshals itself into a Builder.typeMarshalingValueinterface {// Marshal is called by Builder.AddValue. It receives a pointer to a builder // to marshal itself into. It may return an error that occurred during // marshaling, such as unset or invalid values.Marshal(b *Builder) error}// AddValue calls Marshal on v, passing a pointer to the builder to append to.// If Marshal returns an error, it is set on the Builder so that subsequent// appends don't have an effect.func ( *Builder) ( MarshalingValue) { := .Marshal()if != nil { .err = }}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.