diff options
Diffstat (limited to 'vendor/github.com/rs/xid/id.go')
-rw-r--r-- | vendor/github.com/rs/xid/id.go | 107 |
1 files changed, 67 insertions, 40 deletions
diff --git a/vendor/github.com/rs/xid/id.go b/vendor/github.com/rs/xid/id.go index 466faf262..1f536b415 100644 --- a/vendor/github.com/rs/xid/id.go +++ b/vendor/github.com/rs/xid/id.go @@ -47,7 +47,6 @@ import ( "crypto/rand" "database/sql/driver" "encoding/binary" - "errors" "fmt" "hash/crc32" "io/ioutil" @@ -55,6 +54,7 @@ import ( "sort" "sync/atomic" "time" + "unsafe" ) // Code inspired from mgo/bson ObjectId @@ -72,9 +72,6 @@ const ( ) var ( - // ErrInvalidID is returned when trying to unmarshal an invalid ID - ErrInvalidID = errors.New("xid: invalid ID") - // objectIDCounter is atomically incremented when generating a new ObjectId // using NewObjectId() function. It's used as a counter part of an id. // This id is initialized with a random value. @@ -177,7 +174,13 @@ func FromString(id string) (ID, error) { func (id ID) String() string { text := make([]byte, encodedLen) encode(text, id[:]) - return string(text) + return *(*string)(unsafe.Pointer(&text)) +} + +// Encode encodes the id using base32 encoding, writing 20 bytes to dst and return it. +func (id ID) Encode(dst []byte) []byte { + encode(dst, id[:]) + return dst } // MarshalText implements encoding/text TextMarshaler interface @@ -192,32 +195,37 @@ func (id ID) MarshalJSON() ([]byte, error) { if id.IsNil() { return []byte("null"), nil } - text, err := id.MarshalText() - return []byte(`"` + string(text) + `"`), err + text := make([]byte, encodedLen+2) + encode(text[1:encodedLen+1], id[:]) + text[0], text[encodedLen+1] = '"', '"' + return text, nil } // encode by unrolling the stdlib base32 algorithm + removing all safe checks func encode(dst, id []byte) { - dst[0] = encoding[id[0]>>3] - dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] - dst[2] = encoding[(id[1]>>1)&0x1F] - dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] - dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] - dst[5] = encoding[(id[3]>>2)&0x1F] - dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] - dst[7] = encoding[id[4]&0x1F] - dst[8] = encoding[id[5]>>3] - dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] - dst[10] = encoding[(id[6]>>1)&0x1F] - dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] - dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] - dst[13] = encoding[(id[8]>>2)&0x1F] - dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] - dst[15] = encoding[id[9]&0x1F] - dst[16] = encoding[id[10]>>3] - dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] - dst[18] = encoding[(id[11]>>1)&0x1F] + _ = dst[19] + _ = id[11] + dst[19] = encoding[(id[11]<<4)&0x1F] + dst[18] = encoding[(id[11]>>1)&0x1F] + dst[17] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] + dst[16] = encoding[id[10]>>3] + dst[15] = encoding[id[9]&0x1F] + dst[14] = encoding[(id[9]>>5)|(id[8]<<3)&0x1F] + dst[13] = encoding[(id[8]>>2)&0x1F] + dst[12] = encoding[id[8]>>7|(id[7]<<1)&0x1F] + dst[11] = encoding[(id[7]>>4)&0x1F|(id[6]<<4)&0x1F] + dst[10] = encoding[(id[6]>>1)&0x1F] + dst[9] = encoding[(id[6]>>6)&0x1F|(id[5]<<2)&0x1F] + dst[8] = encoding[id[5]>>3] + dst[7] = encoding[id[4]&0x1F] + dst[6] = encoding[id[4]>>5|(id[3]<<3)&0x1F] + dst[5] = encoding[(id[3]>>2)&0x1F] + dst[4] = encoding[id[3]>>7|(id[2]<<1)&0x1F] + dst[3] = encoding[(id[2]>>4)&0x1F|(id[1]<<4)&0x1F] + dst[2] = encoding[(id[1]>>1)&0x1F] + dst[1] = encoding[(id[1]>>6)&0x1F|(id[0]<<2)&0x1F] + dst[0] = encoding[id[0]>>3] } // UnmarshalText implements encoding/text TextUnmarshaler interface @@ -230,7 +238,9 @@ func (id *ID) UnmarshalText(text []byte) error { return ErrInvalidID } } - decode(id, text) + if !decode(id, text) { + return ErrInvalidID + } return nil } @@ -241,23 +251,40 @@ func (id *ID) UnmarshalJSON(b []byte) error { *id = nilID return nil } + // Check the slice length to prevent panic on passing it to UnmarshalText() + if len(b) < 2 { + return ErrInvalidID + } return id.UnmarshalText(b[1 : len(b)-1]) } -// decode by unrolling the stdlib base32 algorithm + removing all safe checks -func decode(id *ID, src []byte) { - id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 - id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 - id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 - id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 - id[4] = dec[src[6]]<<5 | dec[src[7]] - id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 - id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 - id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 - id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 - id[9] = dec[src[14]]<<5 | dec[src[15]] - id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 +// decode by unrolling the stdlib base32 algorithm + customized safe check. +func decode(id *ID, src []byte) bool { + _ = src[19] + _ = id[11] + id[11] = dec[src[17]]<<6 | dec[src[18]]<<1 | dec[src[19]]>>4 + id[10] = dec[src[16]]<<3 | dec[src[17]]>>2 + id[9] = dec[src[14]]<<5 | dec[src[15]] + id[8] = dec[src[12]]<<7 | dec[src[13]]<<2 | dec[src[14]]>>3 + id[7] = dec[src[11]]<<4 | dec[src[12]]>>1 + id[6] = dec[src[9]]<<6 | dec[src[10]]<<1 | dec[src[11]]>>4 + id[5] = dec[src[8]]<<3 | dec[src[9]]>>2 + id[4] = dec[src[6]]<<5 | dec[src[7]] + id[3] = dec[src[4]]<<7 | dec[src[5]]<<2 | dec[src[6]]>>3 + id[2] = dec[src[3]]<<4 | dec[src[4]]>>1 + id[1] = dec[src[1]]<<6 | dec[src[2]]<<1 | dec[src[3]]>>4 + id[0] = dec[src[0]]<<3 | dec[src[1]]>>2 + + // Validate that there are no discarer bits (padding) in src that would + // cause the string-encoded id not to equal src. + var check [4]byte + + check[3] = encoding[(id[11]<<4)&0x1F] + check[2] = encoding[(id[11]>>1)&0x1F] + check[1] = encoding[(id[11]>>6)&0x1F|(id[10]<<2)&0x1F] + check[0] = encoding[id[10]>>3] + return bytes.Equal([]byte(src[16:20]), check[:]) } // Time returns the timestamp part of the id. |