summaryrefslogtreecommitdiff
path: root/vendor/github.com/rs/xid/id.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/rs/xid/id.go')
-rw-r--r--vendor/github.com/rs/xid/id.go107
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.